feat(compress): move repcode reconciliation to Rust

Port ZSTD_seqStore_resolveOffCodes and its repcode-resolution helper to Rust. The C shim keeps Repcodes_t and SeqStore_t ownership in the compressor context while Rust preserves long-literal handling, mismatch materialization, and independent decoder/compressor history updates.

Test Plan:

- cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression (208 tests)

- cargo clippy --manifest-path rust/Cargo.toml

- cargo clippy --manifest-path rust/Cargo.toml --benches

- cargo clippy --manifest-path rust/Cargo.toml --tests

- make -B -C lib -j2 lib
This commit is contained in:
2026-07-18 06:03:55 +02:00
parent 48eb895af3
commit 3bbfacdfd0
2 changed files with 193 additions and 42 deletions
+6 -35
View File
@@ -261,6 +261,10 @@ size_t ZSTD_rust_countSeqStoreMatchBytes(const SeqStore_t* seqStore);
void ZSTD_rust_deriveSeqStoreChunk(SeqStore_t* resultSeqStore,
const SeqStore_t* originalSeqStore,
size_t startIdx, size_t endIdx);
void ZSTD_rust_seqStore_resolveOffCodes(U32 dRep[ZSTD_REP_NUM],
U32 cRep[ZSTD_REP_NUM],
const SeqStore_t* seqStore,
U32 nbSeq);
U32 ZSTD_rust_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM],
U32 offBase, U32 ll0);
U32 ZSTD_rust_finalizeOffBase(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0);
@@ -2738,17 +2742,6 @@ static void ZSTD_deriveSeqStoreChunk(SeqStore_t* resultSeqStore,
startIdx, endIdx);
}
/**
* Returns the raw offset represented by the combination of offBase, ll0, and repcode history.
* offBase must represent a repcode in the numeric representation of ZSTD_storeSeq().
*/
static U32
ZSTD_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM], const U32 offBase, const U32 ll0)
{
assert(OFFBASE_IS_REPCODE(offBase));
return ZSTD_rust_resolveRepcodeToRawOffset(rep, offBase, ll0);
}
/**
* ZSTD_seqStore_resolveOffCodes() reconciles any possible divergences in offset history that may arise
* due to emission of RLE/raw blocks that disturb the offset history,
@@ -2766,30 +2759,8 @@ static void
ZSTD_seqStore_resolveOffCodes(Repcodes_t* const dRepcodes, Repcodes_t* const cRepcodes,
const SeqStore_t* const seqStore, U32 const nbSeq)
{
U32 idx = 0;
U32 const longLitLenIdx = seqStore->longLengthType == ZSTD_llt_literalLength ? seqStore->longLengthPos : nbSeq;
for (; idx < nbSeq; ++idx) {
SeqDef* const seq = seqStore->sequencesStart + idx;
U32 const ll0 = (seq->litLength == 0) && (idx != longLitLenIdx);
U32 const offBase = seq->offBase;
assert(offBase > 0);
if (OFFBASE_IS_REPCODE(offBase)) {
U32 const dRawOffset = ZSTD_resolveRepcodeToRawOffset(dRepcodes->rep, offBase, ll0);
U32 const cRawOffset = ZSTD_resolveRepcodeToRawOffset(cRepcodes->rep, offBase, ll0);
/* Adjust simulated decompression repcode history if we come across a mismatch. Replace
* the repcode with the offset it actually references, determined by the compression
* repcode history.
*/
if (dRawOffset != cRawOffset) {
seq->offBase = OFFSET_TO_OFFBASE(cRawOffset);
}
}
/* Compression repcode history is always updated with values directly from the unmodified seqStore.
* Decompression repcode history may use modified seq->offset value taken from compression repcode history.
*/
ZSTD_updateRep(dRepcodes->rep, seq->offBase, ll0);
ZSTD_updateRep(cRepcodes->rep, offBase, ll0);
}
ZSTD_rust_seqStore_resolveOffCodes(dRepcodes->rep, cRepcodes->rep,
seqStore, nbSeq);
}
/* ZSTD_compressSeqStore_singleBlock():