diff options
| author | 2017-05-20 20:40:13 -0700 | |
|---|---|---|
| committer | 2017-05-24 21:05:59 -0700 | |
| commit | a75145a2c66808f1c4c905da415f0c9c22172dfd (patch) | |
| tree | ffe5d4edf9cb966535bb149311045b334df779ea /src/common/bit_field.h | |
| parent | Merge pull request #2406 from Subv/session_disconnect (diff) | |
| download | yuzu-a75145a2c66808f1c4c905da415f0c9c22172dfd.tar.gz yuzu-a75145a2c66808f1c4c905da415f0c9c22172dfd.tar.xz yuzu-a75145a2c66808f1c4c905da415f0c9c22172dfd.zip | |
Make BitField and ResultCode constexpr-initializable
Diffstat (limited to '')
| -rw-r--r-- | src/common/bit_field.h | 65 |
1 files changed, 42 insertions, 23 deletions
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 030f7caeb..72a01c7a8 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -108,7 +108,7 @@ | |||
| 108 | * symptoms. | 108 | * symptoms. |
| 109 | */ | 109 | */ |
| 110 | #pragma pack(1) | 110 | #pragma pack(1) |
| 111 | template <std::size_t position, std::size_t bits, typename T> | 111 | template <std::size_t Position, std::size_t Bits, typename T> |
| 112 | struct BitField { | 112 | struct BitField { |
| 113 | private: | 113 | private: |
| 114 | // We hide the copy assigment operator here, because the default copy | 114 | // We hide the copy assigment operator here, because the default copy |
| @@ -117,7 +117,45 @@ private: | |||
| 117 | // We don't delete it because we want BitField to be trivially copyable. | 117 | // We don't delete it because we want BitField to be trivially copyable. |
| 118 | BitField& operator=(const BitField&) = default; | 118 | BitField& operator=(const BitField&) = default; |
| 119 | 119 | ||
| 120 | // StorageType is T for non-enum types and the underlying type of T if | ||
| 121 | // T is an enumeration. Note that T is wrapped within an enable_if in the | ||
| 122 | // former case to workaround compile errors which arise when using | ||
| 123 | // std::underlying_type<T>::type directly. | ||
| 124 | typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>, | ||
| 125 | std::enable_if<true, T>>::type::type StorageType; | ||
| 126 | |||
| 127 | // Unsigned version of StorageType | ||
| 128 | typedef typename std::make_unsigned<StorageType>::type StorageTypeU; | ||
| 129 | |||
| 120 | public: | 130 | public: |
| 131 | /// Constants to allow limited introspection of fields if needed | ||
| 132 | static constexpr size_t position = Position; | ||
| 133 | static constexpr size_t bits = Bits; | ||
| 134 | static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; | ||
| 135 | |||
| 136 | /** | ||
| 137 | * Formats a value by masking and shifting it according to the field parameters. A value | ||
| 138 | * containing several bitfields can be assembled by formatting each of their values and ORing | ||
| 139 | * the results together. | ||
| 140 | */ | ||
| 141 | static constexpr FORCE_INLINE StorageType FormatValue(const T& value) { | ||
| 142 | return ((StorageType)value << position) & mask; | ||
| 143 | } | ||
| 144 | |||
| 145 | /** | ||
| 146 | * Extracts a value from the passed storage. In most situations prefer use the member functions | ||
| 147 | * (such as Value() or operator T), but this can be used to extract a value from a bitfield | ||
| 148 | * union in a constexpr context. | ||
| 149 | */ | ||
| 150 | static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { | ||
| 151 | if (std::numeric_limits<T>::is_signed) { | ||
| 152 | std::size_t shift = 8 * sizeof(T) - bits; | ||
| 153 | return (T)((storage << (shift - position)) >> shift); | ||
| 154 | } else { | ||
| 155 | return (T)((storage & mask) >> position); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 121 | // This constructor and assignment operator might be considered ambiguous: | 159 | // This constructor and assignment operator might be considered ambiguous: |
| 122 | // Would they initialize the storage or just the bitfield? | 160 | // Would they initialize the storage or just the bitfield? |
| 123 | // Hence, delete them. Use the Assign method to set bitfield values! | 161 | // Hence, delete them. Use the Assign method to set bitfield values! |
| @@ -126,23 +164,18 @@ public: | |||
| 126 | 164 | ||
| 127 | // Force default constructor to be created | 165 | // Force default constructor to be created |
| 128 | // so that we can use this within unions | 166 | // so that we can use this within unions |
| 129 | BitField() = default; | 167 | constexpr BitField() = default; |
| 130 | 168 | ||
| 131 | FORCE_INLINE operator T() const { | 169 | FORCE_INLINE operator T() const { |
| 132 | return Value(); | 170 | return Value(); |
| 133 | } | 171 | } |
| 134 | 172 | ||
| 135 | FORCE_INLINE void Assign(const T& value) { | 173 | FORCE_INLINE void Assign(const T& value) { |
| 136 | storage = (storage & ~GetMask()) | (((StorageType)value << position) & GetMask()); | 174 | storage = (storage & ~mask) | FormatValue(value); |
| 137 | } | 175 | } |
| 138 | 176 | ||
| 139 | FORCE_INLINE T Value() const { | 177 | FORCE_INLINE T Value() const { |
| 140 | if (std::numeric_limits<T>::is_signed) { | 178 | return ExtractValue(storage); |
| 141 | std::size_t shift = 8 * sizeof(T) - bits; | ||
| 142 | return (T)((storage << (shift - position)) >> shift); | ||
| 143 | } else { | ||
| 144 | return (T)((storage & GetMask()) >> position); | ||
| 145 | } | ||
| 146 | } | 179 | } |
| 147 | 180 | ||
| 148 | // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015 | 181 | // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015 |
| @@ -151,20 +184,6 @@ public: | |||
| 151 | } | 184 | } |
| 152 | 185 | ||
| 153 | private: | 186 | private: |
| 154 | // StorageType is T for non-enum types and the underlying type of T if | ||
| 155 | // T is an enumeration. Note that T is wrapped within an enable_if in the | ||
| 156 | // former case to workaround compile errors which arise when using | ||
| 157 | // std::underlying_type<T>::type directly. | ||
| 158 | typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>, | ||
| 159 | std::enable_if<true, T>>::type::type StorageType; | ||
| 160 | |||
| 161 | // Unsigned version of StorageType | ||
| 162 | typedef typename std::make_unsigned<StorageType>::type StorageTypeU; | ||
| 163 | |||
| 164 | FORCE_INLINE StorageType GetMask() const { | ||
| 165 | return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; | ||
| 166 | } | ||
| 167 | |||
| 168 | StorageType storage; | 187 | StorageType storage; |
| 169 | 188 | ||
| 170 | static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | 189 | static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); |