common/bitfield: make it endianness-aware

This commit is contained in:
Weiyi Wang 2019-01-25 12:16:23 -05:00
parent fa9d6b79f9
commit 055b9513a3
3 changed files with 100 additions and 3 deletions

View file

@ -34,6 +34,7 @@
#include <limits>
#include <type_traits>
#include "common/common_funcs.h"
#include "common/swap.h"
/*
* Abstract bitfield class
@ -108,7 +109,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, typename EndianTag = LETag>
struct BitField {
private:
// UnderlyingType is T for non-enum types and the underlying type of T if
@ -121,6 +122,8 @@ private:
// We store the value as the unsigned type to avoid undefined behaviour on value shifting
using StorageType = std::make_unsigned_t<UnderlyingType>;
using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type;
public:
BitField& operator=(const BitField&) = default;
@ -168,7 +171,7 @@ public:
}
FORCE_INLINE void Assign(const T& value) {
storage = (storage & ~mask) | FormatValue(value);
storage = (static_cast<StorageType>(storage) & ~mask) | FormatValue(value);
}
FORCE_INLINE T Value() const {
@ -180,7 +183,7 @@ public:
}
private:
StorageType storage;
StorageTypeWithEndian storage;
static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range");
@ -196,3 +199,6 @@ private:
static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value,
"BitField must be trivially copyable");
#endif
template <std::size_t Position, std::size_t Bits, typename T>
using BitFieldBE = BitField<Position, Bits, T, BETag>;