use super::gear_hash::{LDM_BUCKET_SIZE_LOG, LDM_HASH_RLOG, LDM_MIN_MATCH_LENGTH};
pub(crate) const LDM_HASHLOG_MIN: u32 = 6;
pub(crate) const LDM_HASHLOG_MAX: u32 = 30;
pub(crate) const LDM_BUCKETSIZELOG_MAX: u32 = 8;
pub(crate) const STRATEGY_BTULTRA: u32 = 8;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub(crate) struct LdmParams {
pub(crate) window_log: u32,
pub(crate) hash_log: u32,
pub(crate) hash_rate_log: u32,
pub(crate) min_match_length: u32,
pub(crate) bucket_size_log: u32,
}
impl LdmParams {
pub(crate) fn adjust_for(window_log: u32, strategy: u32) -> Self {
Self {
window_log,
..Self::default()
}
.derive(strategy)
}
pub(crate) fn derive(self, strategy: u32) -> Self {
assert!(
(1..=9).contains(&strategy),
"strategy must be a upstream zstd 1..=9 ordinal (upstream zstd asserts at \
zstd_ldm.c:149 + zstd_ldm.c:167)"
);
let mut params = self;
if params.hash_rate_log == 0 {
if params.hash_log > 0 && params.window_log > params.hash_log {
params.hash_rate_log = params.window_log - params.hash_log;
} else {
params.hash_rate_log = LDM_HASH_RLOG - (strategy / 3);
}
}
if params.hash_log == 0 {
params.hash_log = if params.window_log <= params.hash_rate_log {
LDM_HASHLOG_MIN
} else {
bounded(
LDM_HASHLOG_MIN,
params.window_log - params.hash_rate_log,
LDM_HASHLOG_MAX,
)
};
}
if params.min_match_length == 0 {
let mut mml = LDM_MIN_MATCH_LENGTH as u32;
if strategy >= STRATEGY_BTULTRA {
mml /= 2;
}
params.min_match_length = mml;
}
if params.bucket_size_log == 0 {
params.bucket_size_log = bounded(LDM_BUCKET_SIZE_LOG, strategy, LDM_BUCKETSIZELOG_MAX);
}
params
}
pub(crate) const fn hash_table_entries(&self) -> usize {
1usize << self.hash_log
}
pub(crate) const fn bucket_slots(&self) -> usize {
1usize << self.bucket_size_log
}
}
#[inline]
const fn bounded(lo: u32, val: u32, hi: u32) -> u32 {
if val < lo {
lo
} else if val > hi {
hi
} else {
val
}
}
#[cfg(test)]
mod tests;