feat(compress): move external sequence conversion to Rust
The external-sequence block path still converted public ZSTD_Sequence values in C, with separate scalar and AVX2 implementations. Move that pure format conversion into zstd_compress_stats.rs so both native configurations share one implementation. Preserve offBase encoding, u16 truncation, the rep-ignored contract, and the long-length side-band marker; leave C responsible for block state, repcode resolution, and long-length bookkeeping. Test Plan: - `cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression` -- 225 passed - `cargo clippy --manifest-path rust/Cargo.toml --no-default-features --features compression` plus benches/tests -- passed before and after formatting - `cargo +nightly fmt --manifest-path rust/Cargo.toml --all` -- passed - `make -B -C lib -j2 lib` -- passed - `make -C tests -j2 test-zstream` -- passed, including 84 deterministic and 14,768 randomized cases
This commit is contained in:
@@ -158,6 +158,46 @@ pub struct ZSTD_Sequence {
|
||||
pub rep: u32,
|
||||
}
|
||||
|
||||
/// Converts public sequences to the internal no-repcodes `SeqDef` format.
|
||||
///
|
||||
/// The return value is a side-band marker: zero means that every length fits
|
||||
/// in its `u16` field; otherwise it is one plus the match-length sequence
|
||||
/// index, or `nb_sequences + 1` plus the literal-length sequence index. This
|
||||
/// is the Rust leaf for C's `convertSequences_noRepcodes()`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_convertSequencesNoRepcodes(
|
||||
dst_seqs: *mut SeqDef,
|
||||
in_seqs: *const ZSTD_Sequence,
|
||||
nb_sequences: usize,
|
||||
) -> usize {
|
||||
if nb_sequences == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let dst_seqs = unsafe { std::slice::from_raw_parts_mut(dst_seqs, nb_sequences) };
|
||||
let in_seqs = unsafe { std::slice::from_raw_parts(in_seqs, nb_sequences) };
|
||||
let mut long_length = 0usize;
|
||||
|
||||
for (index, input) in in_seqs.iter().enumerate() {
|
||||
dst_seqs[index] = SeqDef {
|
||||
offBase: input.offset.wrapping_add(ZSTD_REP_NUM as u32),
|
||||
litLength: input.litLength as u16,
|
||||
mlBase: input.matchLength.wrapping_sub(MINMATCH as u32) as u16,
|
||||
};
|
||||
|
||||
if input.matchLength > 65535 + MINMATCH as u32 {
|
||||
debug_assert_eq!(long_length, 0);
|
||||
long_length = index + 1;
|
||||
}
|
||||
if input.litLength > 65535 {
|
||||
debug_assert_eq!(long_length, 0);
|
||||
long_length = index + nb_sequences + 1;
|
||||
}
|
||||
}
|
||||
|
||||
long_length
|
||||
}
|
||||
|
||||
/// Converts a raw sequence offset to the stored offBase representation.
|
||||
///
|
||||
/// This is the Rust leaf for C's `ZSTD_finalizeOffBase()`. The repcode
|
||||
@@ -1793,6 +1833,65 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_sequences_no_repcodes_maps_fields_and_ignores_rep() {
|
||||
let input = [
|
||||
ZSTD_Sequence {
|
||||
offset: 1,
|
||||
litLength: 7,
|
||||
matchLength: 3,
|
||||
rep: 99,
|
||||
},
|
||||
ZSTD_Sequence {
|
||||
offset: 1234,
|
||||
litLength: 0x12345,
|
||||
matchLength: 17,
|
||||
rep: 1,
|
||||
},
|
||||
];
|
||||
let mut output = [SeqDef::default(); 2];
|
||||
|
||||
let long_length = unsafe {
|
||||
ZSTD_rust_convertSequencesNoRepcodes(output.as_mut_ptr(), input.as_ptr(), input.len())
|
||||
};
|
||||
|
||||
assert_eq!(long_length, input.len() + 1 + 1);
|
||||
assert_eq!(output[0].offBase, 1 + ZSTD_REP_NUM as u32);
|
||||
assert_eq!(output[0].litLength, 7);
|
||||
assert_eq!(output[0].mlBase, 0);
|
||||
assert_eq!(output[1].offBase, 1234 + ZSTD_REP_NUM as u32);
|
||||
assert_eq!(output[1].litLength, 0x2345);
|
||||
assert_eq!(output[1].mlBase, 14);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_sequences_no_repcodes_marks_a_long_match() {
|
||||
let input = [ZSTD_Sequence {
|
||||
offset: 8,
|
||||
litLength: 2,
|
||||
matchLength: 65535 + MINMATCH as u32 + 1,
|
||||
rep: 0,
|
||||
}];
|
||||
let mut output = [SeqDef::default()];
|
||||
|
||||
let long_length = unsafe {
|
||||
ZSTD_rust_convertSequencesNoRepcodes(output.as_mut_ptr(), input.as_ptr(), input.len())
|
||||
};
|
||||
|
||||
assert_eq!(long_length, 1);
|
||||
assert_eq!(output[0].offBase, 8 + ZSTD_REP_NUM as u32);
|
||||
assert_eq!(output[0].litLength, 2);
|
||||
assert_eq!(output[0].mlBase, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_sequences_no_repcodes_accepts_an_empty_range() {
|
||||
let result = unsafe {
|
||||
ZSTD_rust_convertSequencesNoRepcodes(std::ptr::null_mut(), std::ptr::null(), 0)
|
||||
};
|
||||
assert_eq!(result, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compressed_block_state_reset_restores_repcodes_and_repeat_modes() {
|
||||
let mut block_state =
|
||||
|
||||
Reference in New Issue
Block a user