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принимает без ошибок.
Завтра: многопоточность и буферизация.