#include namespace LibDEFLATE { HuffmanTree& HuffmanTree::operator=(HuffmanTree&& other) { m_instant_bits = other.m_instant_bits; m_min_bits = other.m_min_bits; m_max_bits = other.m_max_bits; m_instant = BAN::move(other.m_instant); m_min_code = BAN::move(other.m_min_code); m_slow_table = BAN::move(other.m_slow_table); return *this; } BAN::ErrorOr HuffmanTree::create(BAN::Span bit_lengths) { HuffmanTree result; TRY(result.initialize(bit_lengths)); return result; } BAN::ErrorOr HuffmanTree::initialize(BAN::Span bit_lengths) { m_max_bits = 0; m_min_bits = MAX_BITS; uint16_t max_sym = 0; uint16_t bl_count[MAX_BITS + 1] {}; for (size_t sym = 0; sym < bit_lengths.size(); sym++) { if (bit_lengths[sym] == 0) continue; m_max_bits = BAN::Math::max(bit_lengths[sym], m_max_bits); m_min_bits = BAN::Math::min(bit_lengths[sym], m_min_bits); bl_count[bit_lengths[sym]]++; max_sym = sym; } uint16_t next_code[MAX_BITS + 1] {}; uint16_t code = 0; for (uint8_t bits = 1; bits <= MAX_BITS; bits++) { code = (code + bl_count[bits - 1]) << 1; next_code[bits] = code; m_min_code[bits] = code; } BAN::Vector tree; TRY(tree.resize(max_sym + 1, { .code = 0, .len = 0 })); for (uint16_t sym = 0; sym <= max_sym; sym++) { tree[sym].len = bit_lengths[sym]; if (const uint8_t len = tree[sym].len) tree[sym].code = next_code[len]++; } TRY(build_instant_table(tree.span())); TRY(build_slow_table(tree.span())); return {}; } BAN::ErrorOr HuffmanTree::build_instant_table(BAN::Span tree) { m_instant_bits = BAN::Math::min(9, m_max_bits); TRY(m_instant.resize(1 << m_instant_bits, {})); for (uint16_t sym = 0; sym < tree.size(); sym++) { if (tree[sym].len == 0 || tree[sym].len > m_instant_bits) continue; const uint16_t code = tree[sym].code; const uint16_t shift = m_instant_bits - tree[sym].len; for (uint16_t j = code << shift; j < (code + 1) << shift; j++) m_instant[j] = { sym, tree[sym].len }; } return {}; } BAN::ErrorOr HuffmanTree::build_slow_table(BAN::Span tree) { TRY(m_slow_table.resize(MAX_BITS + 1)); for (uint16_t sym = 0; sym < tree.size(); sym++) { const auto leaf = tree[sym]; if (leaf.len == 0) continue; const size_t offset = leaf.code - m_min_code[leaf.len]; if (offset >= m_slow_table[leaf.len].size()) TRY(m_slow_table[leaf.len].resize(offset + 1)); m_slow_table[leaf.len][offset] = sym; } return {}; } BAN::ErrorOr HuffmanTree::fixed_tree() { struct BitLengths { consteval BitLengths() { size_t i = 0; for (; i <= 143; i++) values[i] = 8; for (; i <= 255; i++) values[i] = 9; for (; i <= 279; i++) values[i] = 7; for (; i <= 287; i++) values[i] = 8; } BAN::Array values; }; static constexpr BitLengths bit_lengths; return TRY(HuffmanTree::create(bit_lengths.values.span())); } BAN::Optional HuffmanTree::get_symbol_instant(uint16_t code) const { ASSERT(code < m_instant.size()); if (const auto entry = m_instant[code]; entry.len) return entry; return {}; } BAN::Optional HuffmanTree::get_symbol(uint16_t code, uint8_t len) const { ASSERT(len <= m_max_bits); const auto& symbols = m_slow_table[len]; const size_t offset = code - m_min_code[len]; if (symbols.size() <= offset) return {}; return symbols[offset]; } }