bitunion.hh revision 4698
14680Sgblack@eecs.umich.edu/* 24680Sgblack@eecs.umich.edu * Copyright (c) 2003-2005 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 374680Sgblack@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: 1964681Sgblack@eecs.umich.edu BitUnionOperators(Type & _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 2094680Sgblack@eecs.umich.edu operator=(const Type & _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 2164680Sgblack@eecs.umich.edu operator<(const Base & 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 2224680Sgblack@eecs.umich.edu operator==(const Base & 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) \ 2454680Sgblack@eecs.umich.edu namespace BitfieldUnderlyingClasses \ 2464680Sgblack@eecs.umich.edu { \ 2474680Sgblack@eecs.umich.edu class name; \ 2484680Sgblack@eecs.umich.edu } \ 2494680Sgblack@eecs.umich.edu class BitfieldUnderlyingClasses::name : \ 2504680Sgblack@eecs.umich.edu public BitfieldBackend::BitfieldTypes<type> \ 2514680Sgblack@eecs.umich.edu { \ 2524680Sgblack@eecs.umich.edu public: \ 2534680Sgblack@eecs.umich.edu typedef type __DataType; \ 2544680Sgblack@eecs.umich.edu union { \ 2554680Sgblack@eecs.umich.edu type __data;\ 2564680Sgblack@eecs.umich.edu 2574680Sgblack@eecs.umich.edu//This closes off the class and union started by the above macro. It is 2584680Sgblack@eecs.umich.edu//followed by a typedef which makes "name" refer to a BitfieldOperator 2594680Sgblack@eecs.umich.edu//class inheriting from the class and union just defined, which completes 2604680Sgblack@eecs.umich.edu//building up the type for the user. 2614680Sgblack@eecs.umich.edu#define EndBitUnion(name) \ 2624680Sgblack@eecs.umich.edu }; \ 2634680Sgblack@eecs.umich.edu }; \ 2644680Sgblack@eecs.umich.edu typedef BitfieldBackend::BitUnionOperators< \ 2654680Sgblack@eecs.umich.edu BitfieldUnderlyingClasses::name::__DataType, \ 2664680Sgblack@eecs.umich.edu BitfieldUnderlyingClasses::name> name; 2674680Sgblack@eecs.umich.edu 2684680Sgblack@eecs.umich.edu//This sets up a bitfield which has other bitfields nested inside of it. The 2694680Sgblack@eecs.umich.edu//__data member functions like the "underlying storage" of the top level 2704680Sgblack@eecs.umich.edu//BitUnion. Like everything else, it overlays with the top level storage, so 2714680Sgblack@eecs.umich.edu//making it a regular bitfield type makes the entire thing function as a 2724680Sgblack@eecs.umich.edu//regular bitfield when referred to by itself. 2734680Sgblack@eecs.umich.edu#define __SubBitUnion(fieldType, first, last, name) \ 2744680Sgblack@eecs.umich.edu class : public BitfieldBackend::BitfieldTypes<__DataType> \ 2754680Sgblack@eecs.umich.edu { \ 2764680Sgblack@eecs.umich.edu public: \ 2774680Sgblack@eecs.umich.edu union { \ 2784680Sgblack@eecs.umich.edu fieldType<first, last> __data; 2794680Sgblack@eecs.umich.edu 2804680Sgblack@eecs.umich.edu//This closes off the union created above and gives it a name. Unlike the top 2814680Sgblack@eecs.umich.edu//level BitUnion, we're interested in creating an object instead of a type. 2824680Sgblack@eecs.umich.edu//The operators are defined in the macro itself instead of a class for 2834680Sgblack@eecs.umich.edu//technical reasons. If someone determines a way to move them to one, please 2844680Sgblack@eecs.umich.edu//do so. 2854680Sgblack@eecs.umich.edu#define EndSubBitUnion(name) \ 2864680Sgblack@eecs.umich.edu }; \ 2874680Sgblack@eecs.umich.edu inline operator const __DataType () \ 2884680Sgblack@eecs.umich.edu { return __data; } \ 2894680Sgblack@eecs.umich.edu \ 2904680Sgblack@eecs.umich.edu inline const __DataType operator = (const __DataType & _data) \ 2914698Sgblack@eecs.umich.edu { return __data = _data;} \ 2924680Sgblack@eecs.umich.edu } name; 2934680Sgblack@eecs.umich.edu 2944680Sgblack@eecs.umich.edu//Regular bitfields 2954680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields. 2964680Sgblack@eecs.umich.edu#define SubBitUnion(name, first, last) \ 2974680Sgblack@eecs.umich.edu __SubBitUnion(Bitfield, first, last, name) 2984680Sgblack@eecs.umich.edu 2994680Sgblack@eecs.umich.edu//Regular bitfields 3004680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields. 3014680Sgblack@eecs.umich.edu#define SignedSubBitUnion(name, first, last) \ 3024680Sgblack@eecs.umich.edu __SubBitUnion(SignedBitfield, first, last, name) 3034680Sgblack@eecs.umich.edu 3044680Sgblack@eecs.umich.edu//Use this to define an arbitrary type overlayed with bitfields. 3054680Sgblack@eecs.umich.edu#define BitUnion(type, name) __BitUnion(type, name) 3064680Sgblack@eecs.umich.edu 3074680Sgblack@eecs.umich.edu//Use this to define conveniently sized values overlayed with bitfields. 3084680Sgblack@eecs.umich.edu#define BitUnion64(name) __BitUnion(uint64_t, name) 3094680Sgblack@eecs.umich.edu#define BitUnion32(name) __BitUnion(uint32_t, name) 3104680Sgblack@eecs.umich.edu#define BitUnion16(name) __BitUnion(uint16_t, name) 3114680Sgblack@eecs.umich.edu#define BitUnion8(name) __BitUnion(uint8_t, name) 3124680Sgblack@eecs.umich.edu 3134680Sgblack@eecs.umich.edu#endif // __BASE_BITUNION_HH__ 314