bitunion.hh revision 12491:8765e1fb564d
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 <functional>
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
59    struct TypeDeducer
60    {
61        template<typename>
62        struct T;
63
64        template<typename C, typename Type1, typename Type2>
65        struct T<void (C::*)(Type1 &, Type2)>
66        {
67            typedef Type1 Storage;
68            typedef Type2 Type;
69        };
70
71        struct Wrapper : public Base
72        {
73            using Base::setter;
74        };
75
76        typedef typename T<decltype(&Wrapper::setter)>::Storage Storage;
77        typedef typename T<decltype(&Wrapper::setter)>::Type Type;
78    };
79
80  protected:
81    typedef typename TypeDeducer::Storage Storage;
82    typedef typename TypeDeducer::Type Type;
83
84    Type getter(const Storage &storage) const = delete;
85    void setter(Storage &storage, Type val) = delete;
86
87    Storage __storage;
88
89    operator Type () const
90    {
91        return Base::getter(__storage);
92    }
93
94    Type
95    operator=(const Type val)
96    {
97        Base::setter(__storage, val);
98        return val;
99    }
100
101    Type
102    operator=(BitfieldTypeImpl<Base> const & other)
103    {
104        return *this = (Type)other;
105    }
106};
107
108//A wrapper for the above class which allows setting and getting.
109template<class Base>
110class BitfieldType : public BitfieldTypeImpl<Base>
111{
112  protected:
113    using Impl = BitfieldTypeImpl<Base>;
114    using typename Impl::Type;
115
116  public:
117    operator Type () const { return Impl::operator Type(); }
118    Type operator=(const Type val) { return Impl::operator=(val); }
119    Type
120    operator=(BitfieldType<Base> const & other)
121    {
122        return Impl::operator=(other);
123    }
124};
125
126//A wrapper which only supports getting.
127template<class Base>
128class BitfieldROType : public BitfieldTypeImpl<Base>
129{
130  public:
131    using Impl = BitfieldTypeImpl<Base>;
132    using typename Impl::Type;
133
134    Type operator=(BitfieldROType<Base> const &other) = delete;
135    operator Type () const { return Impl::operator Type(); }
136};
137
138//A wrapper which only supports setting.
139template <class Base>
140class BitfieldWOType : public BitfieldTypeImpl<Base>
141{
142  protected:
143    using Impl = BitfieldTypeImpl<Base>;
144    using typename Impl::Type;
145
146  public:
147    Type operator=(const Type val) { return Impl::operator=(val); }
148    Type
149    operator=(BitfieldWOType<Base> const & other)
150    {
151        return Impl::operator=(other);
152    }
153};
154
155//This namespace is for classes which implement the backend of the BitUnion
156//stuff. Don't use any of these directly.
157namespace BitfieldBackend
158{
159    template<class Storage, int first, int last>
160    class Unsigned
161    {
162        static_assert(first >= last,
163                      "Bitfield ranges must be specified as <msb, lsb>");
164
165      protected:
166        uint64_t
167        getter(const Storage &storage) const
168        {
169            return bits(storage, first, last);
170        }
171
172        void
173        setter(Storage &storage, uint64_t val)
174        {
175            replaceBits(storage, first, last, val);
176        }
177    };
178
179    template<class Storage, int first, int last>
180    class Signed
181    {
182        static_assert(first >= last,
183                      "Bitfield ranges must be specified as <msb, lsb>");
184
185      protected:
186        int64_t
187        getter(const Storage &storage) const
188        {
189            return sext<first - last + 1>(bits(storage, first, last));
190        }
191
192        void
193        setter(Storage &storage, int64_t val)
194        {
195            replaceBits(storage, first, last, val);
196        }
197    };
198
199    //This class contains the basic bitfield types which are automatically
200    //available within a BitUnion. They inherit their Storage type from the
201    //containing BitUnion.
202    template<class Storage>
203    class BitfieldTypes
204    {
205      protected:
206
207        template<int first, int last=first>
208        using Bitfield = BitfieldType<Unsigned<Storage, first, last> >;
209        template<int first, int last=first>
210        using BitfieldRO =
211                BitfieldROType<Unsigned<Storage, first, last> >;
212        template<int first, int last=first>
213        using BitfieldWO =
214                BitfieldWOType<Unsigned<Storage, first, last> >;
215
216        template<int first, int last=first>
217        using SignedBitfield =
218                BitfieldType<Signed<Storage, first, last> >;
219        template<int first, int last=first>
220        using SignedBitfieldRO =
221                BitfieldROType<Signed<Storage, first, last> >;
222        template<int first, int last=first>
223        using SignedBitfieldWO =
224                BitfieldWOType<Signed<Storage, first, last> >;
225    };
226
227    //When a BitUnion is set up, an underlying class is created which holds
228    //the actual union. This class then inherits from it, and provids the
229    //implementations for various operators. Setting things up this way
230    //prevents having to redefine these functions in every different BitUnion
231    //type. More operators could be implemented in the future, as the need
232    //arises.
233    template <class Base>
234    class BitUnionOperators : public Base
235    {
236        static_assert(sizeof(Base) == sizeof(typename Base::__StorageType),
237                      "BitUnion larger than its storage type.");
238
239      public:
240        BitUnionOperators(typename Base::__StorageType const &val)
241        {
242            Base::__storage = val;
243        }
244
245        BitUnionOperators() {}
246
247        operator const typename Base::__StorageType () const
248        {
249            return Base::__storage;
250        }
251
252        typename Base::__StorageType
253        operator=(typename Base::__StorageType const &val)
254        {
255            Base::__storage = val;
256            return val;
257        }
258
259        typename Base::__StorageType
260        operator=(BitUnionOperators const &other)
261        {
262            Base::__storage = other;
263            return Base::__storage;
264        }
265
266        bool
267        operator<(Base const &base) const
268        {
269            return Base::__storage < base.__storage;
270        }
271
272        bool
273        operator==(Base const &base) const
274        {
275            return Base::__storage == base.__storage;
276        }
277    };
278}
279
280//This macro is a backend for other macros that specialize it slightly.
281//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
282//sticks the class which has the actual union in it, which
283//BitfieldOperators above inherits from. Putting these classes in a special
284//namespace ensures that there will be no collisions with other names as long
285//as the BitUnion names themselves are all distinct and nothing else uses
286//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
287//creates a typedef of the "type" parameter called __StorageType. This allows
288//the type to propagate outside of the macro itself in a controlled way.
289//Finally, the base storage is defined which BitfieldOperators will refer to
290//in the operators it defines. This macro is intended to be followed by
291//bitfield definitions which will end up inside it's union. As explained
292//above, these is overlayed the __storage member in its entirety by each of the
293//bitfields which are defined in the union, creating shared storage with no
294//overhead.
295#define __BitUnion(type, name) \
296    class BitfieldUnderlyingClasses##name : \
297        public BitfieldBackend::BitfieldTypes<type> \
298    { \
299      protected: \
300        typedef type __StorageType; \
301        friend BitfieldBackend::BitUnionBaseType< \
302            BitfieldBackend::BitUnionOperators< \
303                BitfieldUnderlyingClasses##name> >; \
304        friend BitfieldBackend::BitUnionBaseType< \
305                BitfieldUnderlyingClasses##name>; \
306      public: \
307        union { \
308            type __storage;
309
310//This closes off the class and union started by the above macro. It is
311//followed by a typedef which makes "name" refer to a BitfieldOperator
312//class inheriting from the class and union just defined, which completes
313//building up the type for the user.
314#define EndBitUnion(name) \
315        }; \
316    }; \
317    typedef BitfieldBackend::BitUnionOperators< \
318        BitfieldUnderlyingClasses##name> name;
319
320//This sets up a bitfield which has other bitfields nested inside of it. The
321//__storage member functions like the "underlying storage" of the top level
322//BitUnion. Like everything else, it overlays with the top level storage, so
323//making it a regular bitfield type makes the entire thing function as a
324//regular bitfield when referred to by itself.
325#define __SubBitUnion(name, fieldType, ...) \
326    class \
327    { \
328      public: \
329        union { \
330            fieldType<__VA_ARGS__> __storage;
331
332//This closes off the union created above and gives it a name. Unlike the top
333//level BitUnion, we're interested in creating an object instead of a type.
334//The operators are defined in the macro itself instead of a class for
335//technical reasons. If someone determines a way to move them to one, please
336//do so.
337#define EndSubBitUnion(name) \
338        }; \
339        inline operator __StorageType () const \
340        { return __storage; } \
341        \
342        inline __StorageType operator = (const __StorageType & _storage) \
343        { return __storage = _storage;} \
344    } name;
345
346//Regular bitfields
347//These define macros for read/write regular bitfield based subbitfields.
348#define SubBitUnion(name, first, last) \
349    __SubBitUnion(name, Bitfield, first, last)
350
351//Regular bitfields
352//These define macros for read/write regular bitfield based subbitfields.
353#define SignedSubBitUnion(name, first, last) \
354    __SubBitUnion(name, SignedBitfield, first, last)
355
356//Use this to define an arbitrary type overlayed with bitfields.
357#define BitUnion(type, name) __BitUnion(type, name)
358
359//Use this to define conveniently sized values overlayed with bitfields.
360#define BitUnion64(name) __BitUnion(uint64_t, name)
361#define BitUnion32(name) __BitUnion(uint32_t, name)
362#define BitUnion16(name) __BitUnion(uint16_t, name)
363#define BitUnion8(name) __BitUnion(uint8_t, name)
364
365
366//These templates make it possible to define other templates related to
367//BitUnions without having to refer to internal typedefs or the BitfieldBackend
368//namespace.
369
370//To build a template specialization which works for all BitUnions, accept a
371//template argument T, and then use BitUnionType<T> as an argument in the
372//template. To refer to the basic type the BitUnion wraps, use
373//BitUnionBaseType<T>.
374
375//For example:
376//template <typename T>
377//void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; }
378
379//Also, BitUnionBaseType can be used on a BitUnion type directly.
380
381template <typename T>
382using BitUnionType = BitfieldBackend::BitUnionOperators<T>;
383
384namespace BitfieldBackend
385{
386    template<typename T>
387    struct BitUnionBaseType
388    {
389        typedef typename BitUnionType<T>::__StorageType Type;
390    };
391
392    template<typename T>
393    struct BitUnionBaseType<BitUnionType<T> >
394    {
395        typedef typename BitUnionType<T>::__StorageType Type;
396    };
397}
398
399template <typename T>
400using BitUnionBaseType = typename BitfieldBackend::BitUnionBaseType<T>::Type;
401
402
403//An STL style hash structure for hashing BitUnions based on their base type.
404namespace std
405{
406    template <typename T>
407    struct hash<BitUnionType<T> > : public hash<BitUnionBaseType<T> >
408    {
409        size_t
410        operator() (const BitUnionType<T> &val) const
411        {
412            return hash<BitUnionBaseType<T> >::operator()(val);
413        }
414    };
415}
416
417#endif // __BASE_BITUNION_HH__
418