github hellobertrand/zxc v0.13.2
ZXC v0.13.2

3 hours ago

Release Notes

Release v0.13.2 is a performance and hardening patch release. The headline change: levels 6 and 7 now decompress +2–3 % and +10–11 % faster respectively, thanks to a decode-oriented nudge of the Huffman code lengths, at a near-zero ratio cost: compressed output grows by just 0.05 % at level 6 and 0.27 % at level 7.
It also fixes two decoder edge cases (an out-of-bounds read on short RAW literal sections, and an in-place bound that could under-reserve the trailing framing), makes ZXC embeddable as a CMake subproject, and shrinks the shared library by removing duplicate SIMD variants.
There are no changes to the container format or the ABI: v0.13.2 reads and writes the same format v7 archives as v0.13.0 and v0.13.1, and the shared-library soname stays libzxc.so.4.

Drop-in for v0.13.0 / v0.13.1. No format break, no ABI change, no re-link required. Every archive written by any v0.13.x release reads back identically in v0.13.2 and vice versa. One nuance: at levels 6 and 7 the encoder now emits slightly flatter Huffman trees, so archives written at those levels are no longer byte-for-byte identical to v0.13.1's output but they remain standard format v7, readable by every v0.13.x release. Levels 1-5 produce byte-identical output.

Performance

Faster decompression at levels 6 and 7

The encoder now applies a joint flat/length nudge to Huffman code lengths (#336): trees are flattened wherever it costs almost nothing in compressed size, so the PivCo decoder spends fewer cycles per symbol. At level 7, a dynamic-programming tier picks the best nudge per block; level 6 gets the same nudge in its lighter form (#343). Idea by @dougallj.

Level Decompression speed Compression size
6 +2% to +3% +0.05%
7 +10% to +11% +0.27%

Levels 1-5 are unaffected.

Reliability Fixes

Out-of-bounds read on short RAW literal sections (decoder)

RAW literal sections decoded directly from the input buffer could read a few bytes past the end of the compressed input when the section tail was shorter than the decoder's padding requirement and no data followed it. Such sections are now staged through a padded internal buffer, and the conformance tests cover these layouts. (#341)

In-place bound now reserves the trailing framing

zxc_inplace_margin() ignored what the encoder writes after the last data block — the EOF block header and, for seekable archives, the seek table — so the returned bound could fall below the compressed size for seekable archives of incompressible data with small blocks. The worst-case seek table is now reserved unconditionally (4 bytes per block, at most 0.1 % of the payload at the minimum block size, negligible at the default). (#337)

Embedding & Portability

Vendor ZXC as a CMake subproject

ZXC can now be embedded directly into another CMake build via add_subdirectory() or FetchContent (#338). When built as a subproject: the CLI, tests, LTO and -march=native default to OFF; install, doc and formatting targets are disabled; compiler flags are inherited from the parent project instead of being overridden; and a zxc::zxc_lib ALIAS target is provided for consistent linking. A new ZXC_USE_SYSTEM_RAPIDHASH option controls whether the vendored or system rapidhash.h is used. The README documents the vendoring workflow.

No more compiler-rt dependency for x86 CPU detection

CPUID and XGETBV are now issued through direct intrinsics and inline assembly instead of compiler-specific builtins, removing the implicit compiler-rt dependency and making the runtime dispatch robust across more toolchains. (#339)

Build, Binary Size & CI

  • Duplicate SIMD variants removed: the SSE2 and NEON function-multi-versioning variants duplicated the baseline code paths and are gone, shrinking the shared library by roughly a third on arm64 and a quarter on amd64. -mfma is dropped, and the x86 dispatch gates now also check BMI1/BMI2/LZCNT before selecting a variant that uses them. (#331)
  • The ISA-independent dictionary tree setup is compiled once instead of once per SIMD variant. (#327)
  • MSVC /arch mapping and /wd4244 flags fixed, silencing the wrapdb CI warnings. (#326)
  • Wrapper sources are formatted and the formatting is enforced in CI. (#330)
  • Remaining compiler warnings resolved. (#342)
  • The AVX-512 tier is now tested under Intel SDE instead of QEMU, which cannot emulate AVX-512. (#325)
  • npm dev dependencies updated to address audit alerts. (#218, #335)

Internal

  • The GLO/GHI decode loops are deduplicated and macro-folded (−666 lines); the hot paths are byte-identical. (#328)
  • Typo fixes in the documentation.

Changelog

  • fix: fix typos
  • fix: Fix MSVC /arch + /wd4244 flags (wrapdb CI warnings) (#326)
  • perf: Extend code length nudging to level 6 (#343)
  • perf: Optimizes Huffman code lengths for faster PivCo decode (#336)
  • cli: Make project embeddable as a subproject (#338)
  • cli: Resolve compiler warnings (#342)
  • build: Format wrapper sources and guard it in CI (#330)
  • portability: Remove compiler-rt dependency for x86 CPUID (#339)
  • misc: Stage short RAW literal sections to prevent overread (#341)
  • misc: Reserve the trailing framing in the in-place bound (#337)
  • misc: Deduplicate the GLO/GHI decode loops (#328)
  • misc: Update npm dev dependencies to address alerts (#218) (#335)
  • misc: Remove duplicate SSE2/NEON FMV variants, drop -mfma, harden x86 dispatch gates (#331)
  • misc: Compile ISA-independent dict tree setup once, not per-variant (#327)
  • misc: Test the AVX-512 tier under Intel SDE instead of QEMU (#325)

Full Changelog: v0.13.1...v0.13.2

Don't miss a new zxc release

NewReleases is sending notifications on new releases.