vortex_array/arrays/primitive/array/
top_value.rs1use std::hash::Hash;
5
6use rustc_hash::FxBuildHasher;
7use vortex_error::VortexExpect;
8use vortex_error::VortexResult;
9use vortex_mask::AllOr;
10use vortex_mask::Mask;
11use vortex_utils::aliases::hash_map::HashMap;
12
13use crate::ExecutionCtx;
14use crate::arrays::PrimitiveArray;
15use crate::arrays::primitive::NativeValue;
16use crate::dtype::NativePType;
17use crate::match_each_native_ptype;
18use crate::scalar::PValue;
19
20impl PrimitiveArray {
21 pub fn top_value(&self, ctx: &mut ExecutionCtx) -> VortexResult<Option<(PValue, usize)>> {
23 if self.is_empty() {
24 return Ok(None);
25 }
26
27 if self.validity()?.definitely_all_null() {
28 return Ok(None);
29 }
30
31 match_each_native_ptype!(self.ptype(), |P| {
32 let (top, count) = typed_top_value(
33 self.as_slice::<P>(),
34 self.as_ref().validity()?.execute_mask(self.len(), ctx)?,
35 );
36 Ok(Some((top.into(), count)))
37 })
38 }
39}
40
41fn typed_top_value<T>(values: &[T], mask: Mask) -> (T, usize)
42where
43 T: NativePType,
44 NativeValue<T>: Eq + Hash,
45{
46 let mut distinct_values: HashMap<NativeValue<T>, usize, FxBuildHasher> =
47 HashMap::with_hasher(FxBuildHasher);
48 match mask.indices() {
49 AllOr::All => {
50 for value in values.iter().copied() {
51 *distinct_values.entry(NativeValue(value)).or_insert(0) += 1;
52 }
53 }
54 AllOr::None => unreachable!("All invalid arrays should be handled earlier"),
55 AllOr::Some(idxs) => {
56 for &i in idxs {
57 *distinct_values
58 .entry(NativeValue(unsafe { *values.get_unchecked(i) }))
59 .or_insert(0) += 1
60 }
61 }
62 }
63
64 let (&top_value, &top_count) = distinct_values
65 .iter()
66 .max_by_key(|&(_, &count)| count)
67 .vortex_expect("non-empty");
68 (top_value.0, top_count)
69}