mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Make BitField and ResultCode constexpr-initializable
This commit is contained in:
		
							parent
							
								
									cc566dadd8
								
							
						
					
					
						commit
						a75145a2c6
					
				
					 2 changed files with 71 additions and 55 deletions
				
			
		|  | @ -108,7 +108,7 @@ | |||
|  * symptoms. | ||||
|  */ | ||||
| #pragma pack(1) | ||||
| template <std::size_t position, std::size_t bits, typename T> | ||||
| template <std::size_t Position, std::size_t Bits, typename T> | ||||
| struct BitField { | ||||
| private: | ||||
|     // We hide the copy assigment operator here, because the default copy
 | ||||
|  | @ -117,40 +117,6 @@ private: | |||
|     // We don't delete it because we want BitField to be trivially copyable.
 | ||||
|     BitField& operator=(const BitField&) = default; | ||||
| 
 | ||||
| public: | ||||
|     // This constructor and assignment operator might be considered ambiguous:
 | ||||
|     // Would they initialize the storage or just the bitfield?
 | ||||
|     // Hence, delete them. Use the Assign method to set bitfield values!
 | ||||
|     BitField(T val) = delete; | ||||
|     BitField& operator=(T val) = delete; | ||||
| 
 | ||||
|     // Force default constructor to be created
 | ||||
|     // so that we can use this within unions
 | ||||
|     BitField() = default; | ||||
| 
 | ||||
|     FORCE_INLINE operator T() const { | ||||
|         return Value(); | ||||
|     } | ||||
| 
 | ||||
|     FORCE_INLINE void Assign(const T& value) { | ||||
|         storage = (storage & ~GetMask()) | (((StorageType)value << position) & GetMask()); | ||||
|     } | ||||
| 
 | ||||
|     FORCE_INLINE T Value() const { | ||||
|         if (std::numeric_limits<T>::is_signed) { | ||||
|             std::size_t shift = 8 * sizeof(T) - bits; | ||||
|             return (T)((storage << (shift - position)) >> shift); | ||||
|         } else { | ||||
|             return (T)((storage & GetMask()) >> position); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015
 | ||||
|     FORCE_INLINE bool ToBool() const { | ||||
|         return Value() != 0; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     // StorageType 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
 | ||||
|  | @ -161,10 +127,63 @@ private: | |||
|     // Unsigned version of StorageType
 | ||||
|     typedef typename std::make_unsigned<StorageType>::type StorageTypeU; | ||||
| 
 | ||||
|     FORCE_INLINE StorageType GetMask() const { | ||||
|         return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; | ||||
| public: | ||||
|     /// Constants to allow limited introspection of fields if needed
 | ||||
|     static constexpr size_t position = Position; | ||||
|     static constexpr size_t bits = Bits; | ||||
|     static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Formats a value by masking and shifting it according to the field parameters. A value | ||||
|      * containing several bitfields can be assembled by formatting each of their values and ORing | ||||
|      * the results together. | ||||
|      */ | ||||
|     static constexpr FORCE_INLINE StorageType FormatValue(const T& value) { | ||||
|         return ((StorageType)value << position) & mask; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Extracts a value from the passed storage. In most situations prefer use the member functions | ||||
|      * (such as Value() or operator T), but this can be used to extract a value from a bitfield | ||||
|      * union in a constexpr context. | ||||
|      */ | ||||
|     static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { | ||||
|         if (std::numeric_limits<T>::is_signed) { | ||||
|             std::size_t shift = 8 * sizeof(T) - bits; | ||||
|             return (T)((storage << (shift - position)) >> shift); | ||||
|         } else { | ||||
|             return (T)((storage & mask) >> position); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // This constructor and assignment operator might be considered ambiguous:
 | ||||
|     // Would they initialize the storage or just the bitfield?
 | ||||
|     // Hence, delete them. Use the Assign method to set bitfield values!
 | ||||
|     BitField(T val) = delete; | ||||
|     BitField& operator=(T val) = delete; | ||||
| 
 | ||||
|     // Force default constructor to be created
 | ||||
|     // so that we can use this within unions
 | ||||
|     constexpr BitField() = default; | ||||
| 
 | ||||
|     FORCE_INLINE operator T() const { | ||||
|         return Value(); | ||||
|     } | ||||
| 
 | ||||
|     FORCE_INLINE void Assign(const T& value) { | ||||
|         storage = (storage & ~mask) | FormatValue(value); | ||||
|     } | ||||
| 
 | ||||
|     FORCE_INLINE T Value() const { | ||||
|         return ExtractValue(storage); | ||||
|     } | ||||
| 
 | ||||
|     // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015
 | ||||
|     FORCE_INLINE bool ToBool() const { | ||||
|         return Value() != 0; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     StorageType storage; | ||||
| 
 | ||||
|     static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | ||||
|  |  | |||
|  | @ -228,45 +228,42 @@ union ResultCode { | |||
|     // error
 | ||||
|     BitField<31, 1, u32> is_error; | ||||
| 
 | ||||
|     explicit ResultCode(u32 raw) : raw(raw) {} | ||||
|     ResultCode(ErrorDescription description_, ErrorModule module_, ErrorSummary summary_, | ||||
|                ErrorLevel level_) | ||||
|         : raw(0) { | ||||
|         description.Assign(description_); | ||||
|         module.Assign(module_); | ||||
|         summary.Assign(summary_); | ||||
|         level.Assign(level_); | ||||
|     } | ||||
|     constexpr explicit ResultCode(u32 raw) : raw(raw) {} | ||||
| 
 | ||||
|     ResultCode& operator=(const ResultCode& o) { | ||||
|     constexpr ResultCode(ErrorDescription description_, ErrorModule module_, ErrorSummary summary_, | ||||
|                          ErrorLevel level_) | ||||
|         : raw(description.FormatValue(description_) | module.FormatValue(module_) | | ||||
|               summary.FormatValue(summary_) | level.FormatValue(level_)) {} | ||||
| 
 | ||||
|     constexpr ResultCode& operator=(const ResultCode& o) { | ||||
|         raw = o.raw; | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     bool IsSuccess() const { | ||||
|         return is_error == 0; | ||||
|     constexpr bool IsSuccess() const { | ||||
|         return is_error.ExtractValue(raw) == 0; | ||||
|     } | ||||
| 
 | ||||
|     bool IsError() const { | ||||
|         return is_error == 1; | ||||
|     constexpr bool IsError() const { | ||||
|         return is_error.ExtractValue(raw) == 1; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| inline bool operator==(const ResultCode& a, const ResultCode& b) { | ||||
| constexpr bool operator==(const ResultCode& a, const ResultCode& b) { | ||||
|     return a.raw == b.raw; | ||||
| } | ||||
| 
 | ||||
| inline bool operator!=(const ResultCode& a, const ResultCode& b) { | ||||
| constexpr bool operator!=(const ResultCode& a, const ResultCode& b) { | ||||
|     return a.raw != b.raw; | ||||
| } | ||||
| 
 | ||||
| // Convenience functions for creating some common kinds of errors:
 | ||||
| 
 | ||||
| /// The default success `ResultCode`.
 | ||||
| const ResultCode RESULT_SUCCESS(0); | ||||
| constexpr ResultCode RESULT_SUCCESS(0); | ||||
| 
 | ||||
| /// Might be returned instead of a dummy success for unimplemented APIs.
 | ||||
| inline ResultCode UnimplementedFunction(ErrorModule module) { | ||||
| constexpr ResultCode UnimplementedFunction(ErrorModule module) { | ||||
|     return ResultCode(ErrorDescription::NotImplemented, module, ErrorSummary::NotSupported, | ||||
|                       ErrorLevel::Permanent); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue