use std::any::Any;
use std::any::TypeId;
use vortex_array::ArrayRef;
use vortex_array::ArrayView;
use vortex_array::ToCanonical;
use vortex_array::arrays::Primitive;
use vortex_array::arrays::VarBinView;
use vortex_error::VortexExpect;
use super::BoolStats;
use super::FloatStats;
use super::GenerateStatsOptions;
use super::IntegerStats;
use super::StringStats;
struct StatsCache {
entries: Vec<(TypeId, Box<dyn Any>)>,
}
impl StatsCache {
fn new() -> Self {
Self {
entries: Vec::new(),
}
}
fn get_or_insert_with<T: 'static>(&mut self, f: impl FnOnce() -> T) -> &T {
let type_id = TypeId::of::<T>();
let pos = self.entries.iter().position(|(id, _)| *id == type_id);
if let Some(pos) = pos {
self.entries[pos]
.1
.downcast_ref::<T>()
.vortex_expect("we just checked the TypeID")
} else {
self.entries.push((type_id, Box::new(f())));
self.entries
.last()
.vortex_expect("just pushed")
.1
.downcast_ref::<T>()
.vortex_expect("we just checked the TypeID")
}
}
}
pub struct ArrayAndStats {
array: ArrayRef,
cache: StatsCache,
opts: GenerateStatsOptions,
}
impl ArrayAndStats {
pub fn new(array: ArrayRef, opts: GenerateStatsOptions) -> Self {
assert!(
array.is_canonical(),
"ArrayAndStats should only be created with canonical arrays"
);
Self {
array,
cache: StatsCache::new(),
opts,
}
}
pub fn array(&self) -> &ArrayRef {
&self.array
}
pub fn array_as_primitive(&self) -> ArrayView<'_, Primitive> {
self.array
.as_opt::<Primitive>()
.vortex_expect("the array is guaranteed to already be canonical by construction")
}
pub fn array_as_utf8(&self) -> ArrayView<'_, VarBinView> {
self.array
.as_opt::<VarBinView>()
.vortex_expect("the array is guaranteed to already be canonical by construction")
}
pub fn into_array(self) -> ArrayRef {
self.array
}
pub fn array_len(&self) -> usize {
self.array.len()
}
pub fn bool_stats(&mut self) -> &BoolStats {
let array = self.array.clone();
self.cache.get_or_insert_with::<BoolStats>(|| {
BoolStats::generate(&array.to_bool()).vortex_expect("BoolStats shouldn't fail")
})
}
pub fn integer_stats(&mut self) -> &IntegerStats {
let array = self.array.clone();
let opts = self.opts;
self.cache.get_or_insert_with::<IntegerStats>(|| {
IntegerStats::generate_opts(&array.to_primitive(), opts)
})
}
pub fn float_stats(&mut self) -> &FloatStats {
let array = self.array.clone();
let opts = self.opts;
self.cache.get_or_insert_with::<FloatStats>(|| {
FloatStats::generate_opts(&array.to_primitive(), opts)
})
}
pub fn string_stats(&mut self) -> &StringStats {
let array = self.array.clone();
let opts = self.opts;
self.cache.get_or_insert_with::<StringStats>(|| {
StringStats::generate_opts(&array.to_varbinview(), opts)
})
}
pub fn get_or_insert_with<T: 'static>(&mut self, f: impl FnOnce() -> T) -> &T {
self.cache.get_or_insert_with::<T>(f)
}
}