feat(ldm): move limit-table scalar leaf to Rust

Keep the LDM limit-table update on the Rust compression path while leaving
match-state ownership in C. Previously, the C block wrapper combined pointer
subtraction, match-state access, and the bounded scalar update. The wrapper
now computes `curr` from `anchor - window.base`, passes `curr` and
`nextToUpdate` through the narrow U32 ABI, and stores Rust's result before the
existing fast-table dispatch.

The Rust leaf uses explicit wrapping arithmetic to preserve the C U32 behavior:
the strict `curr > nextToUpdate + 1024` threshold and the `MIN(512, ...)`
clamp. Focused tests cover the threshold, one-step update, clamp, nonzero
starting point, and arithmetic wraparound.

Test Plan:
- `cargo test zstd_ldm` -- default-feature test-binary link failed because
  existing dict-builder C symbols are not linked.
- `cargo test --no-default-features --features compression zstd_ldm` -- passed
  (7 tests).
- `make lib-nomt` -- passed.
- `make lib-mt` -- passed.
- `make -C tests test-zstream` -- passed; it emitted the existing
  `tests/zstreamtest.c` unterminated-string warning.
- `cargo clippy`, `cargo clippy --benches`, `cargo clippy --tests`,
  `cargo +nightly fmt`, then the same clippy sequence -- passed.
This commit is contained in:
2026-07-18 15:39:37 +02:00
parent 63ca375557
commit 66cb254532
2 changed files with 39 additions and 9 deletions
+4 -9
View File
@@ -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);
}
+35
View File
@@ -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 {