mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	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
This commit is contained in:
		
							parent
							
								
									a59920ed35
								
							
						
					
					
						commit
						3d73b8d694
					
				
					 1 changed files with 10 additions and 9 deletions
				
			
		|  | @ -111,15 +111,15 @@ | |||
| template <std::size_t Position, std::size_t Bits, typename T> | ||||
| struct BitField { | ||||
| private: | ||||
|     // StorageType is T for non-enum types and the underlying type of T if
 | ||||
|     // UnderlyingType is T for non-enum types and the underlying type of T if
 | ||||
|     // T is an enumeration. Note that T is wrapped within an enable_if in the
 | ||||
|     // former case to workaround compile errors which arise when using
 | ||||
|     // std::underlying_type<T>::type directly.
 | ||||
|     using StorageType = typename std::conditional_t<std::is_enum<T>::value, std::underlying_type<T>, | ||||
|                                                     std::enable_if<true, T>>::type; | ||||
|     using UnderlyingType = typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>, | ||||
|                                                        std::enable_if<true, T>>::type; | ||||
| 
 | ||||
|     // Unsigned version of StorageType
 | ||||
|     using StorageTypeU = std::make_unsigned_t<StorageType>; | ||||
|     // We store the value as the unsigned type to avoid undefined behaviour on value shifting
 | ||||
|     using StorageType = std::make_unsigned_t<UnderlyingType>; | ||||
| 
 | ||||
| public: | ||||
|     BitField& operator=(const BitField&) = default; | ||||
|  | @ -127,7 +127,7 @@ public: | |||
|     /// Constants to allow limited introspection of fields if needed
 | ||||
|     static constexpr std::size_t position = Position; | ||||
|     static constexpr std::size_t bits = Bits; | ||||
|     static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; | ||||
|     static constexpr StorageType mask = (((StorageType)~0) >> (8 * sizeof(T) - bits)) << position; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Formats a value by masking and shifting it according to the field parameters. A value | ||||
|  | @ -144,11 +144,12 @@ public: | |||
|      * union in a constexpr context. | ||||
|      */ | ||||
|     static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { | ||||
|         if (std::numeric_limits<T>::is_signed) { | ||||
|         if constexpr (std::numeric_limits<UnderlyingType>::is_signed) { | ||||
|             std::size_t shift = 8 * sizeof(T) - bits; | ||||
|             return (T)((storage << (shift - position)) >> shift); | ||||
|             return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >> | ||||
|                                   shift); | ||||
|         } else { | ||||
|             return (T)((storage & mask) >> position); | ||||
|             return static_cast<T>((storage & mask) >> position); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue