bitunion.hh revision 12625
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 3412491Sgabeblack@google.com#include <functional> 3512625Sgabeblack@google.com#include <iostream> 3612450Sgabeblack@google.com#include <type_traits> 3712625Sgabeblack@google.com#include <typeinfo> 3812450Sgabeblack@google.com 394680Sgblack@eecs.umich.edu#include "base/bitfield.hh" 404680Sgblack@eecs.umich.edu 415543Ssaidi@eecs.umich.edu// The following implements the BitUnion system of defining bitfields 424680Sgblack@eecs.umich.edu//on top of an underlying class. This is done through the pervasive use of 434680Sgblack@eecs.umich.edu//both named and unnamed unions which all contain the same actual storage. 444680Sgblack@eecs.umich.edu//Since they're unioned with each other, all of these storage locations 454680Sgblack@eecs.umich.edu//overlap. This allows all of the bitfields to manipulate the same data 464680Sgblack@eecs.umich.edu//without having to have access to each other. More details are provided with 474680Sgblack@eecs.umich.edu//the individual components. 484680Sgblack@eecs.umich.edu 4912450Sgabeblack@google.com//This class wraps around another which defines getter/setter functions which 5012450Sgabeblack@google.com//manipulate the underlying data. The type of the underlying data and the type 5112450Sgabeblack@google.com//of the bitfield itself are inferred from the argument types of the setter 5212450Sgabeblack@google.com//function. 5312450Sgabeblack@google.comtemplate<class Base> 5412450Sgabeblack@google.comclass BitfieldTypeImpl : public Base 5512450Sgabeblack@google.com{ 5612450Sgabeblack@google.com static_assert(std::is_empty<Base>::value, 5712450Sgabeblack@google.com "Bitfield base class must be empty."); 5812450Sgabeblack@google.com 5912450Sgabeblack@google.com private: 6012450Sgabeblack@google.com 6112465Sgabeblack@google.com struct TypeDeducer 6212465Sgabeblack@google.com { 6312465Sgabeblack@google.com template<typename> 6412465Sgabeblack@google.com struct T; 6512450Sgabeblack@google.com 6612465Sgabeblack@google.com template<typename C, typename Type1, typename Type2> 6712465Sgabeblack@google.com struct T<void (C::*)(Type1 &, Type2)> 6812465Sgabeblack@google.com { 6912465Sgabeblack@google.com typedef Type1 Storage; 7012465Sgabeblack@google.com typedef Type2 Type; 7112465Sgabeblack@google.com }; 7212450Sgabeblack@google.com 7312465Sgabeblack@google.com struct Wrapper : public Base 7412465Sgabeblack@google.com { 7512465Sgabeblack@google.com using Base::setter; 7612465Sgabeblack@google.com }; 7712465Sgabeblack@google.com 7812465Sgabeblack@google.com typedef typename T<decltype(&Wrapper::setter)>::Storage Storage; 7912465Sgabeblack@google.com typedef typename T<decltype(&Wrapper::setter)>::Type Type; 8012450Sgabeblack@google.com }; 8112450Sgabeblack@google.com 8212450Sgabeblack@google.com protected: 8312465Sgabeblack@google.com typedef typename TypeDeducer::Storage Storage; 8412465Sgabeblack@google.com typedef typename TypeDeducer::Type Type; 8512450Sgabeblack@google.com 8612450Sgabeblack@google.com Type getter(const Storage &storage) const = delete; 8712450Sgabeblack@google.com void setter(Storage &storage, Type val) = delete; 8812450Sgabeblack@google.com 8912450Sgabeblack@google.com Storage __storage; 9012450Sgabeblack@google.com 9112450Sgabeblack@google.com operator Type () const 9212450Sgabeblack@google.com { 9312450Sgabeblack@google.com return Base::getter(__storage); 9412450Sgabeblack@google.com } 9512450Sgabeblack@google.com 9612450Sgabeblack@google.com Type 9712450Sgabeblack@google.com operator=(const Type val) 9812450Sgabeblack@google.com { 9912450Sgabeblack@google.com Base::setter(__storage, val); 10012450Sgabeblack@google.com return val; 10112450Sgabeblack@google.com } 10212450Sgabeblack@google.com 10312450Sgabeblack@google.com Type 10412450Sgabeblack@google.com operator=(BitfieldTypeImpl<Base> const & other) 10512450Sgabeblack@google.com { 10612450Sgabeblack@google.com return *this = (Type)other; 10712450Sgabeblack@google.com } 10812450Sgabeblack@google.com}; 10912450Sgabeblack@google.com 11012450Sgabeblack@google.com//A wrapper for the above class which allows setting and getting. 11112450Sgabeblack@google.comtemplate<class Base> 11212450Sgabeblack@google.comclass BitfieldType : public BitfieldTypeImpl<Base> 11312450Sgabeblack@google.com{ 11412450Sgabeblack@google.com protected: 11512450Sgabeblack@google.com using Impl = BitfieldTypeImpl<Base>; 11612450Sgabeblack@google.com using typename Impl::Type; 11712450Sgabeblack@google.com 11812450Sgabeblack@google.com public: 11912450Sgabeblack@google.com operator Type () const { return Impl::operator Type(); } 12012450Sgabeblack@google.com Type operator=(const Type val) { return Impl::operator=(val); } 12112450Sgabeblack@google.com Type 12212450Sgabeblack@google.com operator=(BitfieldType<Base> const & other) 12312450Sgabeblack@google.com { 12412450Sgabeblack@google.com return Impl::operator=(other); 12512450Sgabeblack@google.com } 12612450Sgabeblack@google.com}; 12712450Sgabeblack@google.com 12812450Sgabeblack@google.com//A wrapper which only supports getting. 12912450Sgabeblack@google.comtemplate<class Base> 13012450Sgabeblack@google.comclass BitfieldROType : public BitfieldTypeImpl<Base> 13112450Sgabeblack@google.com{ 13212450Sgabeblack@google.com public: 13312450Sgabeblack@google.com using Impl = BitfieldTypeImpl<Base>; 13412450Sgabeblack@google.com using typename Impl::Type; 13512450Sgabeblack@google.com 13612450Sgabeblack@google.com Type operator=(BitfieldROType<Base> const &other) = delete; 13712450Sgabeblack@google.com operator Type () const { return Impl::operator Type(); } 13812450Sgabeblack@google.com}; 13912450Sgabeblack@google.com 14012450Sgabeblack@google.com//A wrapper which only supports setting. 14112450Sgabeblack@google.comtemplate <class Base> 14212450Sgabeblack@google.comclass BitfieldWOType : public BitfieldTypeImpl<Base> 14312450Sgabeblack@google.com{ 14412450Sgabeblack@google.com protected: 14512450Sgabeblack@google.com using Impl = BitfieldTypeImpl<Base>; 14612450Sgabeblack@google.com using typename Impl::Type; 14712450Sgabeblack@google.com 14812450Sgabeblack@google.com public: 14912450Sgabeblack@google.com Type operator=(const Type val) { return Impl::operator=(val); } 15012450Sgabeblack@google.com Type 15112450Sgabeblack@google.com operator=(BitfieldWOType<Base> const & other) 15212450Sgabeblack@google.com { 15312450Sgabeblack@google.com return Impl::operator=(other); 15412450Sgabeblack@google.com } 15512450Sgabeblack@google.com}; 15612450Sgabeblack@google.com 1574680Sgblack@eecs.umich.edu//This namespace is for classes which implement the backend of the BitUnion 15812450Sgabeblack@google.com//stuff. Don't use any of these directly. 1594680Sgblack@eecs.umich.edunamespace BitfieldBackend 1604680Sgblack@eecs.umich.edu{ 16112450Sgabeblack@google.com template<class Storage, int first, int last> 16212450Sgabeblack@google.com class Unsigned 1634680Sgblack@eecs.umich.edu { 16412450Sgabeblack@google.com static_assert(first >= last, 16512450Sgabeblack@google.com "Bitfield ranges must be specified as <msb, lsb>"); 16612450Sgabeblack@google.com 1674680Sgblack@eecs.umich.edu protected: 16812450Sgabeblack@google.com uint64_t 16912450Sgabeblack@google.com getter(const Storage &storage) const 1704680Sgblack@eecs.umich.edu { 17112450Sgabeblack@google.com return bits(storage, first, last); 1724680Sgblack@eecs.umich.edu } 1734680Sgblack@eecs.umich.edu 17412450Sgabeblack@google.com void 17512450Sgabeblack@google.com setter(Storage &storage, uint64_t val) 1764680Sgblack@eecs.umich.edu { 17712450Sgabeblack@google.com replaceBits(storage, first, last, val); 1784680Sgblack@eecs.umich.edu } 1794680Sgblack@eecs.umich.edu }; 1804680Sgblack@eecs.umich.edu 18112450Sgabeblack@google.com template<class Storage, int first, int last> 18212450Sgabeblack@google.com class Signed 18312450Sgabeblack@google.com { 18412450Sgabeblack@google.com static_assert(first >= last, 18512450Sgabeblack@google.com "Bitfield ranges must be specified as <msb, lsb>"); 18612450Sgabeblack@google.com 18712450Sgabeblack@google.com protected: 18812450Sgabeblack@google.com int64_t 18912450Sgabeblack@google.com getter(const Storage &storage) const 19012450Sgabeblack@google.com { 19112450Sgabeblack@google.com return sext<first - last + 1>(bits(storage, first, last)); 19212450Sgabeblack@google.com } 19312450Sgabeblack@google.com 19412450Sgabeblack@google.com void 19512450Sgabeblack@google.com setter(Storage &storage, int64_t val) 19612450Sgabeblack@google.com { 19712450Sgabeblack@google.com replaceBits(storage, first, last, val); 19812450Sgabeblack@google.com } 19912450Sgabeblack@google.com }; 20012450Sgabeblack@google.com 20112450Sgabeblack@google.com //This class contains the basic bitfield types which are automatically 20212450Sgabeblack@google.com //available within a BitUnion. They inherit their Storage type from the 20312450Sgabeblack@google.com //containing BitUnion. 20412450Sgabeblack@google.com template<class Storage> 20512450Sgabeblack@google.com class BitfieldTypes 2064680Sgblack@eecs.umich.edu { 2074680Sgblack@eecs.umich.edu protected: 20812450Sgabeblack@google.com 2094680Sgblack@eecs.umich.edu template<int first, int last=first> 21012450Sgabeblack@google.com using Bitfield = BitfieldType<Unsigned<Storage, first, last> >; 21112450Sgabeblack@google.com template<int first, int last=first> 21212450Sgabeblack@google.com using BitfieldRO = 21312450Sgabeblack@google.com BitfieldROType<Unsigned<Storage, first, last> >; 21412450Sgabeblack@google.com template<int first, int last=first> 21512450Sgabeblack@google.com using BitfieldWO = 21612450Sgabeblack@google.com BitfieldWOType<Unsigned<Storage, first, last> >; 21710289SAndreas.Sandberg@ARM.com 2184680Sgblack@eecs.umich.edu template<int first, int last=first> 21912450Sgabeblack@google.com using SignedBitfield = 22012450Sgabeblack@google.com BitfieldType<Signed<Storage, first, last> >; 2214680Sgblack@eecs.umich.edu template<int first, int last=first> 22212450Sgabeblack@google.com using SignedBitfieldRO = 22312450Sgabeblack@google.com BitfieldROType<Signed<Storage, first, last> >; 22412450Sgabeblack@google.com template<int first, int last=first> 22512450Sgabeblack@google.com using SignedBitfieldWO = 22612450Sgabeblack@google.com BitfieldWOType<Signed<Storage, first, last> >; 2274680Sgblack@eecs.umich.edu }; 2284680Sgblack@eecs.umich.edu 2294680Sgblack@eecs.umich.edu //When a BitUnion is set up, an underlying class is created which holds 2304680Sgblack@eecs.umich.edu //the actual union. This class then inherits from it, and provids the 2314680Sgblack@eecs.umich.edu //implementations for various operators. Setting things up this way 2324680Sgblack@eecs.umich.edu //prevents having to redefine these functions in every different BitUnion 2334680Sgblack@eecs.umich.edu //type. More operators could be implemented in the future, as the need 2344680Sgblack@eecs.umich.edu //arises. 23512450Sgabeblack@google.com template <class Base> 2364680Sgblack@eecs.umich.edu class BitUnionOperators : public Base 2374680Sgblack@eecs.umich.edu { 23812450Sgabeblack@google.com static_assert(sizeof(Base) == sizeof(typename Base::__StorageType), 23912450Sgabeblack@google.com "BitUnion larger than its storage type."); 24012450Sgabeblack@google.com 2414680Sgblack@eecs.umich.edu public: 24212450Sgabeblack@google.com BitUnionOperators(typename Base::__StorageType const &val) 2434681Sgblack@eecs.umich.edu { 24412450Sgabeblack@google.com Base::__storage = val; 2454681Sgblack@eecs.umich.edu } 2464681Sgblack@eecs.umich.edu 2474681Sgblack@eecs.umich.edu BitUnionOperators() {} 2484681Sgblack@eecs.umich.edu 24912450Sgabeblack@google.com operator const typename Base::__StorageType () const 2504680Sgblack@eecs.umich.edu { 25112450Sgabeblack@google.com return Base::__storage; 2524680Sgblack@eecs.umich.edu } 2534680Sgblack@eecs.umich.edu 25412450Sgabeblack@google.com typename Base::__StorageType 25512450Sgabeblack@google.com operator=(typename Base::__StorageType const &val) 2564680Sgblack@eecs.umich.edu { 25712450Sgabeblack@google.com Base::__storage = val; 25812450Sgabeblack@google.com return val; 2594680Sgblack@eecs.umich.edu } 2604680Sgblack@eecs.umich.edu 26112450Sgabeblack@google.com typename Base::__StorageType 26212450Sgabeblack@google.com operator=(BitUnionOperators const &other) 26310640Sgabeblack@google.com { 26412450Sgabeblack@google.com Base::__storage = other; 26512450Sgabeblack@google.com return Base::__storage; 26610640Sgabeblack@google.com } 26710640Sgabeblack@google.com 2684680Sgblack@eecs.umich.edu bool 26912450Sgabeblack@google.com operator<(Base const &base) const 2704680Sgblack@eecs.umich.edu { 27112450Sgabeblack@google.com return Base::__storage < base.__storage; 2724680Sgblack@eecs.umich.edu } 2734680Sgblack@eecs.umich.edu 2744680Sgblack@eecs.umich.edu bool 27512450Sgabeblack@google.com operator==(Base const &base) const 2764680Sgblack@eecs.umich.edu { 27712450Sgabeblack@google.com return Base::__storage == base.__storage; 2784680Sgblack@eecs.umich.edu } 2794680Sgblack@eecs.umich.edu }; 2804680Sgblack@eecs.umich.edu} 2814680Sgblack@eecs.umich.edu 2824680Sgblack@eecs.umich.edu//This macro is a backend for other macros that specialize it slightly. 2834680Sgblack@eecs.umich.edu//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and 2844680Sgblack@eecs.umich.edu//sticks the class which has the actual union in it, which 2854680Sgblack@eecs.umich.edu//BitfieldOperators above inherits from. Putting these classes in a special 2864680Sgblack@eecs.umich.edu//namespace ensures that there will be no collisions with other names as long 2874680Sgblack@eecs.umich.edu//as the BitUnion names themselves are all distinct and nothing else uses 2884680Sgblack@eecs.umich.edu//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself 28912450Sgabeblack@google.com//creates a typedef of the "type" parameter called __StorageType. This allows 2904680Sgblack@eecs.umich.edu//the type to propagate outside of the macro itself in a controlled way. 2914680Sgblack@eecs.umich.edu//Finally, the base storage is defined which BitfieldOperators will refer to 2924680Sgblack@eecs.umich.edu//in the operators it defines. This macro is intended to be followed by 2934680Sgblack@eecs.umich.edu//bitfield definitions which will end up inside it's union. As explained 29412450Sgabeblack@google.com//above, these is overlayed the __storage member in its entirety by each of the 2954680Sgblack@eecs.umich.edu//bitfields which are defined in the union, creating shared storage with no 2964680Sgblack@eecs.umich.edu//overhead. 2974680Sgblack@eecs.umich.edu#define __BitUnion(type, name) \ 2985442Sgblack@eecs.umich.edu class BitfieldUnderlyingClasses##name : \ 2994680Sgblack@eecs.umich.edu public BitfieldBackend::BitfieldTypes<type> \ 3004680Sgblack@eecs.umich.edu { \ 30112454Sgabeblack@google.com protected: \ 30212454Sgabeblack@google.com typedef type __StorageType; \ 30312454Sgabeblack@google.com friend BitfieldBackend::BitUnionBaseType< \ 30412454Sgabeblack@google.com BitfieldBackend::BitUnionOperators< \ 30512454Sgabeblack@google.com BitfieldUnderlyingClasses##name> >; \ 30612454Sgabeblack@google.com friend BitfieldBackend::BitUnionBaseType< \ 30712454Sgabeblack@google.com BitfieldUnderlyingClasses##name>; \ 3084680Sgblack@eecs.umich.edu public: \ 3094680Sgblack@eecs.umich.edu union { \ 31012450Sgabeblack@google.com type __storage; 3114680Sgblack@eecs.umich.edu 3124680Sgblack@eecs.umich.edu//This closes off the class and union started by the above macro. It is 3134680Sgblack@eecs.umich.edu//followed by a typedef which makes "name" refer to a BitfieldOperator 3144680Sgblack@eecs.umich.edu//class inheriting from the class and union just defined, which completes 3154680Sgblack@eecs.umich.edu//building up the type for the user. 3164680Sgblack@eecs.umich.edu#define EndBitUnion(name) \ 3174680Sgblack@eecs.umich.edu }; \ 3184680Sgblack@eecs.umich.edu }; \ 3194680Sgblack@eecs.umich.edu typedef BitfieldBackend::BitUnionOperators< \ 3205442Sgblack@eecs.umich.edu BitfieldUnderlyingClasses##name> name; 3214680Sgblack@eecs.umich.edu 3224680Sgblack@eecs.umich.edu//This sets up a bitfield which has other bitfields nested inside of it. The 32312450Sgabeblack@google.com//__storage member functions like the "underlying storage" of the top level 3244680Sgblack@eecs.umich.edu//BitUnion. Like everything else, it overlays with the top level storage, so 3254680Sgblack@eecs.umich.edu//making it a regular bitfield type makes the entire thing function as a 3264680Sgblack@eecs.umich.edu//regular bitfield when referred to by itself. 32712450Sgabeblack@google.com#define __SubBitUnion(name, fieldType, ...) \ 32812450Sgabeblack@google.com class \ 3294680Sgblack@eecs.umich.edu { \ 3304680Sgblack@eecs.umich.edu public: \ 3314680Sgblack@eecs.umich.edu union { \ 33212450Sgabeblack@google.com fieldType<__VA_ARGS__> __storage; 3334680Sgblack@eecs.umich.edu 3344680Sgblack@eecs.umich.edu//This closes off the union created above and gives it a name. Unlike the top 3354680Sgblack@eecs.umich.edu//level BitUnion, we're interested in creating an object instead of a type. 3364680Sgblack@eecs.umich.edu//The operators are defined in the macro itself instead of a class for 3374680Sgblack@eecs.umich.edu//technical reasons. If someone determines a way to move them to one, please 3384680Sgblack@eecs.umich.edu//do so. 3394680Sgblack@eecs.umich.edu#define EndSubBitUnion(name) \ 3404680Sgblack@eecs.umich.edu }; \ 34112450Sgabeblack@google.com inline operator __StorageType () const \ 34212450Sgabeblack@google.com { return __storage; } \ 3434680Sgblack@eecs.umich.edu \ 34412450Sgabeblack@google.com inline __StorageType operator = (const __StorageType & _storage) \ 34512450Sgabeblack@google.com { return __storage = _storage;} \ 3464680Sgblack@eecs.umich.edu } name; 3474680Sgblack@eecs.umich.edu 3484680Sgblack@eecs.umich.edu//Regular bitfields 3494680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields. 3504680Sgblack@eecs.umich.edu#define SubBitUnion(name, first, last) \ 35112450Sgabeblack@google.com __SubBitUnion(name, Bitfield, first, last) 3524680Sgblack@eecs.umich.edu 3534680Sgblack@eecs.umich.edu//Regular bitfields 3544680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields. 3554680Sgblack@eecs.umich.edu#define SignedSubBitUnion(name, first, last) \ 35612450Sgabeblack@google.com __SubBitUnion(name, SignedBitfield, first, last) 3574680Sgblack@eecs.umich.edu 3584680Sgblack@eecs.umich.edu//Use this to define an arbitrary type overlayed with bitfields. 3594680Sgblack@eecs.umich.edu#define BitUnion(type, name) __BitUnion(type, name) 3604680Sgblack@eecs.umich.edu 3614680Sgblack@eecs.umich.edu//Use this to define conveniently sized values overlayed with bitfields. 3624680Sgblack@eecs.umich.edu#define BitUnion64(name) __BitUnion(uint64_t, name) 3634680Sgblack@eecs.umich.edu#define BitUnion32(name) __BitUnion(uint32_t, name) 3644680Sgblack@eecs.umich.edu#define BitUnion16(name) __BitUnion(uint16_t, name) 3654680Sgblack@eecs.umich.edu#define BitUnion8(name) __BitUnion(uint8_t, name) 3664680Sgblack@eecs.umich.edu 36712451Sgabeblack@google.com 36812451Sgabeblack@google.com//These templates make it possible to define other templates related to 36912451Sgabeblack@google.com//BitUnions without having to refer to internal typedefs or the BitfieldBackend 37012451Sgabeblack@google.com//namespace. 37112451Sgabeblack@google.com 37212451Sgabeblack@google.com//To build a template specialization which works for all BitUnions, accept a 37312451Sgabeblack@google.com//template argument T, and then use BitUnionType<T> as an argument in the 37412451Sgabeblack@google.com//template. To refer to the basic type the BitUnion wraps, use 37512451Sgabeblack@google.com//BitUnionBaseType<T>. 37612451Sgabeblack@google.com 37712451Sgabeblack@google.com//For example: 37812451Sgabeblack@google.com//template <typename T> 37912451Sgabeblack@google.com//void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; } 38012451Sgabeblack@google.com 38112451Sgabeblack@google.com//Also, BitUnionBaseType can be used on a BitUnion type directly. 38212451Sgabeblack@google.com 38312451Sgabeblack@google.comtemplate <typename T> 38412451Sgabeblack@google.comusing BitUnionType = BitfieldBackend::BitUnionOperators<T>; 38512451Sgabeblack@google.com 38612451Sgabeblack@google.comnamespace BitfieldBackend 38712451Sgabeblack@google.com{ 38812451Sgabeblack@google.com template<typename T> 38912451Sgabeblack@google.com struct BitUnionBaseType 39012451Sgabeblack@google.com { 39112451Sgabeblack@google.com typedef typename BitUnionType<T>::__StorageType Type; 39212451Sgabeblack@google.com }; 39312451Sgabeblack@google.com 39412451Sgabeblack@google.com template<typename T> 39512451Sgabeblack@google.com struct BitUnionBaseType<BitUnionType<T> > 39612451Sgabeblack@google.com { 39712451Sgabeblack@google.com typedef typename BitUnionType<T>::__StorageType Type; 39812451Sgabeblack@google.com }; 39912451Sgabeblack@google.com} 40012451Sgabeblack@google.com 40112451Sgabeblack@google.comtemplate <typename T> 40212451Sgabeblack@google.comusing BitUnionBaseType = typename BitfieldBackend::BitUnionBaseType<T>::Type; 40312451Sgabeblack@google.com 40412454Sgabeblack@google.com 40512454Sgabeblack@google.com//An STL style hash structure for hashing BitUnions based on their base type. 40612453Sgabeblack@google.comnamespace std 40712453Sgabeblack@google.com{ 40812453Sgabeblack@google.com template <typename T> 40912453Sgabeblack@google.com struct hash<BitUnionType<T> > : public hash<BitUnionBaseType<T> > 41012453Sgabeblack@google.com { 41112453Sgabeblack@google.com size_t 41212453Sgabeblack@google.com operator() (const BitUnionType<T> &val) const 41312453Sgabeblack@google.com { 41412453Sgabeblack@google.com return hash<BitUnionBaseType<T> >::operator()(val); 41512453Sgabeblack@google.com } 41612453Sgabeblack@google.com }; 41712453Sgabeblack@google.com} 41812453Sgabeblack@google.com 41912625Sgabeblack@google.com 42012625Sgabeblack@google.comnamespace BitfieldBackend 42112625Sgabeblack@google.com{ 42212625Sgabeblack@google.comnamespace 42312625Sgabeblack@google.com{ 42412625Sgabeblack@google.com template<typename T> 42512625Sgabeblack@google.com std::ostream & 42612625Sgabeblack@google.com bitfieldBackendPrinter(std::ostream &os, const T &t) 42712625Sgabeblack@google.com { 42812625Sgabeblack@google.com os << t; 42912625Sgabeblack@google.com return os; 43012625Sgabeblack@google.com } 43112625Sgabeblack@google.com 43212625Sgabeblack@google.com //Since BitUnions are generally numerical values and not character codes, 43312625Sgabeblack@google.com //these specializations attempt to ensure that they get cast to integers 43412625Sgabeblack@google.com //of the appropriate type before printing. 43512625Sgabeblack@google.com template <> 43612625Sgabeblack@google.com std::ostream & 43712625Sgabeblack@google.com bitfieldBackendPrinter(std::ostream &os, const char &t) 43812625Sgabeblack@google.com { 43912625Sgabeblack@google.com os << (const int)t; 44012625Sgabeblack@google.com return os; 44112625Sgabeblack@google.com } 44212625Sgabeblack@google.com 44312625Sgabeblack@google.com template <> 44412625Sgabeblack@google.com std::ostream & 44512625Sgabeblack@google.com bitfieldBackendPrinter(std::ostream &os, const unsigned char &t) 44612625Sgabeblack@google.com { 44712625Sgabeblack@google.com os << (const unsigned int)t; 44812625Sgabeblack@google.com return os; 44912625Sgabeblack@google.com } 45012625Sgabeblack@google.com} 45112625Sgabeblack@google.com} 45212625Sgabeblack@google.com 45312625Sgabeblack@google.com//A default << operator which casts a bitunion to its underlying type and 45412625Sgabeblack@google.com//passes it to BitfieldBackend::bitfieldBackendPrinter. 45512625Sgabeblack@google.comtemplate <typename T> 45612625Sgabeblack@google.comstd::ostream & 45712625Sgabeblack@google.comoperator << (std::ostream &os, const BitUnionType<T> &bu) 45812625Sgabeblack@google.com{ 45912625Sgabeblack@google.com return BitfieldBackend::bitfieldBackendPrinter( 46012625Sgabeblack@google.com os, (BitUnionBaseType<T>)bu); 46112625Sgabeblack@google.com} 46212625Sgabeblack@google.com 4634680Sgblack@eecs.umich.edu#endif // __BASE_BITUNION_HH__ 464