#pragma once
#include <array>
#include <cstring>
#include <vector>
#include <whiteout/common_types.h>
namespace whiteout {
inline constexpr std::array<u32, 17> BIT_MASK = {{
0,
1,
3,
7,
15,
31,
63,
127,
255,
511,
1023,
2047,
4095,
8191,
16383,
32767,
65535,
}};
struct PlainMsbBitReader {
const u8* data = nullptr;
size_t size = 0;
size_t bytePos = 0;
u32 bitBuf = 0;
i32 bitsAvail = 0;
void init(const u8* d, size_t s, size_t startByte = 0) {
data = d;
size = s;
bytePos = startByte;
bitBuf = 0;
bitsAvail = 0;
}
void refill() {
while (bitsAvail <= 24 && bytePos < size) {
bitBuf |= static_cast<u32>(data[bytePos++]) << (24 - bitsAvail);
bitsAvail += 8;
}
}
u32 peekBits(i32 count) {
refill();
return (bitBuf >> (32 - count)) & BIT_MASK[count];
}
void consumeBits(i32 count) {
bitBuf <<= count;
bitsAvail -= count;
}
u32 readBits(i32 count) {
u32 val = peekBits(count);
consumeBits(count);
return val;
}
bool hasData() const {
return bytePos < size || bitsAvail > 0;
}
};
struct MsbBitReader {
const u8* data = nullptr;
size_t size = 0;
size_t bytePos = 0;
u32 bitBuf = 0; i32 bitsAvail = 0;
u8 pendingMarker = 0;
void init(const u8* d, size_t s, size_t startOffset);
void refill();
u32 peekBits(i32 count);
void consumeBits(i32 count);
u32 readBits(i32 count);
void handleRestartMarker();
};
struct MsbBitWriter {
std::vector<u8>* out = nullptr;
u32 bitBuf = 0; i32 bitsUsed = 0;
void init(std::vector<u8>* o);
void writeBits(u32 value, i32 count);
void flushWithPadding();
};
struct LsbBitReader {
const u8* data = nullptr;
size_t size = 0;
size_t bytePos = 0;
u64 bitBuf = 0;
i32 bitsAvail = 0;
void init(const u8* d, size_t s, size_t startByte) {
data = d;
size = s;
bytePos = startByte;
bitBuf = 0;
bitsAvail = 0;
}
void refill() {
if (bitsAvail > 56)
return; if (bytePos + 8 <= size) {
u64 next = 0;
std::memcpy(&next, data + bytePos, 8); bitBuf |= next << bitsAvail;
i32 consume = (64 - bitsAvail) >> 3; bytePos += consume;
bitsAvail += consume * 8;
} else {
while (bitsAvail <= 56 && bytePos < size) {
bitBuf |= static_cast<u64>(data[bytePos++]) << bitsAvail;
bitsAvail += 8;
}
}
}
u32 readBits(i32 count) {
if (bitsAvail < count)
refill();
u32 val = static_cast<u32>(bitBuf) & ((1u << count) - 1);
bitBuf >>= count;
bitsAvail -= count;
return val;
}
u32 peekBits(i32 count) {
if (bitsAvail < count)
refill();
return static_cast<u32>(bitBuf) & ((1u << count) - 1);
}
void consumeBits(i32 count) {
bitBuf >>= count;
bitsAvail -= count;
}
void alignToByte() {
i32 discard = bitsAvail & 7;
bitBuf >>= discard;
bitsAvail -= discard;
}
bool hasData() const {
return bytePos < size || bitsAvail > 0;
}
};
struct LsbBitWriter {
std::vector<u8>* out = nullptr;
u32 bitBuf = 0;
i32 bitsUsed = 0;
void init(std::vector<u8>* o) {
out = o;
bitBuf = 0;
bitsUsed = 0;
}
void writeBits(u32 value, i32 count) {
bitBuf |= value << bitsUsed;
bitsUsed += count;
while (bitsUsed >= 8) {
out->push_back(static_cast<u8>(bitBuf & 0xFF));
bitBuf >>= 8;
bitsUsed -= 8;
}
}
void flush() {
if (bitsUsed > 0) {
out->push_back(static_cast<u8>(bitBuf & 0xFF));
bitBuf = 0;
bitsUsed = 0;
}
}
};
}