#pragma once
#include <array>
#include <vector>
#include <whiteout/common_types.h>
#include "bit_io.h"
namespace whiteout {
inline constexpr i32 HUFFMAN_FAST_BITS = 9;
template <typename SymT, i32 MaxBits>
struct HuffmanDecodeBase {
static constexpr i32 FAST_SIZE = 1 << HUFFMAN_FAST_BITS;
static constexpr i32 MAX_BITS = MaxBits;
std::array<SymT, FAST_SIZE> fastSymbol{};
std::array<u8, FAST_SIZE> fastLen{};
std::array<u32, MaxBits + 2> maxcode{};
std::array<i32, MaxBits + 1> indexDelta{};
std::vector<SymT> symbols;
i32 lookupSlow(u32 code, i32 codeLength) const {
i32 idx = static_cast<i32>(code) + indexDelta[codeLength];
if (idx >= 0 && idx < static_cast<i32>(symbols.size()))
return static_cast<i32>(symbols[idx]);
return -1;
}
};
struct MsbHuffmanTable : HuffmanDecodeBase<u8, 16> {
bool isBuilt = false;
void build(const std::array<u8, 16>& codeLengthCounts, const u8* syms);
i32 decodeSymbol(MsbBitReader& reader) const;
};
struct LsbHuffmanTable : HuffmanDecodeBase<u16, 15> {
bool build(const u8* codeLengths, i32 count);
i32 decode(LsbBitReader& br) const {
br.refill();
u32 peek = static_cast<u32>(br.bitBuf) & (FAST_SIZE - 1);
if (fastLen[peek] != 0) {
br.bitBuf >>= fastLen[peek];
br.bitsAvail -= fastLen[peek];
return fastSymbol[peek];
}
u32 c = 0;
for (i32 len = 1; len <= MAX_BITS; ++len) {
c = (c << 1) | br.readBits(1);
if (c < maxcode[len]) {
return lookupSlow(c, len);
}
}
return -1;
}
};
struct HuffmanCode {
u16 code = 0; u8 length = 0; };
struct HuffmanEncodeTable {
std::array<HuffmanCode, 256> codes{};
void build(const u8* lengthCounts, const u8* symbols, i32 symbolCount);
};
}