From bff97833b62e5b8a8f2cbbbd408f46846e47020d Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sun, 19 Jul 2026 19:08:13 +0200 Subject: [PATCH] feat(compress): move long-match update arithmetic into Rust Move the bounded nextToUpdate catch-up arithmetic used after very long matches into Rust. C continues to calculate the source index against the private match-state window and retains all surrounding assertions and setup; Rust owns the exact wrapping U32 threshold and 192-byte catch-up policy. Test Plan: - cargo fmt --manifest-path rust/Cargo.toml -- --check - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml limit_next_to_update --lib (1 passed) - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml --lib (692 passed) - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings - ulimit -v 41943040 && MAKEFLAGS=-j1 make -B -C programs -j1 zstd - ulimit -v 41943040 && MAKEFLAGS=-j1 make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s (84 tests and both short fuzz rounds passed) --- lib/compress/zstd_compress.c | 4 ++-- rust/src/zstd_compress.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index f434d7249..e2b9eb83d 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -604,6 +604,7 @@ size_t ZSTD_compressStream2_c(ZSTD_CCtx* cctx, ZSTD_EndDirective endOp); int ZSTD_rust_simpleCompress2Level(const void* cctx, size_t srcSize); int ZSTD_rust_simpleCompressStream2Level(const void* cctx, size_t srcSize); +U32 ZSTD_rust_limitNextToUpdate(U32 curr, U32 nextToUpdate); void ZSTD_rust_reduceIndex(U32* hashTable, U32 hashSize, U32* chainTable, U32 chainSize, U32* hashTable3, U32 hashSize3, @@ -4721,8 +4722,7 @@ static void ZSTD_rust_buildSeqStore_prepareMatchState(void* context, const BYTE* const istart = (const BYTE*)src; const U32 curr = (U32)(istart-base); if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); - if (curr > ms->nextToUpdate + 384) - ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384)); + ms->nextToUpdate = ZSTD_rust_limitNextToUpdate(curr, ms->nextToUpdate); } } diff --git a/rust/src/zstd_compress.rs b/rust/src/zstd_compress.rs index 552c408f4..4d3d7e5f5 100644 --- a/rust/src/zstd_compress.rs +++ b/rust/src/zstd_compress.rs @@ -5238,6 +5238,26 @@ pub extern "C" fn ZSTD_rust_windowNeedOverflowCorrection( ) as u32 } +#[inline] +fn limit_next_to_update(curr: u32, next_to_update: u32) -> u32 { + let const_gap = 384u32; + let const_step = 192u32; + if curr > next_to_update.wrapping_add(const_gap) { + curr.wrapping_sub(const_step.min(curr.wrapping_sub(next_to_update).wrapping_sub(const_gap))) + } else { + next_to_update + } +} + +/// Limit a stale matchfinder update point after a very long match. +/// +/// C computes the source index against its private window base; Rust owns the +/// wrapping U32 threshold and bounded catch-up arithmetic. +#[no_mangle] +pub extern "C" fn ZSTD_rust_limitNextToUpdate(curr: u32, next_to_update: u32) -> u32 { + limit_next_to_update(curr, next_to_update) +} + #[inline] fn next_input_size_hint( in_buffer_mode: c_int, @@ -10803,6 +10823,15 @@ mod tests { assert!(!window_need_overflow_correction(27, true, 1024, false)); } + #[test] + fn limit_next_to_update_preserves_threshold_and_bounded_catch_up() { + assert_eq!(limit_next_to_update(884, 500), 500); + assert_eq!(limit_next_to_update(885, 500), 884); + assert_eq!(limit_next_to_update(1000, 500), 884); + assert_eq!(limit_next_to_update(1200, 500), 1008); + assert_eq!(ZSTD_rust_limitNextToUpdate(300, u32::MAX - 100), 283); + } + #[test] fn window_overflow_need_scales_the_frequency_with_correction_count() { assert!(window_can_overflow_correct(27, 3, 16, 0, 0));