1use arrow_array::cast::*;
21use arrow_array::iterator::ArrayIter;
22use arrow_array::*;
23use arrow_buffer::NullBuffer;
24use arrow_data::bit_iterator::try_for_each_valid_idx;
25use arrow_schema::*;
26use std::borrow::BorrowMut;
27use std::cmp::{self, Ordering};
28use std::ops::{BitAnd, BitOr, BitXor};
29use types::ByteViewType;
30
31trait NumericAccumulator<T: ArrowNativeTypeOp>: Copy + Default {
33 fn accumulate(&mut self, value: T);
35 fn accumulate_nullable(&mut self, value: T, valid: bool);
38 fn merge(&mut self, other: Self);
40 fn finish(&mut self) -> T;
42}
43
44#[inline(always)]
47fn select<T: Copy>(m: bool, a: T, b: T) -> T {
48 if m { a } else { b }
49}
50
51#[derive(Clone, Copy)]
52struct SumAccumulator<T: ArrowNativeTypeOp> {
53 sum: T,
54}
55
56impl<T: ArrowNativeTypeOp> Default for SumAccumulator<T> {
57 fn default() -> Self {
58 Self { sum: T::ZERO }
59 }
60}
61
62impl<T: ArrowNativeTypeOp> NumericAccumulator<T> for SumAccumulator<T> {
63 fn accumulate(&mut self, value: T) {
64 self.sum = self.sum.add_wrapping(value);
65 }
66
67 fn accumulate_nullable(&mut self, value: T, valid: bool) {
68 let sum = self.sum;
69 self.sum = select(valid, sum.add_wrapping(value), sum)
70 }
71
72 fn merge(&mut self, other: Self) {
73 self.sum = self.sum.add_wrapping(other.sum);
74 }
75
76 fn finish(&mut self) -> T {
77 self.sum
78 }
79}
80
81#[derive(Clone, Copy)]
82struct MinAccumulator<T: ArrowNativeTypeOp> {
83 min: T,
84}
85
86impl<T: ArrowNativeTypeOp> Default for MinAccumulator<T> {
87 fn default() -> Self {
88 Self {
89 min: T::MAX_TOTAL_ORDER,
90 }
91 }
92}
93
94impl<T: ArrowNativeTypeOp> NumericAccumulator<T> for MinAccumulator<T> {
95 fn accumulate(&mut self, value: T) {
96 let min = self.min;
97 self.min = select(value.is_lt(min), value, min);
98 }
99
100 fn accumulate_nullable(&mut self, value: T, valid: bool) {
101 let min = self.min;
102 let is_lt = valid & value.is_lt(min);
103 self.min = select(is_lt, value, min);
104 }
105
106 fn merge(&mut self, other: Self) {
107 self.accumulate(other.min)
108 }
109
110 fn finish(&mut self) -> T {
111 self.min
112 }
113}
114
115#[derive(Clone, Copy)]
116struct MaxAccumulator<T: ArrowNativeTypeOp> {
117 max: T,
118}
119
120impl<T: ArrowNativeTypeOp> Default for MaxAccumulator<T> {
121 fn default() -> Self {
122 Self {
123 max: T::MIN_TOTAL_ORDER,
124 }
125 }
126}
127
128impl<T: ArrowNativeTypeOp> NumericAccumulator<T> for MaxAccumulator<T> {
129 fn accumulate(&mut self, value: T) {
130 let max = self.max;
131 self.max = select(value.is_gt(max), value, max);
132 }
133
134 fn accumulate_nullable(&mut self, value: T, valid: bool) {
135 let max = self.max;
136 let is_gt = value.is_gt(max) & valid;
137 self.max = select(is_gt, value, max);
138 }
139
140 fn merge(&mut self, other: Self) {
141 self.accumulate(other.max)
142 }
143
144 fn finish(&mut self) -> T {
145 self.max
146 }
147}
148
149fn reduce_accumulators<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
150 mut acc: [A; LANES],
151) -> A {
152 assert!(LANES > 0 && LANES.is_power_of_two());
153 let mut len = LANES;
154
155 while len >= 2 {
158 let mid = len / 2;
159 let (h, t) = acc[..len].split_at_mut(mid);
160
161 for i in 0..mid {
162 h[i].merge(t[i]);
163 }
164 len /= 2;
165 }
166 acc[0]
167}
168
169#[inline(always)]
170fn aggregate_nonnull_chunk<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
171 acc: &mut [A; LANES],
172 values: &[T; LANES],
173) {
174 for i in 0..LANES {
175 acc[i].accumulate(values[i]);
176 }
177}
178
179#[inline(always)]
180fn aggregate_nullable_chunk<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
181 acc: &mut [A; LANES],
182 values: &[T; LANES],
183 validity: u64,
184) {
185 let mut bit = 1;
186 for i in 0..LANES {
187 acc[i].accumulate_nullable(values[i], (validity & bit) != 0);
188 bit <<= 1;
189 }
190}
191
192fn aggregate_nonnull_simple<T: ArrowNativeTypeOp, A: NumericAccumulator<T>>(values: &[T]) -> T {
193 values
194 .iter()
195 .copied()
196 .fold(A::default(), |mut a, b| {
197 a.accumulate(b);
198 a
199 })
200 .finish()
201}
202
203#[inline(never)]
204fn aggregate_nonnull_lanes<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
205 values: &[T],
206) -> T {
207 let mut acc = [A::default(); LANES];
210 let mut chunks = values.chunks_exact(LANES);
211 chunks.borrow_mut().for_each(|chunk| {
212 aggregate_nonnull_chunk(&mut acc, chunk[..LANES].try_into().unwrap());
213 });
214
215 let remainder = chunks.remainder();
216 for i in 0..remainder.len() {
217 acc[i].accumulate(remainder[i]);
218 }
219
220 reduce_accumulators(acc).finish()
221}
222
223#[inline(never)]
224fn aggregate_nullable_lanes<T: ArrowNativeTypeOp, A: NumericAccumulator<T>, const LANES: usize>(
225 values: &[T],
226 validity: &NullBuffer,
227) -> T {
228 assert!(LANES > 0 && 64 % LANES == 0);
229 assert_eq!(values.len(), validity.len());
230
231 let mut acc = [A::default(); LANES];
233 let mut values_chunks = values.chunks_exact(64);
235 let validity_chunks = validity.inner().bit_chunks();
236 let mut validity_chunks_iter = validity_chunks.iter();
237
238 values_chunks.borrow_mut().for_each(|chunk| {
239 let mut validity = unsafe { validity_chunks_iter.next().unwrap_unchecked() };
241 chunk.chunks_exact(LANES).for_each(|chunk| {
243 aggregate_nullable_chunk(&mut acc, chunk[..LANES].try_into().unwrap(), validity);
244 validity >>= LANES;
245 });
246 });
247
248 let remainder = values_chunks.remainder();
249 if !remainder.is_empty() {
250 let mut validity = validity_chunks.remainder_bits();
251
252 let mut remainder_chunks = remainder.chunks_exact(LANES);
253 remainder_chunks.borrow_mut().for_each(|chunk| {
254 aggregate_nullable_chunk(&mut acc, chunk[..LANES].try_into().unwrap(), validity);
255 validity >>= LANES;
256 });
257
258 let remainder = remainder_chunks.remainder();
259 if !remainder.is_empty() {
260 let mut bit = 1;
261 for i in 0..remainder.len() {
262 acc[i].accumulate_nullable(remainder[i], (validity & bit) != 0);
263 bit <<= 1;
264 }
265 }
266 }
267
268 reduce_accumulators(acc).finish()
269}
270
271const PREFERRED_VECTOR_SIZE: usize =
274 if cfg!(all(target_arch = "x86_64", target_feature = "avx512f")) {
275 64
276 } else if cfg!(all(target_arch = "x86_64", target_feature = "avx")) {
277 32
278 } else {
279 16
280 };
281
282const PREFERRED_VECTOR_SIZE_NON_NULL: usize = PREFERRED_VECTOR_SIZE * 2;
284
285fn aggregate<T: ArrowNativeTypeOp, P: ArrowPrimitiveType<Native = T>, A: NumericAccumulator<T>>(
288 array: &PrimitiveArray<P>,
289) -> Option<T> {
290 let null_count = array.null_count();
291 if null_count == array.len() {
292 return None;
293 }
294 let values = array.values().as_ref();
295 match array.nulls() {
296 Some(nulls) if null_count > 0 => {
297 match PREFERRED_VECTOR_SIZE / std::mem::size_of::<T>() {
300 64 => Some(aggregate_nullable_lanes::<T, A, 64>(values, nulls)),
301 32 => Some(aggregate_nullable_lanes::<T, A, 32>(values, nulls)),
302 16 => Some(aggregate_nullable_lanes::<T, A, 16>(values, nulls)),
303 8 => Some(aggregate_nullable_lanes::<T, A, 8>(values, nulls)),
304 4 => Some(aggregate_nullable_lanes::<T, A, 4>(values, nulls)),
305 2 => Some(aggregate_nullable_lanes::<T, A, 2>(values, nulls)),
306 _ => Some(aggregate_nullable_lanes::<T, A, 1>(values, nulls)),
307 }
308 }
309 _ => {
310 let is_float = matches!(
311 array.data_type(),
312 DataType::Float16 | DataType::Float32 | DataType::Float64
313 );
314 if is_float {
315 match PREFERRED_VECTOR_SIZE_NON_NULL / std::mem::size_of::<T>() {
316 64 => Some(aggregate_nonnull_lanes::<T, A, 64>(values)),
317 32 => Some(aggregate_nonnull_lanes::<T, A, 32>(values)),
318 16 => Some(aggregate_nonnull_lanes::<T, A, 16>(values)),
319 8 => Some(aggregate_nonnull_lanes::<T, A, 8>(values)),
320 4 => Some(aggregate_nonnull_lanes::<T, A, 4>(values)),
321 2 => Some(aggregate_nonnull_lanes::<T, A, 2>(values)),
322 _ => Some(aggregate_nonnull_simple::<T, A>(values)),
323 }
324 } else {
325 Some(aggregate_nonnull_simple::<T, A>(values))
328 }
329 }
330 }
331}
332
333pub fn min_boolean(array: &BooleanArray) -> Option<bool> {
343 if array.null_count() == array.len() {
345 return None;
346 }
347
348 match array.nulls() {
350 None => {
351 let bit_chunks = array.values().bit_chunks();
352 if bit_chunks.iter().any(|x| {
353 x != u64::MAX
355 }) {
356 return Some(false);
357 }
358 if bit_chunks.remainder_bits().count_ones() as usize != bit_chunks.remainder_len() {
360 Some(false)
361 } else {
362 Some(true)
363 }
364 }
365 Some(nulls) => {
366 let validity_chunks = nulls.inner().bit_chunks();
367 let value_chunks = array.values().bit_chunks();
368
369 if value_chunks
370 .iter()
371 .zip(validity_chunks.iter())
372 .any(|(value, validity)| {
373 (!value & validity) != 0
376 })
377 {
378 return Some(false);
379 }
380
381 if (!value_chunks.remainder_bits() & validity_chunks.remainder_bits()) != 0 {
383 Some(false)
384 } else {
385 Some(true)
386 }
387 }
388 }
389}
390
391pub fn max_boolean(array: &BooleanArray) -> Option<bool> {
401 if array.null_count() == array.len() {
403 return None;
404 }
405
406 match array.nulls() {
408 None => array
409 .values()
410 .bit_chunks()
411 .iter_padded()
412 .map(|x| x != 0)
414 .find(|b| *b)
415 .or(Some(false)),
416 Some(nulls) => {
417 let validity_chunks = nulls.inner().bit_chunks().iter_padded();
418 let value_chunks = array.values().bit_chunks().iter_padded();
419 value_chunks
420 .zip(validity_chunks)
421 .map(|(value_bits, validity_bits)| (value_bits & validity_bits) != 0)
423 .find(|b| *b)
424 .or(Some(false))
425 }
426 }
427}
428
429fn min_max_helper<T, A: ArrayAccessor<Item = T>, F>(array: A, cmp: F) -> Option<T>
431where
432 F: Fn(&T, &T) -> bool,
433{
434 let null_count = array.null_count();
435 if null_count == array.len() {
436 None
437 } else if null_count == 0 {
438 (0..array.len())
442 .map(|i| unsafe { array.value_unchecked(i) })
443 .reduce(|acc, item| if cmp(&acc, &item) { item } else { acc })
444 } else {
445 let nulls = array.nulls().unwrap();
446 unsafe {
447 let idx = nulls.valid_indices().reduce(|acc_idx, idx| {
448 let acc = array.value_unchecked(acc_idx);
449 let item = array.value_unchecked(idx);
450 if cmp(&acc, &item) { idx } else { acc_idx }
451 });
452 idx.map(|idx| array.value_unchecked(idx))
453 }
454 }
455}
456
457fn min_max_view_helper<T: ByteViewType>(
462 array: &GenericByteViewArray<T>,
463 swap_cond: cmp::Ordering,
464) -> Option<&T::Native> {
465 let null_count = array.null_count();
466 if null_count == array.len() {
467 None
468 } else if null_count == 0 {
469 let target_idx = (0..array.len()).reduce(|acc, item| {
470 let cmp = unsafe { GenericByteViewArray::compare_unchecked(array, item, array, acc) };
472 if cmp == swap_cond { item } else { acc }
473 });
474 unsafe { target_idx.map(|idx| array.value_unchecked(idx)) }
476 } else {
477 let nulls = array.nulls().unwrap();
478
479 let target_idx = nulls.valid_indices().reduce(|acc_idx, idx| {
480 let cmp =
481 unsafe { GenericByteViewArray::compare_unchecked(array, idx, array, acc_idx) };
482 if cmp == swap_cond { idx } else { acc_idx }
483 });
484
485 unsafe { target_idx.map(|idx| array.value_unchecked(idx)) }
487 }
488}
489
490pub fn max_binary<T: OffsetSizeTrait>(array: &GenericBinaryArray<T>) -> Option<&[u8]> {
492 min_max_helper::<&[u8], _, _>(array, |a, b| *a < *b)
493}
494
495pub fn max_binary_view(array: &BinaryViewArray) -> Option<&[u8]> {
497 min_max_view_helper(array, Ordering::Greater)
498}
499
500pub fn max_fixed_size_binary(array: &FixedSizeBinaryArray) -> Option<&[u8]> {
502 min_max_helper::<&[u8], _, _>(array, |a, b| *a < *b)
503}
504
505pub fn min_binary<T: OffsetSizeTrait>(array: &GenericBinaryArray<T>) -> Option<&[u8]> {
507 min_max_helper::<&[u8], _, _>(array, |a, b| *a > *b)
508}
509
510pub fn min_binary_view(array: &BinaryViewArray) -> Option<&[u8]> {
512 min_max_view_helper(array, Ordering::Less)
513}
514
515pub fn min_fixed_size_binary(array: &FixedSizeBinaryArray) -> Option<&[u8]> {
517 min_max_helper::<&[u8], _, _>(array, |a, b| *a > *b)
518}
519
520pub fn max_string<T: OffsetSizeTrait>(array: &GenericStringArray<T>) -> Option<&str> {
522 min_max_helper::<&str, _, _>(array, |a, b| *a < *b)
523}
524
525pub fn max_string_view(array: &StringViewArray) -> Option<&str> {
527 min_max_view_helper(array, Ordering::Greater)
528}
529
530pub fn min_string<T: OffsetSizeTrait>(array: &GenericStringArray<T>) -> Option<&str> {
532 min_max_helper::<&str, _, _>(array, |a, b| *a > *b)
533}
534
535pub fn min_string_view(array: &StringViewArray) -> Option<&str> {
537 min_max_view_helper(array, Ordering::Less)
538}
539
540pub fn sum_array<T: ArrowNumericType, A: ArrayAccessor<Item = T::Native>>(
545 array: A,
546) -> Option<T::Native> {
547 match array.data_type() {
548 DataType::Dictionary(_, _) => {
549 let null_count = array.null_count();
550
551 if null_count == array.len() {
552 return None;
553 }
554
555 let iter = ArrayIter::new(array);
556 let sum = iter
557 .into_iter()
558 .fold(T::default_value(), |accumulator, value| {
559 if let Some(value) = value {
560 accumulator.add_wrapping(value)
561 } else {
562 accumulator
563 }
564 });
565
566 Some(sum)
567 }
568 DataType::RunEndEncoded(run_ends, _) => match run_ends.data_type() {
569 DataType::Int16 => ree::sum_wrapping::<types::Int16Type, T>(&array),
570 DataType::Int32 => ree::sum_wrapping::<types::Int32Type, T>(&array),
571 DataType::Int64 => ree::sum_wrapping::<types::Int64Type, T>(&array),
572 _ => unreachable!(),
573 },
574 _ => sum::<T>(as_primitive_array(&array)),
575 }
576}
577
578pub fn sum_array_checked<T: ArrowNumericType, A: ArrayAccessor<Item = T::Native>>(
585 array: A,
586) -> Result<Option<T::Native>, ArrowError> {
587 match array.data_type() {
588 DataType::Dictionary(_, _) => {
589 let null_count = array.null_count();
590
591 if null_count == array.len() {
592 return Ok(None);
593 }
594
595 let iter = ArrayIter::new(array);
596 let sum = iter
597 .into_iter()
598 .try_fold(T::default_value(), |accumulator, value| {
599 if let Some(value) = value {
600 accumulator.add_checked(value)
601 } else {
602 Ok(accumulator)
603 }
604 })?;
605
606 Ok(Some(sum))
607 }
608 DataType::RunEndEncoded(run_ends, _) => match run_ends.data_type() {
609 DataType::Int16 => ree::sum_checked::<types::Int16Type, T>(&array),
610 DataType::Int32 => ree::sum_checked::<types::Int32Type, T>(&array),
611 DataType::Int64 => ree::sum_checked::<types::Int64Type, T>(&array),
612 _ => unreachable!(),
613 },
614 _ => sum_checked::<T>(as_primitive_array(&array)),
615 }
616}
617
618mod ree {
620 use std::convert::Infallible;
621
622 use arrow_array::cast::AsArray;
623 use arrow_array::types::RunEndIndexType;
624 use arrow_array::{Array, ArrowNativeTypeOp, ArrowNumericType, PrimitiveArray, TypedRunArray};
625 use arrow_buffer::ArrowNativeType;
626 use arrow_schema::ArrowError;
627
628 fn downcast<'a, I: RunEndIndexType, V: ArrowNumericType>(
630 array: &'a dyn Array,
631 ) -> Option<TypedRunArray<'a, I, PrimitiveArray<V>>> {
632 let array = array.as_run_opt::<I>()?;
633 array.downcast::<PrimitiveArray<V>>()
635 }
636
637 pub(super) fn sum_wrapping<I: RunEndIndexType, V: ArrowNumericType>(
639 array: &dyn Array,
640 ) -> Option<V::Native> {
641 let ree = downcast::<I, V>(array)?;
642 let Ok(sum) = fold(ree, |acc, val, len| -> Result<V::Native, Infallible> {
643 Ok(acc.add_wrapping(val.mul_wrapping(V::Native::usize_as(len))))
644 });
645 sum
646 }
647
648 pub(super) fn sum_checked<I: RunEndIndexType, V: ArrowNumericType>(
650 array: &dyn Array,
651 ) -> Result<Option<V::Native>, ArrowError> {
652 let Some(ree) = downcast::<I, V>(array) else {
653 return Err(ArrowError::InvalidArgumentError(
654 "Input run array values are not a PrimitiveArray".to_string(),
655 ));
656 };
657 fold(ree, |acc, val, len| -> Result<V::Native, ArrowError> {
658 let Some(len) = V::Native::from_usize(len) else {
659 return Err(ArrowError::ArithmeticOverflow(format!(
660 "Cannot convert a run-end index ({:?}) to the value type ({})",
661 len,
662 std::any::type_name::<V::Native>()
663 )));
664 };
665 acc.add_checked(val.mul_checked(len)?)
666 })
667 }
668
669 fn fold<'a, I: RunEndIndexType, V: ArrowNumericType, F, E>(
671 array: TypedRunArray<'a, I, PrimitiveArray<V>>,
672 mut f: F,
673 ) -> Result<Option<V::Native>, E>
674 where
675 F: FnMut(V::Native, V::Native, usize) -> Result<V::Native, E>,
676 {
677 let run_ends = array.run_ends();
678 let logical_start = run_ends.offset();
679 let logical_end = run_ends.offset() + run_ends.len();
680 let run_ends = run_ends.sliced_values();
681
682 let values_slice = array.run_array().values_slice();
683 let values = values_slice
684 .as_any()
685 .downcast_ref::<PrimitiveArray<V>>()
686 .unwrap();
688
689 let mut prev_end = 0;
690 let mut acc = V::Native::ZERO;
691 let mut has_non_null_value = false;
692
693 for (run_end, value) in run_ends.zip(values) {
694 let current_run_end = run_end.as_usize().clamp(logical_start, logical_end);
695 let run_length = current_run_end - prev_end;
696
697 if let Some(value) = value {
698 has_non_null_value = true;
699 acc = f(acc, value, run_length)?;
700 }
701
702 prev_end = current_run_end;
703 if current_run_end == logical_end {
704 break;
705 }
706 }
707
708 Ok(if has_non_null_value { Some(acc) } else { None })
709 }
710}
711
712pub fn min_array<T: ArrowNumericType, A: ArrayAccessor<Item = T::Native>>(
715 array: A,
716) -> Option<T::Native> {
717 min_max_array_helper::<T, A, _, _>(array, |a, b| a.is_gt(*b), min)
718}
719
720pub fn max_array<T: ArrowNumericType, A: ArrayAccessor<Item = T::Native>>(
723 array: A,
724) -> Option<T::Native> {
725 min_max_array_helper::<T, A, _, _>(array, |a, b| a.is_lt(*b), max)
726}
727
728fn min_max_array_helper<T, A: ArrayAccessor<Item = T::Native>, F, M>(
729 array: A,
730 cmp: F,
731 m: M,
732) -> Option<T::Native>
733where
734 T: ArrowNumericType,
735 F: Fn(&T::Native, &T::Native) -> bool,
736 M: Fn(&PrimitiveArray<T>) -> Option<T::Native>,
737{
738 match array.data_type() {
739 DataType::Dictionary(_, _) => min_max_helper::<T::Native, _, _>(array, cmp),
740 DataType::RunEndEncoded(run_ends, _) => {
741 let array: &dyn Array = &array;
744 let values = match run_ends.data_type() {
745 DataType::Int16 => array.as_run_opt::<types::Int16Type>()?.values_slice(),
746 DataType::Int32 => array.as_run_opt::<types::Int32Type>()?.values_slice(),
747 DataType::Int64 => array.as_run_opt::<types::Int64Type>()?.values_slice(),
748 _ => return None,
749 };
750 let values = values.as_any().downcast_ref::<PrimitiveArray<T>>()?;
752 m(values)
753 }
754 _ => m(as_primitive_array(&array)),
755 }
756}
757
758macro_rules! bit_operation {
759 ($NAME:ident, $OP:ident, $NATIVE:ident, $DEFAULT:expr, $DOC:expr) => {
760 #[doc = $DOC]
761 pub fn $NAME<T>(array: &PrimitiveArray<T>) -> Option<T::Native>
764 where
765 T: ArrowNumericType,
766 T::Native: $NATIVE<Output = T::Native> + ArrowNativeTypeOp,
767 {
768 let default;
769 if $DEFAULT == -1 {
770 default = T::Native::ONE.neg_wrapping();
771 } else {
772 default = T::default_value();
773 }
774
775 let null_count = array.null_count();
776
777 if null_count == array.len() {
778 return None;
779 }
780
781 let data: &[T::Native] = array.values();
782
783 match array.nulls() {
784 None => {
785 let result = data
786 .iter()
787 .fold(default, |accumulator, value| accumulator.$OP(*value));
788
789 Some(result)
790 }
791 Some(nulls) => {
792 let mut result = default;
793 let data_chunks = data.chunks_exact(64);
794 let remainder = data_chunks.remainder();
795
796 let bit_chunks = nulls.inner().bit_chunks();
797 data_chunks
798 .zip(bit_chunks.iter())
799 .for_each(|(chunk, mask)| {
800 let mut index_mask = 1;
802 chunk.iter().for_each(|value| {
803 if (mask & index_mask) != 0 {
804 result = result.$OP(*value);
805 }
806 index_mask <<= 1;
807 });
808 });
809
810 let remainder_bits = bit_chunks.remainder_bits();
811
812 remainder.iter().enumerate().for_each(|(i, value)| {
813 if remainder_bits & (1 << i) != 0 {
814 result = result.$OP(*value);
815 }
816 });
817
818 Some(result)
819 }
820 }
821 }
822 };
823}
824
825bit_operation!(
826 bit_and,
827 bitand,
828 BitAnd,
829 -1,
830 "Returns the bitwise and of all non-null input values."
831);
832bit_operation!(
833 bit_or,
834 bitor,
835 BitOr,
836 0,
837 "Returns the bitwise or of all non-null input values."
838);
839bit_operation!(
840 bit_xor,
841 bitxor,
842 BitXor,
843 0,
844 "Returns the bitwise xor of all non-null input values."
845);
846
847pub fn bool_and(array: &BooleanArray) -> Option<bool> {
851 min_boolean(array)
852}
853
854pub fn bool_or(array: &BooleanArray) -> Option<bool> {
858 max_boolean(array)
859}
860
861pub fn sum_checked<T: ArrowNumericType>(
868 array: &PrimitiveArray<T>,
869) -> Result<Option<T::Native>, ArrowError> {
870 let null_count = array.null_count();
871
872 if null_count == array.len() {
873 return Ok(None);
874 }
875
876 let data: &[T::Native] = array.values();
877
878 match array.nulls() {
879 None => {
880 let sum = data
881 .iter()
882 .try_fold(T::default_value(), |accumulator, value| {
883 accumulator.add_checked(*value)
884 })?;
885
886 Ok(Some(sum))
887 }
888 Some(nulls) => {
889 let mut sum = T::default_value();
890
891 try_for_each_valid_idx(
892 nulls.len(),
893 nulls.offset(),
894 nulls.null_count(),
895 Some(nulls.validity()),
896 |idx| {
897 unsafe { sum = sum.add_checked(array.value_unchecked(idx))? };
898 Ok::<_, ArrowError>(())
899 },
900 )?;
901
902 Ok(Some(sum))
903 }
904 }
905}
906
907pub fn sum<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native> {
914 aggregate::<T::Native, T, SumAccumulator<T::Native>>(array)
915}
916
917pub fn min<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native> {
929 aggregate::<T::Native, T, MinAccumulator<T::Native>>(array)
930}
931
932pub fn max<T: ArrowNumericType>(array: &PrimitiveArray<T>) -> Option<T::Native> {
944 aggregate::<T::Native, T, MaxAccumulator<T::Native>>(array)
945}
946
947#[cfg(test)]
948mod tests {
949 use super::*;
950 use arrow_array::types::*;
951 use builder::BooleanBuilder;
952 use std::sync::Arc;
953
954 #[test]
955 fn test_primitive_array_sum() {
956 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
957 assert_eq!(15, sum(&a).unwrap());
958 }
959
960 #[test]
961 fn test_primitive_array_float_sum() {
962 let a = Float64Array::from(vec![1.1, 2.2, 3.3, 4.4, 5.5]);
963 assert_eq!(16.5, sum(&a).unwrap());
964 }
965
966 #[test]
967 fn test_primitive_array_sum_with_nulls() {
968 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
969 assert_eq!(10, sum(&a).unwrap());
970 }
971
972 #[test]
973 fn test_primitive_array_sum_all_nulls() {
974 let a = Int32Array::from(vec![None, None, None]);
975 assert_eq!(None, sum(&a));
976 }
977
978 #[test]
979 fn test_primitive_array_sum_large_float_64() {
980 let c = Float64Array::new((1..=100).map(|x| x as f64).collect(), None);
981 assert_eq!(Some((1..=100).sum::<i64>() as f64), sum(&c));
982
983 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
985 let c = Float64Array::new((1..=100).map(|x| x as f64).collect(), Some(validity));
986
987 assert_eq!(
988 Some((1..=100).filter(|i| i % 3 == 0).sum::<i64>() as f64),
989 sum(&c)
990 );
991 }
992
993 #[test]
994 fn test_primitive_array_sum_large_float_32() {
995 let c = Float32Array::new((1..=100).map(|x| x as f32).collect(), None);
996 assert_eq!(Some((1..=100).sum::<i64>() as f32), sum(&c));
997
998 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1000 let c = Float32Array::new((1..=100).map(|x| x as f32).collect(), Some(validity));
1001
1002 assert_eq!(
1003 Some((1..=100).filter(|i| i % 3 == 0).sum::<i64>() as f32),
1004 sum(&c)
1005 );
1006 }
1007
1008 #[test]
1009 fn test_primitive_array_sum_large_64() {
1010 let c = Int64Array::new((1..=100).collect(), None);
1011 assert_eq!(Some((1..=100).sum()), sum(&c));
1012
1013 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1015 let c = Int64Array::new((1..=100).collect(), Some(validity));
1016
1017 assert_eq!(Some((1..=100).filter(|i| i % 3 == 0).sum()), sum(&c));
1018 }
1019
1020 #[test]
1021 fn test_primitive_array_sum_large_32() {
1022 let c = Int32Array::new((1..=100).collect(), None);
1023 assert_eq!(Some((1..=100).sum()), sum(&c));
1024
1025 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1027 let c = Int32Array::new((1..=100).collect(), Some(validity));
1028 assert_eq!(Some((1..=100).filter(|i| i % 3 == 0).sum()), sum(&c));
1029 }
1030
1031 #[test]
1032 fn test_primitive_array_sum_large_16() {
1033 let c = Int16Array::new((1..=100).collect(), None);
1034 assert_eq!(Some((1..=100).sum()), sum(&c));
1035
1036 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1038 let c = Int16Array::new((1..=100).collect(), Some(validity));
1039 assert_eq!(Some((1..=100).filter(|i| i % 3 == 0).sum()), sum(&c));
1040 }
1041
1042 #[test]
1043 fn test_primitive_array_sum_large_8() {
1044 let c = UInt8Array::new((1..=100).collect(), None);
1045 assert_eq!(
1046 Some((1..=100).fold(0_u8, |a, x| a.wrapping_add(x))),
1047 sum(&c)
1048 );
1049
1050 let validity = NullBuffer::new((1..=100).map(|x| x % 3 == 0).collect());
1052 let c = UInt8Array::new((1..=100).collect(), Some(validity));
1053 assert_eq!(
1054 Some(
1055 (1..=100)
1056 .filter(|i| i % 3 == 0)
1057 .fold(0_u8, |a, x| a.wrapping_add(x))
1058 ),
1059 sum(&c)
1060 );
1061 }
1062
1063 #[test]
1064 fn test_primitive_array_bit_and() {
1065 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1066 assert_eq!(0, bit_and(&a).unwrap());
1067 }
1068
1069 #[test]
1070 fn test_primitive_array_bit_and_with_nulls() {
1071 let a = Int32Array::from(vec![None, Some(2), Some(3), None, None]);
1072 assert_eq!(2, bit_and(&a).unwrap());
1073 }
1074
1075 #[test]
1076 fn test_primitive_array_bit_and_all_nulls() {
1077 let a = Int32Array::from(vec![None, None, None]);
1078 assert_eq!(None, bit_and(&a));
1079 }
1080
1081 #[test]
1082 fn test_primitive_array_bit_or() {
1083 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1084 assert_eq!(7, bit_or(&a).unwrap());
1085 }
1086
1087 #[test]
1088 fn test_primitive_array_bit_or_with_nulls() {
1089 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
1090 assert_eq!(7, bit_or(&a).unwrap());
1091 }
1092
1093 #[test]
1094 fn test_primitive_array_bit_or_all_nulls() {
1095 let a = Int32Array::from(vec![None, None, None]);
1096 assert_eq!(None, bit_or(&a));
1097 }
1098
1099 #[test]
1100 fn test_primitive_array_bit_xor() {
1101 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1102 assert_eq!(1, bit_xor(&a).unwrap());
1103 }
1104
1105 #[test]
1106 fn test_primitive_array_bit_xor_with_nulls() {
1107 let a = Int32Array::from(vec![None, Some(2), Some(3), None, Some(5)]);
1108 assert_eq!(4, bit_xor(&a).unwrap());
1109 }
1110
1111 #[test]
1112 fn test_primitive_array_bit_xor_all_nulls() {
1113 let a = Int32Array::from(vec![None, None, None]);
1114 assert_eq!(None, bit_xor(&a));
1115 }
1116
1117 #[test]
1118 fn test_primitive_array_bool_and() {
1119 let a = BooleanArray::from(vec![true, false, true, false, true]);
1120 assert!(!bool_and(&a).unwrap());
1121 }
1122
1123 #[test]
1124 fn test_primitive_array_bool_and_with_nulls() {
1125 let a = BooleanArray::from(vec![None, Some(true), Some(true), None, Some(true)]);
1126 assert!(bool_and(&a).unwrap());
1127 }
1128
1129 #[test]
1130 fn test_primitive_array_bool_and_all_nulls() {
1131 let a = BooleanArray::from(vec![None, None, None]);
1132 assert_eq!(None, bool_and(&a));
1133 }
1134
1135 #[test]
1136 fn test_primitive_array_bool_or() {
1137 let a = BooleanArray::from(vec![true, false, true, false, true]);
1138 assert!(bool_or(&a).unwrap());
1139 }
1140
1141 #[test]
1142 fn test_primitive_array_bool_or_with_nulls() {
1143 let a = BooleanArray::from(vec![None, Some(false), Some(false), None, Some(false)]);
1144 assert!(!bool_or(&a).unwrap());
1145 }
1146
1147 #[test]
1148 fn test_primitive_array_bool_or_all_nulls() {
1149 let a = BooleanArray::from(vec![None, None, None]);
1150 assert_eq!(None, bool_or(&a));
1151 }
1152
1153 #[test]
1154 fn test_primitive_array_min_max() {
1155 let a = Int32Array::from(vec![5, 6, 7, 8, 9]);
1156 assert_eq!(5, min(&a).unwrap());
1157 assert_eq!(9, max(&a).unwrap());
1158 }
1159
1160 #[test]
1161 fn test_primitive_array_min_max_with_nulls() {
1162 let a = Int32Array::from(vec![Some(5), None, None, Some(8), Some(9)]);
1163 assert_eq!(5, min(&a).unwrap());
1164 assert_eq!(9, max(&a).unwrap());
1165 }
1166
1167 #[test]
1168 fn test_primitive_min_max_1() {
1169 let a = Int32Array::from(vec![None, None, Some(5), Some(2)]);
1170 assert_eq!(Some(2), min(&a));
1171 assert_eq!(Some(5), max(&a));
1172 }
1173
1174 #[test]
1175 fn test_primitive_min_max_float_large_nonnull_array() {
1176 let a: Float64Array = (0..256).map(|i| Some((i + 1) as f64)).collect();
1177 assert_eq!(Some(1.0), min(&a));
1179 assert_eq!(Some(256.0), max(&a));
1180
1181 let a: Float64Array = (0..255).map(|i| Some((i + 1) as f64)).collect();
1183 assert_eq!(Some(255.0), max(&a));
1184
1185 let a: Float64Array = (0..257).map(|i| Some((i + 1) as f64)).collect();
1187 assert_eq!(Some(257.0), max(&a));
1188 }
1189
1190 #[test]
1191 fn test_primitive_min_max_float_large_nullable_array() {
1192 let a: Float64Array = (0..256)
1193 .map(|i| {
1194 if (i + 1) % 3 == 0 {
1195 None
1196 } else {
1197 Some((i + 1) as f64)
1198 }
1199 })
1200 .collect();
1201 assert_eq!(Some(1.0), min(&a));
1203 assert_eq!(Some(256.0), max(&a));
1204
1205 let a: Float64Array = (0..256)
1206 .map(|i| {
1207 if i == 0 || i == 255 {
1208 None
1209 } else {
1210 Some((i + 1) as f64)
1211 }
1212 })
1213 .collect();
1214 assert_eq!(Some(2.0), min(&a));
1216 assert_eq!(Some(255.0), max(&a));
1217
1218 let a: Float64Array = (0..256)
1219 .map(|i| if i != 100 { None } else { Some((i) as f64) })
1220 .collect();
1221 assert_eq!(Some(100.0), min(&a));
1223 assert_eq!(Some(100.0), max(&a));
1224
1225 let a: Float64Array = (0..255).map(|i| Some((i + 1) as f64)).collect();
1227 assert_eq!(Some(255.0), max(&a));
1228
1229 let a: Float64Array = (0..257).map(|i| Some((i + 1) as f64)).collect();
1231 assert_eq!(Some(257.0), max(&a));
1232 }
1233
1234 #[test]
1235 fn test_primitive_min_max_float_edge_cases() {
1236 let a: Float64Array = (0..100).map(|_| Some(f64::NEG_INFINITY)).collect();
1237 assert_eq!(Some(f64::NEG_INFINITY), min(&a));
1238 assert_eq!(Some(f64::NEG_INFINITY), max(&a));
1239
1240 let a: Float64Array = (0..100).map(|_| Some(f64::MIN)).collect();
1241 assert_eq!(Some(f64::MIN), min(&a));
1242 assert_eq!(Some(f64::MIN), max(&a));
1243
1244 let a: Float64Array = (0..100).map(|_| Some(f64::MAX)).collect();
1245 assert_eq!(Some(f64::MAX), min(&a));
1246 assert_eq!(Some(f64::MAX), max(&a));
1247
1248 let a: Float64Array = (0..100).map(|_| Some(f64::INFINITY)).collect();
1249 assert_eq!(Some(f64::INFINITY), min(&a));
1250 assert_eq!(Some(f64::INFINITY), max(&a));
1251 }
1252
1253 #[test]
1254 fn test_primitive_min_max_float_all_nans_non_null() {
1255 let a: Float64Array = (0..100).map(|_| Some(f64::NAN)).collect();
1256 assert!(max(&a).unwrap().is_nan());
1257 assert!(min(&a).unwrap().is_nan());
1258 }
1259
1260 #[test]
1261 fn test_primitive_min_max_float_negative_nan() {
1262 let a: Float64Array =
1263 Float64Array::from(vec![f64::NEG_INFINITY, f64::NAN, f64::INFINITY, -f64::NAN]);
1264 let max = max(&a).unwrap();
1265 let min = min(&a).unwrap();
1266 assert!(max.is_nan());
1267 assert!(max.is_sign_positive());
1268
1269 assert!(min.is_nan());
1270 assert!(min.is_sign_negative());
1271 }
1272
1273 #[test]
1274 fn test_primitive_min_max_float_first_nan_nonnull() {
1275 let a: Float64Array = (0..100)
1276 .map(|i| {
1277 if i == 0 {
1278 Some(f64::NAN)
1279 } else {
1280 Some(i as f64)
1281 }
1282 })
1283 .collect();
1284 assert_eq!(Some(1.0), min(&a));
1285 assert!(max(&a).unwrap().is_nan());
1286 }
1287
1288 #[test]
1289 fn test_primitive_min_max_float_last_nan_nonnull() {
1290 let a: Float64Array = (0..100)
1291 .map(|i| {
1292 if i == 99 {
1293 Some(f64::NAN)
1294 } else {
1295 Some((i + 1) as f64)
1296 }
1297 })
1298 .collect();
1299 assert_eq!(Some(1.0), min(&a));
1300 assert!(max(&a).unwrap().is_nan());
1301 }
1302
1303 #[test]
1304 fn test_primitive_min_max_float_first_nan_nullable() {
1305 let a: Float64Array = (0..100)
1306 .map(|i| {
1307 if i == 0 {
1308 Some(f64::NAN)
1309 } else if i % 2 == 0 {
1310 None
1311 } else {
1312 Some(i as f64)
1313 }
1314 })
1315 .collect();
1316 assert_eq!(Some(1.0), min(&a));
1317 assert!(max(&a).unwrap().is_nan());
1318 }
1319
1320 #[test]
1321 fn test_primitive_min_max_float_last_nan_nullable() {
1322 let a: Float64Array = (0..100)
1323 .map(|i| {
1324 if i == 99 {
1325 Some(f64::NAN)
1326 } else if i % 2 == 0 {
1327 None
1328 } else {
1329 Some(i as f64)
1330 }
1331 })
1332 .collect();
1333 assert_eq!(Some(1.0), min(&a));
1334 assert!(max(&a).unwrap().is_nan());
1335 }
1336
1337 #[test]
1338 fn test_primitive_min_max_float_inf_and_nans() {
1339 let a: Float64Array = (0..100)
1340 .map(|i| {
1341 let x = match i % 10 {
1342 0 => f64::NEG_INFINITY,
1343 1 => f64::MIN,
1344 2 => f64::MAX,
1345 4 => f64::INFINITY,
1346 5 => f64::NAN,
1347 _ => i as f64,
1348 };
1349 Some(x)
1350 })
1351 .collect();
1352 assert_eq!(Some(f64::NEG_INFINITY), min(&a));
1353 assert!(max(&a).unwrap().is_nan());
1354 }
1355
1356 fn pad_inputs_and_test_fixed_size_binary(
1357 input: Vec<Option<&[u8]>>,
1358 expected_min: Option<&[u8]>,
1359 expected_max: Option<&[u8]>,
1360 ) {
1361 fn pad_slice(slice: &[u8], len: usize) -> Vec<u8> {
1362 let mut padded = vec![0; len];
1363 padded[..slice.len()].copy_from_slice(slice);
1364 padded
1365 }
1366
1367 let max_len = input
1368 .iter()
1369 .filter_map(|x| x.as_ref().map(|b| b.len()))
1370 .max()
1371 .unwrap_or(0);
1372 let padded_input = input
1373 .iter()
1374 .map(|x| x.as_ref().map(|b| pad_slice(b, max_len)));
1375 let input_arr =
1376 FixedSizeBinaryArray::try_from_sparse_iter_with_size(padded_input, max_len as i32)
1377 .unwrap();
1378 let padded_expected_min = expected_min.map(|b| pad_slice(b, max_len));
1379 let padded_expected_max = expected_max.map(|b| pad_slice(b, max_len));
1380
1381 assert_eq!(
1382 padded_expected_min.as_deref(),
1383 min_fixed_size_binary(&input_arr)
1384 );
1385 assert_eq!(
1386 padded_expected_max.as_deref(),
1387 max_fixed_size_binary(&input_arr)
1388 );
1389 }
1390
1391 macro_rules! test_binary {
1392 ($NAME:ident, $ARRAY:expr, $EXPECTED_MIN:expr, $EXPECTED_MAX: expr) => {
1393 #[test]
1394 fn $NAME() {
1395 let binary = BinaryArray::from($ARRAY);
1396 assert_eq!($EXPECTED_MIN, min_binary(&binary));
1397 assert_eq!($EXPECTED_MAX, max_binary(&binary));
1398
1399 let large_binary = LargeBinaryArray::from($ARRAY);
1400 assert_eq!($EXPECTED_MIN, min_binary(&large_binary));
1401 assert_eq!($EXPECTED_MAX, max_binary(&large_binary));
1402
1403 let binary_view = BinaryViewArray::from($ARRAY);
1404 assert_eq!($EXPECTED_MIN, min_binary_view(&binary_view));
1405 assert_eq!($EXPECTED_MAX, max_binary_view(&binary_view));
1406
1407 pad_inputs_and_test_fixed_size_binary($ARRAY, $EXPECTED_MIN, $EXPECTED_MAX);
1408 }
1409 };
1410 }
1411
1412 test_binary!(
1413 test_binary_min_max_with_nulls,
1414 vec![
1415 Some("b01234567890123".as_bytes()), None,
1417 None,
1418 Some(b"a"),
1419 Some(b"c"),
1420 Some(b"abcdedfg0123456"),
1421 ],
1422 Some("a".as_bytes()),
1423 Some("c".as_bytes())
1424 );
1425
1426 test_binary!(
1427 test_binary_min_max_no_null,
1428 vec![
1429 Some("b".as_bytes()),
1430 Some(b"abcdefghijklmnopqrst"), Some(b"c"),
1432 Some(b"b01234567890123"), ],
1434 Some("abcdefghijklmnopqrst".as_bytes()),
1435 Some("c".as_bytes())
1436 );
1437
1438 test_binary!(test_binary_min_max_all_nulls, vec![None, None], None, None);
1439
1440 test_binary!(
1441 test_binary_min_max_1,
1442 vec![
1443 None,
1444 Some("b01234567890123435".as_bytes()), None,
1446 Some(b"b0123xxxxxxxxxxx"),
1447 Some(b"a")
1448 ],
1449 Some("a".as_bytes()),
1450 Some("b0123xxxxxxxxxxx".as_bytes())
1451 );
1452
1453 macro_rules! test_string {
1454 ($NAME:ident, $ARRAY:expr, $EXPECTED_MIN:expr, $EXPECTED_MAX: expr) => {
1455 #[test]
1456 fn $NAME() {
1457 let string = StringArray::from($ARRAY);
1458 assert_eq!($EXPECTED_MIN, min_string(&string));
1459 assert_eq!($EXPECTED_MAX, max_string(&string));
1460
1461 let large_string = LargeStringArray::from($ARRAY);
1462 assert_eq!($EXPECTED_MIN, min_string(&large_string));
1463 assert_eq!($EXPECTED_MAX, max_string(&large_string));
1464
1465 let string_view = StringViewArray::from($ARRAY);
1466 assert_eq!($EXPECTED_MIN, min_string_view(&string_view));
1467 assert_eq!($EXPECTED_MAX, max_string_view(&string_view));
1468 }
1469 };
1470 }
1471
1472 test_string!(
1473 test_string_min_max_with_nulls,
1474 vec![
1475 Some("b012345678901234"), None,
1477 None,
1478 Some("a"),
1479 Some("c"),
1480 Some("b0123xxxxxxxxxxx")
1481 ],
1482 Some("a"),
1483 Some("c")
1484 );
1485
1486 test_string!(
1487 test_string_min_max_no_null,
1488 vec![
1489 Some("b"),
1490 Some("b012345678901234"), Some("a"),
1492 Some("b012xxxxxxxxxxxx")
1493 ],
1494 Some("a"),
1495 Some("b012xxxxxxxxxxxx")
1496 );
1497
1498 test_string!(
1499 test_string_min_max_all_nulls,
1500 Vec::<Option<&str>>::from_iter([None, None]),
1501 None,
1502 None
1503 );
1504
1505 test_string!(
1506 test_string_min_max_1,
1507 vec![
1508 None,
1509 Some("c12345678901234"), None,
1511 Some("b"),
1512 Some("c1234xxxxxxxxxx")
1513 ],
1514 Some("b"),
1515 Some("c1234xxxxxxxxxx")
1516 );
1517
1518 test_string!(
1519 test_string_min_max_empty,
1520 Vec::<Option<&str>>::new(),
1521 None,
1522 None
1523 );
1524
1525 #[test]
1526 fn test_boolean_min_max_empty() {
1527 let a = BooleanArray::from(vec![] as Vec<Option<bool>>);
1528 assert_eq!(None, min_boolean(&a));
1529 assert_eq!(None, max_boolean(&a));
1530 }
1531
1532 #[test]
1533 fn test_boolean_min_max_all_null() {
1534 let a = BooleanArray::from(vec![None, None]);
1535 assert_eq!(None, min_boolean(&a));
1536 assert_eq!(None, max_boolean(&a));
1537 }
1538
1539 #[test]
1540 fn test_boolean_min_max_no_null() {
1541 let a = BooleanArray::from(vec![Some(true), Some(false), Some(true)]);
1542 assert_eq!(Some(false), min_boolean(&a));
1543 assert_eq!(Some(true), max_boolean(&a));
1544 }
1545
1546 #[test]
1547 fn test_boolean_min_max() {
1548 let a = BooleanArray::from(vec![Some(true), Some(true), None, Some(false), None]);
1549 assert_eq!(Some(false), min_boolean(&a));
1550 assert_eq!(Some(true), max_boolean(&a));
1551
1552 let a = BooleanArray::from(vec![None, Some(true), None, Some(false), None]);
1553 assert_eq!(Some(false), min_boolean(&a));
1554 assert_eq!(Some(true), max_boolean(&a));
1555
1556 let a = BooleanArray::from(vec![Some(false), Some(true), None, Some(false), None]);
1557 assert_eq!(Some(false), min_boolean(&a));
1558 assert_eq!(Some(true), max_boolean(&a));
1559
1560 let a = BooleanArray::from(vec![Some(true), None]);
1561 assert_eq!(Some(true), min_boolean(&a));
1562 assert_eq!(Some(true), max_boolean(&a));
1563
1564 let a = BooleanArray::from(vec![Some(false), None]);
1565 assert_eq!(Some(false), min_boolean(&a));
1566 assert_eq!(Some(false), max_boolean(&a));
1567
1568 let a = BooleanArray::from(vec![Some(true)]);
1569 assert_eq!(Some(true), min_boolean(&a));
1570 assert_eq!(Some(true), max_boolean(&a));
1571
1572 let a = BooleanArray::from(vec![Some(false)]);
1573 assert_eq!(Some(false), min_boolean(&a));
1574 assert_eq!(Some(false), max_boolean(&a));
1575 }
1576
1577 #[test]
1578 fn test_boolean_min_max_smaller() {
1579 let a = BooleanArray::from(vec![Some(false)]);
1580 assert_eq!(Some(false), min_boolean(&a));
1581 assert_eq!(Some(false), max_boolean(&a));
1582
1583 let a = BooleanArray::from(vec![None, Some(false)]);
1584 assert_eq!(Some(false), min_boolean(&a));
1585 assert_eq!(Some(false), max_boolean(&a));
1586
1587 let a = BooleanArray::from(vec![None, Some(true)]);
1588 assert_eq!(Some(true), min_boolean(&a));
1589 assert_eq!(Some(true), max_boolean(&a));
1590
1591 let a = BooleanArray::from(vec![Some(true)]);
1592 assert_eq!(Some(true), min_boolean(&a));
1593 assert_eq!(Some(true), max_boolean(&a));
1594 }
1595
1596 #[test]
1597 fn test_boolean_min_max_64_true_64_false() {
1598 let mut no_nulls = BooleanBuilder::new();
1599 no_nulls.append_slice(&[true; 64]);
1600 no_nulls.append_slice(&[false; 64]);
1601 let no_nulls = no_nulls.finish();
1602
1603 assert_eq!(Some(false), min_boolean(&no_nulls));
1604 assert_eq!(Some(true), max_boolean(&no_nulls));
1605
1606 let mut with_nulls = BooleanBuilder::new();
1607 with_nulls.append_slice(&[true; 31]);
1608 with_nulls.append_null();
1609 with_nulls.append_slice(&[true; 32]);
1610 with_nulls.append_slice(&[false; 1]);
1611 with_nulls.append_nulls(63);
1612 let with_nulls = with_nulls.finish();
1613
1614 assert_eq!(Some(false), min_boolean(&with_nulls));
1615 assert_eq!(Some(true), max_boolean(&with_nulls));
1616 }
1617
1618 #[test]
1619 fn test_boolean_min_max_64_false_64_true() {
1620 let mut no_nulls = BooleanBuilder::new();
1621 no_nulls.append_slice(&[false; 64]);
1622 no_nulls.append_slice(&[true; 64]);
1623 let no_nulls = no_nulls.finish();
1624
1625 assert_eq!(Some(false), min_boolean(&no_nulls));
1626 assert_eq!(Some(true), max_boolean(&no_nulls));
1627
1628 let mut with_nulls = BooleanBuilder::new();
1629 with_nulls.append_slice(&[false; 31]);
1630 with_nulls.append_null();
1631 with_nulls.append_slice(&[false; 32]);
1632 with_nulls.append_slice(&[true; 1]);
1633 with_nulls.append_nulls(63);
1634 let with_nulls = with_nulls.finish();
1635
1636 assert_eq!(Some(false), min_boolean(&with_nulls));
1637 assert_eq!(Some(true), max_boolean(&with_nulls));
1638 }
1639
1640 #[test]
1641 fn test_boolean_min_max_96_true() {
1642 let mut no_nulls = BooleanBuilder::new();
1643 no_nulls.append_slice(&[true; 96]);
1644 let no_nulls = no_nulls.finish();
1645
1646 assert_eq!(Some(true), min_boolean(&no_nulls));
1647 assert_eq!(Some(true), max_boolean(&no_nulls));
1648
1649 let mut with_nulls = BooleanBuilder::new();
1650 with_nulls.append_slice(&[true; 31]);
1651 with_nulls.append_null();
1652 with_nulls.append_slice(&[true; 32]);
1653 with_nulls.append_slice(&[true; 31]);
1654 with_nulls.append_null();
1655 let with_nulls = with_nulls.finish();
1656
1657 assert_eq!(Some(true), min_boolean(&with_nulls));
1658 assert_eq!(Some(true), max_boolean(&with_nulls));
1659 }
1660
1661 #[test]
1662 fn test_boolean_min_max_96_false() {
1663 let mut no_nulls = BooleanBuilder::new();
1664 no_nulls.append_slice(&[false; 96]);
1665 let no_nulls = no_nulls.finish();
1666
1667 assert_eq!(Some(false), min_boolean(&no_nulls));
1668 assert_eq!(Some(false), max_boolean(&no_nulls));
1669
1670 let mut with_nulls = BooleanBuilder::new();
1671 with_nulls.append_slice(&[false; 31]);
1672 with_nulls.append_null();
1673 with_nulls.append_slice(&[false; 32]);
1674 with_nulls.append_slice(&[false; 31]);
1675 with_nulls.append_null();
1676 let with_nulls = with_nulls.finish();
1677
1678 assert_eq!(Some(false), min_boolean(&with_nulls));
1679 assert_eq!(Some(false), max_boolean(&with_nulls));
1680 }
1681
1682 #[test]
1683 fn test_sum_dyn() {
1684 let values = Int8Array::from_iter_values([10_i8, 11, 12, 13, 14, 15, 16, 17]);
1685 let values = Arc::new(values) as ArrayRef;
1686 let keys = Int8Array::from_iter_values([2_i8, 3, 4]);
1687
1688 let dict_array = DictionaryArray::new(keys, values.clone());
1689 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1690 assert_eq!(39, sum_array::<Int8Type, _>(array).unwrap());
1691
1692 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1693 assert_eq!(15, sum_array::<Int32Type, _>(&a).unwrap());
1694
1695 let keys = Int8Array::from(vec![Some(2_i8), None, Some(4)]);
1696 let dict_array = DictionaryArray::new(keys, values.clone());
1697 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1698 assert_eq!(26, sum_array::<Int8Type, _>(array).unwrap());
1699
1700 let keys = Int8Array::from(vec![None, None, None]);
1701 let dict_array = DictionaryArray::new(keys, values.clone());
1702 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1703 assert!(sum_array::<Int8Type, _>(array).is_none());
1704 }
1705
1706 #[test]
1707 fn test_max_min_dyn() {
1708 let values = Int8Array::from_iter_values([10_i8, 11, 12, 13, 14, 15, 16, 17]);
1709 let keys = Int8Array::from_iter_values([2_i8, 3, 4]);
1710 let values = Arc::new(values) as ArrayRef;
1711
1712 let dict_array = DictionaryArray::new(keys, values.clone());
1713 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1714 assert_eq!(14, max_array::<Int8Type, _>(array).unwrap());
1715
1716 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1717 assert_eq!(12, min_array::<Int8Type, _>(array).unwrap());
1718
1719 let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
1720 assert_eq!(5, max_array::<Int32Type, _>(&a).unwrap());
1721 assert_eq!(1, min_array::<Int32Type, _>(&a).unwrap());
1722
1723 let keys = Int8Array::from(vec![Some(2_i8), None, Some(7)]);
1724 let dict_array = DictionaryArray::new(keys, values.clone());
1725 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1726 assert_eq!(17, max_array::<Int8Type, _>(array).unwrap());
1727 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1728 assert_eq!(12, min_array::<Int8Type, _>(array).unwrap());
1729
1730 let keys = Int8Array::from(vec![None, None, None]);
1731 let dict_array = DictionaryArray::new(keys, values.clone());
1732 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1733 assert!(max_array::<Int8Type, _>(array).is_none());
1734 let array = dict_array.downcast_dict::<Int8Array>().unwrap();
1735 assert!(min_array::<Int8Type, _>(array).is_none());
1736 }
1737
1738 #[test]
1739 fn test_max_min_dyn_nan() {
1740 let values = Float32Array::from(vec![5.0_f32, 2.0_f32, f32::NAN]);
1741 let keys = Int8Array::from_iter_values([0_i8, 1, 2]);
1742
1743 let dict_array = DictionaryArray::new(keys, Arc::new(values));
1744 let array = dict_array.downcast_dict::<Float32Array>().unwrap();
1745 assert!(max_array::<Float32Type, _>(array).unwrap().is_nan());
1746
1747 let array = dict_array.downcast_dict::<Float32Array>().unwrap();
1748 assert_eq!(2.0_f32, min_array::<Float32Type, _>(array).unwrap());
1749 }
1750
1751 #[test]
1752 fn test_min_max_sliced_primitive() {
1753 let expected = Some(4.0);
1754 let input: Float64Array = vec![None, Some(4.0)].into_iter().collect();
1755 let actual = min(&input);
1756 assert_eq!(actual, expected);
1757 let actual = max(&input);
1758 assert_eq!(actual, expected);
1759
1760 let sliced_input: Float64Array = vec![None, None, None, None, None, Some(4.0)]
1761 .into_iter()
1762 .collect();
1763 let sliced_input = sliced_input.slice(4, 2);
1764
1765 assert_eq!(&sliced_input, &input);
1766
1767 let actual = min(&sliced_input);
1768 assert_eq!(actual, expected);
1769 let actual = max(&sliced_input);
1770 assert_eq!(actual, expected);
1771 }
1772
1773 #[test]
1774 fn test_min_max_sliced_boolean() {
1775 let expected = Some(true);
1776 let input: BooleanArray = vec![None, Some(true)].into_iter().collect();
1777 let actual = min_boolean(&input);
1778 assert_eq!(actual, expected);
1779 let actual = max_boolean(&input);
1780 assert_eq!(actual, expected);
1781
1782 let sliced_input: BooleanArray = vec![None, None, None, None, None, Some(true)]
1783 .into_iter()
1784 .collect();
1785 let sliced_input = sliced_input.slice(4, 2);
1786
1787 assert_eq!(sliced_input, input);
1788
1789 let actual = min_boolean(&sliced_input);
1790 assert_eq!(actual, expected);
1791 let actual = max_boolean(&sliced_input);
1792 assert_eq!(actual, expected);
1793 }
1794
1795 #[test]
1796 fn test_min_max_sliced_string() {
1797 let expected = Some("foo");
1798 let input: StringArray = vec![None, Some("foo")].into_iter().collect();
1799 let actual = min_string(&input);
1800 assert_eq!(actual, expected);
1801 let actual = max_string(&input);
1802 assert_eq!(actual, expected);
1803
1804 let sliced_input: StringArray = vec![None, None, None, None, None, Some("foo")]
1805 .into_iter()
1806 .collect();
1807 let sliced_input = sliced_input.slice(4, 2);
1808
1809 assert_eq!(&sliced_input, &input);
1810
1811 let actual = min_string(&sliced_input);
1812 assert_eq!(actual, expected);
1813 let actual = max_string(&sliced_input);
1814 assert_eq!(actual, expected);
1815 }
1816
1817 #[test]
1818 fn test_min_max_sliced_binary() {
1819 let expected: Option<&[u8]> = Some(&[5]);
1820 let input: BinaryArray = vec![None, Some(&[5])].into_iter().collect();
1821 let actual = min_binary(&input);
1822 assert_eq!(actual, expected);
1823 let actual = max_binary(&input);
1824 assert_eq!(actual, expected);
1825
1826 let sliced_input: BinaryArray = vec![None, None, None, None, None, Some(&[5])]
1827 .into_iter()
1828 .collect();
1829 let sliced_input = sliced_input.slice(4, 2);
1830
1831 assert_eq!(&sliced_input, &input);
1832
1833 let actual = min_binary(&sliced_input);
1834 assert_eq!(actual, expected);
1835 let actual = max_binary(&sliced_input);
1836 assert_eq!(actual, expected);
1837 }
1838
1839 #[test]
1840 fn test_sum_overflow() {
1841 let a = Int32Array::from(vec![i32::MAX, 1]);
1842
1843 assert_eq!(sum(&a).unwrap(), -2147483648);
1844 assert_eq!(sum_array::<Int32Type, _>(&a).unwrap(), -2147483648);
1845 }
1846
1847 #[test]
1848 fn test_sum_checked_overflow() {
1849 let a = Int32Array::from(vec![i32::MAX, 1]);
1850
1851 sum_checked(&a).expect_err("overflow should be detected");
1852 sum_array_checked::<Int32Type, _>(&a).expect_err("overflow should be detected");
1853 }
1854
1855 fn make_run_array<'a, I: RunEndIndexType, V: ArrowNumericType, ItemType>(
1857 values: impl IntoIterator<Item = &'a ItemType>,
1858 ) -> RunArray<I>
1859 where
1860 ItemType: Clone + Into<Option<V::Native>> + 'static,
1861 {
1862 let mut builder = arrow_array::builder::PrimitiveRunBuilder::<I, V>::new();
1863 for v in values.into_iter() {
1864 builder.append_option((*v).clone().into());
1865 }
1866 builder.finish()
1867 }
1868
1869 #[test]
1870 fn test_ree_sum_array_basic() {
1871 let run_array = make_run_array::<Int16Type, Int32Type, _>(&[10, 10, 20, 30, 30, 30]);
1872 let typed_array = run_array.downcast::<Int32Array>().unwrap();
1873
1874 let result = sum_array::<Int32Type, _>(typed_array);
1875 assert_eq!(result, Some(130));
1876
1877 let result = sum_array_checked::<Int32Type, _>(typed_array).unwrap();
1878 assert_eq!(result, Some(130));
1879 }
1880
1881 #[test]
1882 fn test_ree_sum_array_empty() {
1883 let run_array = make_run_array::<Int16Type, Int32Type, i32>(&[]);
1884 let typed_array = run_array.downcast::<Int32Array>().unwrap();
1885
1886 let result = sum_array::<Int32Type, _>(typed_array);
1887 assert_eq!(result, None);
1888
1889 let result = sum_array_checked::<Int32Type, _>(typed_array).unwrap();
1890 assert_eq!(result, None);
1891 }
1892
1893 #[test]
1894 fn test_ree_sum_array_with_nulls() {
1895 let run_array =
1896 make_run_array::<Int16Type, Int32Type, _>(&[Some(10), None, Some(20), None, Some(30)]);
1897 let typed_array = run_array.downcast::<Int32Array>().unwrap();
1898
1899 let result = sum_array::<Int32Type, _>(typed_array);
1900 assert_eq!(result, Some(60));
1901
1902 let result = sum_array_checked::<Int32Type, _>(typed_array).unwrap();
1903 assert_eq!(result, Some(60));
1904 }
1905
1906 #[test]
1907 fn test_ree_sum_array_with_only_nulls() {
1908 let run_array = make_run_array::<Int16Type, Int16Type, _>(&[None, None, None, None, None]);
1909 let typed_array = run_array.downcast::<Int16Array>().unwrap();
1910
1911 let result = sum_array::<Int16Type, _>(typed_array);
1912 assert_eq!(result, None);
1913
1914 let result = sum_array_checked::<Int16Type, _>(typed_array).unwrap();
1915 assert_eq!(result, None);
1916 }
1917
1918 #[test]
1919 fn test_ree_sum_array_overflow() {
1920 let run_array = make_run_array::<Int16Type, Int8Type, _>(&[126, 2]);
1921 let typed_array = run_array.downcast::<Int8Array>().unwrap();
1922
1923 let result = sum_array::<Int8Type, _>(typed_array);
1925 assert_eq!(result, Some(-128));
1926
1927 let result = sum_array_checked::<Int8Type, _>(typed_array);
1928 assert!(result.is_err());
1929 }
1930
1931 #[test]
1932 fn test_ree_sum_array_sliced() {
1933 let run_array = make_run_array::<Int16Type, UInt8Type, _>(&[0, 10, 10, 10, 20, 30, 30, 30]);
1934 let sliced = run_array.slice(2, 5);
1936 let typed_array = sliced.downcast::<UInt8Array>().unwrap();
1937
1938 let result = sum_array::<UInt8Type, _>(typed_array);
1939 assert_eq!(result, Some(100));
1940
1941 let result = sum_array_checked::<UInt8Type, _>(typed_array).unwrap();
1942 assert_eq!(result, Some(100));
1943 }
1944
1945 #[test]
1946 fn test_ree_min_max_array_basic() {
1947 let run_array = make_run_array::<Int16Type, Int32Type, _>(&[30, 30, 10, 20, 20]);
1948 let typed_array = run_array.downcast::<Int32Array>().unwrap();
1949
1950 let result = min_array::<Int32Type, _>(typed_array);
1951 assert_eq!(result, Some(10));
1952
1953 let result = max_array::<Int32Type, _>(typed_array);
1954 assert_eq!(result, Some(30));
1955 }
1956
1957 #[test]
1958 fn test_ree_min_max_array_empty() {
1959 let run_array = make_run_array::<Int16Type, Int32Type, i32>(&[]);
1960 let typed_array = run_array.downcast::<Int32Array>().unwrap();
1961
1962 let result = min_array::<Int32Type, _>(typed_array);
1963 assert_eq!(result, None);
1964
1965 let result = max_array::<Int32Type, _>(typed_array);
1966 assert_eq!(result, None);
1967 }
1968
1969 #[test]
1970 fn test_ree_min_max_array_float() {
1971 let run_array = make_run_array::<Int16Type, Float64Type, _>(&[5.5, 5.5, 2.1, 8.9, 8.9]);
1972 let typed_array = run_array.downcast::<Float64Array>().unwrap();
1973
1974 let result = min_array::<Float64Type, _>(typed_array);
1975 assert_eq!(result, Some(2.1));
1976
1977 let result = max_array::<Float64Type, _>(typed_array);
1978 assert_eq!(result, Some(8.9));
1979 }
1980
1981 #[test]
1982 fn test_ree_min_max_array_with_nulls() {
1983 let run_array = make_run_array::<Int16Type, UInt8Type, _>(&[None, Some(10)]);
1984 let typed_array = run_array.downcast::<UInt8Array>().unwrap();
1985
1986 let result = min_array::<UInt8Type, _>(typed_array);
1987 assert_eq!(result, Some(10));
1988
1989 let result = max_array::<UInt8Type, _>(typed_array);
1990 assert_eq!(result, Some(10));
1991 }
1992
1993 #[test]
1994 fn test_ree_min_max_array_sliced() {
1995 let run_array = make_run_array::<Int16Type, Int32Type, _>(&[0, 30, 30, 10, 20, 20, 100]);
1996 let sliced = run_array.slice(1, 5);
1998 let typed_array = sliced.downcast::<Int32Array>().unwrap();
1999
2000 let result = min_array::<Int32Type, _>(typed_array);
2001 assert_eq!(result, Some(10));
2002
2003 let result = max_array::<Int32Type, _>(typed_array);
2004 assert_eq!(result, Some(30));
2005 }
2006
2007 #[test]
2008 fn test_ree_min_max_array_sliced_mid_run() {
2009 let run_array = make_run_array::<Int16Type, Int32Type, _>(&[0, 0, 30, 10, 20, 100, 100]);
2010 let sliced = run_array.slice(1, 5);
2012 let typed_array = sliced.downcast::<Int32Array>().unwrap();
2013
2014 let result = min_array::<Int32Type, _>(typed_array);
2015 assert_eq!(result, Some(0));
2016
2017 let result = max_array::<Int32Type, _>(typed_array);
2018 assert_eq!(result, Some(100));
2019 }
2020}