2019-09-09 07:01:26 +00:00
|
|
|
#pragma once
|
2019-10-26 05:41:43 +00:00
|
|
|
#include "types.h"
|
2019-09-09 07:01:26 +00:00
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
// Disable MSVC warnings that we actually handle
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(push)
|
|
|
|
#pragma warning(disable : 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template<typename BackingDataType, typename DataType, unsigned BitIndex, unsigned BitCount>
|
|
|
|
struct BitField
|
|
|
|
{
|
2019-10-26 05:41:43 +00:00
|
|
|
static_assert(!std::is_same_v<DataType, bool> || BitCount == 1, "Boolean bitfields should only be 1 bit");
|
|
|
|
|
2019-10-22 13:07:51 +00:00
|
|
|
// 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;
|
2019-09-09 07:01:26 +00:00
|
|
|
|
2019-10-26 05:41:43 +00:00
|
|
|
ALWAYS_INLINE constexpr BackingDataType GetMask() const
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
return ((static_cast<BackingDataType>(~0)) >> (8 * sizeof(BackingDataType) - BitCount)) << BitIndex;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr operator DataType() const { return GetValue(); }
|
2019-09-09 07:01:26 +00:00
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator=(DataType value)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
SetValue(value);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr DataType operator++()
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
DataType value = GetValue() + 1;
|
|
|
|
SetValue(value);
|
|
|
|
return GetValue();
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr DataType operator++(int)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
DataType value = GetValue();
|
|
|
|
SetValue(value + 1);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr DataType operator--()
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
DataType value = GetValue() - 1;
|
|
|
|
SetValue(value);
|
|
|
|
return GetValue();
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr DataType operator--(int)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
DataType value = GetValue();
|
|
|
|
SetValue(value - 1);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator+=(DataType rhs)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
SetValue(GetValue() + rhs);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator-=(DataType rhs)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
SetValue(GetValue() - rhs);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator*=(DataType rhs)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
SetValue(GetValue() * rhs);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator/=(DataType rhs)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
SetValue(GetValue() / rhs);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator&=(DataType rhs)
|
2019-09-17 06:26:00 +00:00
|
|
|
{
|
|
|
|
SetValue(GetValue() & rhs);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator|=(DataType rhs)
|
2019-09-17 06:26:00 +00:00
|
|
|
{
|
2019-09-17 12:18:58 +00:00
|
|
|
SetValue(GetValue() | rhs);
|
2019-09-17 06:26:00 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator^=(DataType rhs)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
SetValue(GetValue() ^ rhs);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator<<=(DataType rhs)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-09-15 02:42:43 +00:00
|
|
|
SetValue(GetValue() << rhs);
|
2019-09-09 07:01:26 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr BitField& operator>>=(DataType rhs)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
SetValue(GetValue() >> rhs);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr DataType GetValue() const
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-10-04 13:20:42 +00:00
|
|
|
if constexpr (std::is_same_v<DataType, bool>)
|
|
|
|
{
|
2019-09-09 07:01:26 +00:00
|
|
|
return static_cast<DataType>(!!((data & GetMask()) >> BitIndex));
|
2019-10-04 13:20:42 +00:00
|
|
|
}
|
|
|
|
else if constexpr (std::is_signed_v<DataType>)
|
|
|
|
{
|
2020-04-26 14:13:23 +00:00
|
|
|
constexpr int shift = 8 * sizeof(DataType) - BitCount + 1;
|
|
|
|
return (static_cast<DataType>(data >> BitIndex) << shift) >> shift;
|
2019-10-04 13:20:42 +00:00
|
|
|
}
|
2019-09-09 07:01:26 +00:00
|
|
|
else
|
2019-10-04 13:20:42 +00:00
|
|
|
{
|
2019-09-09 07:01:26 +00:00
|
|
|
return static_cast<DataType>((data & GetMask()) >> BitIndex);
|
2019-10-04 13:20:42 +00:00
|
|
|
}
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
|
|
|
|
2020-06-23 09:27:38 +00:00
|
|
|
ALWAYS_INLINE constexpr void SetValue(DataType value)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-11-02 14:15:42 +00:00
|
|
|
data = (data & ~GetMask()) | ((static_cast<BackingDataType>(value) << BitIndex) & GetMask());
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BackingDataType data;
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(pop)
|
2019-10-22 13:07:51 +00:00
|
|
|
#endif
|