use crate::common::bitpacking::{BitReader, BitWriter, packed_bits};
const MIN_BITS_PER_VALUE: u8 = u8::BITS as u8;
const HEADER_BITS: u8 = 6;
pub fn delta_pack(data: &[u64]) -> Vec<u8> {
let mut deltas = Vec::with_capacity(data.len());
let mut prev = 0;
for &value in data {
deltas.push(value - prev);
prev = value;
}
compress_sequence(&deltas)
}
pub fn compress_sequence(data: &[u64]) -> Vec<u8> {
let length = data.len() as u32;
let mut output = Vec::with_capacity(4);
if length == 0 {
return output;
}
let max_value = *data.iter().max().unwrap();
let bits_per_value = packed_bits(max_value).max(MIN_BITS_PER_VALUE);
let mut writer = BitWriter::new(&mut output);
writer.write(bits_per_value - MIN_BITS_PER_VALUE, HEADER_BITS);
for &value in data {
writer.write(value, bits_per_value);
}
writer.finish();
output
}
pub fn decompress_sequence(data: &[u8]) -> Vec<u64> {
if data.is_empty() {
return Vec::new();
}
let mut result = Vec::new();
let mut reader = BitReader::new(data);
let mut remaining_bits = data.len() * u8::BITS as usize;
reader.set_bits(HEADER_BITS);
let bits_per_value = reader.read::<u8>() + MIN_BITS_PER_VALUE;
remaining_bits -= HEADER_BITS as usize;
reader.set_bits(bits_per_value);
while remaining_bits >= bits_per_value as usize {
result.push(reader.read::<u64>());
remaining_bits -= bits_per_value as usize;
}
result
}
pub fn delta_unpack(data: &[u8]) -> Vec<u64> {
let mut sequence = decompress_sequence(data);
let mut prev = 0;
for value in sequence.iter_mut() {
*value += prev;
prev = *value;
}
sequence
}
#[cfg(test)]
mod tests {
use rand::RngExt;
use super::*;
#[test]
fn pack_and_unpack_sorted_data() {
let data = vec![1, 2, 3, 4, 5];
let packed = delta_pack(&data);
let unpacked = delta_unpack(&packed);
assert_eq!(data, unpacked);
}
#[test]
fn pack_and_unpack_unsorted_data() {
let data = vec![5, 3, 1, 4, 2];
let packed = compress_sequence(&data);
let unpacked = decompress_sequence(&packed);
assert_eq!(data, unpacked);
}
#[test]
fn pack_and_unpack_empty_data() {
let data: Vec<u64> = Vec::new();
let packed = delta_pack(&data);
let unpacked = delta_unpack(&packed);
assert_eq!(data, unpacked);
}
#[test]
fn pack_and_unpack_single_element() {
let data = vec![42];
let packed = delta_pack(&data);
let unpacked = delta_unpack(&packed);
assert_eq!(data, unpacked);
}
#[test]
fn pack_and_unpack_large_numbers() {
let data = vec![u64::MAX - 2, u64::MAX - 1, u64::MAX, u64::MAX];
let packed = delta_pack(&data);
let unpacked = delta_unpack(&packed);
assert_eq!(data, unpacked);
}
#[test]
fn pack_and_unpack_large_numbers_unsorted() {
let data = vec![u64::MAX - 2, u64::MAX, u64::MAX, u64::MAX - 1];
let packed = compress_sequence(&data);
let unpacked = decompress_sequence(&packed);
assert_eq!(data, unpacked);
}
#[test]
fn pack_and_unpack_random_data() {
let num_iterations = 100;
let max_length = 100;
let mut rng = rand::rng();
for _ in 0..num_iterations {
let length = rng.random_range(0..max_length);
let mut data = (0..length)
.map(|_| rng.random_range(0..u64::MAX))
.collect::<Vec<_>>();
data.sort();
let packed = delta_pack(&data);
let unpacked = delta_unpack(&packed);
assert_eq!(data, unpacked);
}
}
}