feat(compress): move window lifecycle predicates into Rust
Move shared window initialization and the empty-window and external-dictionary predicates behind the Rust compression seam. Rust now owns the projected five-field lifecycle state, while C retains the containing window and its overflow-correction counter. 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:
@@ -669,6 +669,10 @@ typedef char ZSTD_rust_window_update_state_layout[
|
|||||||
&& offsetof(ZSTD_rust_windowUpdateState, dictLimit) == 3 * sizeof(void*)
|
&& offsetof(ZSTD_rust_windowUpdateState, dictLimit) == 3 * sizeof(void*)
|
||||||
&& offsetof(ZSTD_rust_windowUpdateState, lowLimit) == 3 * sizeof(void*) + sizeof(U32)
|
&& offsetof(ZSTD_rust_windowUpdateState, lowLimit) == 3 * sizeof(void*) + sizeof(U32)
|
||||||
&& sizeof(ZSTD_rust_windowUpdateState) == 3 * sizeof(void*) + 2 * sizeof(U32)) ? 1 : -1];
|
&& sizeof(ZSTD_rust_windowUpdateState) == 3 * sizeof(void*) + 2 * sizeof(U32)) ? 1 : -1];
|
||||||
|
void ZSTD_rust_windowInit(ZSTD_rust_windowUpdateState* state);
|
||||||
|
U32 ZSTD_rust_windowIsEmpty(const void* nextSrc, const void* base,
|
||||||
|
U32 dictLimit, U32 lowLimit);
|
||||||
|
U32 ZSTD_rust_windowHasExtDict(U32 dictLimit, U32 lowLimit);
|
||||||
U32 ZSTD_rust_windowUpdate(ZSTD_rust_windowUpdateState* state,
|
U32 ZSTD_rust_windowUpdate(ZSTD_rust_windowUpdateState* state,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
int forceNonContiguous);
|
int forceNonContiguous);
|
||||||
@@ -1046,9 +1050,8 @@ MEM_STATIC U64 ZSTD_rollingHash_rotate(U64 hash, BYTE toRemove, BYTE toAdd, U64
|
|||||||
|
|
||||||
MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window)
|
MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window)
|
||||||
{
|
{
|
||||||
return window.dictLimit == ZSTD_WINDOW_START_INDEX &&
|
return ZSTD_rust_windowIsEmpty(window.nextSrc, window.base,
|
||||||
window.lowLimit == ZSTD_WINDOW_START_INDEX &&
|
window.dictLimit, window.lowLimit);
|
||||||
(window.nextSrc - window.base) == ZSTD_WINDOW_START_INDEX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1057,7 +1060,7 @@ MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window)
|
|||||||
*/
|
*/
|
||||||
MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
|
MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
|
||||||
{
|
{
|
||||||
return window.lowLimit < window.dictLimit;
|
return ZSTD_rust_windowHasExtDict(window.dictLimit, window.lowLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1305,13 +1308,13 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window,
|
|||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) {
|
MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) {
|
||||||
ZSTD_memset(window, 0, sizeof(*window));
|
ZSTD_rust_windowUpdateState state;
|
||||||
window->base = (BYTE const*)" ";
|
ZSTD_rust_windowInit(&state);
|
||||||
window->dictBase = (BYTE const*)" ";
|
window->nextSrc = (BYTE const*)state.nextSrc;
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_DUBT_UNSORTED_MARK < ZSTD_WINDOW_START_INDEX); /* Start above ZSTD_DUBT_UNSORTED_MARK */
|
window->base = (BYTE const*)state.base;
|
||||||
window->dictLimit = ZSTD_WINDOW_START_INDEX; /* start from >0, so that 1st position is valid */
|
window->dictBase = (BYTE const*)state.dictBase;
|
||||||
window->lowLimit = ZSTD_WINDOW_START_INDEX; /* it ensures first and later CCtx usages compress the same */
|
window->dictLimit = state.dictLimit;
|
||||||
window->nextSrc = window->base + ZSTD_WINDOW_START_INDEX; /* see issue #1241 */
|
window->lowLimit = state.lowLimit;
|
||||||
window->nbOverflowCorrections = 0;
|
window->nbOverflowCorrections = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6818,6 +6818,45 @@ const _: () = {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static WINDOW_INIT_SENTINEL: [u8; 2] = [b' ', 0];
|
||||||
|
|
||||||
|
/// Initialize the projected window fields. C retains the containing object
|
||||||
|
/// and its overflow-correction counter.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ZSTD_rust_windowInit(state: *mut ZSTD_rust_windowUpdateState) {
|
||||||
|
if state.is_null() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let base = WINDOW_INIT_SENTINEL.as_ptr();
|
||||||
|
unsafe {
|
||||||
|
*state = ZSTD_rust_windowUpdateState {
|
||||||
|
nextSrc: base.wrapping_add(2).cast(),
|
||||||
|
base: base.cast(),
|
||||||
|
dictBase: base.cast(),
|
||||||
|
dictLimit: ZSTD_WINDOW_START_INDEX,
|
||||||
|
lowLimit: ZSTD_WINDOW_START_INDEX,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ZSTD_rust_windowIsEmpty(
|
||||||
|
next_src: *const c_void,
|
||||||
|
base: *const c_void,
|
||||||
|
dict_limit: u32,
|
||||||
|
low_limit: u32,
|
||||||
|
) -> c_uint {
|
||||||
|
(dict_limit == ZSTD_WINDOW_START_INDEX
|
||||||
|
&& low_limit == ZSTD_WINDOW_START_INDEX
|
||||||
|
&& (next_src as usize).wrapping_sub(base as usize) == ZSTD_WINDOW_START_INDEX as usize)
|
||||||
|
as c_uint
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ZSTD_rust_windowHasExtDict(dict_limit: u32, low_limit: u32) -> c_uint {
|
||||||
|
(low_limit < dict_limit) as c_uint
|
||||||
|
}
|
||||||
|
|
||||||
/// Update the rolling prefix/ext-dictionary window for one input segment.
|
/// Update the rolling prefix/ext-dictionary window for one input segment.
|
||||||
/// C owns the containing match state; Rust owns this five-field transition.
|
/// C owns the containing match state; Rust owns this five-field transition.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -12608,6 +12647,33 @@ mod tests {
|
|||||||
assert_eq!(state, original);
|
assert_eq!(state, original);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn window_init_sets_empty_sentinel_and_dictionary_predicates() {
|
||||||
|
let mut state = ZSTD_rust_windowUpdateState {
|
||||||
|
nextSrc: ptr::null(),
|
||||||
|
base: ptr::null(),
|
||||||
|
dictBase: ptr::null(),
|
||||||
|
dictLimit: 0,
|
||||||
|
lowLimit: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe { ZSTD_rust_windowInit(&mut state) };
|
||||||
|
|
||||||
|
assert_eq!(state.dictLimit, ZSTD_WINDOW_START_INDEX);
|
||||||
|
assert_eq!(state.lowLimit, ZSTD_WINDOW_START_INDEX);
|
||||||
|
assert_eq!(state.dictBase as usize, state.base as usize);
|
||||||
|
assert_eq!(
|
||||||
|
(state.nextSrc as usize).wrapping_sub(state.base as usize),
|
||||||
|
ZSTD_WINDOW_START_INDEX as usize
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ZSTD_rust_windowIsEmpty(state.nextSrc, state.base, state.dictLimit, state.lowLimit),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert_eq!(ZSTD_rust_windowHasExtDict(10, 2), 1);
|
||||||
|
assert_eq!(ZSTD_rust_windowHasExtDict(10, 10), 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn window_update_preserves_contiguous_input_and_clips_overlapping_extdict() {
|
fn window_update_preserves_contiguous_input_and_clips_overlapping_extdict() {
|
||||||
let storage = [0u8; 64];
|
let storage = [0u8; 64];
|
||||||
|
|||||||
Reference in New Issue
Block a user