bitunion.hh revision 12453
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 using Base::setter; 59 60 template<typename T> 61 struct TypeDeducer; 62 63 template<typename T> 64 friend class TypeDeducer; 65 66 template<typename Type1, typename Type2> 67 struct TypeDeducer<void (Base::*)(Type1 &, Type2)> 68 { 69 typedef Type1 Storage; 70 typedef Type2 Type; 71 }; 72 73 protected: 74 typedef typename TypeDeducer< 75 decltype(&BitfieldTypeImpl<Base>::setter)>::Storage Storage; 76 typedef typename TypeDeducer< 77 decltype(&BitfieldTypeImpl<Base>::setter)>::Type Type; 78 79 Type getter(const Storage &storage) const = delete; 80 void setter(Storage &storage, Type val) = delete; 81 82 Storage __storage; 83 84 operator Type () const 85 { 86 return Base::getter(__storage); 87 } 88 89 Type 90 operator=(const Type val) 91 { 92 Base::setter(__storage, val); 93 return val; 94 } 95 96 Type 97 operator=(BitfieldTypeImpl<Base> const & other) 98 { 99 return *this = (Type)other; 100 } 101}; 102 103//A wrapper for the above class which allows setting and getting. 104template<class Base> 105class BitfieldType : public BitfieldTypeImpl<Base> 106{ 107 protected: 108 using Impl = BitfieldTypeImpl<Base>; 109 using typename Impl::Type; 110 111 public: 112 operator Type () const { return Impl::operator Type(); } 113 Type operator=(const Type val) { return Impl::operator=(val); } 114 Type 115 operator=(BitfieldType<Base> const & other) 116 { 117 return Impl::operator=(other); 118 } 119}; 120 121//A wrapper which only supports getting. 122template<class Base> 123class BitfieldROType : public BitfieldTypeImpl<Base> 124{ 125 public: 126 using Impl = BitfieldTypeImpl<Base>; 127 using typename Impl::Type; 128 129 Type operator=(BitfieldROType<Base> const &other) = delete; 130 operator Type () const { return Impl::operator Type(); } 131}; 132 133//A wrapper which only supports setting. 134template <class Base> 135class BitfieldWOType : public BitfieldTypeImpl<Base> 136{ 137 protected: 138 using Impl = BitfieldTypeImpl<Base>; 139 using typename Impl::Type; 140 141 public: 142 Type operator=(const Type val) { return Impl::operator=(val); } 143 Type 144 operator=(BitfieldWOType<Base> const & other) 145 { 146 return Impl::operator=(other); 147 } 148}; 149 150//This namespace is for classes which implement the backend of the BitUnion 151//stuff. Don't use any of these directly. 152namespace BitfieldBackend 153{ 154 template<class Storage, int first, int last> 155 class Unsigned 156 { 157 static_assert(first >= last, 158 "Bitfield ranges must be specified as <msb, lsb>"); 159 160 protected: 161 uint64_t 162 getter(const Storage &storage) const 163 { 164 return bits(storage, first, last); 165 } 166 167 void 168 setter(Storage &storage, uint64_t val) 169 { 170 replaceBits(storage, first, last, val); 171 } 172 }; 173 174 template<class Storage, int first, int last> 175 class Signed 176 { 177 static_assert(first >= last, 178 "Bitfield ranges must be specified as <msb, lsb>"); 179 180 protected: 181 int64_t 182 getter(const Storage &storage) const 183 { 184 return sext<first - last + 1>(bits(storage, first, last)); 185 } 186 187 void 188 setter(Storage &storage, int64_t val) 189 { 190 replaceBits(storage, first, last, val); 191 } 192 }; 193 194 //This class contains the basic bitfield types which are automatically 195 //available within a BitUnion. They inherit their Storage type from the 196 //containing BitUnion. 197 template<class Storage> 198 class BitfieldTypes 199 { 200 protected: 201 202 template<int first, int last=first> 203 using Bitfield = BitfieldType<Unsigned<Storage, first, last> >; 204 template<int first, int last=first> 205 using BitfieldRO = 206 BitfieldROType<Unsigned<Storage, first, last> >; 207 template<int first, int last=first> 208 using BitfieldWO = 209 BitfieldWOType<Unsigned<Storage, first, last> >; 210 211 template<int first, int last=first> 212 using SignedBitfield = 213 BitfieldType<Signed<Storage, first, last> >; 214 template<int first, int last=first> 215 using SignedBitfieldRO = 216 BitfieldROType<Signed<Storage, first, last> >; 217 template<int first, int last=first> 218 using SignedBitfieldWO = 219 BitfieldWOType<Signed<Storage, first, last> >; 220 }; 221 222 //When a BitUnion is set up, an underlying class is created which holds 223 //the actual union. This class then inherits from it, and provids the 224 //implementations for various operators. Setting things up this way 225 //prevents having to redefine these functions in every different BitUnion 226 //type. More operators could be implemented in the future, as the need 227 //arises. 228 template <class Base> 229 class BitUnionOperators : public Base 230 { 231 static_assert(sizeof(Base) == sizeof(typename Base::__StorageType), 232 "BitUnion larger than its storage type."); 233 234 public: 235 BitUnionOperators(typename Base::__StorageType const &val) 236 { 237 Base::__storage = val; 238 } 239 240 BitUnionOperators() {} 241 242 operator const typename Base::__StorageType () const 243 { 244 return Base::__storage; 245 } 246 247 typename Base::__StorageType 248 operator=(typename Base::__StorageType const &val) 249 { 250 Base::__storage = val; 251 return val; 252 } 253 254 typename Base::__StorageType 255 operator=(BitUnionOperators const &other) 256 { 257 Base::__storage = other; 258 return Base::__storage; 259 } 260 261 bool 262 operator<(Base const &base) const 263 { 264 return Base::__storage < base.__storage; 265 } 266 267 bool 268 operator==(Base const &base) const 269 { 270 return Base::__storage == base.__storage; 271 } 272 }; 273} 274 275//This macro is a backend for other macros that specialize it slightly. 276//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and 277//sticks the class which has the actual union in it, which 278//BitfieldOperators above inherits from. Putting these classes in a special 279//namespace ensures that there will be no collisions with other names as long 280//as the BitUnion names themselves are all distinct and nothing else uses 281//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself 282//creates a typedef of the "type" parameter called __StorageType. This allows 283//the type to propagate outside of the macro itself in a controlled way. 284//Finally, the base storage is defined which BitfieldOperators will refer to 285//in the operators it defines. This macro is intended to be followed by 286//bitfield definitions which will end up inside it's union. As explained 287//above, these is overlayed the __storage member in its entirety by each of the 288//bitfields which are defined in the union, creating shared storage with no 289//overhead. 290#define __BitUnion(type, name) \ 291 class BitfieldUnderlyingClasses##name : \ 292 public BitfieldBackend::BitfieldTypes<type> \ 293 { \ 294 public: \ 295 typedef type __StorageType; \ 296 union { \ 297 type __storage; 298 299//This closes off the class and union started by the above macro. It is 300//followed by a typedef which makes "name" refer to a BitfieldOperator 301//class inheriting from the class and union just defined, which completes 302//building up the type for the user. 303#define EndBitUnion(name) \ 304 }; \ 305 }; \ 306 typedef BitfieldBackend::BitUnionOperators< \ 307 BitfieldUnderlyingClasses##name> name; 308 309//This sets up a bitfield which has other bitfields nested inside of it. The 310//__storage member functions like the "underlying storage" of the top level 311//BitUnion. Like everything else, it overlays with the top level storage, so 312//making it a regular bitfield type makes the entire thing function as a 313//regular bitfield when referred to by itself. 314#define __SubBitUnion(name, fieldType, ...) \ 315 class \ 316 { \ 317 public: \ 318 union { \ 319 fieldType<__VA_ARGS__> __storage; 320 321//This closes off the union created above and gives it a name. Unlike the top 322//level BitUnion, we're interested in creating an object instead of a type. 323//The operators are defined in the macro itself instead of a class for 324//technical reasons. If someone determines a way to move them to one, please 325//do so. 326#define EndSubBitUnion(name) \ 327 }; \ 328 inline operator __StorageType () const \ 329 { return __storage; } \ 330 \ 331 inline __StorageType operator = (const __StorageType & _storage) \ 332 { return __storage = _storage;} \ 333 } name; 334 335//Regular bitfields 336//These define macros for read/write regular bitfield based subbitfields. 337#define SubBitUnion(name, first, last) \ 338 __SubBitUnion(name, Bitfield, first, last) 339 340//Regular bitfields 341//These define macros for read/write regular bitfield based subbitfields. 342#define SignedSubBitUnion(name, first, last) \ 343 __SubBitUnion(name, SignedBitfield, first, last) 344 345//Use this to define an arbitrary type overlayed with bitfields. 346#define BitUnion(type, name) __BitUnion(type, name) 347 348//Use this to define conveniently sized values overlayed with bitfields. 349#define BitUnion64(name) __BitUnion(uint64_t, name) 350#define BitUnion32(name) __BitUnion(uint32_t, name) 351#define BitUnion16(name) __BitUnion(uint16_t, name) 352#define BitUnion8(name) __BitUnion(uint8_t, name) 353 354 355//These templates make it possible to define other templates related to 356//BitUnions without having to refer to internal typedefs or the BitfieldBackend 357//namespace. 358 359//To build a template specialization which works for all BitUnions, accept a 360//template argument T, and then use BitUnionType<T> as an argument in the 361//template. To refer to the basic type the BitUnion wraps, use 362//BitUnionBaseType<T>. 363 364//For example: 365//template <typename T> 366//void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; } 367 368//Also, BitUnionBaseType can be used on a BitUnion type directly. 369 370template <typename T> 371using BitUnionType = BitfieldBackend::BitUnionOperators<T>; 372 373namespace BitfieldBackend 374{ 375 template<typename T> 376 struct BitUnionBaseType 377 { 378 typedef typename BitUnionType<T>::__StorageType Type; 379 }; 380 381 template<typename T> 382 struct BitUnionBaseType<BitUnionType<T> > 383 { 384 typedef typename BitUnionType<T>::__StorageType Type; 385 }; 386} 387 388template <typename T> 389using BitUnionBaseType = typename BitfieldBackend::BitUnionBaseType<T>::Type; 390 391namespace std 392{ 393 template <typename T> 394 struct hash; 395 396 template <typename T> 397 struct hash<BitUnionType<T> > : public hash<BitUnionBaseType<T> > 398 { 399 size_t 400 operator() (const BitUnionType<T> &val) const 401 { 402 return hash<BitUnionBaseType<T> >::operator()(val); 403 } 404 }; 405} 406 407#endif // __BASE_BITUNION_HH__ 408