feat(compress): move window update policy into Rust

Move the shared prefix and external-dictionary window transition into Rust
through a five-field projection. Preserve wrapping pointer-address arithmetic,
contiguous detection, short-dictionary clamping, and overlap clipping while C
retains the private match-state container and copies the projected fields back.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo test --manifest-path rust/Cargo.toml
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; make -B -C programs -j1 zstd
- ulimit -v 41943040; make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s
This commit is contained in:
2026-07-19 19:49:24 +02:00
parent a6b58a7dfc
commit b4ad7ee796
2 changed files with 193 additions and 30 deletions
+162
View File
@@ -6789,6 +6789,88 @@ pub unsafe extern "C" fn ZSTD_rust_windowClear(
}
}
const HASH_READ_SIZE: u32 = 8;
/// Private C window fields projected for the shared window-update policy.
/// Pointer arithmetic is intentionally performed as wrapping address math to
/// mirror the original C implementation's pointer-overflow contract.
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ZSTD_rust_windowUpdateState {
pub nextSrc: *const c_void,
pub base: *const c_void,
pub dictBase: *const c_void,
pub dictLimit: u32,
pub lowLimit: u32,
}
const _: () = {
assert!(offset_of!(ZSTD_rust_windowUpdateState, nextSrc) == 0);
assert!(offset_of!(ZSTD_rust_windowUpdateState, base) == size_of::<usize>());
assert!(offset_of!(ZSTD_rust_windowUpdateState, dictBase) == 2 * size_of::<usize>());
assert!(offset_of!(ZSTD_rust_windowUpdateState, dictLimit) == 3 * size_of::<usize>());
assert!(
offset_of!(ZSTD_rust_windowUpdateState, lowLimit)
== 3 * size_of::<usize>() + size_of::<u32>()
);
assert!(
size_of::<ZSTD_rust_windowUpdateState>() == 3 * size_of::<usize>() + 2 * size_of::<u32>()
);
};
/// Update the rolling prefix/ext-dictionary window for one input segment.
/// C owns the containing match state; Rust owns this five-field transition.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_windowUpdate(
state: *mut ZSTD_rust_windowUpdateState,
src: *const c_void,
src_size: usize,
force_non_contiguous: c_int,
) -> c_uint {
if state.is_null() {
return 1;
}
let state = unsafe { &mut *state };
if src_size == 0 {
return 1;
}
debug_assert!(!state.base.is_null());
debug_assert!(!state.dictBase.is_null());
let ip = src as usize;
let input_end = ip.wrapping_add(src_size);
let mut contiguous = 1;
if ip != state.nextSrc as usize || force_non_contiguous != 0 {
let distance_from_base = (state.nextSrc as usize).wrapping_sub(state.base as usize);
state.lowLimit = state.dictLimit;
debug_assert!(distance_from_base <= u32::MAX as usize);
state.dictLimit = distance_from_base as u32;
state.dictBase = state.base;
state.base = ip.wrapping_sub(distance_from_base) as *const c_void;
if state.dictLimit.wrapping_sub(state.lowLimit) < HASH_READ_SIZE {
state.lowLimit = state.dictLimit;
}
contiguous = 0;
}
state.nextSrc = input_end as *const c_void;
let dict_base = state.dictBase as usize;
if input_end > dict_base.wrapping_add(state.lowLimit as usize)
&& ip < dict_base.wrapping_add(state.dictLimit as usize)
{
let high_input_idx = input_end.wrapping_sub(dict_base);
debug_assert!(high_input_idx < u32::MAX as usize);
let low_limit_max = if high_input_idx > state.dictLimit as usize {
state.dictLimit
} else {
high_input_idx as u32
};
state.lowLimit = low_limit_max;
}
contiguous
}
#[inline]
fn set_pledged_src_size(
stream_stage: c_int,
@@ -12509,6 +12591,86 @@ mod tests {
assert_eq!(dict_limit, 0x89ab_cdef);
}
#[test]
fn window_update_leaves_empty_input_untouched() {
let mut state = ZSTD_rust_windowUpdateState {
nextSrc: ptr::null(),
base: ptr::null(),
dictBase: ptr::null(),
dictLimit: 2,
lowLimit: 2,
};
let original = state;
let result = unsafe { ZSTD_rust_windowUpdate(&mut state, ptr::null(), 0, 0) };
assert_eq!(result, 1);
assert_eq!(state, original);
}
#[test]
fn window_update_preserves_contiguous_input_and_clips_overlapping_extdict() {
let storage = [0u8; 64];
let storage_start = storage.as_ptr() as usize;
let base = unsafe { storage.as_ptr().add(16) };
let next_src = unsafe { base.add(2) };
let mut contiguous_state = ZSTD_rust_windowUpdateState {
nextSrc: next_src.cast(),
base: base.cast(),
dictBase: base.cast(),
dictLimit: 2,
lowLimit: 2,
};
let contiguous =
unsafe { ZSTD_rust_windowUpdate(&mut contiguous_state, next_src.cast(), 3, 0) };
assert_eq!(contiguous, 1);
assert_eq!(contiguous_state.nextSrc as usize, storage_start + 21);
assert_eq!(contiguous_state.base as usize, storage_start + 16);
assert_eq!(contiguous_state.dictBase as usize, storage_start + 16);
assert_eq!(contiguous_state.dictLimit, 2);
assert_eq!(contiguous_state.lowLimit, 2);
let next_src = unsafe { base.add(6) };
let mut forced_state = ZSTD_rust_windowUpdateState {
nextSrc: next_src.cast(),
base: base.cast(),
dictBase: base.cast(),
dictLimit: 5,
lowLimit: 2,
};
let forced = unsafe { ZSTD_rust_windowUpdate(&mut forced_state, next_src.cast(), 3, 1) };
assert_eq!(forced, 0);
assert_eq!(forced_state.base as usize, storage_start + 16);
assert_eq!(forced_state.nextSrc as usize, storage_start + 25);
assert_eq!(forced_state.dictBase as usize, storage_start + 16);
assert_eq!(forced_state.dictLimit, 6);
assert_eq!(forced_state.lowLimit, 6);
let next_src = unsafe { base.add(20) };
let src = unsafe { base.add(4) };
let mut non_contiguous_state = ZSTD_rust_windowUpdateState {
nextSrc: next_src.cast(),
base: base.cast(),
dictBase: base.cast(),
dictLimit: 5,
lowLimit: 2,
};
let non_contiguous =
unsafe { ZSTD_rust_windowUpdate(&mut non_contiguous_state, src.cast(), 10, 0) };
assert_eq!(non_contiguous, 0);
assert_eq!(non_contiguous_state.base as usize, storage_start);
assert_eq!(non_contiguous_state.nextSrc as usize, storage_start + 30);
assert_eq!(non_contiguous_state.dictBase as usize, storage_start + 16);
assert_eq!(non_contiguous_state.dictLimit, 20);
assert_eq!(non_contiguous_state.lowLimit, 14);
}
#[derive(Default)]
struct ResetCCtxTestContext {
events: Vec<&'static str>,