use std::ops::{Shl, ShlAssign, Shr, ShrAssign, Rem, RemAssign, BitOrAssign};
use std::fmt::Debug;
pub mod read;
pub mod write;
pub mod huffman;
pub use read::BitRead;
pub use read::BitReaderBE;
pub use read::BitReaderLE;
pub use write::BitWrite;
pub use write::BitWriterBE;
pub use write::BitWriterLE;
pub trait Numeric: Sized + Copy + Default + Debug +
Shl<u32,Output=Self> + ShlAssign<u32> +
Shr<u32,Output=Self> + ShrAssign<u32> +
Rem<Self,Output=Self> + RemAssign<Self> +
BitOrAssign<Self> {
fn one() -> Self;
fn is_zero(self) -> bool;
fn from_u8(u: u8) -> Self;
fn to_u8(self) -> u8;
}
macro_rules! define_numeric {
($t:ty) => {
impl Numeric for $t {
#[inline(always)]
fn one() -> Self {1}
#[inline(always)]
fn is_zero(self) -> bool {self == 0}
#[inline(always)]
fn from_u8(u: u8) -> Self {u as $t}
#[inline(always)]
fn to_u8(self) -> u8 {self as u8}
}
}
}
pub trait SignedNumeric: Numeric {
fn is_negative(self) -> bool;
fn as_negative(self, bits: u32) -> Self;
fn as_unsigned(self, bits: u32) -> Self;
}
macro_rules! define_signed_numeric {
($t:ty) => {
impl SignedNumeric for $t {
#[inline(always)]
fn is_negative(self) -> bool {self < 0}
#[inline(always)]
fn as_negative(self, bits: u32) -> Self {self + (-1 << (bits - 1))}
#[inline(always)]
fn as_unsigned(self, bits: u32) -> Self {self - (-1 << (bits - 1))}
}
}
}
define_numeric!(u8);
define_numeric!(i8);
define_numeric!(u16);
define_numeric!(i16);
define_numeric!(u32);
define_numeric!(i32);
define_numeric!(u64);
define_numeric!(i64);
define_numeric!(usize);
define_signed_numeric!(i8);
define_signed_numeric!(i16);
define_signed_numeric!(i32);
define_signed_numeric!(i64);
pub trait BitQueue<N: Numeric> {
fn set(&mut self, value: N, bits: u32);
fn value(self) -> N;
fn len(&self) -> u32;
#[inline(always)]
fn is_empty(&self) -> bool {self.len() == 0}
#[inline(always)]
fn clear(&mut self) {self.set(N::default(), 0)}
fn push(&mut self, bits: u32, value: N);
fn pop(&mut self, bits: u32) -> N;
fn drop(&mut self, bits: u32);
}
pub struct BitQueueBE<N: Numeric> {value: N, bits: u32}
impl<N: Numeric> BitQueueBE<N> {
#[inline]
pub fn from_value(value: N, bits: u32) -> BitQueueBE<N> {
BitQueueBE{value: value, bits: bits}
}
#[inline]
pub fn new() -> BitQueueBE<N> {
BitQueueBE{value: N::default(), bits: 0}
}
}
impl<N: Numeric> BitQueue<N> for BitQueueBE<N> {
#[inline]
fn set(&mut self, value: N, bits: u32) {
self.value = value; self.bits = bits;
}
#[inline(always)]
fn value(self) -> N {self.value}
#[inline(always)]
fn len(&self) -> u32 {self.bits}
fn push(&mut self, bits: u32, value: N) {
if !self.value.is_zero() {
self.value <<= bits;
}
self.value |= value;
self.bits += bits;
}
#[inline]
fn pop(&mut self, bits: u32) -> N {
if bits < self.bits {
let offset = self.bits - bits;
let to_return = self.value >> offset;
self.value %= N::one() << offset;
self.bits -= bits;
to_return
} else {
let to_return = self.value;
self.value = N::default();
self.bits = 0;
to_return
}
}
#[inline]
fn drop(&mut self, bits: u32) {
if bits < self.bits {
self.value %= N::one() << (self.bits - bits);
self.bits -= bits;
} else {
self.value = N::default();
self.bits = 0;
}
}
}
impl BitQueueBE<u8> {
#[inline(always)]
fn all_0(&self) -> bool {self.value == 0}
#[inline(always)]
fn all_1(&self) -> bool {self.value == ((1u16 << self.bits) - 1) as u8}
#[inline]
fn pop_0(&mut self) -> u32 {
let zeroes = self.value.leading_zeros() - (8 - self.bits);
self.drop(zeroes + 1);
zeroes
}
#[inline]
fn pop_1(&mut self) -> u32 {
let zeroes =
(self.value ^ ((1 << self.bits) - 1) as u8).leading_zeros() -
(8 - self.bits);
self.drop(zeroes + 1);
zeroes
}
}
pub struct BitQueueLE<N: Numeric> {value: N, bits: u32}
impl<N: Numeric> BitQueueLE<N> {
#[inline]
pub fn from_value(value: N, bits: u32) -> BitQueueLE<N> {
BitQueueLE{value: value, bits: bits}
}
#[inline]
pub fn new() -> BitQueueLE<N> {
BitQueueLE{value: N::default(), bits: 0}
}
}
impl<N: Numeric> BitQueue<N> for BitQueueLE<N> {
#[inline]
fn set(&mut self, value: N, bits: u32) {
self.value = value; self.bits = bits;
}
#[inline(always)]
fn value(self) -> N {self.value}
#[inline(always)]
fn len(&self) -> u32 {self.bits}
#[inline]
fn push(&mut self, bits: u32, mut value: N) {
value <<= self.bits;
self.value |= value;
self.bits += bits;
}
#[inline]
fn pop(&mut self, bits: u32) -> N {
if bits < self.bits {
let to_return = self.value % (N::one() << bits);
self.value >>= bits;
self.bits -= bits;
to_return
} else {
let to_return = self.value;
self.value = N::default();
self.bits = 0;
to_return
}
}
#[inline]
fn drop(&mut self, bits: u32) {
if bits < self.bits {
self.value >>= bits;
self.bits -= bits;
} else {
self.value = N::default();
self.bits = 0;
}
}
}
impl BitQueueLE<u8> {
#[inline(always)]
fn all_0(&self) -> bool {self.value == 0}
#[inline(always)]
fn all_1(&self) -> bool {self.value == ((1u16 << self.bits) - 1) as u8}
#[inline]
fn pop_0(&mut self) -> u32 {
let zeroes = self.value.trailing_zeros();
self.drop(zeroes + 1);
zeroes
}
#[inline]
fn pop_1(&mut self) -> u32 {
let zeroes = (self.value ^ 0xFF).trailing_zeros();
self.drop(zeroes + 1);
zeroes
}
}