فهرست منبع

Make BitField and ResultCode constexpr-initializable

Yuri Kunde Schlesner 9 سال پیش
والد
کامیت
a75145a2c6
2فایلهای تغییر یافته به همراه57 افزوده شده و 41 حذف شده
  1. 42 23
      src/common/bit_field.h
  2. 15 18
      src/core/hle/result.h

+ 42 - 23
src/common/bit_field.h

@@ -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,7 +117,45 @@ private:
     // We don't delete it because we want BitField to be trivially copyable.
     BitField& operator=(const BitField&) = default;
 
+    // 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
+    // std::underlying_type<T>::type directly.
+    typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>,
+                                      std::enable_if<true, T>>::type::type StorageType;
+
+    // Unsigned version of StorageType
+    typedef typename std::make_unsigned<StorageType>::type StorageTypeU;
+
 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!
@@ -126,23 +164,18 @@ public:
 
     // Force default constructor to be created
     // so that we can use this within unions
-    BitField() = default;
+    constexpr BitField() = default;
 
     FORCE_INLINE operator T() const {
         return Value();
     }
 
     FORCE_INLINE void Assign(const T& value) {
-        storage = (storage & ~GetMask()) | (((StorageType)value << position) & GetMask());
+        storage = (storage & ~mask) | FormatValue(value);
     }
 
     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);
-        }
+        return ExtractValue(storage);
     }
 
     // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015
@@ -151,20 +184,6 @@ public:
     }
 
 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
-    // std::underlying_type<T>::type directly.
-    typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>,
-                                      std::enable_if<true, T>>::type::type StorageType;
-
-    // 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;
-    }
-
     StorageType storage;
 
     static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range");

+ 15 - 18
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) {}
+
+    constexpr ResultCode(ErrorDescription description_, ErrorModule module_, ErrorSummary summary_,
+                         ErrorLevel level_)
+        : raw(description.FormatValue(description_) | module.FormatValue(module_) |
+              summary.FormatValue(summary_) | level.FormatValue(level_)) {}
 
-    ResultCode& operator=(const ResultCode& o) {
+    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);
 }