mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-18 06:25:37 +00:00
Common: Force inlining of BitField/SignExtend/ZeroExtend functions
This commit is contained in:
parent
a9e0fe6db2
commit
c7a7d682bc
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
// Disable MSVC warnings that we actually handle
|
// Disable MSVC warnings that we actually handle
|
||||||
|
@ -10,105 +11,107 @@
|
||||||
template<typename BackingDataType, typename DataType, unsigned BitIndex, unsigned BitCount>
|
template<typename BackingDataType, typename DataType, unsigned BitIndex, unsigned BitCount>
|
||||||
struct BitField
|
struct BitField
|
||||||
{
|
{
|
||||||
|
static_assert(!std::is_same_v<DataType, bool> || BitCount == 1, "Boolean bitfields should only be 1 bit");
|
||||||
|
|
||||||
// We have to delete the copy assignment operator otherwise we can't use this class in anonymous structs/unions.
|
// We have to delete the copy assignment operator otherwise we can't use this class in anonymous structs/unions.
|
||||||
BitField& operator=(const BitField& rhs) = delete;
|
BitField& operator=(const BitField& rhs) = delete;
|
||||||
|
|
||||||
constexpr BackingDataType GetMask() const
|
ALWAYS_INLINE constexpr BackingDataType GetMask() const
|
||||||
{
|
{
|
||||||
return ((static_cast<BackingDataType>(~0)) >> (8 * sizeof(BackingDataType) - BitCount)) << BitIndex;
|
return ((static_cast<BackingDataType>(~0)) >> (8 * sizeof(BackingDataType) - BitCount)) << BitIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator DataType() const { return GetValue(); }
|
ALWAYS_INLINE operator DataType() const { return GetValue(); }
|
||||||
|
|
||||||
BitField& operator=(DataType value)
|
ALWAYS_INLINE BitField& operator=(DataType value)
|
||||||
{
|
{
|
||||||
SetValue(value);
|
SetValue(value);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType operator++()
|
ALWAYS_INLINE DataType operator++()
|
||||||
{
|
{
|
||||||
DataType value = GetValue() + 1;
|
DataType value = GetValue() + 1;
|
||||||
SetValue(value);
|
SetValue(value);
|
||||||
return GetValue();
|
return GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType operator++(int)
|
ALWAYS_INLINE DataType operator++(int)
|
||||||
{
|
{
|
||||||
DataType value = GetValue();
|
DataType value = GetValue();
|
||||||
SetValue(value + 1);
|
SetValue(value + 1);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType operator--()
|
ALWAYS_INLINE DataType operator--()
|
||||||
{
|
{
|
||||||
DataType value = GetValue() - 1;
|
DataType value = GetValue() - 1;
|
||||||
SetValue(value);
|
SetValue(value);
|
||||||
return GetValue();
|
return GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType operator--(int)
|
ALWAYS_INLINE DataType operator--(int)
|
||||||
{
|
{
|
||||||
DataType value = GetValue();
|
DataType value = GetValue();
|
||||||
SetValue(value - 1);
|
SetValue(value - 1);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField& operator+=(DataType rhs)
|
ALWAYS_INLINE BitField& operator+=(DataType rhs)
|
||||||
{
|
{
|
||||||
SetValue(GetValue() + rhs);
|
SetValue(GetValue() + rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField& operator-=(DataType rhs)
|
ALWAYS_INLINE BitField& operator-=(DataType rhs)
|
||||||
{
|
{
|
||||||
SetValue(GetValue() - rhs);
|
SetValue(GetValue() - rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField& operator*=(DataType rhs)
|
ALWAYS_INLINE BitField& operator*=(DataType rhs)
|
||||||
{
|
{
|
||||||
SetValue(GetValue() * rhs);
|
SetValue(GetValue() * rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField& operator/=(DataType rhs)
|
ALWAYS_INLINE BitField& operator/=(DataType rhs)
|
||||||
{
|
{
|
||||||
SetValue(GetValue() / rhs);
|
SetValue(GetValue() / rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField& operator&=(DataType rhs)
|
ALWAYS_INLINE BitField& operator&=(DataType rhs)
|
||||||
{
|
{
|
||||||
SetValue(GetValue() & rhs);
|
SetValue(GetValue() & rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField& operator|=(DataType rhs)
|
ALWAYS_INLINE BitField& operator|=(DataType rhs)
|
||||||
{
|
{
|
||||||
SetValue(GetValue() | rhs);
|
SetValue(GetValue() | rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField& operator^=(DataType rhs)
|
ALWAYS_INLINE BitField& operator^=(DataType rhs)
|
||||||
{
|
{
|
||||||
SetValue(GetValue() ^ rhs);
|
SetValue(GetValue() ^ rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField& operator<<=(DataType rhs)
|
ALWAYS_INLINE BitField& operator<<=(DataType rhs)
|
||||||
{
|
{
|
||||||
SetValue(GetValue() << rhs);
|
SetValue(GetValue() << rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField& operator>>=(DataType rhs)
|
ALWAYS_INLINE BitField& operator>>=(DataType rhs)
|
||||||
{
|
{
|
||||||
SetValue(GetValue() >> rhs);
|
SetValue(GetValue() >> rhs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType GetValue() const
|
ALWAYS_INLINE DataType GetValue() const
|
||||||
{
|
{
|
||||||
if constexpr (std::is_same_v<DataType, bool>)
|
if constexpr (std::is_same_v<DataType, bool>)
|
||||||
{
|
{
|
||||||
|
@ -125,10 +128,9 @@ struct BitField
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetValue(DataType value)
|
ALWAYS_INLINE void SetValue(DataType value)
|
||||||
{
|
{
|
||||||
data &= ~GetMask();
|
data = (data & ~GetMask()) | (static_cast<BackingDataType>(value) << BitIndex) & GetMask();
|
||||||
data |= (static_cast<BackingDataType>(value) << BitIndex) & GetMask();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BackingDataType data;
|
BackingDataType data;
|
||||||
|
|
|
@ -42,33 +42,33 @@ using CycleCount = int64_t;
|
||||||
using SimulationTime = int64_t;
|
using SimulationTime = int64_t;
|
||||||
|
|
||||||
// Helpers for simulation time.
|
// Helpers for simulation time.
|
||||||
constexpr SimulationTime SecondsToSimulationTime(SimulationTime s)
|
ALWAYS_INLINE constexpr SimulationTime SecondsToSimulationTime(SimulationTime s)
|
||||||
{
|
{
|
||||||
return s * INT64_C(1000000000);
|
return s * INT64_C(1000000000);
|
||||||
}
|
}
|
||||||
constexpr SimulationTime MillisecondsToSimulationTime(SimulationTime ms)
|
ALWAYS_INLINE constexpr SimulationTime MillisecondsToSimulationTime(SimulationTime ms)
|
||||||
{
|
{
|
||||||
return ms * INT64_C(1000000);
|
return ms * INT64_C(1000000);
|
||||||
}
|
}
|
||||||
constexpr SimulationTime MicrosecondsToSimulationTime(SimulationTime us)
|
ALWAYS_INLINE constexpr SimulationTime MicrosecondsToSimulationTime(SimulationTime us)
|
||||||
{
|
{
|
||||||
return us * INT64_C(1000);
|
return us * INT64_C(1000);
|
||||||
}
|
}
|
||||||
constexpr SimulationTime SimulationTimeToSeconds(SimulationTime s)
|
ALWAYS_INLINE constexpr SimulationTime SimulationTimeToSeconds(SimulationTime s)
|
||||||
{
|
{
|
||||||
return s / INT64_C(1000000000);
|
return s / INT64_C(1000000000);
|
||||||
}
|
}
|
||||||
constexpr SimulationTime SimulationTimeToMilliseconds(SimulationTime ms)
|
ALWAYS_INLINE constexpr SimulationTime SimulationTimeToMilliseconds(SimulationTime ms)
|
||||||
{
|
{
|
||||||
return ms / INT64_C(1000000);
|
return ms / INT64_C(1000000);
|
||||||
}
|
}
|
||||||
constexpr SimulationTime SimulationTimeToMicroseconds(SimulationTime us)
|
ALWAYS_INLINE constexpr SimulationTime SimulationTimeToMicroseconds(SimulationTime us)
|
||||||
{
|
{
|
||||||
return us / INT64_C(1000);
|
return us / INT64_C(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculates the difference between the specified timestamps, accounting for signed overflow.
|
// Calculates the difference between the specified timestamps, accounting for signed overflow.
|
||||||
constexpr SimulationTime GetSimulationTimeDifference(SimulationTime prev, SimulationTime now)
|
ALWAYS_INLINE constexpr SimulationTime GetSimulationTimeDifference(SimulationTime prev, SimulationTime now)
|
||||||
{
|
{
|
||||||
if (prev <= now)
|
if (prev <= now)
|
||||||
return now - prev;
|
return now - prev;
|
||||||
|
@ -78,111 +78,105 @@ constexpr SimulationTime GetSimulationTimeDifference(SimulationTime prev, Simula
|
||||||
|
|
||||||
// Zero-extending helper
|
// Zero-extending helper
|
||||||
template<typename TReturn, typename TValue>
|
template<typename TReturn, typename TValue>
|
||||||
constexpr TReturn ZeroExtend(TValue value)
|
ALWAYS_INLINE constexpr TReturn ZeroExtend(TValue value)
|
||||||
{
|
{
|
||||||
// auto unsigned_val = static_cast<typename std::make_unsigned<TValue>::type>(value);
|
|
||||||
// auto extended_val = static_cast<typename std::make_unsigned<TReturn>::type>(unsigned_val);
|
|
||||||
// return static_cast<TReturn>(extended_val);
|
|
||||||
return static_cast<TReturn>(static_cast<typename std::make_unsigned<TReturn>::type>(
|
return static_cast<TReturn>(static_cast<typename std::make_unsigned<TReturn>::type>(
|
||||||
static_cast<typename std::make_unsigned<TValue>::type>(value)));
|
static_cast<typename std::make_unsigned<TValue>::type>(value)));
|
||||||
}
|
}
|
||||||
// Sign-extending helper
|
// Sign-extending helper
|
||||||
template<typename TReturn, typename TValue>
|
template<typename TReturn, typename TValue>
|
||||||
constexpr TReturn SignExtend(TValue value)
|
ALWAYS_INLINE constexpr TReturn SignExtend(TValue value)
|
||||||
{
|
{
|
||||||
// auto signed_val = static_cast<typename std::make_signed<TValue>::type>(value);
|
|
||||||
// auto extended_val = static_cast<typename std::make_signed<TReturn>::type>(signed_val);
|
|
||||||
// return static_cast<TReturn>(extended_val);
|
|
||||||
return static_cast<TReturn>(
|
return static_cast<TReturn>(
|
||||||
static_cast<typename std::make_signed<TReturn>::type>(static_cast<typename std::make_signed<TValue>::type>(value)));
|
static_cast<typename std::make_signed<TReturn>::type>(static_cast<typename std::make_signed<TValue>::type>(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type-specific helpers
|
// Type-specific helpers
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr u16 ZeroExtend16(TValue value)
|
ALWAYS_INLINE constexpr u16 ZeroExtend16(TValue value)
|
||||||
{
|
{
|
||||||
return ZeroExtend<u16, TValue>(value);
|
return ZeroExtend<u16, TValue>(value);
|
||||||
}
|
}
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr u32 ZeroExtend32(TValue value)
|
ALWAYS_INLINE constexpr u32 ZeroExtend32(TValue value)
|
||||||
{
|
{
|
||||||
return ZeroExtend<u32, TValue>(value);
|
return ZeroExtend<u32, TValue>(value);
|
||||||
}
|
}
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr u64 ZeroExtend64(TValue value)
|
ALWAYS_INLINE constexpr u64 ZeroExtend64(TValue value)
|
||||||
{
|
{
|
||||||
return ZeroExtend<u64, TValue>(value);
|
return ZeroExtend<u64, TValue>(value);
|
||||||
}
|
}
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr u16 SignExtend16(TValue value)
|
ALWAYS_INLINE constexpr u16 SignExtend16(TValue value)
|
||||||
{
|
{
|
||||||
return SignExtend<u16, TValue>(value);
|
return SignExtend<u16, TValue>(value);
|
||||||
}
|
}
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr u32 SignExtend32(TValue value)
|
ALWAYS_INLINE constexpr u32 SignExtend32(TValue value)
|
||||||
{
|
{
|
||||||
return SignExtend<u32, TValue>(value);
|
return SignExtend<u32, TValue>(value);
|
||||||
}
|
}
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr u64 SignExtend64(TValue value)
|
ALWAYS_INLINE constexpr u64 SignExtend64(TValue value)
|
||||||
{
|
{
|
||||||
return SignExtend<u64, TValue>(value);
|
return SignExtend<u64, TValue>(value);
|
||||||
}
|
}
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr u8 Truncate8(TValue value)
|
ALWAYS_INLINE constexpr u8 Truncate8(TValue value)
|
||||||
{
|
{
|
||||||
return static_cast<u8>(static_cast<typename std::make_unsigned<decltype(value)>::type>(value));
|
return static_cast<u8>(static_cast<typename std::make_unsigned<decltype(value)>::type>(value));
|
||||||
}
|
}
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr u16 Truncate16(TValue value)
|
ALWAYS_INLINE constexpr u16 Truncate16(TValue value)
|
||||||
{
|
{
|
||||||
return static_cast<u16>(static_cast<typename std::make_unsigned<decltype(value)>::type>(value));
|
return static_cast<u16>(static_cast<typename std::make_unsigned<decltype(value)>::type>(value));
|
||||||
}
|
}
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr u32 Truncate32(TValue value)
|
ALWAYS_INLINE constexpr u32 Truncate32(TValue value)
|
||||||
{
|
{
|
||||||
return static_cast<u32>(static_cast<typename std::make_unsigned<decltype(value)>::type>(value));
|
return static_cast<u32>(static_cast<typename std::make_unsigned<decltype(value)>::type>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// BCD helpers
|
// BCD helpers
|
||||||
constexpr u8 DecimalToBCD(u8 value)
|
ALWAYS_INLINE constexpr u8 DecimalToBCD(u8 value)
|
||||||
{
|
{
|
||||||
return ((value / 10) << 4) + (value % 10);
|
return ((value / 10) << 4) + (value % 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u8 BCDToDecimal(u8 value)
|
ALWAYS_INLINE constexpr u8 BCDToDecimal(u8 value)
|
||||||
{
|
{
|
||||||
return ((value >> 4) * 10) + (value % 16);
|
return ((value >> 4) * 10) + (value % 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Boolean to integer
|
// Boolean to integer
|
||||||
constexpr u8 BoolToUInt8(bool value)
|
ALWAYS_INLINE constexpr u8 BoolToUInt8(bool value)
|
||||||
{
|
{
|
||||||
return static_cast<u8>(value);
|
return static_cast<u8>(value);
|
||||||
}
|
}
|
||||||
constexpr u16 BoolToUInt16(bool value)
|
ALWAYS_INLINE constexpr u16 BoolToUInt16(bool value)
|
||||||
{
|
{
|
||||||
return static_cast<u16>(value);
|
return static_cast<u16>(value);
|
||||||
}
|
}
|
||||||
constexpr u32 BoolToUInt32(bool value)
|
ALWAYS_INLINE constexpr u32 BoolToUInt32(bool value)
|
||||||
{
|
{
|
||||||
return static_cast<u32>(value);
|
return static_cast<u32>(value);
|
||||||
}
|
}
|
||||||
constexpr u64 BoolToUInt64(bool value)
|
ALWAYS_INLINE constexpr u64 BoolToUInt64(bool value)
|
||||||
{
|
{
|
||||||
return static_cast<u64>(value);
|
return static_cast<u64>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Integer to boolean
|
// Integer to boolean
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr bool ConvertToBool(TValue value)
|
ALWAYS_INLINE constexpr bool ConvertToBool(TValue value)
|
||||||
{
|
{
|
||||||
return static_cast<bool>(value);
|
return static_cast<bool>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsafe integer to boolean
|
// Unsafe integer to boolean
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
constexpr bool ConvertToBoolUnchecked(TValue value)
|
ALWAYS_INLINE constexpr bool ConvertToBoolUnchecked(TValue value)
|
||||||
{
|
{
|
||||||
// static_assert(sizeof(uint8) == sizeof(bool));
|
// static_assert(sizeof(uint8) == sizeof(bool));
|
||||||
bool ret;
|
bool ret;
|
||||||
|
@ -192,7 +186,7 @@ constexpr bool ConvertToBoolUnchecked(TValue value)
|
||||||
|
|
||||||
// Generic sign extension
|
// Generic sign extension
|
||||||
template<int NBITS, typename T>
|
template<int NBITS, typename T>
|
||||||
constexpr T SignExtendN(T value)
|
ALWAYS_INLINE constexpr T SignExtendN(T value)
|
||||||
{
|
{
|
||||||
// http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
|
// http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
|
||||||
constexpr int shift = 8 * sizeof(T) - NBITS;
|
constexpr int shift = 8 * sizeof(T) - NBITS;
|
||||||
|
@ -201,38 +195,38 @@ constexpr T SignExtendN(T value)
|
||||||
|
|
||||||
// Enum class bitwise operators
|
// Enum class bitwise operators
|
||||||
#define IMPLEMENT_ENUM_CLASS_BITWISE_OPERATORS(type_) \
|
#define IMPLEMENT_ENUM_CLASS_BITWISE_OPERATORS(type_) \
|
||||||
inline constexpr type_ operator&(type_ lhs, type_ rhs) \
|
ALWAYS_INLINE constexpr type_ operator&(type_ lhs, type_ rhs) \
|
||||||
{ \
|
{ \
|
||||||
return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) & \
|
return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) & \
|
||||||
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
||||||
} \
|
} \
|
||||||
inline constexpr type_ operator|(type_ lhs, type_ rhs) \
|
ALWAYS_INLINE constexpr type_ operator|(type_ lhs, type_ rhs) \
|
||||||
{ \
|
{ \
|
||||||
return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) | \
|
return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) | \
|
||||||
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
||||||
} \
|
} \
|
||||||
inline constexpr type_ operator^(type_ lhs, type_ rhs) \
|
ALWAYS_INLINE constexpr type_ operator^(type_ lhs, type_ rhs) \
|
||||||
{ \
|
{ \
|
||||||
return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) ^ \
|
return static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) ^ \
|
||||||
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
||||||
} \
|
} \
|
||||||
inline constexpr type_ operator~(type_ val) \
|
ALWAYS_INLINE constexpr type_ operator~(type_ val) \
|
||||||
{ \
|
{ \
|
||||||
return static_cast<type_>(~static_cast<std::underlying_type<type_>::type>(val)); \
|
return static_cast<type_>(~static_cast<std::underlying_type<type_>::type>(val)); \
|
||||||
} \
|
} \
|
||||||
inline constexpr type_& operator&=(type_& lhs, type_ rhs) \
|
ALWAYS_INLINE constexpr type_& operator&=(type_& lhs, type_ rhs) \
|
||||||
{ \
|
{ \
|
||||||
lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) & \
|
lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) & \
|
||||||
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
||||||
return lhs; \
|
return lhs; \
|
||||||
} \
|
} \
|
||||||
inline constexpr type_& operator|=(type_& lhs, type_ rhs) \
|
ALWAYS_INLINE constexpr type_& operator|=(type_& lhs, type_ rhs) \
|
||||||
{ \
|
{ \
|
||||||
lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) | \
|
lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) | \
|
||||||
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
||||||
return lhs; \
|
return lhs; \
|
||||||
} \
|
} \
|
||||||
inline constexpr type_& operator^=(type_& lhs, type_ rhs) \
|
ALWAYS_INLINE constexpr type_& operator^=(type_& lhs, type_ rhs) \
|
||||||
{ \
|
{ \
|
||||||
lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) ^ \
|
lhs = static_cast<type_>(static_cast<std::underlying_type<type_>::type>(lhs) ^ \
|
||||||
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
static_cast<std::underlying_type<type_>::type>(rhs)); \
|
||||||
|
|
Loading…
Reference in a new issue