mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Make BitField and ResultCode constexpr-initializable
This commit is contained in:
		
							parent
							
								
									cc566dadd8
								
							
						
					
					
						commit
						a75145a2c6
					
				@ -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…
	
		Reference in New Issue
	
	Block a user