pub use compactly_derive::EncodeV2 as Encode;
mod ans;
mod arc;
mod arith;
mod array;
mod atmost;
mod bit_context;
mod bools;
mod byte;
mod bytes;
mod floats;
#[cfg(feature = "generate_bit_context")]
pub mod generate_bit_context;
mod ints;
mod low_cardinality;
mod maps;
mod markers;
mod millibits;
mod model;
mod net;
mod nonzero;
mod option;
mod other_crate_types;
mod sets;
mod string;
mod tuples;
mod usizes;
mod vecs;
use crate::{LowCardinality, Small};
pub use ans::Ans;
pub use arith::Range;
#[doc(hidden)] pub use atmost::walks::{Walk, WALKS};
pub use atmost::AtMost;
pub use millibits::Millibits;
#[test]
fn default_context_is_fifty_percent() {
assert_eq!(
bit_context::BitContext::default().probability(),
model::Probability::new(127, 127)
);
}
pub trait EntropyCoder: Default {
fn encode_bits<const N: usize>(
&mut self,
contexts: &mut [bit_context::BitContext; N],
bits: [bool; N],
);
#[inline(always)]
fn encode_bit(&mut self, context: &mut bit_context::BitContext, bit: bool) {
self.encode_bits(std::array::from_mut(context), [bit]);
}
fn encode<T: Encode>(value: &T) -> Self {
let mut writer = Self::default();
value.encode(&mut writer, &mut T::Context::default());
writer
}
#[inline]
fn encode_atmost<const MAX: usize>(
&mut self,
ctx: &mut atmost::AtMostContext<MAX>,
value: AtMost<MAX>,
) {
atmost::walks::encode_bitwise(self, &mut ctx.bits, value.into())
}
fn encode_incompressible_bytes(&mut self, bytes: &[u8]) {
for mut b in bytes.iter().copied() {
for _ in 0..8 {
self.encode_bit(&mut bit_context::BitContext::default(), (b & 1) == 1);
b >>= 1;
}
}
}
}
pub trait EntropyDecoder {
fn decode_bits<const N: usize>(
&mut self,
contexts: &mut [bit_context::BitContext; N],
) -> [bool; N];
#[inline(always)]
fn decode_bit(&mut self, context: &mut bit_context::BitContext) -> bool {
let [bit] = self.decode_bits(std::array::from_mut(context));
bit
}
#[inline]
fn decode_atmost<const MAX: usize>(
&mut self,
ctx: &mut atmost::AtMostContext<MAX>,
) -> AtMost<MAX>
where
Self: Sized,
{
AtMost::new(atmost::walks::decode_bitwise(self, &mut ctx.bits))
}
fn decode_incompressible_bytes(&mut self, bytes: &mut [u8]) -> Result<(), std::io::Error>;
}
pub trait Encode: Sized {
type Context: Default + Clone;
fn encode<E: EntropyCoder>(&self, encoder: &mut E, ctx: &mut Self::Context);
fn decode<D: EntropyDecoder>(
entropy_decoder: &mut D,
ctx: &mut Self::Context,
) -> Result<Self, std::io::Error>;
fn millibits(&self) -> Millibits {
let mut m = Millibits::default();
self.encode(&mut m, &mut Self::Context::default());
m
}
}
pub fn encode<T: Encode>(value: &T) -> Vec<u8> {
let mut writer = arith::Range::default();
value.encode(&mut writer, &mut T::Context::default());
writer.into_vec()
}
pub fn decode<T: Encode>(bytes: &[u8]) -> Option<T> {
let mut reader = arith::Decoder::new(bytes);
T::decode(&mut reader, &mut T::Context::default()).ok()
}
pub trait EncodingStrategy<T> {
type Context: Default + Clone;
fn encode<E: EntropyCoder>(value: &T, writer: &mut E, ctx: &mut Self::Context);
fn decode<D: EntropyDecoder>(
reader: &mut D,
ctx: &mut Self::Context,
) -> Result<T, std::io::Error>;
}
pub fn encode_with<T: Encode, S: EncodingStrategy<T>>(_: S, value: &T) -> Vec<u8> {
let mut writer = Range::default();
S::encode(value, &mut writer, &mut S::Context::default());
writer.into_vec()
}
pub fn decode_with<T: Encode, S: EncodingStrategy<T>>(_: S, bytes: &[u8]) -> Option<T> {
let mut reader = arith::Decoder::new(bytes);
S::decode(&mut reader, &mut S::Context::default()).ok()
}
impl<T, S: EncodingStrategy<T>> Encode for crate::Encoded<T, S> {
type Context = S::Context;
#[inline]
fn encode<E: EntropyCoder>(&self, writer: &mut E, ctx: &mut Self::Context) {
S::encode(&self.value, writer, ctx)
}
#[inline]
fn decode<D: EntropyDecoder>(
reader: &mut D,
ctx: &mut Self::Context,
) -> Result<Self, std::io::Error> {
Ok(Self {
value: S::decode(reader, ctx)?,
_phantom: std::marker::PhantomData,
})
}
}
impl<T: Encode> EncodingStrategy<T> for crate::Normal {
type Context = <T as Encode>::Context;
#[inline]
fn encode<E: EntropyCoder>(value: &T, writer: &mut E, ctx: &mut Self::Context) {
value.encode(writer, ctx)
}
fn decode<D: EntropyDecoder>(
reader: &mut D,
ctx: &mut Self::Context,
) -> Result<T, std::io::Error> {
T::decode(reader, ctx)
}
}
#[cfg(test)]
macro_rules! assert_size {
($v:expr, $expected:expr) => {
let v = $v;
let bytes = super::encode(&v);
let decoded = super::decode(&bytes);
assert_eq!(decoded, Some(v), "decoded value is incorrect");
$expected.assert_eq(&bytes.len().to_string());
};
}
#[cfg(test)]
pub(crate) use assert_size;
#[cfg(test)]
macro_rules! encoded_bits {
($v:expr) => {
crate::v2::encoded_bits!(crate::v2::Range, $v)
};
($coder:ty, $v:expr) => {{
let one = $v;
let bytes = <$coder>::encode(&one);
println!("Bytes are {bytes:?} for {one:?}");
let decoded = <$coder>::decode(&bytes);
assert_eq!(decoded, Some(one), "decoded value is incorrect");
let v = (
($v, $v, $v, $v, $v, $v, $v, $v),
($v, $v, $v, $v, $v, $v, $v, $v),
($v, $v, $v, $v, $v, $v, $v, $v),
($v, $v, $v, $v, $v, $v, $v, $v),
($v, $v, $v, $v, $v, $v, $v, $v),
($v, $v, $v, $v, $v, $v, $v, $v),
($v, $v, $v, $v, $v, $v, $v, $v),
($v, $v, $v, $v, $v, $v, $v, $v),
);
let bytes = <$coder>::encode(&v);
let decoded = <$coder>::decode(&bytes);
assert_eq!(decoded, Some(v), "decoded tuple value is incorrect");
((bytes.len() + 4) / 8).to_string()
}};
}
#[cfg(test)]
pub(crate) use encoded_bits;
#[cfg(test)]
macro_rules! estimated_bits {
($v:expr) => {{
let v = $v;
let bits = crate::v2::Encode::millibits(&v).as_bits();
let bytes = super::encode(&v);
let decoded = super::decode(&bytes);
assert_eq!(decoded, Some(v), "decoded value is incorrect");
bits
}};
}
#[cfg(test)]
pub(crate) use estimated_bits;
#[cfg(test)]
macro_rules! assert_bits_all {
($values:expr, $expected:expr) => {
crate::v2::assert_bits_all!($values, |v| v, $expected);
};
($values:expr, $f:expr, $expected:expr) => {
let f = $f;
let mut iter = ($values).into_iter();
let first = iter
.next()
.expect("assert_bits_all! needs at least one value");
let bits = crate::v2::estimated_bits!(f(first));
for v in iter {
let other = crate::v2::estimated_bits!(f(v));
assert_eq!(other, bits, "encoded size differs for {v:?}");
}
$expected.assert_eq(&bits);
};
}
#[cfg(test)]
pub(crate) use assert_bits_all;
#[cfg(test)]
macro_rules! assert_millibits {
($v:expr, $expected:expr) => {{
let v = $v;
let entropy = crate::v2::Encode::millibits(&v);
let encoded = super::encode(&v);
let decoded = super::decode(&encoded);
assert_eq!(decoded, Some(v), "decoded value is incorrect");
let bits: usize = entropy.as_bits().parse().unwrap();
let s = if entropy == super::Millibits::bits(bits) {
format!("{bits} bits")
} else {
format!("{entropy:?}")
};
$expected.assert_eq(&s);
}};
}
#[cfg(test)]
pub(crate) use assert_millibits;
#[cfg(test)]
macro_rules! check_mixed_bits_and_symbols {
($coder:ty, $make_decoder:expr) => {{
use crate::v2::bit_context::BitContext;
use crate::v2::{EntropyCoder, EntropyDecoder};
for trial in 0..2000 {
let n_ops = rand::random::<usize>() % 200;
#[derive(Debug, Clone, Copy)]
enum Planned {
Bit(bool),
Byte(u8),
}
let mut plan = Vec::new();
for _ in 0..n_ops {
if rand::random::<bool>() {
plan.push(Planned::Bit(rand::random()));
} else {
plan.push(Planned::Byte(rand::random()));
}
}
let mut bit_bank = [BitContext::default(); 8];
for ctx in bit_bank.iter_mut() {
*ctx = rand::random();
}
let mut enc_bits = bit_bank;
let mut enc_bytes = crate::v2::atmost::AtMostContext::<255>::default();
let mut writer = <$coder>::default();
let mut which = 0usize;
for op in &plan {
match *op {
Planned::Bit(b) => {
writer.encode_bit(&mut enc_bits[which % 8], b);
which += 1;
}
Planned::Byte(b) => {
writer.encode_atmost(&mut enc_bytes, crate::v2::AtMost::new(b as usize))
}
}
}
let encoded: Vec<u8> = writer.into_vec();
#[allow(clippy::redundant_closure_call)]
let mut decoder = ($make_decoder)(encoded.as_slice());
let mut dec_bits = bit_bank;
let mut dec_bytes = crate::v2::atmost::AtMostContext::<255>::default();
let mut which = 0usize;
for (i, op) in plan.iter().enumerate() {
match *op {
Planned::Bit(b) => {
let bit = decoder.decode_bit(&mut dec_bits[which % 8]);
which += 1;
assert_eq!(bit, b, "bit {i} of trial {trial}");
}
Planned::Byte(b) => {
let v = decoder.decode_atmost(&mut dec_bytes);
assert_eq!(usize::from(v), b as usize, "byte {i} of trial {trial}");
}
}
}
assert_eq!(enc_bits, dec_bits, "bit contexts must adapt identically");
assert_eq!(enc_bytes, dec_bytes, "byte contexts must adapt identically");
}
}};
}
#[cfg(test)]
pub(crate) use check_mixed_bits_and_symbols;