From 0895523291bd57a529770025a0e91fe081ee677f Mon Sep 17 00:00:00 2001 From: Michiel Date: Tue, 10 Nov 2026 15:56:16 +0100 Subject: [PATCH 1/9] `optState_t`: rename to `OptState` --- lib/compress/zstd_compress.rs | 4 ++-- lib/compress/zstd_compress_internal.rs | 4 ++-- lib/compress/zstd_opt.rs | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/compress/zstd_compress.rs b/lib/compress/zstd_compress.rs index 3d613933..62386af3 100644 --- a/lib/compress/zstd_compress.rs +++ b/lib/compress/zstd_compress.rs @@ -208,7 +208,7 @@ pub struct ZSTD_MatchState_t { pub chainTable: *mut u32, pub forceNonContiguous: core::ffi::c_int, pub dedicatedDictSearch: core::ffi::c_int, - pub opt: optState_t, + pub opt: OptState, pub dictMatchState: *const ZSTD_MatchState_t, pub cParams: ZSTD_compressionParameters, pub ldmSeqStore: *const RawSeqStore_t, @@ -724,7 +724,7 @@ use crate::lib::compress::huf_compress::{ HUF_validateCTable, HUF_writeCTable_wksp, }; use crate::lib::compress::zstd_compress_internal::{ - optState_t, BufferedPolicy, CParamMode, CompressionStage, DictMode, DictTableLoadMethod, + OptState, BufferedPolicy, CParamMode, CompressionStage, DictMode, DictTableLoadMethod, LongLengthType, SeqCollector, StreamStage, TableFillPurpose, ZSTD_BlockCompressor_f, ZSTD_LLcode, ZSTD_MLcode, ZSTD_blockSplitCtx, ZSTD_blockState_t, ZSTD_entropyCTables_t, ZSTD_fseCTables_t, ZSTD_getSequenceLength, ZSTD_hufCTables_t, ZSTD_localDict, ZSTD_match_t, diff --git a/lib/compress/zstd_compress_internal.rs b/lib/compress/zstd_compress_internal.rs index 2fa355f1..6985d316 100644 --- a/lib/compress/zstd_compress_internal.rs +++ b/lib/compress/zstd_compress_internal.rs @@ -302,7 +302,7 @@ pub enum OptPrice { #[repr(C)] #[derive(Default)] -pub struct optState_t { +pub struct OptState { pub litFreq: *mut [core::ffi::c_uint; MaxLit as usize + 1], pub litLengthFreq: *mut [core::ffi::c_uint; MaxLL as usize + 1], pub matchLengthFreq: *mut [core::ffi::c_uint; MaxML as usize + 1], @@ -324,7 +324,7 @@ pub struct optState_t { /// The statistics tables are reserved in the workspace by `ZSTD_reset_matchState`, and so /// are only valid when the strategy is at least `ZSTD_btopt`. -impl optState_t { +impl OptState { pub(crate) unsafe fn litFreq(&self) -> &[core::ffi::c_uint; MaxLit as usize + 1] { &*self.litFreq } diff --git a/lib/compress/zstd_opt.rs b/lib/compress/zstd_opt.rs index f514839e..81d45708 100644 --- a/lib/compress/zstd_opt.rs +++ b/lib/compress/zstd_opt.rs @@ -38,7 +38,7 @@ use crate::lib::compress::zstd_compress::{ RawSeqStore_t, SeqStore_t, ZSTD_MatchState_t, ZSTD_optimal_t, ZSTD_resetSeqStore, ZSTD_OPT_SIZE, }; use crate::lib::compress::zstd_compress_internal::{ - optState_t, DictMatchState, DictMode, DictModeMarker, ExtDict, NoDict, OptPrice, ZSTD_LLcode, + DictMatchState, DictMode, DictModeMarker, ExtDict, NoDict, OptPrice, OptState, ZSTD_LLcode, ZSTD_MLcode, ZSTD_count, ZSTD_count_2segments, ZSTD_hash32Ptr, ZSTD_hashPtr, ZSTD_index_overlap_check, ZSTD_match_t, ZSTD_storeSeq, ZSTD_updateRep, }; @@ -92,11 +92,11 @@ const fn WEIGHT(stat: u32, optLevel: u32) -> u32 { } } -fn ZSTD_compressedLiterals(opt_state: &optState_t) -> bool { +fn ZSTD_compressedLiterals(opt_state: &OptState) -> bool { opt_state.literalCompressionMode != ParamSwitch::Disable } -fn ZSTD_setBasePrices(opt_state: &mut optState_t, optLevel: u32) { +fn ZSTD_setBasePrices(opt_state: &mut OptState, optLevel: u32) { if ZSTD_compressedLiterals(opt_state) { opt_state.litSumBasePrice = WEIGHT(opt_state.litSum, optLevel); } @@ -142,7 +142,7 @@ fn ZSTD_scaleStats(table: &mut [core::ffi::c_uint], logTarget: u32) -> u32 { /// using src for literals stats, and baseline stats for sequence symbols /// otherwise downscale existing stats, to be used as seed for next block. unsafe fn ZSTD_rescaleFreqs( - opt_state: &mut optState_t, + opt_state: &mut OptState, src: *const u8, srcSize: usize, optLevel: u32, @@ -268,7 +268,7 @@ unsafe fn ZSTD_rescaleFreqs( /// price of a single literal. /// does not include price of literalLength symbol -unsafe fn ZSTD_rawLiteralCost(literal: u8, opt_state: &optState_t, optLevel: u32) -> u32 { +unsafe fn ZSTD_rawLiteralCost(literal: u8, opt_state: &OptState, optLevel: u32) -> u32 { if !ZSTD_compressedLiterals(opt_state) { return 8 * BITCOST_MULTIPLIER; // Uncompressed - 8 bytes per literal. } @@ -287,7 +287,7 @@ unsafe fn ZSTD_rawLiteralCost(literal: u8, opt_state: &optState_t, optLevel: u32 } /// Cost of literalLength symbol -unsafe fn ZSTD_litLengthPrice(litLength: u32, opt_state: &optState_t, optLevel: u32) -> u32 { +unsafe fn ZSTD_litLengthPrice(litLength: u32, opt_state: &OptState, optLevel: u32) -> u32 { if opt_state.priceType == OptPrice::Predef { return WEIGHT(litLength, optLevel); } @@ -320,7 +320,7 @@ unsafe fn ZSTD_litLengthPrice(litLength: u32, opt_state: &optState_t, optLevel: unsafe fn ZSTD_getMatchPrice( offBase: u32, matchLength: u32, - opt_state: &optState_t, + opt_state: &OptState, optLevel: u32, ) -> u32 { let offCode = ZSTD_highbit32(offBase); @@ -358,7 +358,7 @@ unsafe fn ZSTD_getMatchPrice( /// assumption: literals + litLength <= iend unsafe fn ZSTD_updateStats( - opt_state: &mut optState_t, + opt_state: &mut OptState, litLength: u32, literals: *const u8, offBase: u32, From 55cab78dfc36967adec7dddf19a766b8bdbdfbd1 Mon Sep 17 00:00:00 2001 From: Michiel Date: Tue, 10 Nov 2026 15:58:15 +0100 Subject: [PATCH 2/9] `ZSTD_compressedLiterals`: impl on `OptState` --- lib/compress/zstd_opt.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/compress/zstd_opt.rs b/lib/compress/zstd_opt.rs index 81d45708..b36e8090 100644 --- a/lib/compress/zstd_opt.rs +++ b/lib/compress/zstd_opt.rs @@ -92,12 +92,14 @@ const fn WEIGHT(stat: u32, optLevel: u32) -> u32 { } } -fn ZSTD_compressedLiterals(opt_state: &OptState) -> bool { - opt_state.literalCompressionMode != ParamSwitch::Disable +impl OptState { + fn compress_literals(&self) -> bool { + self.literalCompressionMode != ParamSwitch::Disable + } } fn ZSTD_setBasePrices(opt_state: &mut OptState, optLevel: u32) { - if ZSTD_compressedLiterals(opt_state) { + if opt_state.compress_literals() { opt_state.litSumBasePrice = WEIGHT(opt_state.litSum, optLevel); } opt_state.litLengthSumBasePrice = WEIGHT(opt_state.litLengthSum, optLevel); @@ -147,7 +149,7 @@ unsafe fn ZSTD_rescaleFreqs( srcSize: usize, optLevel: u32, ) { - let compressedLiterals = ZSTD_compressedLiterals(opt_state); + let compressedLiterals = opt_state.compress_literals(); opt_state.priceType = OptPrice::Dynamic; if opt_state.litLengthSum == 0 { @@ -269,7 +271,7 @@ unsafe fn ZSTD_rescaleFreqs( /// price of a single literal. /// does not include price of literalLength symbol unsafe fn ZSTD_rawLiteralCost(literal: u8, opt_state: &OptState, optLevel: u32) -> u32 { - if !ZSTD_compressedLiterals(opt_state) { + if !opt_state.compress_literals() { return 8 * BITCOST_MULTIPLIER; // Uncompressed - 8 bytes per literal. } @@ -365,7 +367,7 @@ unsafe fn ZSTD_updateStats( matchLength: u32, ) { // literals - if ZSTD_compressedLiterals(opt_state) { + if opt_state.compress_literals() { let litFreq = opt_state.litFreq_mut(); for u in 0..litLength { let freq = &mut litFreq[usize::from(*literals.add(u as usize))]; From 1d82c63851e10f6163174c2a0d9137bd7576314b Mon Sep 17 00:00:00 2001 From: Michiel Date: Tue, 10 Nov 2026 15:59:36 +0100 Subject: [PATCH 3/9] `ZSTD_setBasePrices`: impl on `OptState` --- lib/compress/zstd_opt.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/compress/zstd_opt.rs b/lib/compress/zstd_opt.rs index b36e8090..2953c8e7 100644 --- a/lib/compress/zstd_opt.rs +++ b/lib/compress/zstd_opt.rs @@ -96,15 +96,15 @@ impl OptState { fn compress_literals(&self) -> bool { self.literalCompressionMode != ParamSwitch::Disable } -} -fn ZSTD_setBasePrices(opt_state: &mut OptState, optLevel: u32) { - if opt_state.compress_literals() { - opt_state.litSumBasePrice = WEIGHT(opt_state.litSum, optLevel); + fn set_base_prices(&mut self, optLevel: u32) { + if self.compress_literals() { + self.litSumBasePrice = WEIGHT(self.litSum, optLevel); + } + self.litLengthSumBasePrice = WEIGHT(self.litLengthSum, optLevel); + self.matchLengthSumBasePrice = WEIGHT(self.matchLengthSum, optLevel); + self.offCodeSumBasePrice = WEIGHT(self.offCodeSum, optLevel); } - opt_state.litLengthSumBasePrice = WEIGHT(opt_state.litLengthSum, optLevel); - opt_state.matchLengthSumBasePrice = WEIGHT(opt_state.matchLengthSum, optLevel); - opt_state.offCodeSumBasePrice = WEIGHT(opt_state.offCodeSum, optLevel); } fn ZSTD_downscaleStats( @@ -265,7 +265,7 @@ unsafe fn ZSTD_rescaleFreqs( opt_state.offCodeSum = ZSTD_scaleStats(opt_state.offCodeFreq_mut(), 11); } - ZSTD_setBasePrices(opt_state, optLevel); + opt_state.set_base_prices(optLevel); } /// price of a single literal. @@ -1514,7 +1514,7 @@ unsafe fn ZSTD_compressBlock_opt_generic( } // update all costs - ZSTD_setBasePrices(&mut ms.opt, OPT_LEVEL); + ms.opt.set_base_prices(OPT_LEVEL); } } } From 8df032eeb2ff9fe37f3d665860683bee0928c2ba Mon Sep 17 00:00:00 2001 From: Michiel Date: Tue, 10 Nov 2026 16:32:53 +0100 Subject: [PATCH 4/9] `ZSTD_optimal_t`: initialize with Default --- lib/compress/zstd_compress.rs | 16 ++++++++-------- lib/compress/zstd_opt.rs | 8 +------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/lib/compress/zstd_compress.rs b/lib/compress/zstd_compress.rs index 62386af3..0ea27f4a 100644 --- a/lib/compress/zstd_compress.rs +++ b/lib/compress/zstd_compress.rs @@ -234,7 +234,7 @@ pub struct rawSeq { pub matchLength: u32, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Default)] #[repr(C)] pub struct ZSTD_optimal_t { pub price: core::ffi::c_int, @@ -724,13 +724,13 @@ use crate::lib::compress::huf_compress::{ HUF_validateCTable, HUF_writeCTable_wksp, }; use crate::lib::compress::zstd_compress_internal::{ - OptState, BufferedPolicy, CParamMode, CompressionStage, DictMode, DictTableLoadMethod, - LongLengthType, SeqCollector, StreamStage, TableFillPurpose, ZSTD_BlockCompressor_f, - ZSTD_LLcode, ZSTD_MLcode, ZSTD_blockSplitCtx, ZSTD_blockState_t, ZSTD_entropyCTables_t, - ZSTD_fseCTables_t, ZSTD_getSequenceLength, ZSTD_hufCTables_t, ZSTD_localDict, ZSTD_match_t, - ZSTD_minGain, ZSTD_noCompressBlock, ZSTD_prefixDict, ZSTD_storeSeq, ZSTD_storeSeqOnly, - ZSTD_updateRep, HASH_READ_SIZE, REPCODE1_TO_OFFBASE, REPCODE3_TO_OFFBASE, ZSTD_CHUNKSIZE_MAX, - ZSTD_CURRENT_MAX, ZSTD_DUBT_UNSORTED_MARK, ZSTD_SHORT_CACHE_TAG_BITS, ZSTD_WINDOW_START_INDEX, + BufferedPolicy, CParamMode, CompressionStage, DictMode, DictTableLoadMethod, LongLengthType, + OptState, SeqCollector, StreamStage, TableFillPurpose, ZSTD_BlockCompressor_f, ZSTD_LLcode, + ZSTD_MLcode, ZSTD_blockSplitCtx, ZSTD_blockState_t, ZSTD_entropyCTables_t, ZSTD_fseCTables_t, + ZSTD_getSequenceLength, ZSTD_hufCTables_t, ZSTD_localDict, ZSTD_match_t, ZSTD_minGain, + ZSTD_noCompressBlock, ZSTD_prefixDict, ZSTD_storeSeq, ZSTD_storeSeqOnly, ZSTD_updateRep, + HASH_READ_SIZE, REPCODE1_TO_OFFBASE, REPCODE3_TO_OFFBASE, ZSTD_CHUNKSIZE_MAX, ZSTD_CURRENT_MAX, + ZSTD_DUBT_UNSORTED_MARK, ZSTD_SHORT_CACHE_TAG_BITS, ZSTD_WINDOW_START_INDEX, }; use crate::lib::compress::zstd_compress_literals::ZSTD_compressLiterals; use crate::lib::compress::zstd_compress_sequences::{ diff --git a/lib/compress/zstd_opt.rs b/lib/compress/zstd_opt.rs index 2953c8e7..67e23519 100644 --- a/lib/compress/zstd_opt.rs +++ b/lib/compress/zstd_opt.rs @@ -1155,13 +1155,7 @@ unsafe fn ZSTD_compressBlock_opt_generic( let opt = &mut *ms.opt.priceTable; let matches = &mut *ms.opt.matchTable; - let mut lastStretch = ZSTD_optimal_t { - price: 0, - off: 0, - mlen: 0, - litlen: 0, - rep: [0; 3], - }; + let mut lastStretch = ZSTD_optimal_t::default(); let mut optLdm = ZSTD_optLdm_t { seqStore: if !ms.ldmSeqStore.is_null() { *ms.ldmSeqStore From 86913f42ad21862ca040e30ea4df4512f5151276 Mon Sep 17 00:00:00 2001 From: Michiel Date: Wed, 11 Nov 2026 10:53:40 +0100 Subject: [PATCH 5/9] `ZSTD_optLdm_t`: rename to `OptLdm` --- lib/compress/zstd_opt.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/compress/zstd_opt.rs b/lib/compress/zstd_opt.rs index 67e23519..94d9e2dc 100644 --- a/lib/compress/zstd_opt.rs +++ b/lib/compress/zstd_opt.rs @@ -10,7 +10,7 @@ pub type ZSTD_getAllMatchesFn = unsafe fn( ) -> usize; #[repr(C)] -pub struct ZSTD_optLdm_t { +pub struct OptLdm { pub seqStore: RawSeqStore_t, pub startPosInBlock: u32, pub endPosInBlock: u32, @@ -1015,7 +1015,7 @@ fn ZSTD_selectBtGetAllMatches(ms: &ZSTD_MatchState_t, dictMode: DictMode) -> ZST /// Calculates the beginning and end of the next match in the current block. /// Updates 'pos' and 'posInSequence' of the ldmSeqStore. unsafe fn ZSTD_opt_getNextMatchAndUpdateSeqStore( - optLdm: &mut ZSTD_optLdm_t, + optLdm: &mut OptLdm, currPosInBlock: u32, blockBytesRemaining: u32, ) { @@ -1077,7 +1077,7 @@ unsafe fn ZSTD_opt_getNextMatchAndUpdateSeqStore( unsafe fn ZSTD_optLdm_maybeAddMatch( matches: &mut [ZSTD_match_t; ZSTD_OPT_SIZE], nbMatches: &mut usize, - optLdm: &ZSTD_optLdm_t, + optLdm: &OptLdm, currPosInBlock: u32, minMatch: u32, ) { @@ -1106,7 +1106,7 @@ unsafe fn ZSTD_optLdm_maybeAddMatch( /// Wrapper function to update ldm seq store and call ldm functions as necessary. unsafe fn ZSTD_optLdm_processMatchCandidate( - optLdm: &mut ZSTD_optLdm_t, + optLdm: &mut OptLdm, matches: &mut [ZSTD_match_t; ZSTD_OPT_SIZE], nbMatches: &mut usize, currPosInBlock: u32, @@ -1156,7 +1156,7 @@ unsafe fn ZSTD_compressBlock_opt_generic( let opt = &mut *ms.opt.priceTable; let matches = &mut *ms.opt.matchTable; let mut lastStretch = ZSTD_optimal_t::default(); - let mut optLdm = ZSTD_optLdm_t { + let mut optLdm = OptLdm { seqStore: if !ms.ldmSeqStore.is_null() { *ms.ldmSeqStore } else { From fd107686e383f70f8a439d39741e6695da945510 Mon Sep 17 00:00:00 2001 From: Michiel Date: Wed, 11 Nov 2026 10:58:59 +0100 Subject: [PATCH 6/9] `ZSTD_opt_getNextMatchAndUpdateSeqStore`: impl on `OptLdm` --- lib/compress/zstd_opt.rs | 115 ++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/lib/compress/zstd_opt.rs b/lib/compress/zstd_opt.rs index 94d9e2dc..0fbe39e9 100644 --- a/lib/compress/zstd_opt.rs +++ b/lib/compress/zstd_opt.rs @@ -1012,62 +1012,64 @@ fn ZSTD_selectBtGetAllMatches(ms: &ZSTD_MatchState_t, dictMode: DictMode) -> ZST getAllMatchesFns[dictMode as usize][mls.wrapping_sub(3) as usize] } -/// Calculates the beginning and end of the next match in the current block. -/// Updates 'pos' and 'posInSequence' of the ldmSeqStore. -unsafe fn ZSTD_opt_getNextMatchAndUpdateSeqStore( - optLdm: &mut OptLdm, - currPosInBlock: u32, - blockBytesRemaining: u32, -) { - // Setting match end position to MAX to ensure we never use an LDM during this block - if optLdm.seqStore.size == 0 || optLdm.seqStore.pos >= optLdm.seqStore.size { - optLdm.startPosInBlock = u32::MAX; - optLdm.endPosInBlock = u32::MAX; - return; - } - // Calculate appropriate bytes left in matchLength and litLength - // after adjusting based on ldmSeqStore->posInSequence - let currSeq = *optLdm.seqStore.seq.add(optLdm.seqStore.pos); - let currBlockEndPos = currPosInBlock.wrapping_add(blockBytesRemaining); - let literalsBytesRemaining = if optLdm.seqStore.posInSequence < currSeq.litLength as usize { - (currSeq.litLength).wrapping_sub(optLdm.seqStore.posInSequence as u32) - } else { - 0 - }; - let matchBytesRemaining = if literalsBytesRemaining == 0 { - (currSeq.matchLength) - .wrapping_sub((optLdm.seqStore.posInSequence as u32).wrapping_sub(currSeq.litLength)) - } else { - currSeq.matchLength - }; +impl OptLdm { + /// Calculates the beginning and end of the next match in the current block. + /// Updates 'pos' and 'posInSequence' of the ldmSeqStore. + unsafe fn get_next_match_and_update_seq_store( + &mut self, + currPosInBlock: u32, + blockBytesRemaining: u32, + ) { + // Setting match end position to MAX to ensure we never use an LDM during this block + if self.seqStore.size == 0 || self.seqStore.pos >= self.seqStore.size { + self.startPosInBlock = u32::MAX; + self.endPosInBlock = u32::MAX; + return; + } + // Calculate appropriate bytes left in matchLength and litLength + // after adjusting based on ldmSeqStore->posInSequence + let currSeq = *self.seqStore.seq.add(self.seqStore.pos); + let currBlockEndPos = currPosInBlock.wrapping_add(blockBytesRemaining); + let literalsBytesRemaining = if self.seqStore.posInSequence < currSeq.litLength as usize { + (currSeq.litLength).wrapping_sub(self.seqStore.posInSequence as u32) + } else { + 0 + }; + let matchBytesRemaining = if literalsBytesRemaining == 0 { + (currSeq.matchLength) + .wrapping_sub((self.seqStore.posInSequence as u32).wrapping_sub(currSeq.litLength)) + } else { + currSeq.matchLength + }; - // If there are more literal bytes than bytes remaining in block, no ldm is possible - if literalsBytesRemaining >= blockBytesRemaining { - optLdm.startPosInBlock = u32::MAX; - optLdm.endPosInBlock = u32::MAX; - ZSTD_ldm_skipRawSeqStoreBytes(&mut optLdm.seqStore, blockBytesRemaining as usize); - return; - } + // If there are more literal bytes than bytes remaining in block, no ldm is possible + if literalsBytesRemaining >= blockBytesRemaining { + self.startPosInBlock = u32::MAX; + self.endPosInBlock = u32::MAX; + ZSTD_ldm_skipRawSeqStoreBytes(&mut self.seqStore, blockBytesRemaining as usize); + return; + } - // Matches may be < minMatch by this process. In that case, we will reject them - // when we are deciding whether or not to add the ldm - optLdm.startPosInBlock = currPosInBlock.wrapping_add(literalsBytesRemaining); - optLdm.endPosInBlock = optLdm.startPosInBlock.wrapping_add(matchBytesRemaining); - optLdm.offset = currSeq.offset; - - if optLdm.endPosInBlock > currBlockEndPos { - // Match ends after the block ends, we can't use the whole match - optLdm.endPosInBlock = currBlockEndPos; - ZSTD_ldm_skipRawSeqStoreBytes( - &mut optLdm.seqStore, - currBlockEndPos.wrapping_sub(currPosInBlock) as usize, - ); - } else { - // Consume number of bytes equal to size of sequence left - ZSTD_ldm_skipRawSeqStoreBytes( - &mut optLdm.seqStore, - literalsBytesRemaining.wrapping_add(matchBytesRemaining) as usize, - ); + // Matches may be < minMatch by this process. In that case, we will reject them + // when we are deciding whether or not to add the ldm + self.startPosInBlock = currPosInBlock.wrapping_add(literalsBytesRemaining); + self.endPosInBlock = self.startPosInBlock.wrapping_add(matchBytesRemaining); + self.offset = currSeq.offset; + + if self.endPosInBlock > currBlockEndPos { + // Match ends after the block ends, we can't use the whole match + self.endPosInBlock = currBlockEndPos; + ZSTD_ldm_skipRawSeqStoreBytes( + &mut self.seqStore, + currBlockEndPos.wrapping_sub(currPosInBlock) as usize, + ); + } else { + // Consume number of bytes equal to size of sequence left + ZSTD_ldm_skipRawSeqStoreBytes( + &mut self.seqStore, + literalsBytesRemaining.wrapping_add(matchBytesRemaining) as usize, + ); + } } } @@ -1125,7 +1127,7 @@ unsafe fn ZSTD_optLdm_processMatchCandidate( let posOvershoot = currPosInBlock.wrapping_sub(optLdm.endPosInBlock); ZSTD_ldm_skipRawSeqStoreBytes(&mut optLdm.seqStore, posOvershoot as usize); } - ZSTD_opt_getNextMatchAndUpdateSeqStore(optLdm, currPosInBlock, remainingBytes); + optLdm.get_next_match_and_update_seq_store(currPosInBlock, remainingBytes); } ZSTD_optLdm_maybeAddMatch(matches, nbMatches, optLdm, currPosInBlock, minMatch); } @@ -1167,8 +1169,7 @@ unsafe fn ZSTD_compressBlock_opt_generic( offset: 0, }; - ZSTD_opt_getNextMatchAndUpdateSeqStore( - &mut optLdm, + optLdm.get_next_match_and_update_seq_store( ip.offset_from_unsigned(istart) as u32, iend.offset_from_unsigned(ip) as u32, ); From 7db9590d9cec3af267730784c6639f524c7e3143 Mon Sep 17 00:00:00 2001 From: Michiel Date: Wed, 11 Nov 2026 11:09:13 +0100 Subject: [PATCH 7/9] `ZSTD_optLdm_processMatchCandidate`: impl on `OptLdm` --- lib/compress/zstd_opt.rs | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/compress/zstd_opt.rs b/lib/compress/zstd_opt.rs index 0fbe39e9..5cad2860 100644 --- a/lib/compress/zstd_opt.rs +++ b/lib/compress/zstd_opt.rs @@ -1106,30 +1106,32 @@ unsafe fn ZSTD_optLdm_maybeAddMatch( } } -/// Wrapper function to update ldm seq store and call ldm functions as necessary. -unsafe fn ZSTD_optLdm_processMatchCandidate( - optLdm: &mut OptLdm, - matches: &mut [ZSTD_match_t; ZSTD_OPT_SIZE], - nbMatches: &mut usize, - currPosInBlock: u32, - remainingBytes: u32, - minMatch: u32, -) { - if optLdm.seqStore.size == 0 || optLdm.seqStore.pos >= optLdm.seqStore.size { - return; - } +impl OptLdm { + /// Wrapper function to update ldm seq store and call ldm functions as necessary. + unsafe fn process_match_candidate( + &mut self, + matches: &mut [ZSTD_match_t; ZSTD_OPT_SIZE], + nbMatches: &mut usize, + currPosInBlock: u32, + remainingBytes: u32, + minMatch: u32, + ) { + if self.seqStore.size == 0 || self.seqStore.pos >= self.seqStore.size { + return; + } - if currPosInBlock >= optLdm.endPosInBlock { - if currPosInBlock > optLdm.endPosInBlock { - // The position at which ZSTD_optLdm_processMatchCandidate() is called is not necessarily - // at the end of a match from the ldm seq store, and will often be some bytes - // over beyond matchEndPosInBlock. As such, we need to correct for these "overshoots" - let posOvershoot = currPosInBlock.wrapping_sub(optLdm.endPosInBlock); - ZSTD_ldm_skipRawSeqStoreBytes(&mut optLdm.seqStore, posOvershoot as usize); + if currPosInBlock >= self.endPosInBlock { + if currPosInBlock > self.endPosInBlock { + // The position at which ZSTD_optLdm_processMatchCandidate() is called is not necessarily + // at the end of a match from the ldm seq store, and will often be some bytes + // over beyond matchEndPosInBlock. As such, we need to correct for these "overshoots" + let posOvershoot = currPosInBlock.wrapping_sub(self.endPosInBlock); + ZSTD_ldm_skipRawSeqStoreBytes(&mut self.seqStore, posOvershoot as usize); + } + self.get_next_match_and_update_seq_store(currPosInBlock, remainingBytes); } - optLdm.get_next_match_and_update_seq_store(currPosInBlock, remainingBytes); + ZSTD_optLdm_maybeAddMatch(matches, nbMatches, self, currPosInBlock, minMatch); } - ZSTD_optLdm_maybeAddMatch(matches, nbMatches, optLdm, currPosInBlock, minMatch); } unsafe fn ZSTD_compressBlock_opt_generic( @@ -1192,8 +1194,7 @@ unsafe fn ZSTD_compressBlock_opt_generic( litlen == 0, minMatch, ); - ZSTD_optLdm_processMatchCandidate( - &mut optLdm, + optLdm.process_match_candidate( matches, &mut nbMatches, ip.offset_from_unsigned(istart) as u32, @@ -1363,8 +1364,7 @@ unsafe fn ZSTD_compressBlock_opt_generic( minMatch, ); - ZSTD_optLdm_processMatchCandidate( - &mut optLdm, + optLdm.process_match_candidate( matches, &mut nbMatches, inr.offset_from_unsigned(istart) as u32, From a70e6975cbd53e29ccf332b77238f5d7929e4d58 Mon Sep 17 00:00:00 2001 From: Michiel Date: Wed, 11 Nov 2026 11:11:19 +0100 Subject: [PATCH 8/9] `ZSTD_optLdm_maybeAddMatch`: mark safe --- lib/compress/zstd_opt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstd_opt.rs b/lib/compress/zstd_opt.rs index 5cad2860..49b36311 100644 --- a/lib/compress/zstd_opt.rs +++ b/lib/compress/zstd_opt.rs @@ -1076,7 +1076,7 @@ impl OptLdm { /// Adds a match if it's long enough, /// based on it's 'matchStartPosInBlock' and 'matchEndPosInBlock', /// into 'matches'. Maintains the correct ordering of 'matches'. -unsafe fn ZSTD_optLdm_maybeAddMatch( +fn ZSTD_optLdm_maybeAddMatch( matches: &mut [ZSTD_match_t; ZSTD_OPT_SIZE], nbMatches: &mut usize, optLdm: &OptLdm, From 8a7a31a420394be1c769110ce7ef9d7c787a5d7c Mon Sep 17 00:00:00 2001 From: Michiel Date: Wed, 11 Nov 2026 11:17:28 +0100 Subject: [PATCH 9/9] `zstd_opt.rs`: move definitions below imports --- lib/compress/zstd_opt.rs | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/compress/zstd_opt.rs b/lib/compress/zstd_opt.rs index 49b36311..2a350395 100644 --- a/lib/compress/zstd_opt.rs +++ b/lib/compress/zstd_opt.rs @@ -1,3 +1,25 @@ +use crate::lib::common::bits::ZSTD_highbit32; +use crate::lib::common::fse::{FSE_CState_t, FSE_getMaxNbBits}; +use crate::lib::common::huf::HUF_repeat; +use crate::lib::common::mem::MEM_read32; +use crate::lib::common::zstd_internal::{ + LL_bits, ML_bits, MaxLL, MaxLit, MaxML, MaxOff, RepCodes, MINMATCH, ZSTD_OPT_NUM, ZSTD_REP_NUM, +}; +use crate::lib::compress::hist::HIST_count_simple; +use crate::lib::compress::huf_compress::HUF_getNbBitsFromCTable; +use crate::lib::compress::zstd_compress::{ + RawSeqStore_t, SeqStore_t, ZSTD_MatchState_t, ZSTD_optimal_t, ZSTD_resetSeqStore, ZSTD_OPT_SIZE, +}; +use crate::lib::compress::zstd_compress_internal::{ + DictMatchState, DictMode, DictModeMarker, ExtDict, NoDict, OptPrice, OptState, ZSTD_LLcode, + ZSTD_MLcode, ZSTD_count, ZSTD_count_2segments, ZSTD_hash32Ptr, ZSTD_hashPtr, + ZSTD_index_overlap_check, ZSTD_match_t, ZSTD_storeSeq, ZSTD_updateRep, +}; +use crate::lib::compress::zstd_ldm::ZSTD_ldm_skipRawSeqStoreBytes; +use crate::lib::polyfill::PointerExt; +use crate::lib::zstd::{ParamSwitch, ZSTD_BLOCKSIZE_MAX}; +use core::mem::MaybeUninit; + pub type ZSTD_getAllMatchesFn = unsafe fn( &mut [ZSTD_match_t; ZSTD_OPT_SIZE], &mut ZSTD_MatchState_t, @@ -25,28 +47,6 @@ pub enum BaseDirective { Guaranteed = 1, } -use crate::lib::common::bits::ZSTD_highbit32; -use crate::lib::common::fse::{FSE_CState_t, FSE_getMaxNbBits}; -use crate::lib::common::huf::HUF_repeat; -use crate::lib::common::mem::MEM_read32; -use crate::lib::common::zstd_internal::{ - LL_bits, ML_bits, MaxLL, MaxLit, MaxML, MaxOff, RepCodes, MINMATCH, ZSTD_OPT_NUM, ZSTD_REP_NUM, -}; -use crate::lib::compress::hist::HIST_count_simple; -use crate::lib::compress::huf_compress::HUF_getNbBitsFromCTable; -use crate::lib::compress::zstd_compress::{ - RawSeqStore_t, SeqStore_t, ZSTD_MatchState_t, ZSTD_optimal_t, ZSTD_resetSeqStore, ZSTD_OPT_SIZE, -}; -use crate::lib::compress::zstd_compress_internal::{ - DictMatchState, DictMode, DictModeMarker, ExtDict, NoDict, OptPrice, OptState, ZSTD_LLcode, - ZSTD_MLcode, ZSTD_count, ZSTD_count_2segments, ZSTD_hash32Ptr, ZSTD_hashPtr, - ZSTD_index_overlap_check, ZSTD_match_t, ZSTD_storeSeq, ZSTD_updateRep, -}; -use crate::lib::compress::zstd_ldm::ZSTD_ldm_skipRawSeqStoreBytes; -use crate::lib::polyfill::PointerExt; -use crate::lib::zstd::{ParamSwitch, ZSTD_BLOCKSIZE_MAX}; -use core::mem::MaybeUninit; - #[inline] fn ZSTD_newRep(rep: &RepCodes, offBase: u32, ll0: bool) -> RepCodes { let mut newReps = *rep;