use crate::lossless::bit_io::reader::BitReader;
use crate::lossless::constants::{CODE_TO_PLANE, CODE_TO_PLANE_CODES};
pub(crate) fn read_prefix_value(symbol: u32, br: &mut BitReader<'_>) -> u32 {
if symbol < 4 {
return symbol + 1;
}
let extra_bits = (symbol - 2) >> 1;
let offset = (2 + (symbol & 1)) << extra_bits;
offset + br.read_bits(extra_bits) + 1
}
#[allow(
clippy::cast_possible_wrap,
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_lossless,
reason = "xsize <= 16384 (14-bit) and the computed distance is a small non-negative value; \
`as` (not From) is required to stay a const fn"
)]
pub(crate) const fn plane_code_to_distance(xsize: u32, plane_code: u32) -> u32 {
if plane_code as usize > CODE_TO_PLANE_CODES {
return plane_code - CODE_TO_PLANE_CODES as u32;
}
let dc = CODE_TO_PLANE[(plane_code - 1) as usize] as i32;
let yoffset = dc >> 4;
let xoffset = 8 - (dc & 0x0f);
let dist = yoffset * xsize as i32 + xoffset;
if dist >= 1 { dist as u32 } else { 1 }
}
pub(crate) const fn prefix_encode(value: u32) -> (u32, u32, u32) {
if value <= 4 {
return (value - 1, 0, 0);
}
let d = value - 1;
let highest_bit = d.ilog2();
let second_highest_bit = (d >> (highest_bit - 1)) & 1;
let extra_bits = highest_bit - 1;
let extra_value = d & ((1 << extra_bits) - 1);
(
2 * highest_bit + second_highest_bit,
extra_bits,
extra_value,
)
}
#[cfg(test)]
#[allow(
clippy::cast_possible_truncation,
reason = "CODE_TO_PLANE_CODES is 120 and every emitted distance is bounded by \
WINDOW_SIZE, so both narrowing casts are value-preserving"
)]
pub(crate) fn distance_to_plane_code(xsize: u32, dist: u32) -> u32 {
for plane_code in 1..=CODE_TO_PLANE_CODES as u32 {
if plane_code_to_distance(xsize, plane_code) == dist {
return plane_code;
}
}
dist + CODE_TO_PLANE_CODES as u32
}
pub(crate) struct PlaneCodeMap {
entries: [(u32, u32); CODE_TO_PLANE_CODES],
}
impl PlaneCodeMap {
#[allow(
clippy::cast_possible_truncation,
reason = "CODE_TO_PLANE_CODES is 120, so each plane code fits u32"
)]
pub(crate) fn new(xsize: u32) -> Self {
let mut entries = [(0u32, 0u32); CODE_TO_PLANE_CODES];
for (index, entry) in entries.iter_mut().enumerate() {
let plane_code = index as u32 + 1;
*entry = (plane_code_to_distance(xsize, plane_code), plane_code);
}
entries.sort_unstable();
Self { entries }
}
#[allow(
clippy::cast_possible_truncation,
reason = "CODE_TO_PLANE_CODES is 120 and every emitted distance is bounded \
by WINDOW_SIZE, so the miss-fallback cast is value-preserving"
)]
pub(crate) fn plane_code(&self, dist: u32) -> u32 {
let index = self.entries.partition_point(|&(d, _)| d < dist);
match self.entries.get(index) {
Some(&(d, plane_code)) if d == dist => plane_code,
_ => dist + CODE_TO_PLANE_CODES as u32,
}
}
}
#[cfg(test)]
mod tests {
use super::{
PlaneCodeMap, distance_to_plane_code, plane_code_to_distance, prefix_encode,
read_prefix_value,
};
use crate::lossless::bit_io::reader::BitReader;
use crate::lossless::bit_io::writer::BitWriter;
use crate::lossless::constants::{MAX_COPY_LENGTH, WINDOW_SIZE};
use proptest::prelude::*;
#[test]
fn small_symbols_are_literal_with_no_extra_bits() {
for sym in 0..4u32 {
let mut br = BitReader::new(&[0xFF]); assert_eq!(read_prefix_value(sym, &mut br), sym + 1);
assert!(!br.is_eos());
}
}
#[test]
fn symbol_four_reads_one_extra_bit() {
let mut br0 = BitReader::new(&[0x00]);
assert_eq!(read_prefix_value(4, &mut br0), 5); let mut br1 = BitReader::new(&[0x01]);
assert_eq!(read_prefix_value(4, &mut br1), 6); }
#[test]
fn symbol_five_uses_odd_offset() {
let mut br0 = BitReader::new(&[0x00]);
assert_eq!(read_prefix_value(5, &mut br0), 7);
let mut br1 = BitReader::new(&[0x01]);
assert_eq!(read_prefix_value(5, &mut br1), 8);
}
#[test]
fn plane_code_anchors() {
assert_eq!(plane_code_to_distance(100, 1), 100);
assert_eq!(plane_code_to_distance(100, 2), 1);
}
#[test]
fn plane_code_above_120_is_linear() {
assert_eq!(plane_code_to_distance(100, 121), 1);
assert_eq!(plane_code_to_distance(100, 200), 80);
}
#[test]
fn plane_code_distance_never_zero() {
for xsize in [1u32, 2, 16, 100, 1000, 16384] {
for pc in 1..=200u32 {
assert!(plane_code_to_distance(xsize, pc) >= 1);
}
}
}
#[test]
fn prefix_encode_known_values() {
assert_eq!(prefix_encode(1), (0, 0, 0));
assert_eq!(prefix_encode(4), (3, 0, 0));
assert_eq!(prefix_encode(5), (4, 1, 0));
assert_eq!(prefix_encode(6), (4, 1, 1));
assert_eq!(prefix_encode(7), (5, 1, 0));
assert_eq!(prefix_encode(8), (5, 1, 1));
assert_eq!(prefix_encode(MAX_COPY_LENGTH), (23, 10, 1023));
}
#[test]
fn prefix_symbol_bounds_fit_the_alphabets() {
for value in [1u32, 2, 4, 5, 255, 256, MAX_COPY_LENGTH] {
let (symbol, extra_bits, _) = prefix_encode(value);
assert!(symbol <= 23, "length symbol {symbol} for value {value}");
assert!(extra_bits <= 10);
}
let (symbol, extra_bits, _) = prefix_encode(WINDOW_SIZE + 120);
assert_eq!(symbol, 39);
assert!(extra_bits <= 18);
}
#[test]
fn plane_code_map_matches_reference_exhaustive() {
for xsize in [1u32, 2, 3, 4, 7, 8, 16, 100, 1000, 16384] {
let map = PlaneCodeMap::new(xsize);
let mut dists = alloc::vec![1u32, 2, 100, 100_000, WINDOW_SIZE];
for k in 0..=16i64 {
for off in -16..=16i64 {
let d = k * i64::from(xsize) + off;
if let Ok(d) = u32::try_from(d)
&& d >= 1
{
dists.push(d);
}
}
}
for &dist in &dists {
assert_eq!(
map.plane_code(dist),
distance_to_plane_code(xsize, dist),
"mismatch at xsize={xsize} dist={dist}"
);
}
}
}
#[test]
fn distance_to_plane_code_known_values() {
assert_eq!(distance_to_plane_code(100, 100), 1);
assert_eq!(distance_to_plane_code(100, 1), 2);
assert_eq!(distance_to_plane_code(100, 100_000), 100_120);
}
fn round_trip_prefix(value: u32) -> u32 {
let (symbol, extra_bits, extra_value) = prefix_encode(value);
let mut bw = BitWriter::new();
bw.write_bits(extra_value, extra_bits);
let bytes = bw.into_bytes();
let mut br = BitReader::new(&bytes);
read_prefix_value(symbol, &mut br)
}
proptest! {
#[test]
fn prefix_encode_inverts_read_prefix_value(value in 1u32..=1_048_576) {
let (symbol, extra_bits, _) = prefix_encode(value);
prop_assert!(extra_bits <= 24);
prop_assert!(symbol < 40);
prop_assert_eq!(round_trip_prefix(value), value);
}
#[test]
fn distance_to_plane_code_inverts_plane_code_to_distance(
xsize in prop_oneof![
Just(1u32), Just(2u32), Just(16u32),
Just(100u32), Just(1000u32), Just(16384u32),
],
dist in 1u32..=WINDOW_SIZE,
) {
let plane_code = distance_to_plane_code(xsize, dist);
prop_assert_eq!(plane_code_to_distance(xsize, plane_code), dist);
let (symbol, extra_bits, _) = prefix_encode(plane_code);
prop_assert!(symbol < 40);
prop_assert!(extra_bits <= 24);
}
#[test]
fn plane_code_map_matches_reference(
xsize in prop_oneof![
Just(1u32), Just(2u32), Just(3u32), Just(16u32),
Just(100u32), Just(1000u32), Just(16384u32),
],
dist in 1u32..=WINDOW_SIZE,
) {
let map = PlaneCodeMap::new(xsize);
prop_assert_eq!(map.plane_code(dist), distance_to_plane_code(xsize, dist));
}
}
}