diff --git a/lib/compress/zstd_ldm.c b/lib/compress/zstd_ldm.c index c7e1d558c..1c859f589 100644 --- a/lib/compress/zstd_ldm.c +++ b/lib/compress/zstd_ldm.c @@ -185,6 +185,7 @@ void ZSTD_rust_ldm_skipRawSeqStoreBytes(void* rawSeqStore, size_t nbBytes); size_t ZSTD_rust_ldm_blockCompress( void* rawSeqStore, void* blockContext, void* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize, U32 minMatch, int useOptimalParser); +U32 ZSTD_rust_ldm_limitTableUpdate(U32 curr, U32 nextToUpdate); const U64* ZSTD_ldm_rust_gearTable(void); void ZSTD_ldm_rust_prepareBlock(void* blockContext, const void* anchor); @@ -206,14 +207,6 @@ typedef struct { ZSTD_BlockCompressor_f blockCompressor; } ZSTD_rust_ldm_block_context; -static void ZSTD_rust_ldm_limitTableUpdate(ZSTD_MatchState_t* ms, const BYTE* anchor) -{ - U32 const curr = (U32)(anchor - ms->window.base); - if (curr > ms->nextToUpdate + 1024) { - ms->nextToUpdate = curr - MIN(512, curr - ms->nextToUpdate - 1024); - } -} - static void ZSTD_rust_ldm_fillFastTables(ZSTD_MatchState_t* ms, const BYTE* end) { switch (ms->cParams.strategy) { @@ -243,7 +236,9 @@ static void ZSTD_rust_ldm_fillFastTables(ZSTD_MatchState_t* ms, const BYTE* end) void ZSTD_ldm_rust_prepareBlock(void* blockContext, const void* anchor) { ZSTD_rust_ldm_block_context* const context = (ZSTD_rust_ldm_block_context*)blockContext; - ZSTD_rust_ldm_limitTableUpdate(context->ms, (const BYTE*)anchor); + U32 const curr = (U32)((const BYTE*)anchor - context->ms->window.base); + context->ms->nextToUpdate = ZSTD_rust_ldm_limitTableUpdate( + curr, context->ms->nextToUpdate); ZSTD_rust_ldm_fillFastTables(context->ms, (const BYTE*)anchor); } diff --git a/rust/src/zstd_ldm.rs b/rust/src/zstd_ldm.rs index 3edade89d..34a12b5d7 100644 --- a/rust/src/zstd_ldm.rs +++ b/rust/src/zstd_ldm.rs @@ -187,6 +187,16 @@ fn bounded(lower: u32, value: u32, upper: u32) -> u32 { value.max(lower).min(upper) } +/// Return the next match-table update point using the C scalar rule. +#[no_mangle] +pub extern "C" fn ZSTD_rust_ldm_limitTableUpdate(curr: u32, next_to_update: u32) -> u32 { + if curr > next_to_update.wrapping_add(1024) { + curr.wrapping_sub(512u32.min(curr.wrapping_sub(next_to_update).wrapping_sub(1024))) + } else { + next_to_update + } +} + #[inline] unsafe fn ldm_bucket(hash_table: *mut LdmEntry, hash: u32, bucket_size_log: u32) -> *mut LdmEntry { unsafe { hash_table.add((hash as usize) << bucket_size_log) } @@ -1007,6 +1017,31 @@ pub unsafe extern "C" fn ZSTD_rust_ldm_blockCompress( mod tests { use super::*; + #[test] + fn limit_table_update_keeps_threshold_strict() { + assert_eq!(ZSTD_rust_ldm_limitTableUpdate(1024, 0), 0); + } + + #[test] + fn limit_table_update_moves_one_step_past_threshold() { + assert_eq!(ZSTD_rust_ldm_limitTableUpdate(1025, 0), 1024); + } + + #[test] + fn limit_table_update_clamps_to_512() { + assert_eq!(ZSTD_rust_ldm_limitTableUpdate(2048, 0), 1536); + } + + #[test] + fn limit_table_update_preserves_nonzero_next_to_update() { + assert_eq!(ZSTD_rust_ldm_limitTableUpdate(2000, 500), 1524); + } + + #[test] + fn limit_table_update_wraps_u32_arithmetic() { + assert_eq!(ZSTD_rust_ldm_limitTableUpdate(1000, u32::MAX - 511), 512); + } + #[test] fn parameter_defaults_follow_the_c_rules() { let mut params = LdmParams {