use crate::codes::omega_tables;
use crate::traits::*;
use num_primitive::PrimitiveNumber;
#[must_use]
#[inline(always)]
pub fn len_omega_param<const USE_TABLE: bool>(n: u64) -> usize {
debug_assert!(n < u64::MAX);
if USE_TABLE {
if n < omega_tables::LEN.len() as u64 {
return omega_tables::LEN[n as usize] as usize;
}
}
recursive_len(n + 1)
}
#[must_use]
#[inline(always)]
pub fn len_omega(n: u64) -> usize {
len_omega_param::<true>(n)
}
const fn recursive_len(n: u64) -> usize {
if n <= 1 {
return 1;
}
let λ = n.ilog2() as u64;
recursive_len(λ) + λ as usize + 1
}
pub trait OmegaRead<E: Endianness>: BitRead<E> {
fn read_omega(&mut self) -> Result<u64, Self::Error>;
}
pub trait OmegaReadParam<E: Endianness>: BitRead<E> {
fn read_omega_param<const USE_TABLE: bool>(&mut self) -> Result<u64, Self::Error>;
}
#[inline(always)]
fn default_read_omega<E: Endianness, B: BitRead<E>>(backend: &mut B) -> Result<u64, B::Error> {
read_omega_from_state::<E, B>(backend, 1)
}
#[inline(always)]
fn read_omega_from_state<E: Endianness, B: BitRead<E>>(
backend: &mut B,
mut n: u64,
) -> Result<u64, B::Error> {
loop {
let bit: u64 = backend.peek_bits(1)?.as_to();
if bit == 0 {
backend.skip_bits_after_peek(1);
return Ok(n - 1);
}
let λ = n;
n = backend.read_bits(λ as usize + 1)?;
if E::IS_LITTLE {
n = (n >> 1) | (1 << λ);
}
}
}
impl<B: BitRead<BE>> OmegaReadParam<BE> for B {
#[inline(always)]
fn read_omega_param<const USE_TABLE: bool>(&mut self) -> Result<u64, Self::Error> {
const {
if USE_TABLE {
omega_tables::check_read_table(B::PEEK_BITS)
}
}
if USE_TABLE {
let (len_with_flag, value) = omega_tables::read_table_be(self);
if len_with_flag > 0 {
return Ok(value);
} else if len_with_flag < 0 {
return read_omega_from_state::<BE, _>(self, value);
}
}
default_read_omega(self)
}
}
impl<B: BitRead<LE>> OmegaReadParam<LE> for B {
#[inline(always)]
fn read_omega_param<const USE_TABLE: bool>(&mut self) -> Result<u64, Self::Error> {
const {
if USE_TABLE {
omega_tables::check_read_table(B::PEEK_BITS)
}
}
if USE_TABLE {
let (len_with_flag, value) = omega_tables::read_table_le(self);
if len_with_flag > 0 {
return Ok(value);
} else if len_with_flag < 0 {
return read_omega_from_state::<LE, _>(self, value);
}
}
default_read_omega(self)
}
}
pub trait OmegaWrite<E: Endianness>: BitWrite<E> {
fn write_omega(&mut self, n: u64) -> Result<usize, Self::Error>;
}
pub trait OmegaWriteParam<E: Endianness>: BitWrite<E> {
fn write_omega_param<const USE_TABLE: bool>(&mut self, n: u64) -> Result<usize, Self::Error>;
}
impl<B: BitWrite<BE>> OmegaWriteParam<BE> for B {
#[inline(always)]
fn write_omega_param<const USE_TABLE: bool>(&mut self, n: u64) -> Result<usize, Self::Error> {
debug_assert!(n < u64::MAX);
if USE_TABLE {
if let Some(len) = omega_tables::write_table_be(self, n)? {
return Ok(len);
}
}
Ok(recursive_omega_write::<BE, _>(n + 1, self)? + self.write_bits(0, 1)?)
}
}
impl<B: BitWrite<LE>> OmegaWriteParam<LE> for B {
#[inline(always)]
fn write_omega_param<const USE_TABLE: bool>(&mut self, n: u64) -> Result<usize, Self::Error> {
debug_assert!(n < u64::MAX);
if USE_TABLE {
if let Some(len) = omega_tables::write_table_le(self, n)? {
return Ok(len);
}
}
Ok(recursive_omega_write::<LE, _>(n + 1, self)? + self.write_bits(0, 1)?)
}
}
#[inline(always)]
fn recursive_omega_write<E: Endianness, B: BitWrite<E>>(
mut n: u64,
writer: &mut B,
) -> Result<usize, B::Error> {
if n <= 1 {
return Ok(0);
}
let λ = n.ilog2();
if E::IS_LITTLE {
#[cfg(feature = "checks")]
{
n &= u64::MAX >> (u64::BITS - λ);
}
n = (n << 1) | 1;
}
Ok(recursive_omega_write::<E, _>(λ as u64, writer)? + writer.write_bits(n, λ as usize + 1)?)
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
#[allow(clippy::unusual_byte_groupings)]
fn test_omega() {
for (value, expected_be, expected_le) in [
(0, 0, 0),
(1, 0b10_0 << (64 - 3), 0b0_01),
(2, 0b11_0 << (64 - 3), 0b0_11),
(3, 0b10_100_0 << (64 - 6), 0b0_001_01),
(4, 0b10_101_0 << (64 - 6), 0b0_011_01),
(5, 0b10_110_0 << (64 - 6), 0b0_101_01),
(6, 0b10_111_0 << (64 - 6), 0b0_111_01),
(7, 0b11_1000_0 << (64 - 7), 0b0_0001_11),
(15, 0b10_100_10000_0 << (64 - 11), 0b0_00001_001_01),
(99, 0b10_110_1100100_0 << (64 - 13), 0b0_1001001_101_01),
(
999,
0b11_1001_1111101000_0 << (64 - 17),
0b0_1111010001_0011_11,
),
(
999_999,
0b10_100_10011_11110100001001000000_0 << (64 - 31),
0b0_11101000010010000001_00111_001_01,
),
] {
let mut data = [0_u64];
let mut writer = <BufBitWriter<BE, _>>::new(MemWordWriterSlice::new(&mut data));
writer.write_omega(value).unwrap();
drop(writer);
assert_eq!(
data[0].to_be(),
expected_be,
"\nfor value: {}\ngot: {:064b}\nexp: {:064b}\n",
value,
data[0].to_be(),
expected_be,
);
let mut data = [0_u64];
let mut writer = <BufBitWriter<LE, _>>::new(MemWordWriterSlice::new(&mut data));
writer.write_omega(value).unwrap();
drop(writer);
assert_eq!(
data[0].to_le(),
expected_le,
"\nfor value: {}\ngot: {:064b}\nexp: {:064b}\n",
value,
data[0].to_le(),
expected_le,
);
}
}
}