use crate::pq_simd::PackedCodes4bit;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) enum ClusterStorage {
Uncompressed(Vec<u32>),
#[cfg(feature = "id-compression")]
Compressed {
data: Vec<u8>,
num_ids: usize,
universe_size: u32,
},
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(super) struct Cluster {
pub(super) storage: ClusterStorage,
pub(super) filter_bitmask: u64,
#[serde(skip)]
pub(super) fastscan_codes: Option<PackedCodes4bit>,
#[serde(skip)]
pub(super) adc_codes: Option<Vec<u8>>,
#[cfg(feature = "id-compression")]
#[serde(skip)]
#[allow(dead_code)]
decompressed_cache: Option<Vec<u32>>,
}
impl Cluster {
pub(super) fn new(ids: Vec<u32>, filter_bitmask: u64) -> Self {
Self {
storage: ClusterStorage::Uncompressed(ids),
filter_bitmask,
fastscan_codes: None,
adc_codes: None,
#[cfg(feature = "id-compression")]
decompressed_cache: None,
}
}
#[cfg(feature = "id-compression")]
pub(super) fn new_compressed(
ids: Vec<u32>,
filter_bitmask: u64,
_compressor: &crate::compression::DeltaVarintCompressor,
universe_size: u32,
) -> Result<Self, crate::compression::CompressionError> {
let mut sorted_ids = ids;
sorted_ids.sort();
sorted_ids.dedup();
let compressed = crate::compression::compress_set_enveloped(
&sorted_ids,
universe_size,
crate::compression::ChooseConfig::default(),
)?;
Ok(Self {
storage: ClusterStorage::Compressed {
data: compressed,
num_ids: sorted_ids.len(),
universe_size,
},
filter_bitmask,
fastscan_codes: None,
adc_codes: None,
decompressed_cache: None,
})
}
#[cfg(feature = "id-compression")]
#[allow(dead_code)]
pub(super) fn get_ids(&mut self) -> Result<&[u32], crate::compression::CompressionError> {
match &self.storage {
ClusterStorage::Uncompressed(ids) => Ok(ids),
ClusterStorage::Compressed {
data,
universe_size,
..
} => {
if let Some(ref cached) = self.decompressed_cache {
return Ok(cached);
}
let (_choice, u2, decompressed) =
crate::compression::decompress_set_enveloped(data)?;
if u2 != *universe_size {
return Err(crate::compression::CompressionError::DecompressionFailed(
"universe mismatch in envelope".to_string(),
));
}
self.decompressed_cache = Some(decompressed);
#[allow(clippy::unwrap_used)]
Ok(self.decompressed_cache.as_ref().unwrap())
}
}
}
pub(super) fn get_ids_ref(&self) -> Cow<'_, [u32]> {
match &self.storage {
ClusterStorage::Uncompressed(ids) => Cow::Borrowed(ids),
#[cfg(feature = "id-compression")]
ClusterStorage::Compressed {
data,
universe_size,
..
} => Cow::Owned(
crate::compression::decompress_set_enveloped(data)
.map(|(_choice, u2, ids)| {
if u2 == *universe_size {
ids
} else {
Vec::new()
}
})
.unwrap_or_else(|_| Vec::new()),
),
}
}
#[allow(dead_code)]
pub(super) fn len(&self) -> usize {
match &self.storage {
ClusterStorage::Uncompressed(ids) => ids.len(),
#[cfg(feature = "id-compression")]
ClusterStorage::Compressed { num_ids, .. } => *num_ids,
}
}
#[cfg(feature = "id-compression")]
#[allow(dead_code)]
pub(super) fn clear_cache(&mut self) {
self.decompressed_cache = None;
}
pub(super) fn set_fastscan_codes(&mut self, codes: Option<PackedCodes4bit>) {
self.fastscan_codes = codes;
}
pub(super) fn set_adc_codes(&mut self, codes: Option<Vec<u8>>) {
self.adc_codes = codes;
}
pub(super) fn owned_bytes(&self) -> usize {
let storage_bytes = match &self.storage {
ClusterStorage::Uncompressed(ids) => ids.capacity() * std::mem::size_of::<u32>(),
#[cfg(feature = "id-compression")]
ClusterStorage::Compressed { data, .. } => data.capacity(),
};
let fastscan_bytes = self
.fastscan_codes
.as_ref()
.map(|codes| codes.data.capacity())
.unwrap_or(0);
let adc_bytes = self
.adc_codes
.as_ref()
.map(|codes| codes.capacity())
.unwrap_or(0);
#[cfg(feature = "id-compression")]
let cache_bytes = self
.decompressed_cache
.as_ref()
.map(|ids| ids.capacity() * std::mem::size_of::<u32>())
.unwrap_or(0);
#[cfg(not(feature = "id-compression"))]
let cache_bytes = 0;
storage_bytes + fastscan_bytes + adc_bytes + cache_bytes
}
}