use rawdb::likely;
use crate::{Error, ValueStrategy};
use super::EncodedChunk;
pub trait CompressionStrategy<T>: ValueStrategy<T> {
type Decoder;
const MAX_UNCOMPRESSED_CHUNK_SIZE: usize;
fn compress_chunk(values: &[T], values_per_page: usize) -> crate::Result<EncodedChunk>;
fn decoder(header: &[u8]) -> crate::Result<Self::Decoder>;
fn decompress_page_into(
decoder: &mut Self::Decoder,
body: &[u8],
expected_len: usize,
dst: &mut Vec<T>,
) -> crate::Result<()>;
#[inline]
fn decompress_page_append(
decoder: &mut Self::Decoder,
body: &[u8],
expected_len: usize,
dst: &mut Vec<T>,
) -> crate::Result<()> {
let mut values = Vec::with_capacity(expected_len);
Self::decompress_page_into(decoder, body, expected_len, &mut values)?;
dst.extend(values);
Ok(())
}
#[inline]
fn values_to_bytes(values: &[T]) -> Vec<u8> {
let byte_len = size_of_val(values);
let mut bytes = Vec::with_capacity(byte_len);
if Self::IS_NATIVE_LAYOUT {
unsafe {
std::ptr::copy_nonoverlapping(
values.as_ptr() as *const u8,
bytes.as_mut_ptr(),
byte_len,
);
bytes.set_len(byte_len);
}
} else {
for v in values {
Self::write_to_vec(v, &mut bytes);
}
}
bytes
}
#[inline]
fn bytes_to_values_into(
bytes: &[u8],
expected_len: usize,
dst: &mut Vec<T>,
) -> crate::Result<()> {
let expected_bytes = expected_len * size_of::<T>();
dst.clear();
dst.reserve(expected_len);
if !likely(bytes.len() == expected_bytes) {
return Err(Error::DecompressionMismatch {
expected_len,
actual_len: bytes.len() / size_of::<T>(),
});
}
if Self::IS_NATIVE_LAYOUT {
unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
dst.as_mut_ptr() as *mut u8,
expected_bytes,
);
dst.set_len(expected_len);
}
} else {
let value_size = size_of::<T>();
for index in 0..expected_len {
let from = index * value_size;
dst.push(Self::read(&bytes[from..from + value_size])?);
}
}
Ok(())
}
}