bitfield.h (3499B)
1 // SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 #include "types.h" 6 #include <type_traits> 7 8 // Disable MSVC warnings that we actually handle 9 #ifdef _MSC_VER 10 #pragma warning(push) 11 #pragma warning(disable : 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning) 12 #endif 13 14 template<typename BackingDataType, typename DataType, unsigned BitIndex, unsigned BitCount> 15 struct BitField 16 { 17 static_assert(!std::is_same_v<DataType, bool> || BitCount == 1, "Boolean bitfields should only be 1 bit"); 18 19 // We have to delete the copy assignment operator otherwise we can't use this class in anonymous structs/unions. 20 BitField& operator=(const BitField& rhs) = delete; 21 22 ALWAYS_INLINE constexpr BackingDataType GetMask() const 23 { 24 return ((static_cast<BackingDataType>(~0)) >> (8 * sizeof(BackingDataType) - BitCount)) << BitIndex; 25 } 26 27 ALWAYS_INLINE constexpr operator DataType() const { return GetValue(); } 28 29 ALWAYS_INLINE constexpr BitField& operator=(DataType value) 30 { 31 SetValue(value); 32 return *this; 33 } 34 35 ALWAYS_INLINE constexpr DataType operator++() 36 { 37 DataType value = GetValue() + 1; 38 SetValue(value); 39 return GetValue(); 40 } 41 42 ALWAYS_INLINE constexpr DataType operator++(int) 43 { 44 DataType value = GetValue(); 45 SetValue(value + 1); 46 return value; 47 } 48 49 ALWAYS_INLINE constexpr DataType operator--() 50 { 51 DataType value = GetValue() - 1; 52 SetValue(value); 53 return GetValue(); 54 } 55 56 ALWAYS_INLINE constexpr DataType operator--(int) 57 { 58 DataType value = GetValue(); 59 SetValue(value - 1); 60 return value; 61 } 62 63 ALWAYS_INLINE constexpr BitField& operator+=(DataType rhs) 64 { 65 SetValue(GetValue() + rhs); 66 return *this; 67 } 68 69 ALWAYS_INLINE constexpr BitField& operator-=(DataType rhs) 70 { 71 SetValue(GetValue() - rhs); 72 return *this; 73 } 74 75 ALWAYS_INLINE constexpr BitField& operator*=(DataType rhs) 76 { 77 SetValue(GetValue() * rhs); 78 return *this; 79 } 80 81 ALWAYS_INLINE constexpr BitField& operator/=(DataType rhs) 82 { 83 SetValue(GetValue() / rhs); 84 return *this; 85 } 86 87 ALWAYS_INLINE constexpr BitField& operator&=(DataType rhs) 88 { 89 SetValue(GetValue() & rhs); 90 return *this; 91 } 92 93 ALWAYS_INLINE constexpr BitField& operator|=(DataType rhs) 94 { 95 SetValue(GetValue() | rhs); 96 return *this; 97 } 98 99 ALWAYS_INLINE constexpr BitField& operator^=(DataType rhs) 100 { 101 SetValue(GetValue() ^ rhs); 102 return *this; 103 } 104 105 ALWAYS_INLINE constexpr BitField& operator<<=(DataType rhs) 106 { 107 SetValue(GetValue() << rhs); 108 return *this; 109 } 110 111 ALWAYS_INLINE constexpr BitField& operator>>=(DataType rhs) 112 { 113 SetValue(GetValue() >> rhs); 114 return *this; 115 } 116 117 ALWAYS_INLINE constexpr DataType GetValue() const 118 { 119 if constexpr (std::is_same_v<DataType, bool>) 120 { 121 return static_cast<DataType>(!!((data & GetMask()) >> BitIndex)); 122 } 123 else if constexpr (std::is_signed_v<DataType>) 124 { 125 constexpr int shift = 8 * sizeof(DataType) - BitCount; 126 return (static_cast<DataType>(data >> BitIndex) << shift) >> shift; 127 } 128 else 129 { 130 return static_cast<DataType>((data & GetMask()) >> BitIndex); 131 } 132 } 133 134 ALWAYS_INLINE constexpr void SetValue(DataType value) 135 { 136 data = (data & ~GetMask()) | ((static_cast<BackingDataType>(value) << BitIndex) & GetMask()); 137 } 138 139 BackingDataType data; 140 }; 141 142 #ifdef _MSC_VER 143 #pragma warning(pop) 144 #endif