diff options
| author | 2018-11-10 23:41:30 -0500 | |
|---|---|---|
| committer | 2018-11-16 15:49:57 +0100 | |
| commit | 786995a81e999617e426b5ea5b867cabb2ee6ec3 (patch) | |
| tree | d204320d2b720f7252026665096defc95976de8a /src/common/bit_field.h | |
| parent | Merge pull request #1709 from ogniK5377/docked-mode-crash (diff) | |
| download | yuzu-786995a81e999617e426b5ea5b867cabb2ee6ec3.tar.gz yuzu-786995a81e999617e426b5ea5b867cabb2ee6ec3.tar.xz yuzu-786995a81e999617e426b5ea5b867cabb2ee6ec3.zip | |
Common/Bitfield: store value as unsigned type
Storing signed type causes the following behaviour: extractValue can do overflow/negative left shift. Now it only relies on two implementation-defined behaviours (which are almost always defined as we want): unsigned->signed conversion and signed right shift
Diffstat (limited to '')
| -rw-r--r-- | src/common/bit_field.h | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index bf803da8d..21e07925d 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -117,21 +117,21 @@ 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 | constexpr BitField& operator=(const BitField&) = default; | 118 | constexpr BitField& operator=(const BitField&) = default; |
| 119 | 119 | ||
| 120 | // StorageType is T for non-enum types and the underlying type of T if | 120 | // UnderlyingType 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 | 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 | 122 | // former case to workaround compile errors which arise when using |
| 123 | // std::underlying_type<T>::type directly. | 123 | // std::underlying_type<T>::type directly. |
| 124 | using StorageType = typename std::conditional_t<std::is_enum<T>::value, std::underlying_type<T>, | 124 | using UnderlyingType = typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>, |
| 125 | std::enable_if<true, T>>::type; | 125 | std::enable_if<true, T>>::type; |
| 126 | 126 | ||
| 127 | // Unsigned version of StorageType | 127 | // We store the value as the unsigned type to avoid undefined behaviour on value shifting |
| 128 | using StorageTypeU = std::make_unsigned_t<StorageType>; | 128 | using StorageType = std::make_unsigned_t<UnderlyingType>; |
| 129 | 129 | ||
| 130 | public: | 130 | public: |
| 131 | /// Constants to allow limited introspection of fields if needed | 131 | /// Constants to allow limited introspection of fields if needed |
| 132 | static constexpr std::size_t position = Position; | 132 | static constexpr std::size_t position = Position; |
| 133 | static constexpr std::size_t bits = Bits; | 133 | static constexpr std::size_t bits = Bits; |
| 134 | static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; | 134 | static constexpr StorageType mask = (((StorageType)~0) >> (8 * sizeof(T) - bits)) << position; |
| 135 | 135 | ||
| 136 | /** | 136 | /** |
| 137 | * Formats a value by masking and shifting it according to the field parameters. A value | 137 | * Formats a value by masking and shifting it according to the field parameters. A value |
| @@ -148,11 +148,12 @@ public: | |||
| 148 | * union in a constexpr context. | 148 | * union in a constexpr context. |
| 149 | */ | 149 | */ |
| 150 | static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { | 150 | static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { |
| 151 | if (std::numeric_limits<T>::is_signed) { | 151 | if constexpr (std::numeric_limits<UnderlyingType>::is_signed) { |
| 152 | std::size_t shift = 8 * sizeof(T) - bits; | 152 | std::size_t shift = 8 * sizeof(T) - bits; |
| 153 | return (T)((storage << (shift - position)) >> shift); | 153 | return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >> |
| 154 | shift); | ||
| 154 | } else { | 155 | } else { |
| 155 | return (T)((storage & mask) >> position); | 156 | return static_cast<T>((storage & mask) >> position); |
| 156 | } | 157 | } |
| 157 | } | 158 | } |
| 158 | 159 | ||