Created
April 17, 2019 20:22
-
-
Save Yangff/9a8816b9a9f45fcb8af30f8991b02b2d to your computer and use it in GitHub Desktop.
Bit Field for c++, inspired by https://codereview.stackexchange.com/questions/54342/template-for-endianness-free-code-data-always-packed-as-big-endian and https://blog.codef00.com/2014/12/06/portable-bitfields-using-c11/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <cstddef> | |
#include <type_traits> | |
#include <cstring> | |
#include <cstdio> | |
template <size_t Size> | |
struct MinimumTypeHelper { | |
typedef | |
typename std::conditional<Size == 0 , void, | |
typename std::conditional<Size <= 8 , uint8_t, | |
typename std::conditional<Size <= 16, uint16_t, | |
typename std::conditional<Size <= 32, uint32_t, | |
typename std::conditional<Size <= 64, uint64_t, | |
void>::type>::type>::type>::type>::type type; | |
}; | |
template<int firstBit, int bitSize> | |
struct BitFieldMember | |
{ | |
using self_t = BitFieldMember<firstBit, bitSize>; | |
using T = typename MinimumTypeHelper<bitSize>::type; | |
static constexpr size_t firstByte = firstBit / 8; | |
static constexpr size_t lastByte = (firstBit + bitSize - 1) / 8; | |
static constexpr size_t tail = ((-(firstBit + bitSize)) % 8 + 8) % 8; | |
static constexpr size_t mask = (T(1) << bitSize) - 1; | |
uint8_t *_this() | |
{ | |
return reinterpret_cast<uint8_t *>(this); | |
} | |
operator T() const { | |
T ret = 0; | |
for (size_t ii = firstByte; ii <= lastByte; ++ii ) { | |
ret = (ret << 8) | _this()[ii]; | |
} | |
return (ret >> tail) & mask; | |
} | |
self_t& operator = (T m) { | |
m = (m & mask); | |
T write_mask = mask; | |
int ii = lastByte; | |
if (tail) { // take care of wrapping | |
uint8_t m1 = (m << tail) & 0xff; | |
uint8_t wm1 = (write_mask << tail) & 0xff; | |
uint8_t* ref = _this() + ii; | |
(*ref) &= (~wm1) & 0xff; | |
(*ref) |= (m1 & 0xff); | |
m >>= (8-tail); | |
write_mask >>= (8-tail); | |
ii--; | |
} | |
for (; ii >= 0 && 0 != write_mask; ii--) { | |
uint8_t* ref = _this() + ii; | |
(*ref) &= (~write_mask) & 0xff; | |
(*ref) |= (m & 0xff); | |
m >>= 8; | |
write_mask >>= 8; | |
} | |
return *this; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment