use super::*;
use alloc::vec;
fn test_table() -> HuffmanTable {
let packed_decode = vec![
u16::from(b'A') | (1u16 << 8),
u16::from(b'B') | (2u16 << 8),
u16::from(b'C') | (1u16 << 8),
u16::from(b'D') | (2u16 << 8),
];
HuffmanTable {
packed_decode,
weights: Vec::new(),
max_num_bits: 2,
state_mask: 0b11,
bits: Vec::new(),
bit_ranks: Vec::new(),
weight_sum: 0,
weight_rank_count: [0; (MAX_MAX_NUM_BITS as usize) + 1],
last_weight: 0,
fse_table: FSETable::new(255),
}
}
#[test]
fn build_decoder_rejects_fse_streams_with_256_explicit_weights() {
use crate::bit_io::BitWriter;
use crate::fse::fse_encoder::{FSEEncoder, build_table_from_symbol_counts};
let weights: Vec<u8> = (0..256).map(|i| if i % 2 == 0 { 1 } else { 2 }).collect();
let mut encoded = Vec::new();
{
let mut writer = BitWriter::from(&mut encoded);
let mut counts = [0usize; 13];
for &w in &weights {
counts[w as usize] += 1;
}
let mut encoder = FSEEncoder::new(
build_table_from_symbol_counts(&counts, 6, false),
&mut writer,
);
encoder.encode_interleaved(&weights);
writer.flush();
}
assert!(
encoded.len() < 128,
"fixture must fit the FSE-described header byte, got {}",
encoded.len()
);
let mut description = Vec::with_capacity(encoded.len() + 1);
description.push(encoded.len() as u8);
description.extend_from_slice(&encoded);
let mut table = HuffmanTable::new();
let result = table.build_decoder(description.as_slice());
assert!(
matches!(result, Err(HuffmanTableError::TooManyWeights { .. })),
"256 explicit weights must be rejected, got {result:?}"
);
}
#[test]
fn decode_symbol_and_advance_scalar_matches_manual_transition() {
let table = test_table();
let initial_state = 1_u64;
let packed = table.packed_decode[initial_state as usize];
let entry_num_bits = (packed >> 8) as u8;
let entry_symbol = packed as u8;
let mut manual_br =
BitReaderReversed::<crate::cpu_kernel::ScalarKernel>::new(&[0b10101010, 0b01010101]);
let expected_new_bits = manual_br.get_bits(entry_num_bits);
let expected_state = ((initial_state << entry_num_bits) & table.state_mask) | expected_new_bits;
let mut decoder = HuffmanDecoder {
table: &table,
state: initial_state,
};
let mut br =
BitReaderReversed::<crate::cpu_kernel::ScalarKernel>::new(&[0b10101010, 0b01010101]);
let symbol = decoder.decode_symbol_and_advance(&mut br);
assert_eq!(symbol, entry_symbol);
assert_eq!(decoder.state, expected_state);
}
#[test]
fn every_kernel_advances_the_state_alike() {
let mut table = test_table();
table.packed_decode[3] = u16::from(b'D') | (1u16 << 8);
let source = [0b10101010, 0b01010101];
const START: u64 = 3;
let mut scalar = HuffmanDecoder::new(&table);
scalar.state = START;
let mut scalar_br = BitReaderReversed::<crate::cpu_kernel::ScalarKernel>::new(&source);
let scalar_symbol = scalar.decode_symbol_and_advance(&mut scalar_br);
assert_ne!(scalar.state, 0, "the masked state must be nonzero");
macro_rules! same_as_scalar {
($kernel:ty) => {{
let mut decoder = HuffmanDecoder::new(&table);
decoder.state = START;
let mut reader = BitReaderReversed::<$kernel>::new(&source);
assert_eq!(
decoder.decode_symbol_and_advance(&mut reader),
scalar_symbol,
"{} decoded another symbol",
stringify!($kernel)
);
assert_eq!(
decoder.state,
scalar.state,
"{} advanced the state differently",
stringify!($kernel)
);
}};
}
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
feature = "kernel-bmi2"
))]
if std::arch::is_x86_feature_detected!("bmi2") {
same_as_scalar!(crate::cpu_kernel::Bmi2Kernel);
}
#[cfg(all(target_arch = "x86_64", feature = "kernel-avx2"))]
if std::arch::is_x86_feature_detected!("avx2") && std::arch::is_x86_feature_detected!("bmi2") {
same_as_scalar!(crate::cpu_kernel::Avx2Kernel);
}
#[cfg(all(target_arch = "x86_64", feature = "kernel-vbmi2"))]
if std::arch::is_x86_feature_detected!("avx512vbmi2")
&& std::arch::is_x86_feature_detected!("avx512f")
&& std::arch::is_x86_feature_detected!("avx512vl")
&& std::arch::is_x86_feature_detected!("avx512bw")
&& std::arch::is_x86_feature_detected!("bmi2")
&& std::arch::is_x86_feature_detected!("avx2")
{
same_as_scalar!(crate::cpu_kernel::Vbmi2Kernel);
}
#[cfg(all(target_arch = "aarch64", feature = "kernel-neon"))]
same_as_scalar!(crate::cpu_kernel::NeonKernel);
#[cfg(all(target_arch = "aarch64", feature = "kernel-sve", feature = "std"))]
if std::arch::is_aarch64_feature_detected!("sve") {
same_as_scalar!(crate::cpu_kernel::SveKernel);
}
}