use std::any::Any;
use std::any::TypeId;
use std::sync::Arc;
use parking_lot::Mutex;
use vortex_array::ArrayRef;
use vortex_array::ArrayView;
use vortex_array::ExecutionCtx;
use vortex_array::arrays::Bool;
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;
use crate::trace;
type StatsEntry = (TypeId, Arc<dyn Any + Send + Sync>);
struct StatsCache {
entries: Arc<Mutex<Vec<StatsEntry>>>,
}
impl StatsCache {
fn new() -> Self {
Self {
entries: Arc::new(Mutex::new(Vec::new())),
}
}
fn get_or_insert_with<T: Send + Sync + 'static>(&self, f: impl FnOnce() -> T) -> Arc<T> {
let type_id = TypeId::of::<T>();
let mut guard = self.entries.lock();
if let Some(pos) = guard.iter().position(|(id, _)| *id == type_id) {
Arc::clone(&guard[pos].1)
.downcast::<T>()
.ok()
.vortex_expect("we just checked the TypeID")
} else {
let new_arc: Arc<T> = {
let _span = trace::generate_stats_span(std::any::type_name::<T>()).entered();
Arc::new(f())
};
guard.push((type_id, Arc::clone(&new_arc) as Arc<dyn Any + Send + Sync>));
new_arc
}
}
}
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(&self, ctx: &mut ExecutionCtx) -> Arc<BoolStats> {
let array = self.array.clone();
self.cache.get_or_insert_with::<BoolStats>(|| {
let bool_array = array
.as_opt::<Bool>()
.vortex_expect("the array is guaranteed to already be canonical by construction")
.into_owned();
BoolStats::generate(&bool_array, ctx).vortex_expect("BoolStats shouldn't fail")
})
}
pub fn integer_stats(&self, ctx: &mut ExecutionCtx) -> Arc<IntegerStats> {
let array = self.array.clone();
let opts = self.opts;
self.cache.get_or_insert_with::<IntegerStats>(|| {
let primitive = array
.as_opt::<Primitive>()
.vortex_expect("the array is guaranteed to already be canonical by construction")
.into_owned();
IntegerStats::generate_opts(&primitive, opts, ctx)
})
}
pub fn float_stats(&self, ctx: &mut ExecutionCtx) -> Arc<FloatStats> {
let array = self.array.clone();
let opts = self.opts;
self.cache.get_or_insert_with::<FloatStats>(|| {
let primitive = array
.as_opt::<Primitive>()
.vortex_expect("the array is guaranteed to already be canonical by construction")
.into_owned();
FloatStats::generate_opts(&primitive, opts, ctx)
})
}
pub fn string_stats(&self, ctx: &mut ExecutionCtx) -> Arc<StringStats> {
let array = self.array.clone();
let opts = self.opts;
self.cache.get_or_insert_with::<StringStats>(|| {
let varbinview = array
.as_opt::<VarBinView>()
.vortex_expect("the array is guaranteed to already be canonical by construction")
.into_owned();
StringStats::generate_opts(&varbinview, opts, ctx)
})
}
pub fn get_or_insert_with<T: Send + Sync + 'static>(&self, f: impl FnOnce() -> T) -> Arc<T> {
self.cache.get_or_insert_with::<T>(f)
}
}