pub(crate) const INFINITY: f32 = 1.7e38;
const COPY_LEN_MASK: u32 = 0x01FF_FFFF;
const LEN_CODE_SHIFT: u32 = 25;
const INSERT_LEN_MASK: u32 = 0x07FF_FFFF;
const DCODE_SHIFT: u32 = 27;
pub(crate) const START_POS_QUEUE_SIZE: usize = 8;
#[derive(Copy, Clone, Debug)]
pub(crate) struct ZopfliNode {
pub(crate) length: u32,
pub(crate) distance: u32,
pub(crate) dcode_insert_length: u32,
payload: u32,
}
impl Default for ZopfliNode {
fn default() -> Self {
Self {
length: 1,
distance: 0,
dcode_insert_length: 0,
payload: INFINITY.to_bits(),
}
}
}
impl ZopfliNode {
#[inline(always)]
pub(crate) const fn copy_length(&self) -> u32 {
self.length & COPY_LEN_MASK
}
#[inline(always)]
pub(crate) const fn length_code(&self) -> u32 {
let modifier = self.length >> LEN_CODE_SHIFT;
#[cfg(feature = "experimental")]
if modifier >= 96 {
return modifier - 96;
}
self.copy_length() + 9 - modifier
}
#[inline(always)]
pub(crate) const fn copy_distance(&self) -> u32 {
self.distance
}
#[inline(always)]
pub(crate) const fn distance_code(&self) -> u32 {
let short_code = self.dcode_insert_length >> DCODE_SHIFT;
if short_code == 0 {
self.copy_distance() + crate::shared::distance::NUM_DISTANCE_SHORT_CODES - 1
} else {
short_code - 1
}
}
#[inline(always)]
pub(crate) const fn insert_length(&self) -> u32 {
self.dcode_insert_length & INSERT_LEN_MASK
}
#[inline(always)]
pub(crate) const fn command_length(&self) -> u32 {
self.copy_length() + self.insert_length()
}
#[inline(always)]
pub(crate) const fn cost(&self) -> f32 {
f32::from_bits(self.payload)
}
#[inline(always)]
pub(crate) const fn set_cost(&mut self, cost: f32) {
self.payload = cost.to_bits();
}
#[inline(always)]
pub(crate) const fn shortcut(&self) -> u32 {
self.payload
}
#[inline(always)]
pub(crate) const fn set_shortcut(&mut self, shortcut: u32) {
self.payload = shortcut;
}
#[inline(always)]
pub(crate) const fn next(&self) -> u32 {
self.payload
}
#[inline(always)]
pub(crate) const fn set_next(&mut self, next: u32) {
self.payload = next;
}
#[expect(
clippy::too_many_arguments,
reason = "mirrors UpdateZopfliNode, whose parameters are all needed"
)]
#[inline(always)]
pub(crate) fn record(
&mut self,
pos: usize,
start_pos: usize,
len: usize,
len_code: usize,
dist: usize,
short_code: usize,
cost: f32,
) {
let modifier = (len + 9 - len_code) as u32;
#[cfg(feature = "experimental")]
let modifier = if modifier >= 96 {
96 + len_code as u32
} else {
modifier
};
self.length = (len as u32) | (modifier << LEN_CODE_SHIFT);
self.distance = dist as u32;
self.dcode_insert_length =
((short_code as u32) << DCODE_SHIFT) | ((pos - start_pos) as u32);
self.set_cost(cost);
}
}
#[derive(Copy, Clone, Debug)]
pub(crate) struct PosData {
pub(crate) pos: usize,
pub(crate) distance_cache: [i32; 4],
pub(crate) costdiff: f32,
pub(crate) cost: f32,
}
impl Default for PosData {
fn default() -> Self {
Self {
pos: 0,
distance_cache: [0; 4],
costdiff: 0.0,
cost: 0.0,
}
}
}
pub(crate) struct StartPosQueue {
queue: [PosData; START_POS_QUEUE_SIZE],
idx: usize,
}
impl Default for StartPosQueue {
fn default() -> Self {
Self {
queue: [PosData::default(); START_POS_QUEUE_SIZE],
idx: 0,
}
}
}
impl StartPosQueue {
pub(crate) const fn clear(&mut self) {
self.idx = 0;
}
pub(crate) const fn len(&self) -> usize {
if self.idx < START_POS_QUEUE_SIZE {
self.idx
} else {
START_POS_QUEUE_SIZE
}
}
pub(crate) fn push(&mut self, posdata: PosData) {
let start = !self.idx & (START_POS_QUEUE_SIZE - 1);
self.idx += 1;
let len = self.len();
self.queue[start] = posdata;
for offset in start..start + len.saturating_sub(1) {
let here = offset & (START_POS_QUEUE_SIZE - 1);
let next = (offset + 1) & (START_POS_QUEUE_SIZE - 1);
if self.queue[here].costdiff > self.queue[next].costdiff {
self.queue.swap(here, next);
}
}
}
pub(crate) fn at(&self, k: usize) -> &PosData {
&self.queue[k.wrapping_sub(self.idx) & (START_POS_QUEUE_SIZE - 1)]
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
fn candidate(pos: usize, costdiff: f32) -> PosData {
PosData {
pos,
costdiff,
..PosData::default()
}
}
#[test]
fn a_fresh_node_is_the_reference_stub() {
let node = ZopfliNode::default();
assert_eq!(node.length, 1);
assert_eq!(node.distance, 0);
assert_eq!(node.dcode_insert_length, 0);
assert_eq!(node.cost(), INFINITY);
}
#[test]
fn a_node_round_trips_its_packed_fields() {
let mut nodes = vec![ZopfliNode::default(); 64];
nodes[10 + 20].record(10, 4, 20, 20, 1234, 0, 7.5);
let node = nodes[30];
assert_eq!(node.copy_length(), 20);
assert_eq!(node.length_code(), 20);
assert_eq!(node.copy_distance(), 1234);
assert_eq!(node.insert_length(), 6);
assert_eq!(node.command_length(), 26);
assert_eq!(node.cost(), 7.5);
}
#[test]
fn a_dictionary_length_code_survives_the_packing() {
let mut nodes = vec![ZopfliNode::default(); 64];
nodes[10].record(0, 0, 10, 14, 9000, 0, 1.0);
assert_eq!(nodes[10].copy_length(), 10);
assert_eq!(nodes[10].length_code(), 14);
nodes[12].record(0, 0, 12, 9, 9000, 0, 1.0);
assert_eq!(nodes[12].copy_length(), 12);
assert_eq!(nodes[12].length_code(), 9);
}
#[test]
fn a_short_distance_code_is_stored_one_higher() {
let mut nodes = vec![ZopfliNode::default(); 64];
nodes[5].record(0, 0, 5, 5, 40, 1, 1.0);
assert_eq!(nodes[5].distance_code(), 0);
nodes[6].record(0, 0, 6, 6, 40, 0, 1.0);
assert_eq!(nodes[6].distance_code(), 40 + 15);
}
#[test]
fn the_payload_serves_all_three_phases_in_turn() {
let mut node = ZopfliNode::default();
node.set_cost(12.25);
assert_eq!(node.cost(), 12.25);
node.set_shortcut(99);
assert_eq!(node.shortcut(), 99);
node.set_next(7);
assert_eq!(node.next(), 7);
}
#[test]
fn an_empty_queue_has_no_candidates() {
let queue = StartPosQueue::default();
assert_eq!(queue.len(), 0);
}
#[test]
fn the_queue_returns_candidates_cheapest_first() {
let mut queue = StartPosQueue::default();
for (pos, costdiff) in [(0usize, 5.0f32), (1, 3.0), (2, 9.0), (3, 1.0)] {
queue.push(candidate(pos, costdiff));
}
assert_eq!(queue.len(), 4);
let order: Vec<usize> = (0..queue.len()).map(|k| queue.at(k).pos).collect();
assert_eq!(order, vec![3, 1, 0, 2]);
}
#[test]
fn the_queue_never_grows_past_eight_and_stays_sorted() {
let mut rng = 0x2468_ACE0_1357_9BDFu64;
let mut queue = StartPosQueue::default();
for pos in 0..200usize {
rng ^= rng << 13;
rng ^= rng >> 7;
rng ^= rng << 17;
let costdiff = ((rng >> 40) as i32 - 8192) as f32 / 64.0;
queue.push(candidate(pos, costdiff));
assert!(queue.len() <= START_POS_QUEUE_SIZE);
assert_eq!(queue.len(), (pos + 1).min(START_POS_QUEUE_SIZE));
let costs: Vec<f32> = (0..queue.len()).map(|k| queue.at(k).costdiff).collect();
assert!(
costs.windows(2).all(|pair| pair[0] <= pair[1]),
"queue out of order after {pos} pushes: {costs:?}"
);
}
}
#[test]
fn a_full_queue_holds_eight_distinct_candidates() {
let mut queue = StartPosQueue::default();
for pos in 0..8usize {
queue.push(candidate(pos, (8 - pos) as f32));
}
let mut seen: Vec<usize> = (0..queue.len()).map(|k| queue.at(k).pos).collect();
seen.sort_unstable();
assert_eq!(seen, (0..8).collect::<Vec<_>>());
}
#[test]
fn a_late_cheap_candidate_reaches_the_front() {
let mut queue = StartPosQueue::default();
for pos in 0..8usize {
queue.push(candidate(pos, 10.0 + pos as f32));
}
queue.push(candidate(100, -1.0));
assert_eq!(queue.at(0).pos, 100);
assert_eq!(queue.len(), START_POS_QUEUE_SIZE);
}
#[test]
fn clearing_forgets_every_candidate() {
let mut queue = StartPosQueue::default();
for pos in 0..5usize {
queue.push(candidate(pos, pos as f32));
}
queue.clear();
assert_eq!(queue.len(), 0);
queue.push(candidate(42, 0.0));
assert_eq!((queue.len(), queue.at(0).pos), (1, 42));
}
#[test]
fn equal_costs_keep_the_newer_candidate_first() {
let mut queue = StartPosQueue::default();
queue.push(candidate(1, 4.0));
queue.push(candidate(2, 4.0));
assert_eq!(queue.at(0).pos, 2);
assert_eq!(queue.at(1).pos, 1);
}
}