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));
165template <
typename Storage>
168 static_assert(std::is_unsigned<Storage>::value,
169 "readUnsignedBitsDyn Storage must be unsigned");
171 for (std::size_t i = 0; i < width; ++i) {
172 std::size_t src = bitOffset + i;
173 Storage bit =
static_cast<Storage
>((bytes[src >> 3] >> (src & 7)) & 1u);
174 result |=
static_cast<Storage
>(bit << i);
180template <
typename Signed>
183 static_assert(std::is_signed<Signed>::value,
184 "readSignedBitsDyn Signed must be signed");
185 using Unsigned =
typename std::make_unsigned<Signed>::type;
186 Unsigned u = readUnsignedBitsDyn<Unsigned>(bytes, bitOffset, width);
187 if (width <
sizeof(Unsigned) * 8) {
189 static_cast<Unsigned
>(
static_cast<Unsigned
>(1) << (width - 1));
190 u =
static_cast<Unsigned
>((u ^ signBit) - signBit);
192 return static_cast<Signed
>(u);
196template <
typename Storage>
198 std::size_t bitOffset, std::size_t width) {
199 static_assert(std::is_unsigned<Storage>::value,
200 "writeUnsignedBitsDyn Storage must be unsigned");
201 for (std::size_t i = 0; i < width; ++i) {
202 std::size_t dst = bitOffset + i;
203 std::size_t shift = dst & 7;
204 uint8_t mask =
static_cast<uint8_t
>(1u << shift);
205 uint8_t bit =
static_cast<uint8_t
>((value >> i) &
static_cast<Storage
>(1));
207 static_cast<uint8_t
>((bytes[dst >> 3] &
static_cast<uint8_t
>(~mask)) |
208 static_cast<uint8_t
>(bit << shift));
213template <
typename Signed>
215 std::size_t bitOffset, std::size_t width) {
216 static_assert(std::is_signed<Signed>::value,
217 "writeSignedBitsDyn Signed must be signed");
218 using Unsigned =
typename std::make_unsigned<Signed>::type;
219 writeUnsignedBitsDyn<Unsigned>(bytes,
static_cast<Unsigned
>(value), bitOffset,
226 uint8_t *dst, std::size_t width) {
227 for (std::size_t i = 0; i < width; ++i) {
228 std::size_t s = srcBitOffset + i;
229 uint8_t bit =
static_cast<uint8_t
>((src[s >> 3] >> (s & 7)) & 1u);
230 dst[i >> 3] =
static_cast<uint8_t
>(dst[i >> 3] | (bit << (i & 7)));
237 const uint8_t *src, std::size_t width) {
238 for (std::size_t i = 0; i < width; ++i) {
239 std::size_t d = dstBitOffset + i;
240 std::size_t shift = d & 7;
241 uint8_t mask =
static_cast<uint8_t
>(1u << shift);
242 uint8_t bit =
static_cast<uint8_t
>((src[i >> 3] >> (i & 7)) & 1u);
244 static_cast<uint8_t
>((dst[d >> 3] &
static_cast<uint8_t
>(~mask)) |
245 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...
Signed readSignedBitsDyn(const uint8_t *bytes, std::size_t bitOffset, std::size_t width)
Runtime-offset form of readSignedBits.
constexpr Signed readSignedBits(const uint8_t *bytes)
Read Width bits starting at BitOffset (LSB-first) and sign-extend into the signed integer type Signed...
void copyBitsInDyn(const uint8_t *src, std::size_t srcBitOffset, uint8_t *dst, std::size_t width)
Runtime-offset form of copyBitsIn.
void copyBitsOutDyn(uint8_t *dst, std::size_t dstBitOffset, const uint8_t *src, std::size_t width)
Runtime-offset form of copyBitsOut.
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.
void writeSignedBitsDyn(uint8_t *bytes, Signed value, std::size_t bitOffset, std::size_t width)
Runtime-offset form of writeSignedBits.
Storage readUnsignedBitsDyn(const uint8_t *bytes, std::size_t bitOffset, std::size_t width)
Runtime-offset form of readUnsignedBits.
constexpr void writeUnsignedBits(uint8_t *bytes, Storage value)
Write the low Width bits of value into bytes starting at BitOffset (LSB-first).
void writeUnsignedBitsDyn(uint8_t *bytes, Storage value, std::size_t bitOffset, std::size_t width)
Runtime-offset form of writeUnsignedBits.
constexpr Storage readUnsignedBits(const uint8_t *bytes)
Read Width bits starting at BitOffset (LSB-first within bytes) and return them zero-extended in Stora...