#[cfg(any(feature = "bitunpack", test))]
use alloc::vec;
use alloc::vec::Vec;
#[cfg(any(feature = "bitpack", test))]
pub(crate) const fn encode_bound(nb_elts: usize, nb_bits: u32) -> usize {
(nb_elts * nb_bits as usize).div_ceil(8)
}
#[cfg(any(feature = "bitpack", test))]
pub(crate) fn encode(src: &[u8], width: usize, nb_bits: u32) -> Vec<u8> {
let nb_elts = src.len() / width;
if nb_elts == 0 || nb_bits == 0 {
return Vec::new();
}
if nb_bits as usize == width * 8 {
return src[..nb_elts * width].to_vec();
}
let mut out = Vec::with_capacity(encode_bound(nb_elts, nb_bits));
let mut state = 0u64;
let mut bits = 0u32;
let mut put = |value: u64, count: u32| {
state |= value << bits;
bits += count;
while bits >= 8 {
out.push(state as u8);
state >>= 8;
bits -= 8;
}
};
for element in src.chunks_exact(width) {
let mut buffer = [0u8; 8];
buffer[..width].copy_from_slice(element);
let value = u64::from_le_bytes(buffer);
if nb_bits > 56 {
put(value & 0xFFFF_FFFF, 32);
put(value >> 32, nb_bits - 32);
} else {
put(value, nb_bits);
}
}
if bits > 0 {
out.push(state as u8);
}
out
}
#[cfg(any(feature = "bitunpack", test))]
pub(crate) fn decode(src: &[u8], nb_elts: usize, width: usize, nb_bits: u32) -> (Vec<u8>, usize) {
let used = (nb_elts * nb_bits as usize).div_ceil(8);
let mut out = vec![0u8; nb_elts * width];
if nb_elts == 0 {
return (out, 0);
}
let mask = if nb_bits == 64 {
u64::MAX
} else {
(1u64 << nb_bits) - 1
};
let mut position = 0usize;
for element in out.chunks_exact_mut(width) {
let byte = position / 8;
let shift = (position % 8) as u32;
let mut window = [0u8; 16];
let end = (byte + 9).min(used).min(src.len());
window[..end - byte].copy_from_slice(&src[byte..end]);
let value = (u128::from_le_bytes(window) >> shift) as u64 & mask;
element.copy_from_slice(&value.to_le_bytes()[..width]);
position += nb_bits as usize;
}
(out, used)
}
pub(crate) mod writer;
#[cfg(test)]
mod tests;