bitunion.hh revision 12465
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 <iostream> 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; 408 409 template <typename T> 410 struct hash<BitUnionType<T> > : public hash<BitUnionBaseType<T> > 411 { 412 size_t 413 operator() (const BitUnionType<T> &val) const 414 { 415 return hash<BitUnionBaseType<T> >::operator()(val); 416 } 417 }; 418} 419 420#endif // __BASE_BITUNION_HH__ 421