refactor(compress): move LDM fast-table policy to Rust

Move the strategy classification that decides whether LDM preparation fills
fast or double-fast tables into Rust.  C retains the private match-state,
configuration-specific table-fill leaves, and the existing excluded-DFAST
assertion.  Add enum-value ABI checks plus focused tests for valid and invalid
strategy classifications.

Test Plan:
- `ulimit -v 41943040; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check`
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings`
- `ulimit -v 41943040; make -j1`
- `ulimit -v 41943040; make -j1 -C tests test`
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings`
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/cli/Cargo.toml --all-targets`

The integrated checks ran at the combined working-tree tip under a serial
40 GiB virtual-memory limit. Standalone root Rust unit linking remains
unavailable because the crate imports C-owned bridge symbols without a Cargo
build/link setup.
This commit is contained in:
2026-07-20 09:49:57 +02:00
parent 4409ef1e16
commit 7ea0cbd96e
2 changed files with 61 additions and 10 deletions
+47
View File
@@ -23,8 +23,16 @@ const LDM_MIN_MATCH_LENGTH: u32 = 64;
const HASH_READ_SIZE: usize = 8;
const ZSTD_REP_NUM: usize = 3;
const ZSTD_WINDOW_START_INDEX: u32 = 2;
const ZSTD_FAST_STRATEGY: c_int = 1;
const ZSTD_DFAST_STRATEGY: c_int = 2;
const ZSTD_STRATEGY_MAX: c_int = 9;
const ZSTD_BTOPT: c_int = 7;
const LDM_FAST_TABLES_NONE: c_int = 0;
const LDM_FAST_TABLES_FAST: c_int = 1;
const LDM_FAST_TABLES_DFAST: c_int = 2;
const LDM_FAST_TABLES_INVALID: c_int = -1;
#[repr(C)]
#[derive(Clone, Copy)]
struct LdmEntry {
@@ -196,6 +204,20 @@ pub extern "C" fn ZSTD_rust_ldm_limitTableUpdate(curr: u32, next_to_update: u32)
}
}
/// Classify the C-owned table update needed before an LDM literal segment.
///
/// The table fill itself stays in C because it owns the private match state;
/// Rust owns only this deterministic strategy policy.
#[no_mangle]
pub extern "C" fn ZSTD_rust_ldm_fastTableKind(strategy: c_int) -> c_int {
match strategy {
ZSTD_FAST_STRATEGY => LDM_FAST_TABLES_FAST,
ZSTD_DFAST_STRATEGY => LDM_FAST_TABLES_DFAST,
3..=ZSTD_STRATEGY_MAX => LDM_FAST_TABLES_NONE,
_ => LDM_FAST_TABLES_INVALID,
}
}
#[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) }
@@ -1075,6 +1097,31 @@ mod tests {
assert!(use_optimal_parser(9));
}
#[test]
fn fast_table_kind_preserves_c_strategy_dispatch() {
assert_eq!(
ZSTD_rust_ldm_fastTableKind(ZSTD_FAST_STRATEGY),
LDM_FAST_TABLES_FAST
);
assert_eq!(
ZSTD_rust_ldm_fastTableKind(ZSTD_DFAST_STRATEGY),
LDM_FAST_TABLES_DFAST
);
for strategy in 3..=ZSTD_STRATEGY_MAX {
assert_eq!(ZSTD_rust_ldm_fastTableKind(strategy), LDM_FAST_TABLES_NONE);
}
}
#[test]
fn fast_table_kind_rejects_invalid_strategy_values() {
assert_eq!(ZSTD_rust_ldm_fastTableKind(0), LDM_FAST_TABLES_INVALID);
assert_eq!(
ZSTD_rust_ldm_fastTableKind(ZSTD_STRATEGY_MAX + 1),
LDM_FAST_TABLES_INVALID
);
assert_eq!(ZSTD_rust_ldm_fastTableKind(-1), LDM_FAST_TABLES_INVALID);
}
#[test]
fn raw_sequence_skipping_merges_short_tail_matches() {
let mut sequences = [