#![allow(dead_code)]
pub(crate) mod common;
pub(crate) mod decoder32;
pub(crate) mod decoder64;
pub(crate) mod encoder;
pub(crate) mod simd;
pub(crate) mod tables;
pub(crate) use encoder::EncodeResult;
#[derive(Debug, Clone, Default)]
pub struct CodedCbHeader {
pub pass_length: [u32; 2],
pub num_passes: u32,
pub k_max: u32,
pub missing_msbs: u32,
}
pub(crate) fn init_block_encoder_tables() -> bool {
let _ = common::encoder_tables();
true
}
pub(crate) fn init_block_decoder_tables() -> bool {
let _ = common::decoder_tables();
true
}
pub(crate) type EncodeCodeblock32Fn = fn(
buf: &[u32],
missing_msbs: u32,
num_passes: u32,
width: u32,
height: u32,
stride: u32,
) -> crate::error::Result<EncodeResult>;
pub(crate) type EncodeCodeblock64Fn = fn(
buf: &[u64],
missing_msbs: u32,
num_passes: u32,
width: u32,
height: u32,
stride: u32,
) -> crate::error::Result<EncodeResult>;
pub(crate) type DecodeCodeblock32Fn = fn(
coded_data: &mut [u8],
decoded_data: &mut [u32],
missing_msbs: u32,
num_passes: u32,
lengths1: u32,
lengths2: u32,
width: u32,
height: u32,
stride: u32,
stripe_causal: bool,
) -> crate::error::Result<bool>;
pub(crate) type DecodeCodeblock64Fn = fn(
coded_data: &mut [u8],
decoded_data: &mut [u64],
missing_msbs: u32,
num_passes: u32,
lengths1: u32,
lengths2: u32,
width: u32,
height: u32,
stride: u32,
stripe_causal: bool,
) -> crate::error::Result<bool>;
#[inline]
pub(crate) fn get_encode_codeblock32() -> EncodeCodeblock32Fn {
encoder::encode_codeblock32
}
#[inline]
pub(crate) fn get_encode_codeblock64() -> EncodeCodeblock64Fn {
encoder::encode_codeblock64
}
#[inline]
pub(crate) fn get_decode_codeblock32() -> DecodeCodeblock32Fn {
decoder32::decode_codeblock32
}
#[inline]
pub(crate) fn get_decode_codeblock64() -> DecodeCodeblock64Fn {
decoder64::decode_codeblock64
}
#[cfg(test)]
mod tests {
use super::*;
fn make_mag32(mu_p: u32, p: u32) -> u32 {
if mu_p == 0 {
return 0;
}
(2 * mu_p + 1) << (p - 1)
}
fn make_mag64(mu_p: u64, p: u32) -> u64 {
if mu_p == 0 {
return 0;
}
(2 * mu_p + 1) << (p - 1)
}
fn roundtrip32(samples: &[u32], width: u32, height: u32, missing_msbs: u32) {
let stride = width;
assert_eq!(samples.len(), (stride * height) as usize);
let enc_result =
encoder::encode_codeblock32(samples, missing_msbs, 1, width, height, stride)
.expect("encode failed");
let dec_h = height.max(2).next_multiple_of(2);
let mut decoded = vec![0u32; (stride * dec_h) as usize];
if enc_result.length >= 2 {
let mut coded = enc_result.data.clone();
coded.resize(coded.len() + 64, 0);
decoder32::decode_codeblock32(
&mut coded,
&mut decoded,
missing_msbs,
1,
enc_result.length,
0,
width,
height,
stride,
false,
)
.expect("decode failed");
}
for y in 0..height as usize {
for x in 0..width as usize {
let idx = y * stride as usize + x;
assert_eq!(
decoded[idx], samples[idx],
"mismatch at ({x}, {y}): got 0x{:08X}, expected 0x{:08X}",
decoded[idx], samples[idx],
);
}
}
}
fn roundtrip64(samples: &[u64], width: u32, height: u32, missing_msbs: u32) {
let stride = width;
assert_eq!(samples.len(), (stride * height) as usize);
let enc_result =
encoder::encode_codeblock64(samples, missing_msbs, 1, width, height, stride)
.expect("encode failed");
let dec_h = height.max(2).next_multiple_of(2);
let mut decoded = vec![0u64; (stride * dec_h) as usize];
if enc_result.length >= 2 {
let mut coded = enc_result.data.clone();
coded.resize(coded.len() + 64, 0);
decoder64::decode_codeblock64(
&mut coded,
&mut decoded,
missing_msbs,
1,
enc_result.length,
0,
width,
height,
stride,
false,
)
.expect("decode failed");
}
for y in 0..height as usize {
for x in 0..width as usize {
let idx = y * stride as usize + x;
assert_eq!(
decoded[idx], samples[idx],
"mismatch at ({x}, {y}): got 0x{:016X}, expected 0x{:016X}",
decoded[idx], samples[idx],
);
}
}
}
#[test]
fn roundtrip_zeros_4x4() {
roundtrip32(&[0u32; 16], 4, 4, 0);
}
#[test]
fn roundtrip_zeros_8x8() {
roundtrip32(&vec![0u32; 64], 8, 8, 0);
}
#[test]
fn roundtrip_16x16_zeros() {
roundtrip32(&vec![0u32; 256], 16, 16, 0);
}
#[test]
fn roundtrip_32x32_zeros() {
roundtrip32(&vec![0u32; 1024], 32, 32, 0);
}
#[test]
fn roundtrip_64x64_zeros() {
let samples = vec![0u32; 4096];
let enc_result =
encoder::encode_codeblock32(&samples, 0, 1, 64, 64, 64).expect("encode failed");
assert!(enc_result.length > 0);
}
#[test]
fn roundtrip_64x64_nonzero() {
let p = 1u32;
let msbs = 29u32;
let n = 64 * 64;
let samples: Vec<u32> = (0..n).map(|i| make_mag32((i as u32 % 10) + 1, p)).collect();
roundtrip32(&samples, 64, 64, msbs);
}
#[test]
fn roundtrip_single_sample() {
let mag = make_mag32(1, 1); roundtrip32(&[mag], 1, 1, 29);
}
#[test]
fn roundtrip_uniform_4x4() {
let mag = make_mag32(3, 1); let mag_arr = [mag; 16];
roundtrip32(&mag_arr, 4, 4, 29);
}
#[test]
fn roundtrip_simple_4x4() {
let p = 1u32;
let msbs = 29u32;
let samples: Vec<u32> = (1..=16).map(|k| make_mag32(k, p)).collect();
roundtrip32(&samples, 4, 4, msbs);
}
#[test]
fn roundtrip_8x8_pattern() {
let p = 2u32;
let msbs = 28u32;
let a = make_mag32(1, p); let b = make_mag32(3, p); let mut samples = vec![0u32; 64];
for y in 0..8u32 {
for x in 0..8u32 {
samples[(y * 8 + x) as usize] = if (x + y) % 2 == 0 { a } else { b };
}
}
roundtrip32(&samples, 8, 8, msbs);
}
#[test]
fn roundtrip_signed_4x4() {
let p = 1u32;
let msbs = 29u32;
let samples: Vec<u32> = (1..=16)
.map(|k| {
let mag = make_mag32(k, p);
if k % 3 == 0 {
mag | 0x80000000
} else {
mag
}
})
.collect();
roundtrip32(&samples, 4, 4, msbs);
}
#[test]
fn roundtrip_sparse_8x8() {
let p = 1u32;
let msbs = 29u32;
let mut samples = vec![0u32; 64];
samples[0] = make_mag32(1, p);
samples[7] = make_mag32(2, p);
samples[9] = make_mag32(4, p) | 0x80000000; samples[35] = make_mag32(3, p);
samples[63] = make_mag32(5, p);
roundtrip32(&samples, 8, 8, msbs);
}
#[test]
fn roundtrip_centered_gradient_33x33_kmax8() {
use super::decoder32;
use super::encoder;
let width = 33u32;
let height = 33u32;
let kmax = 8u32;
let shift = 31 - kmax;
let missing_msbs = kmax - 1;
let mut samples = Vec::with_capacity((width * height) as usize);
let mut expected = Vec::with_capacity((width * height) as usize);
for y in 0..height {
for x in 0..width {
let pixel = ((3 * x + 7 * y) & 0xFF) as i32;
let centered = pixel - 128;
expected.push(centered);
let sign = if centered < 0 { 0x8000_0000 } else { 0 };
let mag = centered.unsigned_abs() << shift;
samples.push(sign | mag);
}
}
let enc_result =
encoder::encode_codeblock32(&samples, missing_msbs, 1, width, height, width)
.expect("encode failed");
let mut coded = enc_result.data.clone();
coded.resize(coded.len() + 64, 0);
let dec_h = height.max(2).next_multiple_of(2);
let mut decoded = vec![0u32; (width * dec_h) as usize];
decoder32::decode_codeblock32(
&mut coded,
&mut decoded,
missing_msbs,
1,
enc_result.length,
0,
width,
height,
width,
false,
)
.expect("decode failed");
for y in 0..height as usize {
for x in 0..width as usize {
let v = decoded[y * width as usize + x];
let mag = ((v & 0x7FFF_FFFF) >> shift) as i32;
let got = if (v >> 31) != 0 { -mag } else { mag };
assert_eq!(
got,
expected[y * width as usize + x],
"mismatch at ({x}, {y})"
);
}
}
}
#[test]
fn roundtrip_4x4_64bit() {
let p = 1u32;
let msbs = 61u32;
let samples: Vec<u64> = (1..=16).map(|k| make_mag64(k as u64, p)).collect();
roundtrip64(&samples, 4, 4, msbs);
}
#[test]
fn roundtrip_zeros_64bit_8x8() {
roundtrip64(&vec![0u64; 64], 8, 8, 0);
}
#[test]
fn roundtrip_signed_64bit_4x4() {
let p = 1u32;
let msbs = 61u32;
let samples: Vec<u64> = (1..=16)
.map(|k| {
let mag = make_mag64(k as u64, p);
if k % 2 == 0 {
mag | (1u64 << 63)
} else {
mag
}
})
.collect();
roundtrip64(&samples, 4, 4, msbs);
}
#[test]
fn roundtrip_various_block_sizes() {
let p = 1u32;
let msbs = 29u32;
for &(w, h) in &[(4u32, 4), (4, 8), (8, 4), (8, 8), (16, 16)] {
let n = (w * h) as usize;
let samples: Vec<u32> = (0..n)
.map(|i| {
let mu = (i as u32 % 15) + 1; make_mag32(mu, p)
})
.collect();
roundtrip32(&samples, w, h, msbs);
}
}
#[test]
fn roundtrip_16x16_nonzero() {
let p = 2u32;
let msbs = 28u32;
let n = 16 * 16;
let samples: Vec<u32> = (0..n)
.map(|i| {
let mu = (i as u32 % 7) + 1;
let mag = make_mag32(mu, p);
if i % 5 == 0 {
mag | 0x80000000
} else {
mag
}
})
.collect();
roundtrip32(&samples, 16, 16, msbs);
}
}