use crate::traits::*;
#[must_use]
#[inline(always)]
pub const fn len_rice(n: u64, log2_b: usize) -> usize {
debug_assert!(log2_b < 64);
(n >> log2_b) as usize + 1 + log2_b
}
#[must_use]
#[cfg(feature = "std")]
pub fn log2_b(p: f64) -> usize {
((-((5f64.sqrt() + 1.0) / 2.0).ln() / (-p).ln_1p()).log2()).ceil() as usize
}
pub trait RiceRead<E: Endianness>: BitRead<E> {
#[inline(always)]
fn read_rice(&mut self, log2_b: usize) -> Result<u64, Self::Error> {
debug_assert!(log2_b < 64);
Ok((self.read_unary()? << log2_b) + self.read_bits(log2_b)?)
}
}
pub trait RiceWrite<E: Endianness>: BitWrite<E> {
#[inline(always)]
fn write_rice(&mut self, n: u64, log2_b: usize) -> Result<usize, Self::Error> {
debug_assert!(log2_b < 64);
let mut written_bits = self.write_unary(n >> log2_b)?;
#[cfg(feature = "checks")]
{
let n = n & (1_u128 << log2_b).wrapping_sub(1) as u64;
written_bits += self.write_bits(n, log2_b)?;
}
#[cfg(not(feature = "checks"))]
{
written_bits += self.write_bits(n, log2_b)?;
}
Ok(written_bits)
}
}
impl<E: Endianness, B: BitRead<E>> RiceRead<E> for B {}
impl<E: Endianness, B: BitWrite<E>> RiceWrite<E> for B {}
#[cfg(test)]
#[cfg(feature = "std")]
mod tests {
use super::*;
#[test]
fn test_log2_b() {
use crate::prelude::golomb::b;
let mut p = 1.0;
for _ in 0..100 {
p *= 0.9;
let golomb = b(p);
if golomb & -(golomb as i64) as u64 == golomb {
assert_eq!(golomb, 1 << log2_b(p));
}
}
}
}