Files
zstd-rs/lib/compress/zstd_opt.c
T
ddidderr 5d03dca147 feat(compress): port the optimal parser to Rust
Move the binary-tree optimal and ultra block parsers into Rust with a narrow
C projection of match-state, sequence-store, and entropy-table fields. Keep
the established C entry points as wrappers, and avoid reading uninitialized
entropy costs during dictionary tree updates.

Test Plan:
- cargo test --manifest-path rust/Cargo.toml
- cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check
- make -B -C tests test-zstream V=1
- git diff --check

Refs: rust/src/zstd_opt.rs, lib/compress/zstd_opt.c
2026-07-12 09:51:45 +02:00

244 lines
8.7 KiB
C

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one or both of these licenses.
*/
/* The optimal parser is implemented in rust/src/zstd_opt.rs. Keep the
* private ZSTD_MatchState_t and entropy-table layouts on the C side: this
* translation unit only projects the leaves Rust needs and preserves the
* established C entry points. */
#include "zstd_compress_internal.h"
#include "zstd_opt.h"
#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \
|| !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \
|| !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR)
typedef struct {
U32* hashTable;
U32* chainTable;
const BYTE* base;
const BYTE* dictBase;
U32 dictLimit;
U32 lowLimit;
U32 loadedDictEnd;
U32* nextToUpdate;
U32 hashLog;
U32 chainLog;
U32 searchLog;
U32 windowLog;
int useCPredict;
U32* hashTable3;
U32 hashLog3;
const BYTE* nextSrc;
U32 minMatch;
U32 targetLength;
optState_t* opt;
const void* dictMatchState;
const RawSeqStore_t* ldmSeqStore;
const BYTE** windowBase;
U32* windowDictLimit;
U32* windowLowLimit;
const size_t* hufCTable;
int hufRepeatValid;
const U32* fseLitLengthCTable;
const U32* fseMatchLengthCTable;
const U32* fseOffCodeCTable;
} ZSTD_RustOptState;
typedef char ZSTD_rust_opt_seqdef_layout[(sizeof(SeqDef) == 8) ? 1 : -1];
typedef char ZSTD_rust_opt_match_layout[(sizeof(ZSTD_match_t) == 8) ? 1 : -1];
typedef char ZSTD_rust_opt_rawseq_layout[(sizeof(rawSeq) == 12) ? 1 : -1];
typedef char ZSTD_rust_opt_seqstore_layout[
(offsetof(SeqStore_t, longLengthPos) == 9 * sizeof(size_t) + 4) ? 1 : -1];
typedef char ZSTD_rust_optimal_layout[
(sizeof(ZSTD_optimal_t) == 4 * sizeof(U32) + sizeof(U32) * ZSTD_REP_NUM) ? 1 : -1];
typedef char ZSTD_rust_opt_rep_count[(ZSTD_REP_NUM == 3) ? 1 : -1];
static void ZSTD_rustOptState_init(
ZSTD_RustOptState* const out,
ZSTD_MatchState_t* const ms,
const ZSTD_RustOptState* const dms)
{
out->hashTable = ms->hashTable;
out->chainTable = ms->chainTable;
out->base = ms->window.base;
out->dictBase = ms->window.dictBase;
out->dictLimit = ms->window.dictLimit;
out->lowLimit = ms->window.lowLimit;
out->loadedDictEnd = ms->loadedDictEnd;
out->nextToUpdate = &ms->nextToUpdate;
out->hashLog = ms->cParams.hashLog;
out->chainLog = ms->cParams.chainLog;
out->searchLog = ms->cParams.searchLog;
#ifdef ZSTD_C_PREDICT
out->useCPredict = 1;
#else
out->useCPredict = 0;
#endif
out->windowLog = ms->cParams.windowLog;
out->hashTable3 = ms->hashTable3;
out->hashLog3 = ms->hashLog3;
out->nextSrc = ms->window.nextSrc;
out->minMatch = ms->cParams.minMatch;
out->targetLength = ms->cParams.targetLength;
out->opt = &ms->opt;
out->dictMatchState = dms;
out->ldmSeqStore = ms->ldmSeqStore;
out->windowBase = &ms->window.base;
out->windowDictLimit = &ms->window.dictLimit;
out->windowLowLimit = &ms->window.lowLimit;
out->hufCTable = NULL;
out->hufRepeatValid = 0;
out->fseLitLengthCTable = NULL;
out->fseMatchLengthCTable = NULL;
out->fseOffCodeCTable = NULL;
}
static void ZSTD_rustOptState_projectCosts(
ZSTD_RustOptState* const out,
ZSTD_MatchState_t* const ms)
{
const ZSTD_entropyCTables_t* const costs = ms->opt.symbolCosts;
out->hufCTable = costs ? costs->huf.CTable : NULL;
out->hufRepeatValid = costs && costs->huf.repeatMode == HUF_repeat_valid;
out->fseLitLengthCTable = costs ? costs->fse.litlengthCTable : NULL;
out->fseMatchLengthCTable = costs ? costs->fse.matchlengthCTable : NULL;
out->fseOffCodeCTable = costs ? costs->fse.offcodeCTable : NULL;
}
static void ZSTD_rustOptState_init_with_dict(
ZSTD_RustOptState* const out,
ZSTD_MatchState_t* const ms)
{
ZSTD_rustOptState_init(out, ms, NULL);
}
static void ZSTD_rustOptState_init_with_costs(
ZSTD_RustOptState* const out,
ZSTD_MatchState_t* const ms,
const ZSTD_RustOptState* const dms)
{
ZSTD_rustOptState_init(out, ms, dms);
ZSTD_rustOptState_projectCosts(out, ms);
}
void ZSTD_rust_opt_updateTree(
ZSTD_RustOptState* state,
const void* ip, const void* iend,
U32 mls, int dictMode);
size_t ZSTD_rust_compressBlock_opt(
ZSTD_RustOptState* state, void* seqStore, U32 rep[ZSTD_REP_NUM],
const void* src, size_t srcSize, int optLevel, int dictMode);
void ZSTD_rust_initStats_ultra(
ZSTD_RustOptState* state, void* seqStore, const U32 rep[ZSTD_REP_NUM],
const void* src, size_t srcSize);
size_t ZSTD_rust_compressBlock_btultra2(
ZSTD_RustOptState* state, void* seqStore, U32 rep[ZSTD_REP_NUM],
const void* src, size_t srcSize);
enum {
ZSTD_rust_dict_noDict = 0,
ZSTD_rust_dict_extDict = 1,
ZSTD_rust_dict_dictMatchState = 2,
};
void ZSTD_updateTree(ZSTD_MatchState_t* const ms, const BYTE* const ip,
const BYTE* const iend)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_dict(&state, ms);
ZSTD_rust_opt_updateTree(&state, ip, iend, ms->cParams.minMatch,
ZSTD_rust_dict_noDict);
}
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
size_t ZSTD_compressBlock_btopt(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
0, ZSTD_rust_dict_noDict);
}
size_t ZSTD_compressBlock_btopt_dictMatchState(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_RustOptState dictState;
ZSTD_MatchState_t dictCopy = *ms->dictMatchState;
ZSTD_rustOptState_init(&dictState, &dictCopy, NULL);
ZSTD_rustOptState_init_with_costs(&state, ms, &dictState);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
0, ZSTD_rust_dict_dictMatchState);
}
size_t ZSTD_compressBlock_btopt_extDict(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
0, ZSTD_rust_dict_extDict);
}
#endif
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
size_t ZSTD_compressBlock_btultra(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
2, ZSTD_rust_dict_noDict);
}
size_t ZSTD_compressBlock_btultra_dictMatchState(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_RustOptState dictState;
ZSTD_MatchState_t dictCopy = *ms->dictMatchState;
ZSTD_rustOptState_init(&dictState, &dictCopy, NULL);
ZSTD_rustOptState_init_with_costs(&state, ms, &dictState);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
2, ZSTD_rust_dict_dictMatchState);
}
size_t ZSTD_compressBlock_btultra_extDict(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_opt(&state, seqStore, rep, src, srcSize,
2, ZSTD_rust_dict_extDict);
}
size_t ZSTD_compressBlock_btultra2(
ZSTD_MatchState_t* const ms, SeqStore_t* const seqStore,
U32 rep[ZSTD_REP_NUM], const void* const src, size_t const srcSize)
{
ZSTD_RustOptState state;
ZSTD_rustOptState_init_with_costs(&state, ms, NULL);
return ZSTD_rust_compressBlock_btultra2(&state, seqStore, rep, src,
srcSize);
}
#endif
#endif /* any optimal parser entry point is enabled */