bitunion.hh revision 5543
14680Sgblack@eecs.umich.edu/*
25442Sgblack@eecs.umich.edu * Copyright (c) 2007-2008 The Regents of The University of Michigan
34680Sgblack@eecs.umich.edu * All rights reserved.
44680Sgblack@eecs.umich.edu *
54680Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
64680Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
74680Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
84680Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
94680Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
104680Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
114680Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
124680Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
134680Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
144680Sgblack@eecs.umich.edu * this software without specific prior written permission.
154680Sgblack@eecs.umich.edu *
164680Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174680Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184680Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194680Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204680Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214680Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224680Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234680Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244680Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254680Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264680Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274680Sgblack@eecs.umich.edu *
284680Sgblack@eecs.umich.edu * Authors: Gabe Black
294680Sgblack@eecs.umich.edu */
304680Sgblack@eecs.umich.edu
314680Sgblack@eecs.umich.edu#ifndef __BASE_BITUNION_HH__
324680Sgblack@eecs.umich.edu#define __BASE_BITUNION_HH__
334680Sgblack@eecs.umich.edu
344680Sgblack@eecs.umich.edu#include <inttypes.h>
354680Sgblack@eecs.umich.edu#include "base/bitfield.hh"
364680Sgblack@eecs.umich.edu
375543Ssaidi@eecs.umich.edu//      The following implements the BitUnion system of defining bitfields
384680Sgblack@eecs.umich.edu//on top of an underlying class. This is done through the pervasive use of
394680Sgblack@eecs.umich.edu//both named and unnamed unions which all contain the same actual storage.
404680Sgblack@eecs.umich.edu//Since they're unioned with each other, all of these storage locations
414680Sgblack@eecs.umich.edu//overlap. This allows all of the bitfields to manipulate the same data
424680Sgblack@eecs.umich.edu//without having to have access to each other. More details are provided with
434680Sgblack@eecs.umich.edu//the individual components.
444680Sgblack@eecs.umich.edu
454680Sgblack@eecs.umich.edu//This namespace is for classes which implement the backend of the BitUnion
464680Sgblack@eecs.umich.edu//stuff. Don't use any of these directly, except for the Bitfield classes in
474680Sgblack@eecs.umich.edu//the *BitfieldTypes class(es).
484680Sgblack@eecs.umich.edunamespace BitfieldBackend
494680Sgblack@eecs.umich.edu{
504680Sgblack@eecs.umich.edu    //A base class for all bitfields. It instantiates the actual storage,
514680Sgblack@eecs.umich.edu    //and provides getBits and setBits functions for manipulating it. The
524680Sgblack@eecs.umich.edu    //Data template parameter is type of the underlying storage.
534680Sgblack@eecs.umich.edu    template<class Data>
544680Sgblack@eecs.umich.edu    class BitfieldBase
554680Sgblack@eecs.umich.edu    {
564680Sgblack@eecs.umich.edu      protected:
574680Sgblack@eecs.umich.edu        Data __data;
584680Sgblack@eecs.umich.edu
594680Sgblack@eecs.umich.edu        //This function returns a range of bits from the underlying storage.
604680Sgblack@eecs.umich.edu        //It relies on the "bits" function above. It's the user's
614680Sgblack@eecs.umich.edu        //responsibility to make sure that there is a properly overloaded
624680Sgblack@eecs.umich.edu        //version of this function for whatever type they want to overlay.
634680Sgblack@eecs.umich.edu        inline uint64_t
644680Sgblack@eecs.umich.edu        getBits(int first, int last) const
654680Sgblack@eecs.umich.edu        {
664680Sgblack@eecs.umich.edu            return bits(__data, first, last);
674680Sgblack@eecs.umich.edu        }
684680Sgblack@eecs.umich.edu
694680Sgblack@eecs.umich.edu        //Similar to the above, but for settings bits with replaceBits.
704680Sgblack@eecs.umich.edu        inline void
714680Sgblack@eecs.umich.edu        setBits(int first, int last, uint64_t val)
724680Sgblack@eecs.umich.edu        {
734680Sgblack@eecs.umich.edu            replaceBits(__data, first, last, val);
744680Sgblack@eecs.umich.edu        }
754680Sgblack@eecs.umich.edu    };
764680Sgblack@eecs.umich.edu
774680Sgblack@eecs.umich.edu    //This class contains all the "regular" bitfield classes. It is inherited
784680Sgblack@eecs.umich.edu    //by all BitUnions which give them access to those types.
794680Sgblack@eecs.umich.edu    template<class Type>
804680Sgblack@eecs.umich.edu    class RegularBitfieldTypes
814680Sgblack@eecs.umich.edu    {
824680Sgblack@eecs.umich.edu      protected:
834680Sgblack@eecs.umich.edu        //This class implements ordinary bitfields, that is a span of bits
844680Sgblack@eecs.umich.edu        //who's msb is "first", and who's lsb is "last".
854680Sgblack@eecs.umich.edu        template<int first, int last=first>
864680Sgblack@eecs.umich.edu        class Bitfield : public BitfieldBase<Type>
874680Sgblack@eecs.umich.edu        {
884680Sgblack@eecs.umich.edu          public:
894680Sgblack@eecs.umich.edu            operator uint64_t () const
904680Sgblack@eecs.umich.edu            {
914680Sgblack@eecs.umich.edu                return this->getBits(first, last);
924680Sgblack@eecs.umich.edu            }
934680Sgblack@eecs.umich.edu
944680Sgblack@eecs.umich.edu            uint64_t
954680Sgblack@eecs.umich.edu            operator=(const uint64_t _data)
964680Sgblack@eecs.umich.edu            {
974680Sgblack@eecs.umich.edu                this->setBits(first, last, _data);
984680Sgblack@eecs.umich.edu                return _data;
994680Sgblack@eecs.umich.edu            }
1004680Sgblack@eecs.umich.edu        };
1014680Sgblack@eecs.umich.edu
1024680Sgblack@eecs.umich.edu        //A class which specializes the above so that it can only be read
1034680Sgblack@eecs.umich.edu        //from. This is accomplished explicitly making sure the assignment
1044680Sgblack@eecs.umich.edu        //operator is blocked. The conversion operator is carried through
1054680Sgblack@eecs.umich.edu        //inheritance. This will unfortunately need to be copied into each
1064680Sgblack@eecs.umich.edu        //bitfield type due to limitations with how templates work
1074680Sgblack@eecs.umich.edu        template<int first, int last=first>
1084680Sgblack@eecs.umich.edu        class BitfieldRO : public Bitfield<first, last>
1094680Sgblack@eecs.umich.edu        {
1104680Sgblack@eecs.umich.edu          private:
1114680Sgblack@eecs.umich.edu            uint64_t
1124680Sgblack@eecs.umich.edu            operator=(const uint64_t _data);
1134680Sgblack@eecs.umich.edu        };
1144680Sgblack@eecs.umich.edu
1154680Sgblack@eecs.umich.edu        //Similar to the above, but only allows writing.
1164680Sgblack@eecs.umich.edu        template<int first, int last=first>
1174680Sgblack@eecs.umich.edu        class BitfieldWO : public Bitfield<first, last>
1184680Sgblack@eecs.umich.edu        {
1194680Sgblack@eecs.umich.edu          private:
1204680Sgblack@eecs.umich.edu            operator uint64_t () const;
1214680Sgblack@eecs.umich.edu
1224680Sgblack@eecs.umich.edu          public:
1234680Sgblack@eecs.umich.edu            using Bitfield<first, last>::operator=;
1244680Sgblack@eecs.umich.edu        };
1254680Sgblack@eecs.umich.edu    };
1264680Sgblack@eecs.umich.edu
1274680Sgblack@eecs.umich.edu    //This class contains all the "regular" bitfield classes. It is inherited
1284680Sgblack@eecs.umich.edu    //by all BitUnions which give them access to those types.
1294680Sgblack@eecs.umich.edu    template<class Type>
1304680Sgblack@eecs.umich.edu    class SignedBitfieldTypes
1314680Sgblack@eecs.umich.edu    {
1324680Sgblack@eecs.umich.edu      protected:
1334680Sgblack@eecs.umich.edu        //This class implements ordinary bitfields, that is a span of bits
1344680Sgblack@eecs.umich.edu        //who's msb is "first", and who's lsb is "last".
1354680Sgblack@eecs.umich.edu        template<int first, int last=first>
1364680Sgblack@eecs.umich.edu        class SignedBitfield : public BitfieldBase<Type>
1374680Sgblack@eecs.umich.edu        {
1384680Sgblack@eecs.umich.edu          public:
1394680Sgblack@eecs.umich.edu            operator int64_t () const
1404680Sgblack@eecs.umich.edu            {
1414680Sgblack@eecs.umich.edu                return sext<first - last + 1>(this->getBits(first, last));
1424680Sgblack@eecs.umich.edu            }
1434680Sgblack@eecs.umich.edu
1444680Sgblack@eecs.umich.edu            int64_t
1454680Sgblack@eecs.umich.edu            operator=(const int64_t _data)
1464680Sgblack@eecs.umich.edu            {
1474680Sgblack@eecs.umich.edu                this->setBits(first, last, _data);
1484680Sgblack@eecs.umich.edu                return _data;
1494680Sgblack@eecs.umich.edu            }
1504680Sgblack@eecs.umich.edu        };
1514680Sgblack@eecs.umich.edu
1524680Sgblack@eecs.umich.edu        //A class which specializes the above so that it can only be read
1534680Sgblack@eecs.umich.edu        //from. This is accomplished explicitly making sure the assignment
1544680Sgblack@eecs.umich.edu        //operator is blocked. The conversion operator is carried through
1554680Sgblack@eecs.umich.edu        //inheritance. This will unfortunately need to be copied into each
1564680Sgblack@eecs.umich.edu        //bitfield type due to limitations with how templates work
1574680Sgblack@eecs.umich.edu        template<int first, int last=first>
1584680Sgblack@eecs.umich.edu        class SignedBitfieldRO : public SignedBitfield<first, last>
1594680Sgblack@eecs.umich.edu        {
1604680Sgblack@eecs.umich.edu          private:
1614680Sgblack@eecs.umich.edu            int64_t
1624680Sgblack@eecs.umich.edu            operator=(const int64_t _data);
1634680Sgblack@eecs.umich.edu        };
1644680Sgblack@eecs.umich.edu
1654680Sgblack@eecs.umich.edu        //Similar to the above, but only allows writing.
1664680Sgblack@eecs.umich.edu        template<int first, int last=first>
1674680Sgblack@eecs.umich.edu        class SignedBitfieldWO : public SignedBitfield<first, last>
1684680Sgblack@eecs.umich.edu        {
1694680Sgblack@eecs.umich.edu          private:
1704680Sgblack@eecs.umich.edu            operator int64_t () const;
1714680Sgblack@eecs.umich.edu
1724680Sgblack@eecs.umich.edu          public:
1734680Sgblack@eecs.umich.edu            int64_t operator=(const int64_t _data)
1744680Sgblack@eecs.umich.edu            {
1754680Sgblack@eecs.umich.edu                *((SignedBitfield<first, last> *)this) = _data;
1764680Sgblack@eecs.umich.edu                return _data;
1774680Sgblack@eecs.umich.edu            }
1784680Sgblack@eecs.umich.edu        };
1794680Sgblack@eecs.umich.edu    };
1804680Sgblack@eecs.umich.edu
1814680Sgblack@eecs.umich.edu    template<class Type>
1824680Sgblack@eecs.umich.edu    class BitfieldTypes : public RegularBitfieldTypes<Type>,
1834680Sgblack@eecs.umich.edu                          public SignedBitfieldTypes<Type>
1844680Sgblack@eecs.umich.edu    {};
1854680Sgblack@eecs.umich.edu
1864680Sgblack@eecs.umich.edu    //When a BitUnion is set up, an underlying class is created which holds
1874680Sgblack@eecs.umich.edu    //the actual union. This class then inherits from it, and provids the
1884680Sgblack@eecs.umich.edu    //implementations for various operators. Setting things up this way
1894680Sgblack@eecs.umich.edu    //prevents having to redefine these functions in every different BitUnion
1904680Sgblack@eecs.umich.edu    //type. More operators could be implemented in the future, as the need
1914680Sgblack@eecs.umich.edu    //arises.
1924680Sgblack@eecs.umich.edu    template <class Type, class Base>
1934680Sgblack@eecs.umich.edu    class BitUnionOperators : public Base
1944680Sgblack@eecs.umich.edu    {
1954680Sgblack@eecs.umich.edu      public:
1965136Sgblack@eecs.umich.edu        BitUnionOperators(Type const & _data)
1974681Sgblack@eecs.umich.edu        {
1984681Sgblack@eecs.umich.edu            Base::__data = _data;
1994681Sgblack@eecs.umich.edu        }
2004681Sgblack@eecs.umich.edu
2014681Sgblack@eecs.umich.edu        BitUnionOperators() {}
2024681Sgblack@eecs.umich.edu
2034680Sgblack@eecs.umich.edu        operator Type () const
2044680Sgblack@eecs.umich.edu        {
2054680Sgblack@eecs.umich.edu            return Base::__data;
2064680Sgblack@eecs.umich.edu        }
2074680Sgblack@eecs.umich.edu
2084680Sgblack@eecs.umich.edu        Type
2095136Sgblack@eecs.umich.edu        operator=(Type const & _data)
2104680Sgblack@eecs.umich.edu        {
2114680Sgblack@eecs.umich.edu            Base::__data = _data;
2124680Sgblack@eecs.umich.edu            return _data;
2134680Sgblack@eecs.umich.edu        }
2144680Sgblack@eecs.umich.edu
2154680Sgblack@eecs.umich.edu        bool
2165136Sgblack@eecs.umich.edu        operator<(Base const & base) const
2174680Sgblack@eecs.umich.edu        {
2184680Sgblack@eecs.umich.edu            return Base::__data < base.__data;
2194680Sgblack@eecs.umich.edu        }
2204680Sgblack@eecs.umich.edu
2214680Sgblack@eecs.umich.edu        bool
2225136Sgblack@eecs.umich.edu        operator==(Base const & base) const
2234680Sgblack@eecs.umich.edu        {
2244680Sgblack@eecs.umich.edu            return Base::__data == base.__data;
2254680Sgblack@eecs.umich.edu        }
2264680Sgblack@eecs.umich.edu    };
2274680Sgblack@eecs.umich.edu}
2284680Sgblack@eecs.umich.edu
2294680Sgblack@eecs.umich.edu//This macro is a backend for other macros that specialize it slightly.
2304680Sgblack@eecs.umich.edu//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
2314680Sgblack@eecs.umich.edu//sticks the class which has the actual union in it, which
2324680Sgblack@eecs.umich.edu//BitfieldOperators above inherits from. Putting these classes in a special
2334680Sgblack@eecs.umich.edu//namespace ensures that there will be no collisions with other names as long
2344680Sgblack@eecs.umich.edu//as the BitUnion names themselves are all distinct and nothing else uses
2354680Sgblack@eecs.umich.edu//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
2364680Sgblack@eecs.umich.edu//creates a typedef of the "type" parameter called __DataType. This allows
2374680Sgblack@eecs.umich.edu//the type to propagate outside of the macro itself in a controlled way.
2384680Sgblack@eecs.umich.edu//Finally, the base storage is defined which BitfieldOperators will refer to
2394680Sgblack@eecs.umich.edu//in the operators it defines. This macro is intended to be followed by
2404680Sgblack@eecs.umich.edu//bitfield definitions which will end up inside it's union. As explained
2414680Sgblack@eecs.umich.edu//above, these is overlayed the __data member in its entirety by each of the
2424680Sgblack@eecs.umich.edu//bitfields which are defined in the union, creating shared storage with no
2434680Sgblack@eecs.umich.edu//overhead.
2444680Sgblack@eecs.umich.edu#define __BitUnion(type, name) \
2455442Sgblack@eecs.umich.edu    class BitfieldUnderlyingClasses##name : \
2464680Sgblack@eecs.umich.edu        public BitfieldBackend::BitfieldTypes<type> \
2474680Sgblack@eecs.umich.edu    { \
2484680Sgblack@eecs.umich.edu      public: \
2494680Sgblack@eecs.umich.edu        typedef type __DataType; \
2504680Sgblack@eecs.umich.edu        union { \
2514680Sgblack@eecs.umich.edu            type __data;\
2524680Sgblack@eecs.umich.edu
2534680Sgblack@eecs.umich.edu//This closes off the class and union started by the above macro. It is
2544680Sgblack@eecs.umich.edu//followed by a typedef which makes "name" refer to a BitfieldOperator
2554680Sgblack@eecs.umich.edu//class inheriting from the class and union just defined, which completes
2564680Sgblack@eecs.umich.edu//building up the type for the user.
2574680Sgblack@eecs.umich.edu#define EndBitUnion(name) \
2584680Sgblack@eecs.umich.edu        }; \
2594680Sgblack@eecs.umich.edu    }; \
2604680Sgblack@eecs.umich.edu    typedef BitfieldBackend::BitUnionOperators< \
2615442Sgblack@eecs.umich.edu        BitfieldUnderlyingClasses##name::__DataType, \
2625442Sgblack@eecs.umich.edu        BitfieldUnderlyingClasses##name> name;
2634680Sgblack@eecs.umich.edu
2644680Sgblack@eecs.umich.edu//This sets up a bitfield which has other bitfields nested inside of it. The
2654680Sgblack@eecs.umich.edu//__data member functions like the "underlying storage" of the top level
2664680Sgblack@eecs.umich.edu//BitUnion. Like everything else, it overlays with the top level storage, so
2674680Sgblack@eecs.umich.edu//making it a regular bitfield type makes the entire thing function as a
2684680Sgblack@eecs.umich.edu//regular bitfield when referred to by itself.
2694680Sgblack@eecs.umich.edu#define __SubBitUnion(fieldType, first, last, name) \
2704680Sgblack@eecs.umich.edu    class : public BitfieldBackend::BitfieldTypes<__DataType> \
2714680Sgblack@eecs.umich.edu    { \
2724680Sgblack@eecs.umich.edu      public: \
2734680Sgblack@eecs.umich.edu        union { \
2744680Sgblack@eecs.umich.edu            fieldType<first, last> __data;
2754680Sgblack@eecs.umich.edu
2764680Sgblack@eecs.umich.edu//This closes off the union created above and gives it a name. Unlike the top
2774680Sgblack@eecs.umich.edu//level BitUnion, we're interested in creating an object instead of a type.
2784680Sgblack@eecs.umich.edu//The operators are defined in the macro itself instead of a class for
2794680Sgblack@eecs.umich.edu//technical reasons. If someone determines a way to move them to one, please
2804680Sgblack@eecs.umich.edu//do so.
2814680Sgblack@eecs.umich.edu#define EndSubBitUnion(name) \
2824680Sgblack@eecs.umich.edu        }; \
2834680Sgblack@eecs.umich.edu        inline operator const __DataType () \
2844680Sgblack@eecs.umich.edu        { return __data; } \
2854680Sgblack@eecs.umich.edu        \
2864680Sgblack@eecs.umich.edu        inline const __DataType operator = (const __DataType & _data) \
2874698Sgblack@eecs.umich.edu        { return __data = _data;} \
2884680Sgblack@eecs.umich.edu    } name;
2894680Sgblack@eecs.umich.edu
2904680Sgblack@eecs.umich.edu//Regular bitfields
2914680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields.
2924680Sgblack@eecs.umich.edu#define SubBitUnion(name, first, last) \
2934680Sgblack@eecs.umich.edu    __SubBitUnion(Bitfield, first, last, name)
2944680Sgblack@eecs.umich.edu
2954680Sgblack@eecs.umich.edu//Regular bitfields
2964680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields.
2974680Sgblack@eecs.umich.edu#define SignedSubBitUnion(name, first, last) \
2984680Sgblack@eecs.umich.edu    __SubBitUnion(SignedBitfield, first, last, name)
2994680Sgblack@eecs.umich.edu
3004680Sgblack@eecs.umich.edu//Use this to define an arbitrary type overlayed with bitfields.
3014680Sgblack@eecs.umich.edu#define BitUnion(type, name) __BitUnion(type, name)
3024680Sgblack@eecs.umich.edu
3034680Sgblack@eecs.umich.edu//Use this to define conveniently sized values overlayed with bitfields.
3044680Sgblack@eecs.umich.edu#define BitUnion64(name) __BitUnion(uint64_t, name)
3054680Sgblack@eecs.umich.edu#define BitUnion32(name) __BitUnion(uint32_t, name)
3064680Sgblack@eecs.umich.edu#define BitUnion16(name) __BitUnion(uint16_t, name)
3074680Sgblack@eecs.umich.edu#define BitUnion8(name) __BitUnion(uint8_t, name)
3084680Sgblack@eecs.umich.edu
3094680Sgblack@eecs.umich.edu#endif // __BASE_BITUNION_HH__
310