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)
This commit is contained in:
2026-07-19 19:08:13 +02:00
parent e95778be1a
commit bff97833b6
2 changed files with 31 additions and 2 deletions
+2 -2
View File
@@ -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);
}
}
+29
View File
@@ -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));