use crate::block::types as bt;
pub const LZ4HC_CLEVEL_MIN: i32 = 2;
pub const LZ4HC_CLEVEL_DEFAULT: i32 = 9;
pub const LZ4HC_CLEVEL_OPT_MIN: i32 = 10;
pub const LZ4HC_CLEVEL_MAX: i32 = 12;
pub const LZ4HC_DICTIONARY_LOGSIZE: u32 = 16;
pub const LZ4HC_MAXD: usize = 1 << LZ4HC_DICTIONARY_LOGSIZE; pub const LZ4HC_MAXD_MASK: usize = LZ4HC_MAXD - 1;
pub const LZ4HC_HASH_LOG: u32 = 15;
pub const LZ4HC_HASHTABLESIZE: usize = 1 << LZ4HC_HASH_LOG; pub const LZ4HC_HASH_MASK: u32 = (LZ4HC_HASHTABLESIZE - 1) as u32;
pub const LZ4HC_HASHSIZE: usize = 4;
pub const LZ4MID_HASHSIZE: usize = 8;
pub const LZ4MID_HASHLOG: u32 = LZ4HC_HASH_LOG - 1; pub const LZ4MID_HASHTABLESIZE: usize = 1 << LZ4MID_HASHLOG;
pub const OPTIMAL_ML: i32 = (bt::ML_MASK - 1) as i32 + bt::MINMATCH as i32;
pub const LZ4_OPT_NUM: usize = 1 << 12;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum DictCtxDirective {
NoDictCtx,
UsingDictCtxHc,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u32)]
pub enum HcStrategy {
Lz4Mid = 0,
Lz4Hc = 1,
Lz4Opt = 2,
}
#[derive(Clone, Copy, Debug)]
pub struct CParams {
pub strat: HcStrategy,
pub nb_searches: u32,
pub target_length: u32,
}
pub static K_CL_TABLE: [CParams; (LZ4HC_CLEVEL_MAX + 1) as usize] = [
CParams {
strat: HcStrategy::Lz4Mid,
nb_searches: 2,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Mid,
nb_searches: 2,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Mid,
nb_searches: 2,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Hc,
nb_searches: 4,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Hc,
nb_searches: 8,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Hc,
nb_searches: 16,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Hc,
nb_searches: 32,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Hc,
nb_searches: 64,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Hc,
nb_searches: 128,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Hc,
nb_searches: 256,
target_length: 16,
},
CParams {
strat: HcStrategy::Lz4Opt,
nb_searches: 96,
target_length: 64,
},
CParams {
strat: HcStrategy::Lz4Opt,
nb_searches: 512,
target_length: 128,
},
CParams {
strat: HcStrategy::Lz4Opt,
nb_searches: 16384,
target_length: LZ4_OPT_NUM as u32,
},
];
#[inline]
pub fn get_clevel_params(mut c_level: i32) -> CParams {
if c_level < 1 {
c_level = LZ4HC_CLEVEL_DEFAULT;
}
c_level = c_level.min(LZ4HC_CLEVEL_MAX);
K_CL_TABLE[c_level as usize]
}
#[inline(always)]
pub unsafe fn read64(ptr: *const u8) -> u64 {
core::ptr::read_unaligned(ptr as *const u64)
}
#[inline(always)]
pub unsafe fn read_le64(ptr: *const u8) -> u64 {
#[cfg(target_endian = "little")]
{
read64(ptr)
}
#[cfg(not(target_endian = "little"))]
{
(*ptr) as u64
| ((*ptr.add(1)) as u64) << 8
| ((*ptr.add(2)) as u64) << 16
| ((*ptr.add(3)) as u64) << 24
| ((*ptr.add(4)) as u64) << 32
| ((*ptr.add(5)) as u64) << 40
| ((*ptr.add(6)) as u64) << 48
| ((*ptr.add(7)) as u64) << 56
}
}
#[inline(always)]
pub unsafe fn hash_ptr(ptr: *const u8) -> u32 {
bt::read32(ptr).wrapping_mul(2_654_435_761u32) >> (bt::MINMATCH as u32 * 8 - LZ4HC_HASH_LOG)
}
#[inline(always)]
pub fn mid_hash4(v: u32) -> u32 {
v.wrapping_mul(2_654_435_761u32) >> (32 - LZ4MID_HASHLOG)
}
#[inline(always)]
pub unsafe fn mid_hash4_ptr(ptr: *const u8) -> u32 {
mid_hash4(bt::read32(ptr))
}
#[inline(always)]
pub fn mid_hash7(v: u64) -> u32 {
((v << (64 - 56)).wrapping_mul(58_295_818_150_454_627u64) >> (64 - LZ4MID_HASHLOG)) as u32
}
#[inline(always)]
pub unsafe fn mid_hash8_ptr(ptr: *const u8) -> u32 {
mid_hash7(read_le64(ptr))
}
#[inline(always)]
pub fn nb_common_bytes32(val: u32) -> u32 {
debug_assert!(val != 0);
#[cfg(target_endian = "little")]
{
val.trailing_zeros() >> 3
}
#[cfg(not(target_endian = "little"))]
{
val.leading_zeros() >> 3
}
}
#[inline(always)]
pub unsafe fn hc_count(ip: *const u8, match_ptr: *const u8, p_in_limit: *const u8) -> u32 {
bt::count(ip, match_ptr, p_in_limit)
}
#[inline(always)]
pub unsafe fn count_back(
ip: *const u8,
match_ptr: *const u8,
i_min: *const u8,
m_min: *const u8,
) -> i32 {
let mut back: i32 = 0;
let min = {
let di = i_min.offset_from(ip) as i32; let dm = m_min.offset_from(match_ptr) as i32; di.max(dm) };
debug_assert!(min <= 0);
while (back - min) > 3 {
let vi = bt::read32(ip.offset(back as isize - 4));
let vm = bt::read32(match_ptr.offset(back as isize - 4));
let v = vi ^ vm;
if v != 0 {
#[cfg(target_endian = "little")]
let common_high = v.leading_zeros() >> 3;
#[cfg(not(target_endian = "little"))]
let common_high = v.trailing_zeros() >> 3;
return back - common_high as i32;
}
back -= 4;
}
while back > min && *ip.offset(back as isize - 1) == *match_ptr.offset(back as isize - 1) {
back -= 1;
}
back
}
#[repr(C)]
pub struct HcCCtxInternal {
pub hash_table: [u32; LZ4HC_HASHTABLESIZE],
pub chain_table: [u16; LZ4HC_MAXD],
pub end: *const u8,
pub prefix_start: *const u8,
pub dict_start: *const u8,
pub dict_limit: u32,
pub low_limit: u32,
pub next_to_update: u32,
pub compression_level: i16,
pub favor_dec_speed: i8,
pub dirty: i8,
pub dict_ctx: *const HcCCtxInternal,
}
unsafe impl Send for HcCCtxInternal {}
impl HcCCtxInternal {
pub const fn new() -> Self {
Self {
hash_table: [0u32; LZ4HC_HASHTABLESIZE],
chain_table: [0u16; LZ4HC_MAXD],
end: core::ptr::null(),
prefix_start: core::ptr::null(),
dict_start: core::ptr::null(),
dict_limit: 0,
low_limit: 0,
next_to_update: 0,
compression_level: 0,
favor_dec_speed: 0,
dirty: 0,
dict_ctx: core::ptr::null(),
}
}
}
impl Default for HcCCtxInternal {
fn default() -> Self {
Self::new()
}
}
pub fn clear_tables(hc4: &mut HcCCtxInternal) {
hc4.hash_table.fill(0u32);
hc4.chain_table.fill(0xFFFFu16); }
pub unsafe fn init_internal(hc4: &mut HcCCtxInternal, start: *const u8) {
let buffer_size = hc4.end.offset_from(hc4.prefix_start) as usize;
let mut new_starting_offset: usize = buffer_size + hc4.dict_limit as usize;
debug_assert!(new_starting_offset >= buffer_size);
if new_starting_offset > (1usize << 30) {
clear_tables(hc4);
new_starting_offset = 0;
}
new_starting_offset += 64 * 1024;
hc4.next_to_update = new_starting_offset as u32;
hc4.prefix_start = start;
hc4.end = start;
hc4.dict_start = start;
hc4.dict_limit = new_starting_offset as u32;
hc4.low_limit = new_starting_offset as u32;
}