use std::cmp::min;
use std::convert::{TryFrom, TryInto};
use std::marker::PhantomData;
use crate::bit_reader::BitReader;
use crate::{CompressorConfig};
use crate::bit_writer::BitWriter;
use crate::bits;
use crate::constants::{BITS_TO_ENCODE_DELTA_ENCODING_ORDER, BITS_TO_ENCODE_N_ENTRIES, MAX_DELTA_ENCODING_ORDER};
use crate::errors::{QCompressError, QCompressResult};
#[derive(Clone, Debug, PartialEq)]
pub struct Flags {
pub use_5_bit_code_len: bool,
pub delta_encoding_order: usize,
pub use_min_count_encoding: bool,
pub use_gcds: bool,
pub(crate) phantom: PhantomData<()>,
}
impl TryFrom<Vec<bool>> for Flags {
type Error = QCompressError;
fn try_from(bools: Vec<bool>) -> QCompressResult<Self> {
let mut flags = Flags {
use_5_bit_code_len: false,
delta_encoding_order: 0,
use_min_count_encoding: false,
use_gcds: false,
phantom: PhantomData,
};
let mut bit_iter = bools.iter();
flags.use_5_bit_code_len = bit_iter.next() == Some(&true);
let mut delta_encoding_bits = Vec::new();
while delta_encoding_bits.len() < BITS_TO_ENCODE_DELTA_ENCODING_ORDER {
delta_encoding_bits.push(bit_iter.next().cloned().unwrap_or(false));
}
flags.delta_encoding_order = bits::bits_to_usize(&delta_encoding_bits);
flags.use_min_count_encoding = bit_iter.next() == Some(&true);
flags.use_gcds = bit_iter.next() == Some(&true);
for &bit in bit_iter {
if bit {
return Err(QCompressError::compatibility(
"cannot parse flags; likely written by newer version of q_compress"
));
}
}
Ok(flags)
}
}
impl TryInto<Vec<bool>> for &Flags {
type Error = QCompressError;
fn try_into(self) -> QCompressResult<Vec<bool>> {
let mut res = vec![self.use_5_bit_code_len];
if self.delta_encoding_order > MAX_DELTA_ENCODING_ORDER {
return Err(QCompressError::invalid_argument(format!(
"delta encoding order may not exceed {} (was {})",
MAX_DELTA_ENCODING_ORDER,
self.delta_encoding_order,
)));
}
let delta_bits = bits::usize_truncated_to_bits(self.delta_encoding_order, BITS_TO_ENCODE_DELTA_ENCODING_ORDER);
res.extend(delta_bits);
res.push(self.use_min_count_encoding);
res.push(self.use_gcds);
let necessary_len = res.iter()
.rposition(|&bit| bit)
.map(|idx| idx + 1)
.unwrap_or(0);
res.truncate(necessary_len);
Ok(res)
}
}
impl Flags {
pub(crate) fn parse_from(reader: &mut BitReader) -> QCompressResult<Self> {
reader.aligned_byte_idx()?; let mut bools = Vec::new();
loop {
bools.extend(reader.read(7)?);
if !reader.read_one()? {
break;
}
}
Self::try_from(bools)
}
pub(crate) fn write(&self, writer: &mut BitWriter) -> QCompressResult<()> {
let bools: Vec<bool> = self.try_into()?;
for i in 0_usize..(bools.len() / 7) + 1 {
let start = i * 7;
let end = min(start + 7, bools.len());
writer.write(&bools[start..end]);
if end < bools.len() {
writer.write_one(true);
}
}
writer.finish_byte();
Ok(())
}
pub(crate) fn bits_to_encode_code_len(&self) -> usize {
if self.use_5_bit_code_len {
5
} else {
4
}
}
pub(crate) fn bits_to_encode_count(&self, n: usize) -> usize {
if self.use_min_count_encoding {
((n + 1) as f64).log2().ceil() as usize
} else {
BITS_TO_ENCODE_N_ENTRIES
}
}
}
impl From<&CompressorConfig> for Flags {
fn from(config: &CompressorConfig) -> Self {
Flags {
use_5_bit_code_len: true,
delta_encoding_order: config.delta_encoding_order,
use_min_count_encoding: true,
use_gcds: config.use_gcds,
phantom: PhantomData,
}
}
}