#![allow(dead_code)]
use crate::vardct::common::floor_log2_nonzero;
const LZ77_FLAG: u32 = 1 << 31;
const CONTEXT_MASK: u32 = !LZ77_FLAG;
#[derive(Debug, Clone, Copy, Default)]
pub struct Token {
context_and_flags: u32,
pub value: u32,
}
impl Token {
#[inline]
pub const fn new(context: u32, value: u32) -> Self {
Self {
context_and_flags: context,
value,
}
}
#[inline]
pub const fn lz77_length(context: u32, value: u32) -> Self {
Self {
context_and_flags: context | LZ77_FLAG,
value,
}
}
#[inline]
pub const fn context(&self) -> u32 {
self.context_and_flags & CONTEXT_MASK
}
#[inline]
pub const fn is_lz77_length(&self) -> bool {
(self.context_and_flags & LZ77_FLAG) != 0
}
#[inline]
pub fn set_context(&mut self, context: u32) {
self.context_and_flags = (self.context_and_flags & LZ77_FLAG) | (context & CONTEXT_MASK);
}
#[inline]
pub fn set_lz77_length(&mut self, is_lz77: bool) {
if is_lz77 {
self.context_and_flags |= LZ77_FLAG;
} else {
self.context_and_flags &= CONTEXT_MASK;
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct EncodedUint {
pub token: u32,
pub nbits: u32,
pub bits: u32,
}
impl From<EncodedUint> for (u32, u32) {
fn from(e: EncodedUint) -> (u32, u32) {
(e.token, e.nbits)
}
}
pub struct UintCoder;
impl UintCoder {
#[inline]
pub fn encode(value: u32) -> EncodedUint {
if value < 16 {
EncodedUint {
token: value,
nbits: 0,
bits: 0,
}
} else {
let n = floor_log2_nonzero(value);
let m = value - (1 << n);
let token = (n << 2) + (m >> (n - 2));
let nbits = n - 2;
let bits = value & ((1u32 << nbits) - 1);
EncodedUint { token, nbits, bits }
}
}
}
pub struct Lz77UintCoder;
impl Lz77UintCoder {
#[inline]
pub fn encode(value: u32) -> EncodedUint {
if value == 0 {
EncodedUint {
token: 0,
nbits: 0,
bits: 0,
}
} else {
let n = floor_log2_nonzero(value);
let m = value - (1 << n);
let token = 1 + n;
let nbits = n;
let bits = m;
EncodedUint { token, nbits, bits }
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_uint_coder_small_values() {
for i in 0..16 {
let encoded = UintCoder::encode(i);
assert_eq!(encoded.token, i);
assert_eq!(encoded.nbits, 0);
assert_eq!(encoded.bits, 0);
}
}
#[test]
fn test_uint_coder_values() {
let e = UintCoder::encode(16);
assert_eq!(e.token, 16, "token for 16");
assert_eq!(e.nbits, 2, "nbits for 16");
assert_eq!(e.bits, 0, "bits for 16");
let e = UintCoder::encode(17);
assert_eq!(e.token, 16, "token for 17");
assert_eq!(e.nbits, 2, "nbits for 17");
assert_eq!(e.bits, 1, "bits for 17");
let e = UintCoder::encode(20);
assert_eq!(e.token, 17, "token for 20");
assert_eq!(e.nbits, 2, "nbits for 20");
assert_eq!(e.bits, 0, "bits for 20");
let e = UintCoder::encode(24);
assert_eq!(e.token, 18, "token for 24");
assert_eq!(e.nbits, 2, "nbits for 24");
assert_eq!(e.bits, 0, "bits for 24");
let e = UintCoder::encode(28);
assert_eq!(e.token, 19, "token for 28");
assert_eq!(e.nbits, 2, "nbits for 28");
assert_eq!(e.bits, 0, "bits for 28");
let e = UintCoder::encode(32);
assert_eq!(e.token, 20, "token for 32");
assert_eq!(e.nbits, 3, "nbits for 32");
assert_eq!(e.bits, 0, "bits for 32");
}
#[test]
fn test_uint_coder_large_value() {
let e = UintCoder::encode(65535);
assert_eq!(e.token, 63, "token for 65535");
assert_eq!(e.nbits, 13, "nbits for 65535");
assert_eq!(e.bits, 8191, "bits for 65535");
let n = e.token >> 2;
let top_bits = e.token & 3;
let m = (top_bits << e.nbits) + e.bits;
let reconstructed = (1u32 << n) + m;
assert_eq!(reconstructed, 65535);
}
#[test]
fn test_token_size() {
assert_eq!(core::mem::size_of::<Token>(), 8);
}
#[test]
fn test_token_packed_fields() {
let t = Token::new(42, 100);
assert_eq!(t.context(), 42);
assert_eq!(t.value, 100);
assert!(!t.is_lz77_length());
let t = Token::lz77_length(42, 100);
assert_eq!(t.context(), 42);
assert_eq!(t.value, 100);
assert!(t.is_lz77_length());
let mut t = Token::new(10, 200);
t.set_context(99);
assert_eq!(t.context(), 99);
assert!(!t.is_lz77_length());
t.set_lz77_length(true);
assert!(t.is_lz77_length());
assert_eq!(t.context(), 99);
t.set_context(77);
assert_eq!(t.context(), 77);
assert!(t.is_lz77_length());
t.set_lz77_length(false);
assert!(!t.is_lz77_length());
assert_eq!(t.context(), 77);
}
#[test]
fn test_lz77_uint_coder() {
let e = Lz77UintCoder::encode(0);
assert_eq!(e.token, 0);
assert_eq!(e.nbits, 0);
assert_eq!(e.bits, 0);
let e = Lz77UintCoder::encode(1);
assert_eq!(e.token, 1);
assert_eq!(e.nbits, 0);
assert_eq!(e.bits, 0);
let e = Lz77UintCoder::encode(2);
assert_eq!(e.token, 2);
assert_eq!(e.nbits, 1);
assert_eq!(e.bits, 0);
let e = Lz77UintCoder::encode(3);
assert_eq!(e.token, 2);
assert_eq!(e.nbits, 1);
assert_eq!(e.bits, 1);
let e = Lz77UintCoder::encode(7);
assert_eq!(e.token, 3);
assert_eq!(e.nbits, 2);
assert_eq!(e.bits, 3);
for v in 0..1000 {
let e = Lz77UintCoder::encode(v);
let reconstructed = if e.token == 0 {
0
} else {
let n = e.token - 1;
(1u32 << n) + e.bits
};
assert_eq!(reconstructed, v, "roundtrip failed for value {}", v);
}
}
}