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