summaryrefslogtreecommitdiff
path: root/src/common/bit_field.h
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2017-05-20 20:40:13 -0700
committerGravatar Yuri Kunde Schlesner2017-05-24 21:05:59 -0700
commita75145a2c66808f1c4c905da415f0c9c22172dfd (patch)
treeffe5d4edf9cb966535bb149311045b334df779ea /src/common/bit_field.h
parentMerge pull request #2406 from Subv/session_disconnect (diff)
downloadyuzu-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.h65
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)
111template <std::size_t position, std::size_t bits, typename T> 111template <std::size_t Position, std::size_t Bits, typename T>
112struct BitField { 112struct BitField {
113private: 113private:
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
120public: 130public:
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
153private: 186private:
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");