Skip to content

compress.deflate: build Huffman trees via the shared hash.huffman builder - #27394

Merged
JalonSolov merged 2 commits into
vlang:masterfrom
quaesitor-scientiam:deflate-shared-huffman
Jun 9, 2026
Merged

JalonSolov merged 2 commits into
vlang:masterfrom
quaesitor-scientiam:deflate-shared-huffman

Conversation

@quaesitor-scientiam

@quaesitor-scientiam quaesitor-scientiam commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor

What

Migrates compress.deflate onto hash.huffman (merged in #27392), removing its two in-tree copies of the canonical Huffman code-assignment (RFC 1951 §3.2.2 bl_count / next_code).

This is the second half of #27358 (the first half — the shared module + the HPACK migration — landed in #27392).

Changes

  • Decode — build_huff_tree() now fills its flat LSB-first lookup table via huffman.flat_table(). The table format (entry = (symbol << 5) | length, 0xFFFF_FFFF for invalid) and the huff_decode loop are unchanged. build_huff_tree() now returns !HuffTree so an over-subscribed (malformed) code surfaces as a clean error instead of a silently corrupt table; all call sites propagate with !.
  • Encode — fixed_litlen_encode() takes its reversed codes straight from huffman.build(..., bit_order: .lsb_first).codes.

No behavior change for any valid DEFLATE stream (incomplete codes are still accepted).

Performance

Benchmarked before/after with v -prod (full method + corpora in the #27392 benchmark comment):

corpus baseline this PR Δ
text-8MiB (fixed, decode) ~627 MB/s ~636 MB/s parity (noise)
dyn-2MiB (dynamic, decode) ~345 MB/s ~346 MB/s parity (noise)
small-256B (fixed, build) ~204k inflates/s ~227k inflates/s +10.8%
dyn-small400 (dynamic, build) ~110k inflates/s ~118k inflates/s +7.5%

Decode-dominated throughput is unchanged (the decode loop is byte-for-byte identical); build-dominated workloads (many small streams) are faster, because flat_table() skips the invalid table pre-fill for complete codes — which V's fixed trees and most dynamic trees are. The build-dominated ranges are non-overlapping across runs, so the speedup is real, not jitter.

Tests

compress.deflate / gzip / zlib / snappy / zstd suites stay green; -cstrict -cc clang clean; v fmt -verify clean.

🤖 Generated with Claude Code

Closes #27358.

…lder

Replace the two in-tree copies of the canonical Huffman code-assignment
(RFC 1951 §3.2.2 bl_count / next_code) with calls to hash.huffman, the shared
builder added for vlang#27358:

- Decode: build_huff_tree() now fills its flat LSB-first lookup table via
  huffman.flat_table(). The table format (entry = (symbol << 5) | length,
  0xFFFF_FFFF for invalid) and the decode loop are unchanged. flat_table()
  assigns each code inline while filling (no intermediate codes array) and skips
  the invalid pre-fill for complete codes, so it does strictly less work than
  the old hand-rolled loop on the common path. build_huff_tree() now returns
  `!HuffTree` so an over-subscribed (malformed) code surfaces as a clean error
  instead of a silently corrupt table; all call sites propagate with `!`.

- Encode: fixed_litlen_encode() takes its reversed codes straight from
  huffman.build(..., bit_order: .lsb_first).codes.

No behavior change for any valid DEFLATE stream (incomplete codes are still
accepted). Benchmarked before/after with -prod: decode-dominated throughput
(8 MiB fixed-Huffman text, 2 MiB dynamic-Huffman) is unchanged, and the
build-dominated paths (thousands of small dynamic-block streams) are ~5-11%
faster than the old code, since the fixed trees and most dynamic trees are
complete and skip the invalid pre-fill. compress.deflate / gzip / zlib suites
stay green.

This is the second half of vlang#27358 (depends on the hash.huffman module PR).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.

Comment thread vlib/compress/deflate/deflate_compress.v Outdated
Comment thread vlib/compress/deflate/deflate_compress.v Outdated
…f panicking

Address review on vlang#27394: fixed_litlen_encode() now returns
`!([]u32, []int)` and deflate_compress_fixed() returns `![]u8`, propagating
the (in practice unreachable) huffman.build error instead of panicking. This
matches the decode-side build_huff_tree(), which already returns `!` in this
PR, and keeps a clean error path end to end. The public compress* APIs are
unchanged (already `![]u8`).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@JalonSolov
JalonSolov merged commit a063235 into vlang:master Jun 9, 2026
78 of 83 checks passed
@quaesitor-scientiam
quaesitor-scientiam deleted the deflate-shared-huffman branch June 28, 2026 03:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shared canonical Huffman builder (hash.huffman) for compress.deflate and net.http HPACK

2 participants