bitunion.hh revision 12453
1/*
2 * Copyright (c) 2007-2008 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Gabe Black
29 */
30
31#ifndef __BASE_BITUNION_HH__
32#define __BASE_BITUNION_HH__
33
34#include <iostream>
35#include <type_traits>
36
37#include "base/bitfield.hh"
38
39//      The following implements the BitUnion system of defining bitfields
40//on top of an underlying class. This is done through the pervasive use of
41//both named and unnamed unions which all contain the same actual storage.
42//Since they're unioned with each other, all of these storage locations
43//overlap. This allows all of the bitfields to manipulate the same data
44//without having to have access to each other. More details are provided with
45//the individual components.
46
47//This class wraps around another which defines getter/setter functions which
48//manipulate the underlying data. The type of the underlying data and the type
49//of the bitfield itself are inferred from the argument types of the setter
50//function.
51template<class Base>
52class BitfieldTypeImpl : public Base
53{
54    static_assert(std::is_empty<Base>::value,
55                  "Bitfield base class must be empty.");
56
57  private:
58    using Base::setter;
59
60    template<typename T>
61    struct TypeDeducer;
62
63    template<typename T>
64    friend class TypeDeducer;
65
66    template<typename Type1, typename Type2>
67    struct TypeDeducer<void (Base::*)(Type1 &, Type2)>
68    {
69        typedef Type1 Storage;
70        typedef Type2 Type;
71    };
72
73  protected:
74    typedef typename TypeDeducer<
75            decltype(&BitfieldTypeImpl<Base>::setter)>::Storage Storage;
76    typedef typename TypeDeducer<
77            decltype(&BitfieldTypeImpl<Base>::setter)>::Type Type;
78
79    Type getter(const Storage &storage) const = delete;
80    void setter(Storage &storage, Type val) = delete;
81
82    Storage __storage;
83
84    operator Type () const
85    {
86        return Base::getter(__storage);
87    }
88
89    Type
90    operator=(const Type val)
91    {
92        Base::setter(__storage, val);
93        return val;
94    }
95
96    Type
97    operator=(BitfieldTypeImpl<Base> const & other)
98    {
99        return *this = (Type)other;
100    }
101};
102
103//A wrapper for the above class which allows setting and getting.
104template<class Base>
105class BitfieldType : public BitfieldTypeImpl<Base>
106{
107  protected:
108    using Impl = BitfieldTypeImpl<Base>;
109    using typename Impl::Type;
110
111  public:
112    operator Type () const { return Impl::operator Type(); }
113    Type operator=(const Type val) { return Impl::operator=(val); }
114    Type
115    operator=(BitfieldType<Base> const & other)
116    {
117        return Impl::operator=(other);
118    }
119};
120
121//A wrapper which only supports getting.
122template<class Base>
123class BitfieldROType : public BitfieldTypeImpl<Base>
124{
125  public:
126    using Impl = BitfieldTypeImpl<Base>;
127    using typename Impl::Type;
128
129    Type operator=(BitfieldROType<Base> const &other) = delete;
130    operator Type () const { return Impl::operator Type(); }
131};
132
133//A wrapper which only supports setting.
134template <class Base>
135class BitfieldWOType : public BitfieldTypeImpl<Base>
136{
137  protected:
138    using Impl = BitfieldTypeImpl<Base>;
139    using typename Impl::Type;
140
141  public:
142    Type operator=(const Type val) { return Impl::operator=(val); }
143    Type
144    operator=(BitfieldWOType<Base> const & other)
145    {
146        return Impl::operator=(other);
147    }
148};
149
150//This namespace is for classes which implement the backend of the BitUnion
151//stuff. Don't use any of these directly.
152namespace BitfieldBackend
153{
154    template<class Storage, int first, int last>
155    class Unsigned
156    {
157        static_assert(first >= last,
158                      "Bitfield ranges must be specified as <msb, lsb>");
159
160      protected:
161        uint64_t
162        getter(const Storage &storage) const
163        {
164            return bits(storage, first, last);
165        }
166
167        void
168        setter(Storage &storage, uint64_t val)
169        {
170            replaceBits(storage, first, last, val);
171        }
172    };
173
174    template<class Storage, int first, int last>
175    class Signed
176    {
177        static_assert(first >= last,
178                      "Bitfield ranges must be specified as <msb, lsb>");
179
180      protected:
181        int64_t
182        getter(const Storage &storage) const
183        {
184            return sext<first - last + 1>(bits(storage, first, last));
185        }
186
187        void
188        setter(Storage &storage, int64_t val)
189        {
190            replaceBits(storage, first, last, val);
191        }
192    };
193
194    //This class contains the basic bitfield types which are automatically
195    //available within a BitUnion. They inherit their Storage type from the
196    //containing BitUnion.
197    template<class Storage>
198    class BitfieldTypes
199    {
200      protected:
201
202        template<int first, int last=first>
203        using Bitfield = BitfieldType<Unsigned<Storage, first, last> >;
204        template<int first, int last=first>
205        using BitfieldRO =
206                BitfieldROType<Unsigned<Storage, first, last> >;
207        template<int first, int last=first>
208        using BitfieldWO =
209                BitfieldWOType<Unsigned<Storage, first, last> >;
210
211        template<int first, int last=first>
212        using SignedBitfield =
213                BitfieldType<Signed<Storage, first, last> >;
214        template<int first, int last=first>
215        using SignedBitfieldRO =
216                BitfieldROType<Signed<Storage, first, last> >;
217        template<int first, int last=first>
218        using SignedBitfieldWO =
219                BitfieldWOType<Signed<Storage, first, last> >;
220    };
221
222    //When a BitUnion is set up, an underlying class is created which holds
223    //the actual union. This class then inherits from it, and provids the
224    //implementations for various operators. Setting things up this way
225    //prevents having to redefine these functions in every different BitUnion
226    //type. More operators could be implemented in the future, as the need
227    //arises.
228    template <class Base>
229    class BitUnionOperators : public Base
230    {
231        static_assert(sizeof(Base) == sizeof(typename Base::__StorageType),
232                      "BitUnion larger than its storage type.");
233
234      public:
235        BitUnionOperators(typename Base::__StorageType const &val)
236        {
237            Base::__storage = val;
238        }
239
240        BitUnionOperators() {}
241
242        operator const typename Base::__StorageType () const
243        {
244            return Base::__storage;
245        }
246
247        typename Base::__StorageType
248        operator=(typename Base::__StorageType const &val)
249        {
250            Base::__storage = val;
251            return val;
252        }
253
254        typename Base::__StorageType
255        operator=(BitUnionOperators const &other)
256        {
257            Base::__storage = other;
258            return Base::__storage;
259        }
260
261        bool
262        operator<(Base const &base) const
263        {
264            return Base::__storage < base.__storage;
265        }
266
267        bool
268        operator==(Base const &base) const
269        {
270            return Base::__storage == base.__storage;
271        }
272    };
273}
274
275//This macro is a backend for other macros that specialize it slightly.
276//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
277//sticks the class which has the actual union in it, which
278//BitfieldOperators above inherits from. Putting these classes in a special
279//namespace ensures that there will be no collisions with other names as long
280//as the BitUnion names themselves are all distinct and nothing else uses
281//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
282//creates a typedef of the "type" parameter called __StorageType. This allows
283//the type to propagate outside of the macro itself in a controlled way.
284//Finally, the base storage is defined which BitfieldOperators will refer to
285//in the operators it defines. This macro is intended to be followed by
286//bitfield definitions which will end up inside it's union. As explained
287//above, these is overlayed the __storage member in its entirety by each of the
288//bitfields which are defined in the union, creating shared storage with no
289//overhead.
290#define __BitUnion(type, name) \
291    class BitfieldUnderlyingClasses##name : \
292        public BitfieldBackend::BitfieldTypes<type> \
293    { \
294      public: \
295        typedef type __StorageType; \
296        union { \
297            type __storage;
298
299//This closes off the class and union started by the above macro. It is
300//followed by a typedef which makes "name" refer to a BitfieldOperator
301//class inheriting from the class and union just defined, which completes
302//building up the type for the user.
303#define EndBitUnion(name) \
304        }; \
305    }; \
306    typedef BitfieldBackend::BitUnionOperators< \
307        BitfieldUnderlyingClasses##name> name;
308
309//This sets up a bitfield which has other bitfields nested inside of it. The
310//__storage member functions like the "underlying storage" of the top level
311//BitUnion. Like everything else, it overlays with the top level storage, so
312//making it a regular bitfield type makes the entire thing function as a
313//regular bitfield when referred to by itself.
314#define __SubBitUnion(name, fieldType, ...) \
315    class \
316    { \
317      public: \
318        union { \
319            fieldType<__VA_ARGS__> __storage;
320
321//This closes off the union created above and gives it a name. Unlike the top
322//level BitUnion, we're interested in creating an object instead of a type.
323//The operators are defined in the macro itself instead of a class for
324//technical reasons. If someone determines a way to move them to one, please
325//do so.
326#define EndSubBitUnion(name) \
327        }; \
328        inline operator __StorageType () const \
329        { return __storage; } \
330        \
331        inline __StorageType operator = (const __StorageType & _storage) \
332        { return __storage = _storage;} \
333    } name;
334
335//Regular bitfields
336//These define macros for read/write regular bitfield based subbitfields.
337#define SubBitUnion(name, first, last) \
338    __SubBitUnion(name, Bitfield, first, last)
339
340//Regular bitfields
341//These define macros for read/write regular bitfield based subbitfields.
342#define SignedSubBitUnion(name, first, last) \
343    __SubBitUnion(name, SignedBitfield, first, last)
344
345//Use this to define an arbitrary type overlayed with bitfields.
346#define BitUnion(type, name) __BitUnion(type, name)
347
348//Use this to define conveniently sized values overlayed with bitfields.
349#define BitUnion64(name) __BitUnion(uint64_t, name)
350#define BitUnion32(name) __BitUnion(uint32_t, name)
351#define BitUnion16(name) __BitUnion(uint16_t, name)
352#define BitUnion8(name) __BitUnion(uint8_t, name)
353
354
355//These templates make it possible to define other templates related to
356//BitUnions without having to refer to internal typedefs or the BitfieldBackend
357//namespace.
358
359//To build a template specialization which works for all BitUnions, accept a
360//template argument T, and then use BitUnionType<T> as an argument in the
361//template. To refer to the basic type the BitUnion wraps, use
362//BitUnionBaseType<T>.
363
364//For example:
365//template <typename T>
366//void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; }
367
368//Also, BitUnionBaseType can be used on a BitUnion type directly.
369
370template <typename T>
371using BitUnionType = BitfieldBackend::BitUnionOperators<T>;
372
373namespace BitfieldBackend
374{
375    template<typename T>
376    struct BitUnionBaseType
377    {
378        typedef typename BitUnionType<T>::__StorageType Type;
379    };
380
381    template<typename T>
382    struct BitUnionBaseType<BitUnionType<T> >
383    {
384        typedef typename BitUnionType<T>::__StorageType Type;
385    };
386}
387
388template <typename T>
389using BitUnionBaseType = typename BitfieldBackend::BitUnionBaseType<T>::Type;
390
391namespace std
392{
393    template <typename T>
394    struct hash;
395
396    template <typename T>
397    struct hash<BitUnionType<T> > : public hash<BitUnionBaseType<T> >
398    {
399        size_t
400        operator() (const BitUnionType<T> &val) const
401        {
402            return hash<BitUnionBaseType<T> >::operator()(val);
403        }
404    };
405}
406
407#endif // __BASE_BITUNION_HH__
408