From a75145a2c66808f1c4c905da415f0c9c22172dfd Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sat, 20 May 2017 20:40:13 -0700 Subject: [PATCH] Make BitField and ResultCode constexpr-initializable --- src/common/bit_field.h | 93 +++++++++++++++++++++++++----------------- src/core/hle/result.h | 33 +++++++-------- 2 files changed, 71 insertions(+), 55 deletions(-) diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 030f7caeb..72a01c7a8 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h @@ -108,7 +108,7 @@ * symptoms. */ #pragma pack(1) -template +template 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::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::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::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"); diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 13b948871..db548bd76 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -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); }