bitunion.hh revision 11800:54436a1784dc
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 "base/bitfield.hh"
35
36//      The following implements the BitUnion system of defining bitfields
37//on top of an underlying class. This is done through the pervasive use of
38//both named and unnamed unions which all contain the same actual storage.
39//Since they're unioned with each other, all of these storage locations
40//overlap. This allows all of the bitfields to manipulate the same data
41//without having to have access to each other. More details are provided with
42//the individual components.
43
44//This namespace is for classes which implement the backend of the BitUnion
45//stuff. Don't use any of these directly, except for the Bitfield classes in
46//the *BitfieldTypes class(es).
47namespace BitfieldBackend
48{
49    //A base class for all bitfields. It instantiates the actual storage,
50    //and provides getBits and setBits functions for manipulating it. The
51    //Data template parameter is type of the underlying storage.
52    template<class Data>
53    class BitfieldBase
54    {
55      protected:
56        Data __data;
57
58        //This function returns a range of bits from the underlying storage.
59        //It relies on the "bits" function above. It's the user's
60        //responsibility to make sure that there is a properly overloaded
61        //version of this function for whatever type they want to overlay.
62        inline uint64_t
63        getBits(int first, int last) const
64        {
65            return bits(__data, first, last);
66        }
67
68        //Similar to the above, but for settings bits with replaceBits.
69        inline void
70        setBits(int first, int last, uint64_t val)
71        {
72            replaceBits(__data, first, last, val);
73        }
74    };
75
76    //This class contains all the "regular" bitfield classes. It is inherited
77    //by all BitUnions which give them access to those types.
78    template<class Type>
79    class RegularBitfieldTypes
80    {
81      protected:
82        //This class implements ordinary bitfields, that is a span of bits
83        //who's msb is "first", and who's lsb is "last".
84        template<int first, int last=first>
85        class Bitfield : public BitfieldBase<Type>
86        {
87            static_assert(first >= last,
88                          "Bitfield ranges must be specified as <msb, lsb>");
89
90          public:
91            operator uint64_t () const
92            {
93                return this->getBits(first, last);
94            }
95
96            uint64_t
97            operator=(const uint64_t _data)
98            {
99                this->setBits(first, last, _data);
100                return _data;
101            }
102
103            uint64_t
104            operator=(Bitfield<first, last> const & other)
105            {
106                return *this = (uint64_t)other;
107            }
108        };
109
110        //A class which specializes the above so that it can only be read
111        //from. This is accomplished explicitly making sure the assignment
112        //operator is blocked. The conversion operator is carried through
113        //inheritance. This will unfortunately need to be copied into each
114        //bitfield type due to limitations with how templates work
115        template<int first, int last=first>
116        class BitfieldRO : public Bitfield<first, last>
117        {
118          private:
119            uint64_t
120            operator=(const uint64_t _data);
121
122            uint64_t
123            operator=(const Bitfield<first, last>& other);
124        };
125
126        //Similar to the above, but only allows writing.
127        template<int first, int last=first>
128        class BitfieldWO : public Bitfield<first, last>
129        {
130          private:
131            operator uint64_t () const;
132
133          public:
134            using Bitfield<first, last>::operator=;
135        };
136    };
137
138    //This class contains all the "regular" bitfield classes. It is inherited
139    //by all BitUnions which give them access to those types.
140    template<class Type>
141    class SignedBitfieldTypes
142    {
143      protected:
144        //This class implements ordinary bitfields, that is a span of bits
145        //who's msb is "first", and who's lsb is "last".
146        template<int first, int last=first>
147        class SignedBitfield : public BitfieldBase<Type>
148        {
149          public:
150            operator int64_t () const
151            {
152                return sext<first - last + 1>(this->getBits(first, last));
153            }
154
155            int64_t
156            operator=(const int64_t _data)
157            {
158                this->setBits(first, last, _data);
159                return _data;
160            }
161
162            int64_t
163            operator=(SignedBitfield<first, last> const & other)
164            {
165                return *this = (int64_t)other;
166            }
167        };
168
169        //A class which specializes the above so that it can only be read
170        //from. This is accomplished explicitly making sure the assignment
171        //operator is blocked. The conversion operator is carried through
172        //inheritance. This will unfortunately need to be copied into each
173        //bitfield type due to limitations with how templates work
174        template<int first, int last=first>
175        class SignedBitfieldRO : public SignedBitfield<first, last>
176        {
177          private:
178            int64_t
179            operator=(const int64_t _data);
180
181            int64_t
182            operator=(const SignedBitfield<first, last>& other);
183        };
184
185        //Similar to the above, but only allows writing.
186        template<int first, int last=first>
187        class SignedBitfieldWO : public SignedBitfield<first, last>
188        {
189          private:
190            operator int64_t () const;
191
192          public:
193            using SignedBitfield<first, last>::operator=;
194        };
195    };
196
197    template<class Type>
198    class BitfieldTypes : public RegularBitfieldTypes<Type>,
199                          public SignedBitfieldTypes<Type>
200    {};
201
202    //When a BitUnion is set up, an underlying class is created which holds
203    //the actual union. This class then inherits from it, and provids the
204    //implementations for various operators. Setting things up this way
205    //prevents having to redefine these functions in every different BitUnion
206    //type. More operators could be implemented in the future, as the need
207    //arises.
208    template <class Type, class Base>
209    class BitUnionOperators : public Base
210    {
211      public:
212        BitUnionOperators(Type const & _data)
213        {
214            Base::__data = _data;
215        }
216
217        BitUnionOperators() {}
218
219        operator const Type () const
220        {
221            return Base::__data;
222        }
223
224        Type
225        operator=(Type const & _data)
226        {
227            Base::__data = _data;
228            return _data;
229        }
230
231        Type
232        operator=(BitUnionOperators const & other)
233        {
234            Base::__data = other;
235            return Base::__data;
236        }
237
238        bool
239        operator<(Base const & base) const
240        {
241            return Base::__data < base.__data;
242        }
243
244        bool
245        operator==(Base const & base) const
246        {
247            return Base::__data == base.__data;
248        }
249    };
250}
251
252//This macro is a backend for other macros that specialize it slightly.
253//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
254//sticks the class which has the actual union in it, which
255//BitfieldOperators above inherits from. Putting these classes in a special
256//namespace ensures that there will be no collisions with other names as long
257//as the BitUnion names themselves are all distinct and nothing else uses
258//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
259//creates a typedef of the "type" parameter called __DataType. This allows
260//the type to propagate outside of the macro itself in a controlled way.
261//Finally, the base storage is defined which BitfieldOperators will refer to
262//in the operators it defines. This macro is intended to be followed by
263//bitfield definitions which will end up inside it's union. As explained
264//above, these is overlayed the __data member in its entirety by each of the
265//bitfields which are defined in the union, creating shared storage with no
266//overhead.
267#define __BitUnion(type, name) \
268    class BitfieldUnderlyingClasses##name : \
269        public BitfieldBackend::BitfieldTypes<type> \
270    { \
271      public: \
272        typedef type __DataType; \
273        union { \
274            type __data;\
275
276//This closes off the class and union started by the above macro. It is
277//followed by a typedef which makes "name" refer to a BitfieldOperator
278//class inheriting from the class and union just defined, which completes
279//building up the type for the user.
280#define EndBitUnion(name) \
281        }; \
282    }; \
283    typedef BitfieldBackend::BitUnionOperators< \
284        BitfieldUnderlyingClasses##name::__DataType, \
285        BitfieldUnderlyingClasses##name> name;
286
287//This sets up a bitfield which has other bitfields nested inside of it. The
288//__data member functions like the "underlying storage" of the top level
289//BitUnion. Like everything else, it overlays with the top level storage, so
290//making it a regular bitfield type makes the entire thing function as a
291//regular bitfield when referred to by itself.
292#define __SubBitUnion(fieldType, first, last, name) \
293    class : public BitfieldBackend::BitfieldTypes<__DataType> \
294    { \
295      public: \
296        union { \
297            fieldType<first, last> __data;
298
299//This closes off the union created above and gives it a name. Unlike the top
300//level BitUnion, we're interested in creating an object instead of a type.
301//The operators are defined in the macro itself instead of a class for
302//technical reasons. If someone determines a way to move them to one, please
303//do so.
304#define EndSubBitUnion(name) \
305        }; \
306        inline operator __DataType () const \
307        { return __data; } \
308        \
309        inline __DataType operator = (const __DataType & _data) \
310        { return __data = _data;} \
311    } name;
312
313//Regular bitfields
314//These define macros for read/write regular bitfield based subbitfields.
315#define SubBitUnion(name, first, last) \
316    __SubBitUnion(Bitfield, first, last, name)
317
318//Regular bitfields
319//These define macros for read/write regular bitfield based subbitfields.
320#define SignedSubBitUnion(name, first, last) \
321    __SubBitUnion(SignedBitfield, first, last, name)
322
323//Use this to define an arbitrary type overlayed with bitfields.
324#define BitUnion(type, name) __BitUnion(type, name)
325
326//Use this to define conveniently sized values overlayed with bitfields.
327#define BitUnion64(name) __BitUnion(uint64_t, name)
328#define BitUnion32(name) __BitUnion(uint32_t, name)
329#define BitUnion16(name) __BitUnion(uint16_t, name)
330#define BitUnion8(name) __BitUnion(uint8_t, name)
331
332#endif // __BASE_BITUNION_HH__
333