use crate::codec::SketchBytes;
use crate::codec::SketchSlice;
use crate::error::Error;
use crate::hll::HllType;
use crate::hll::container::COUPON_EMPTY;
use crate::hll::container::Container;
use crate::hll::serialization::*;
#[derive(Debug, Clone, PartialEq)]
pub struct List {
container: Container,
}
impl Default for List {
fn default() -> Self {
const LG_INIT_LIST_SIZE: usize = 3;
Self::new(LG_INIT_LIST_SIZE)
}
}
impl List {
pub fn new(lg_size: usize) -> Self {
Self {
container: Container::new(lg_size),
}
}
pub fn update(&mut self, coupon: u32) {
for value in self.container.coupons.iter_mut() {
if value == &COUPON_EMPTY {
*value = coupon;
self.container.len += 1;
break;
} else if value == &coupon {
break;
}
}
}
pub fn container(&self) -> &Container {
&self.container
}
pub fn deserialize(
mut cursor: SketchSlice,
lg_arr: usize,
coupon_count: usize,
empty: bool,
compact: bool,
) -> Result<Self, Error> {
let array_size = if compact { coupon_count } else { 1 << lg_arr };
let mut coupons = vec![0u32; array_size];
if !empty && coupon_count > 0 {
for (i, coupon) in coupons.iter_mut().enumerate() {
*coupon = cursor.read_u32_le().map_err(|_| {
Error::insufficient_data(format!(
"expect {coupon_count} coupons, failed at index {i}"
))
})?;
}
}
Ok(Self {
container: Container::from_coupons(lg_arr, coupons.into_boxed_slice(), coupon_count),
})
}
pub fn serialize(&self, lg_config_k: u8, hll_type: HllType) -> Vec<u8> {
let compact = true; let empty = self.container.is_empty();
let coupon_count = self.container.len();
let lg_arr = self.container.lg_size();
let array_size = if compact { coupon_count } else { 1 << lg_arr };
let total_size = LIST_PREAMBLE_SIZE + (array_size * 4);
let mut bytes = SketchBytes::with_capacity(total_size);
bytes.write_u8(LIST_PREINTS);
bytes.write_u8(SERIAL_VERSION);
bytes.write_u8(HLL_FAMILY_ID);
bytes.write_u8(lg_config_k);
bytes.write_u8(lg_arr as u8);
let mut flags = 0u8;
if empty {
flags |= EMPTY_FLAG_MASK;
}
if compact {
flags |= COMPACT_FLAG_MASK;
}
bytes.write_u8(flags);
bytes.write_u8(coupon_count as u8);
bytes.write_u8(encode_mode_byte(CUR_MODE_LIST, hll_type as u8));
if !empty {
let mut write_idx = 0;
for coupon in self.container.coupons.iter().copied() {
if compact && coupon == 0 {
continue; }
bytes.write_u32_le(coupon);
write_idx += 1;
if write_idx >= array_size {
break;
}
}
}
bytes.into_bytes()
}
}