mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30: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. |  * symptoms. | ||||||
|  */ |  */ | ||||||
| #pragma pack(1) | #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 { | struct BitField { | ||||||
| private: | private: | ||||||
|     // We hide the copy assigment operator here, because the default copy
 |     // 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.
 |     // We don't delete it because we want BitField to be trivially copyable.
 | ||||||
|     BitField& operator=(const BitField&) = default; |     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
 |     // 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
 |     // 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
 |     // former case to workaround compile errors which arise when using
 | ||||||
|  | @ -161,10 +127,63 @@ private: | ||||||
|     // Unsigned version of StorageType
 |     // Unsigned version of StorageType
 | ||||||
|     typedef typename std::make_unsigned<StorageType>::type StorageTypeU; |     typedef typename std::make_unsigned<StorageType>::type StorageTypeU; | ||||||
| 
 | 
 | ||||||
|     FORCE_INLINE StorageType GetMask() const { | public: | ||||||
|         return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; |     /// 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; |     StorageType storage; | ||||||
| 
 | 
 | ||||||
|     static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); |     static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | ||||||
|  |  | ||||||
|  | @ -228,45 +228,42 @@ union ResultCode { | ||||||
|     // error
 |     // error
 | ||||||
|     BitField<31, 1, u32> is_error; |     BitField<31, 1, u32> is_error; | ||||||
| 
 | 
 | ||||||
|     explicit ResultCode(u32 raw) : raw(raw) {} |     constexpr 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_); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     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; |         raw = o.raw; | ||||||
|         return *this; |         return *this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool IsSuccess() const { |     constexpr bool IsSuccess() const { | ||||||
|         return is_error == 0; |         return is_error.ExtractValue(raw) == 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool IsError() const { |     constexpr bool IsError() const { | ||||||
|         return is_error == 1; |         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; |     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; |     return a.raw != b.raw; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Convenience functions for creating some common kinds of errors:
 | // Convenience functions for creating some common kinds of errors:
 | ||||||
| 
 | 
 | ||||||
| /// The default success `ResultCode`.
 | /// 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.
 | /// 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, |     return ResultCode(ErrorDescription::NotImplemented, module, ErrorSummary::NotSupported, | ||||||
|                       ErrorLevel::Permanent); |                       ErrorLevel::Permanent); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue