#![cfg_attr(doctest, doc = include_str!("../README.md"))]
#![allow(unused_unsafe)]
#![warn(missing_docs)]
use std::marker::Sized;
#[cfg(test)]
#[macro_use]
pub(crate) mod tests;
#[macro_use]
mod macros;
#[macro_use]
mod macros_simple;
trait Available {
fn available() -> bool;
}
trait UnsafeBitPacker {
const BLOCK_LEN: usize;
unsafe fn compress(decompressed: &[u32], compressed: &mut [u8], num_bits: u8) -> usize;
unsafe fn compress_sorted(
initial: u32,
decompressed: &[u32],
compressed: &mut [u8],
num_bits: u8,
) -> usize;
unsafe fn compress_strictly_sorted(
initial: Option<u32>,
decompressed: &[u32],
compressed: &mut [u8],
num_bits: u8,
) -> usize;
unsafe fn decompress(compressed: &[u8], decompressed: &mut [u32], num_bits: u8) -> usize;
unsafe fn decompress_sorted(
initial: u32,
compressed: &[u8],
decompressed: &mut [u32],
num_bits: u8,
) -> usize;
unsafe fn decompress_strictly_sorted(
initial: Option<u32>,
compressed: &[u8],
decompressed: &mut [u32],
num_bits: u8,
) -> usize;
unsafe fn num_bits(decompressed: &[u32]) -> u8;
unsafe fn num_bits_sorted(initial: u32, decompressed: &[u32]) -> u8;
unsafe fn num_bits_strictly_sorted(initial: Option<u32>, decompressed: &[u32]) -> u8;
}
pub trait BitPacker: Sized + Clone + Copy {
const BLOCK_LEN: usize;
fn new() -> Self;
fn compress(&self, decompressed: &[u32], compressed: &mut [u8], num_bits: u8) -> usize;
fn compress_sorted(
&self,
initial: u32,
decompressed: &[u32],
compressed: &mut [u8],
num_bits: u8,
) -> usize;
fn compress_strictly_sorted(
&self,
initial: Option<u32>,
decompressed: &[u32],
compressed: &mut [u8],
num_bits: u8,
) -> usize;
fn decompress(&self, compressed: &[u8], decompressed: &mut [u32], num_bits: u8) -> usize;
fn decompress_sorted(
&self,
initial: u32,
compressed: &[u8],
decompressed: &mut [u32],
num_bits: u8,
) -> usize;
fn decompress_strictly_sorted(
&self,
initial: Option<u32>,
compressed: &[u8],
decompressed: &mut [u32],
num_bits: u8,
) -> usize;
fn num_bits(&self, decompressed: &[u32]) -> u8;
fn num_bits_sorted(&self, initial: u32, decompressed: &[u32]) -> u8;
fn num_bits_strictly_sorted(&self, initial: Option<u32>, decompressed: &[u32]) -> u8;
#[must_use]
fn compressed_block_size(num_bits: u8) -> usize {
Self::BLOCK_LEN * (num_bits as usize) / 8
}
}
fn most_significant_bit(v: u32) -> u8 {
if v == 0 {
0
} else {
32u8 - (v.leading_zeros() as u8)
}
}
#[cfg(all(feature = "bitpacker1x", any(test, not(debug_assertions))))]
mod bitpacker1x;
#[cfg(all(feature = "bitpacker4x", any(test, not(debug_assertions))))]
mod bitpacker4x;
#[cfg(all(feature = "bitpacker1x", debug_assertions))]
mod bitpacker1x_simple;
#[cfg(all(feature = "bitpacker4x", debug_assertions))]
mod bitpacker4x_simple;
#[cfg(feature = "bitpacker8x")]
mod bitpacker8x;
#[cfg(all(feature = "bitpacker1x", not(debug_assertions)))]
pub use bitpacker1x::BitPacker1x;
#[cfg(all(feature = "bitpacker1x", debug_assertions))]
pub use bitpacker1x_simple::BitPacker1x;
#[cfg(all(feature = "bitpacker4x", not(debug_assertions)))]
pub use bitpacker4x::BitPacker4x;
#[cfg(all(feature = "bitpacker4x", debug_assertions))]
pub use bitpacker4x_simple::BitPacker4x;
#[cfg(feature = "bitpacker8x")]
pub use bitpacker8x::BitPacker8x;
#[cfg(test)]
mod tests_unit {
use super::*;
#[test]
#[should_panic(expected = "`decompressed`'s len is not `BLOCK_LEN=128`")]
fn test_num_bits_block_too_long() {
let bit_packer = BitPacker4x::new();
let v = vec![0u32; BitPacker4x::BLOCK_LEN + 1];
bit_packer.num_bits(&v[..]);
}
#[test]
#[should_panic(expected = "`decompressed`'s len is not `BLOCK_LEN=128`")]
fn test_num_bits_block_too_short() {
let bit_packer = BitPacker4x::new();
let v = vec![0u32; BitPacker4x::BLOCK_LEN - 1];
bit_packer.num_bits(&v[..]);
}
}
#[cfg(test)]
mod functional_tests {
use crate::{BitPacker, BitPacker4x};
use proptest::prelude::*;
proptest! {
#[test]
#[ignore]
fn check_block(
values in prop::collection::vec(u32::arbitrary(), BitPacker4x::BLOCK_LEN),
) {
let bit_packer = BitPacker4x::new();
let bit_width = bit_packer.num_bits(&*values);
let mut block = vec![0u8; BitPacker4x::compressed_block_size(bit_width)];
bit_packer.compress(&values, &mut block, bit_width);
let mut decoded_values = vec![0x10101010; BitPacker4x::BLOCK_LEN];
bit_packer.decompress(&block, &mut decoded_values, bit_width);
prop_assert_eq!(values, decoded_values);
}
#[ignore]
#[test]
fn check_sorted_block(
(values, init_value) in prop::collection::vec(u32::arbitrary(), BitPacker4x::BLOCK_LEN).prop_flat_map(|mut values| {
values.sort_unstable();
let min_value = values[0];
(Just(values), 0..=min_value)
}),
) {
let bit_packer = BitPacker4x::new();
let bit_width = bit_packer.num_bits_sorted(init_value, &*values);
let mut block = vec![0u8; BitPacker4x::compressed_block_size(bit_width)];
bit_packer.compress_sorted(init_value, &values, &mut block, bit_width);
let mut decoded_values = vec![0x10101010; BitPacker4x::BLOCK_LEN];
bit_packer.decompress_sorted(init_value, &block, &mut decoded_values, bit_width);
prop_assert_eq!(values, decoded_values);
}
}
}