29#ifndef ESI_BITACCESS_H
30#define ESI_BITACCESS_H
42template <
typename Storage, std::
size_t BitOffset, std::
size_t W
idth>
44 static_assert(std::is_unsigned<Storage>::value,
45 "readUnsignedBits Storage must be unsigned");
46 static_assert(Width != 0,
"readUnsignedBits Width must be non-zero");
47 static_assert(
sizeof(Storage) * 8 >= Width,
48 "readUnsignedBits Storage is narrower than Width");
50 for (std::size_t i = 0; i < Width; ++i) {
51 std::size_t src = BitOffset + i;
52 Storage bit =
static_cast<Storage
>((bytes[src >> 3] >> (src & 7)) & 1u);
53 result |=
static_cast<Storage
>(bit << i);
61template <
typename Signed, std::
size_t BitOffset, std::
size_t W
idth>
63 static_assert(std::is_signed<Signed>::value,
64 "readSignedBits Signed must be signed");
65 static_assert(Width != 0,
"readSignedBits Width must be non-zero");
66 static_assert(
sizeof(Signed) * 8 >= Width,
67 "readSignedBits Signed is narrower than Width");
68 using Unsigned =
typename std::make_unsigned<Signed>::type;
69 Unsigned u = readUnsignedBits<Unsigned, BitOffset, Width>(bytes);
70 if constexpr (Width <
sizeof(Unsigned) * 8) {
75 constexpr Unsigned signBit =
static_cast<Unsigned
>(1) << (Width - 1);
76 u =
static_cast<Unsigned
>((u ^ signBit) - signBit);
78 return static_cast<Signed
>(u);
83template <
typename Storage, std::
size_t BitOffset, std::
size_t W
idth>
85 static_assert(std::is_unsigned<Storage>::value,
86 "writeUnsignedBits Storage must be unsigned");
87 static_assert(Width != 0,
"writeUnsignedBits Width must be non-zero");
88 static_assert(
sizeof(Storage) * 8 >= Width,
89 "writeUnsignedBits Storage is narrower than Width");
90 for (std::size_t i = 0; i < Width; ++i) {
91 std::size_t dst = BitOffset + i;
92 std::size_t shift = dst & 7;
93 uint8_t mask =
static_cast<uint8_t
>(1u << shift);
94 uint8_t bit =
static_cast<uint8_t
>((value >> i) &
static_cast<Storage
>(1));
96 static_cast<uint8_t
>((bytes[dst >> 3] &
static_cast<uint8_t
>(~mask)) |
97 static_cast<uint8_t
>(bit << shift));
103template <
typename Signed, std::
size_t BitOffset, std::
size_t W
idth>
105 static_assert(std::is_signed<Signed>::value,
106 "writeSignedBits Signed must be signed");
107 static_assert(Width != 0,
"writeSignedBits Width must be non-zero");
108 static_assert(
sizeof(Signed) * 8 >= Width,
109 "writeSignedBits Signed is narrower than Width");
110 using Unsigned =
typename std::make_unsigned<Signed>::type;
111 writeUnsignedBits<Unsigned, BitOffset, Width>(bytes,
112 static_cast<Unsigned
>(value));
123template <std::
size_t BitOffset, std::
size_t W
idth>
124inline constexpr void copyBitsIn(
const uint8_t *src, uint8_t *dst) {
125 static_assert(Width != 0,
"copyBitsIn Width must be non-zero");
126 for (std::size_t i = 0; i < Width; ++i) {
127 std::size_t s = BitOffset + i;
128 uint8_t bit =
static_cast<uint8_t
>((src[s >> 3] >> (s & 7)) & 1u);
129 dst[i >> 3] =
static_cast<uint8_t
>(dst[i >> 3] | (bit << (i & 7)));
136template <std::
size_t BitOffset, std::
size_t W
idth>
137inline constexpr void copyBitsOut(uint8_t *dst,
const uint8_t *src) {
138 static_assert(Width != 0,
"copyBitsOut Width must be non-zero");
139 for (std::size_t i = 0; i < Width; ++i) {
140 std::size_t d = BitOffset + i;
141 std::size_t shift = d & 7;
142 uint8_t mask =
static_cast<uint8_t
>(1u << shift);
143 uint8_t bit =
static_cast<uint8_t
>((src[i >> 3] >> (i & 7)) & 1u);
145 static_cast<uint8_t
>((dst[d >> 3] &
static_cast<uint8_t
>(~mask)) |
146 static_cast<uint8_t
>(bit << shift));
constexpr void copyBitsOut(uint8_t *dst, const uint8_t *src)
Inverse of copyBitsIn: take Width bits packed LSB-first from bit 0 of src and write them into dst sta...
constexpr Signed readSignedBits(const uint8_t *bytes)
Read Width bits starting at BitOffset (LSB-first) and sign-extend into the signed integer type Signed...
constexpr void copyBitsIn(const uint8_t *src, uint8_t *dst)
Copy Width bits out of src starting at BitOffset into dst packed LSB-first from bit 0.
constexpr void writeSignedBits(uint8_t *bytes, Signed value)
Convenience overload for signed values.
constexpr void writeUnsignedBits(uint8_t *bytes, Storage value)
Write the low Width bits of value into bytes starting at BitOffset (LSB-first).
constexpr Storage readUnsignedBits(const uint8_t *bytes)
Read Width bits starting at BitOffset (LSB-first within bytes) and return them zero-extended in Stora...