Writing a competitive BZip2 encoder in Ada from scratch in a few days – part 2
День 2: строим дерево Хаффмана
Переписал bz2.adb
на чистые структуры:
Bit_Writer
, MTF
, RLE
, Burrows_Wheeler
, Huffman
.
Каждая структура = пакет + скрытый тип + конструктор Create
, методы Encode
, Flush
, Reset
.
Huffman
- Считаем частоты 256 байт + 2 служебных символа (
RUNA
,RUNB
). - Строим дерево:
Node
(частота, символ, левый, правый). - Сортируем список узлов по частоте, склеиваем два минимальных, повторяем, пока не останется один корень.
- Коды длиной ≤ 20 бит (требование BZip2).
- Генерируем таблицу
Code_Length[0..257]
иCode_Value[0..257]
.
Оптимизация
- Если дерево выдаёт слишком длинные коды, увеличиваем частоты всех символов на 1 и перестраиваем — быстро сходится.
- Память: дерево живёт только во время построения, затем храним только таблицы.
Интеграция
Huffman.Encode
получает поток MTF/RLE-символов, пишет в Bit_Writer
:
- 16-битная маска
0x425A
("BZ"). - 8-битная версия
0x68
. - Таблица длин кодов (передаём как 4-битные значения).
- Сами данные: коды Хаффмана + биты RLE-последовательностей.
Итог за день
- 400 строк Ada, 0 зависимостей.
- Код компилируется
gnatmake -O2 bz2.adb
за 0.3 с. - Тест:
echo "abracadabra" | ./bz2 > out.bz2
,bunzip2
принимает без ошибок.
Завтра: многопоточность и буферизация.