feat(compress): move CDict table copy leaf to Rust

ZSTD_copyCDictTableIntoCCtx only transformed tagged CDict match-table
entries or copied untagged entries; context-owned table selection remains in
C. Keep that policy and both call sites in C, forwarding the selected flag
through a narrow ABI. Rust removes the frozen eight-bit short-cache tag or
uses copy_nonoverlapping for C memcpy-equivalent copying without adding
validation.

Test Plan:
- Focused and full compression Rust tests passed (2 and 267 tests).
- `make -B -C lib -j2 lib` passed.
- `make -C tests -j2 fuzzer` passed.
- `./tests/fuzzer -s4560 -t47 -i48 -v` passed.
- Clippy normal/benches/tests before and after `cargo +nightly fmt` passed.
- `git diff --check` and `git diff --cached --check` passed.
This commit is contained in:
2026-07-18 09:47:55 +02:00
parent 3c51a97814
commit 745858e980
2 changed files with 59 additions and 12 deletions
+5 -12
View File
@@ -66,6 +66,8 @@ int ZSTD_rust_simpleCompress2Level(const void* cctx);
int ZSTD_rust_simpleCompressStream2Level(const void* cctx);
void ZSTD_rust_reduceTable(U32* table, U32 size, U32 reducerValue,
int preserveMark);
void ZSTD_rust_copyCDictTableIntoCCtx(U32* dst, U32 const* src,
size_t tableSize, int tagged);
U64 ZSTD_rust_advanceHashSalt(U64 hashSalt, U64 hashSaltEntropy);
int ZSTD_rust_indexTooCloseToMax(size_t nextSrcBaseOffset);
int ZSTD_rust_dictTooBig(size_t loadedDictSize);
@@ -1877,18 +1879,9 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
static void ZSTD_copyCDictTableIntoCCtx(U32* dst, U32 const* src, size_t tableSize,
ZSTD_compressionParameters const* cParams) {
if (ZSTD_CDictIndicesAreTagged(cParams)){
/* Remove tags from the CDict table if they are present.
* See docs on "short cache" in zstd_compress_internal.h for context. */
size_t i;
for (i = 0; i < tableSize; i++) {
U32 const taggedIndex = src[i];
U32 const index = taggedIndex >> ZSTD_SHORT_CACHE_TAG_BITS;
dst[i] = index;
}
} else {
ZSTD_memcpy(dst, src, tableSize * sizeof(U32));
}
ZSTD_STATIC_ASSERT(ZSTD_SHORT_CACHE_TAG_BITS == 8);
ZSTD_rust_copyCDictTableIntoCCtx(dst, src, tableSize,
ZSTD_CDictIndicesAreTagged(cParams));
}
static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
+54
View File
@@ -83,6 +83,7 @@ const ZSTD_ROWSIZE: usize = 16;
const ZSTD_WINDOW_START_INDEX: u32 = 2;
const ZSTD_DUBT_UNSORTED_MARK: u32 = 1;
const ZSTD_INDEXOVERFLOW_MARGIN: usize = 16usize << 20;
const ZSTD_SHORT_CACHE_TAG_BITS: u32 = 8;
const ZSTD_CURRENT_MAX: usize = if size_of::<usize>() == 8 {
3500usize << 20
} else {
@@ -345,6 +346,25 @@ pub unsafe extern "C" fn ZSTD_rust_reduceTable(
reduce_table_internal(table, reducer_value, preserve_mark != 0);
}
/// Copies a CDict match table into a CCtx, removing short-cache tags when the
/// C-owned compression parameters say the source table is tagged.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_copyCDictTableIntoCCtx(
dst: *mut u32,
src: *const u32,
table_size: usize,
tagged: c_int,
) {
if tagged != 0 {
for i in 0..table_size {
let index = unsafe { *src.add(i) } >> ZSTD_SHORT_CACHE_TAG_BITS;
unsafe { *dst.add(i) = index };
}
} else if table_size != 0 {
unsafe { ptr::copy_nonoverlapping(src, dst, table_size) };
}
}
#[inline]
fn zeroed_state() -> ZSTD_compressedBlockState_t {
/* The state contains only integer arrays and enum fields. */
@@ -856,6 +876,40 @@ mod tests {
assert_eq!(table[ZSTD_ROWSIZE * 2 - 1], u32::MAX - 4);
}
#[test]
fn copy_cdict_table_removes_short_cache_tags() {
let source = [0x1234_56ff, 0xdead_beef, 0x0000_0100, u32::MAX];
let mut destination = [0u32; 4];
unsafe {
ZSTD_rust_copyCDictTableIntoCCtx(
destination.as_mut_ptr(),
source.as_ptr(),
source.len(),
1,
);
}
assert_eq!(destination, [0x0012_3456, 0x00de_adbe, 1, 0x00ff_ffff]);
}
#[test]
fn copy_cdict_table_preserves_untagged_entries() {
let source = [0, 2, 0x1234_5678, u32::MAX];
let mut destination = [0xa5a5_a5a5; 4];
unsafe {
ZSTD_rust_copyCDictTableIntoCCtx(
destination.as_mut_ptr(),
source.as_ptr(),
source.len(),
0,
);
}
assert_eq!(destination, source);
}
#[test]
fn bitmix_and_hash_salt_match_the_c_arithmetic() {
assert_eq!(bitmix(0x0123_4567_89ab_cdef, 8), 0xd498_d855_4e8d_d8cb);