// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.
let Lz77Params {
enabled: lz77_enabled,
min_symbol,
min_length,
} = histograms.lz77_params;
let state = if lz77_enabled { let min_symbol = min_symbol.unwrap(); let min_length = min_length.unwrap(); let dist_multiplier = image_width.unwrap_or(0) as u32;
let lz_dist_cluster = *histograms.context_map.last().unwrap() as usize; let lz_conf = &histograms.uint_configs[lz_dist_cluster]; let is_rle = histograms.codes.single_symbol(lz_dist_cluster) == Some(1)
&& lz_conf.is_split_exponent_zero();
/// Specialized fast path for when all HybridUint configs are 420. /// /// # Preconditions /// - `histograms.can_use_config_420_fast_path()` must be true (no LZ77, all configs are 420) /// - This assumes `SymbolReaderState::None` (verified by debug_assert) #[inline(always)] pub fn read_unsigned_clustered_config_420(
&mutself,
histograms: &Histograms,
br: &mut BitReader,
cluster: usize,
) -> u32 {
debug_assert!(matches!(self.state, SymbolReaderState::None));
debug_assert!(histograms.can_use_config_420_fast_path());
let token = match &histograms.codes {
Codes::Huffman(hc) => hc.read(br, cluster),
Codes::Ans(ans) => self.ans_reader.read(ans, br, cluster),
};
HybridUint::read_config_420(token, br)
}
/// Specialized fast path for signed reads when all configs are 420. /// See [`read_unsigned_clustered_config_420`] for preconditions. #[inline(always)] pub fn read_signed_clustered_config_420(
&mutself,
histograms: &Histograms,
br: &mut BitReader,
cluster: usize,
) -> i32 { let unsigned = self.read_unsigned_clustered_config_420(histograms, br, cluster);
unpack_signed(unsigned)
}
pub fn restore<const N: usize>(&mutself, checkpoint: Checkpoint<N>) { match checkpoint.state {
StateCheckpoint::None => { if !matches!(self.state, SymbolReaderState::None) {
panic!("checkpoint type mismatch");
}
}
StateCheckpoint::Lz77 {
num_to_copy,
copy_pos,
num_decoded,
window,
} => { let SymbolReaderState::Lz77(lz77_state) = &mutself.state else {
panic!("checkpoint type mismatch");
};
let num_rewind = lz77_state.num_decoded - num_decoded; let rewind_window = &window[..num_rewind as usize];
let start = (num_decoded & Lz77State::WINDOW_MASK) as usize; let end = ((num_decoded + num_rewind) & Lz77State::WINDOW_MASK) as usize; if start < end {
lz77_state.window[start..end].copy_from_slice(rewind_window);
} else {
let window_first = &mut lz77_state.window[start..];
let first_len = window_first.len();
window_first.copy_from_slice(&rewind_window[..first_len]);
lz77_state.window[..end].copy_from_slice(&rewind_window[first_len..]);
}
/// Returns true if the config 420 fast path can be safely used.
/// Config 420: split_exponent=4, msb_in_token=2, lsb_in_token=0 (common pattern)
/// Requires: all configs are 420 AND LZ77 is disabled
pub fn can_use_config_420_fast_path(&self) -> bool {
!self.lz77_params.enabled && self.uint_configs.iter().all(|cfg| cfg.is_config_420())
}
}
#[cfg(test)]
impl Histograms {
/// Builds a decoder that reads an octet at a time and emits its bit-reversed value.
pub fn reverse_octet(num_contexts: usize) -> Self {
let d = HuffmanCodes::byte_histogram();
let codes = Codes::Huffman(d);
let uint_configs = vec![HybridUint::new(8, 0, 0)];
Self {
lz77_params: Lz77Params {
enabled: false,
min_symbol: None,
min_length: None,
},
lz77_length_uint: None,
uint_configs,
log_alpha_size: 15,
context_map: vec![0u8; num_contexts],
codes,
}
}
#[cfg(test)]
mod test {
use std::ops::ControlFlow;
use test_log::test;
use super::*;
#[test]
fn rle_arb() {
let histograms = Histograms::rle(1, 240, 3);
arbtest::arbtest(|u| {
let width = u.int_in_range(1usize..=256)?;
let mut bitstream = Vec::new();
let mut expected_bytes = Vec::new();
u.arbitrary_loop(None, None, |u| {
let do_repeat = !expected_bytes.is_empty() && u.ratio(1, 4)?;
let range = if do_repeat { 240u8..=255 } else { 0u8..=239 };
let byte = u.int_in_range(range)?;
bitstream.push(byte);
if do_repeat {
let count = byte as usize - 237;
let sym = *expected_bytes.last().unwrap();
for _ in 0..count {
expected_bytes.push(sym);
}
} else {
expected_bytes.push(byte);
}
Ok(if expected_bytes.len() >= 256 {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
})
})?;
for b in &mut bitstream {
*b = b.reverse_bits();
}
// Read RLE
let mut br = BitReader::new(&bitstream);
let mut reader = SymbolReader::new(&histograms, &mut br, Some(width)).unwrap();
for expected in expected_bytes {
let actual = reader.read_unsigned_clustered(&histograms, &mut br, 0);
assert_eq!(actual, expected as u32);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.