1use std::any::type_name;
5use std::fmt::Debug;
6use std::fmt::Formatter;
7use std::hash::Hash;
8use std::hash::Hasher;
9use std::ops::Range;
10use std::ptr;
11use std::sync::Arc;
12
13use vortex_buffer::ByteBuffer;
14use vortex_error::VortexExpect;
15use vortex_error::VortexResult;
16use vortex_error::vortex_ensure;
17use vortex_error::vortex_ensure_eq;
18use vortex_error::vortex_err;
19use vortex_error::vortex_panic;
20use vortex_mask::Mask;
21
22use crate::AnyCanonical;
23use crate::Array;
24use crate::ArrayEq;
25use crate::ArrayHash;
26use crate::ArrayView;
27use crate::Canonical;
28use crate::ExecutionCtx;
29use crate::ExecutionResult;
30use crate::IntoArray;
31use crate::VTable;
32use crate::aggregate_fn::fns::sum::sum;
33use crate::array::ArrayData;
34use crate::array::ArrayId;
35use crate::array::ArrayInner;
36use crate::array::ArraySlots;
37use crate::array::DynArrayData;
38use crate::array::probe::ArrayProbe;
39use crate::array::probe::RepeatedArrayProbe;
40use crate::arrays::Constant;
41use crate::arrays::DictArray;
42use crate::arrays::FilterArray;
43use crate::arrays::SliceArray;
44use crate::buffer::BufferHandle;
45use crate::builders::ArrayBuilder;
46use crate::dtype::DType;
47use crate::expr::stats::Precision;
48use crate::expr::stats::Stat;
49use crate::expr::stats::StatsProviderExt;
50use crate::matcher::Matcher;
51use crate::optimizer::ArrayOptimizer;
52use crate::scalar::Scalar;
53use crate::scalar::ScalarValue;
54use crate::stats::StatsSetRef;
55use crate::validity::Validity;
56
57pub struct DepthFirstArrayIterator {
59 stack: Vec<ArrayRef>,
60}
61
62impl Iterator for DepthFirstArrayIterator {
63 type Item = ArrayRef;
64
65 fn next(&mut self) -> Option<Self::Item> {
66 let next = self.stack.pop()?;
67 for child in next.children().into_iter().rev() {
68 self.stack.push(child);
69 }
70 Some(next)
71 }
72}
73
74#[derive(Clone)]
80pub struct ArrayRef(Arc<ArrayInner<dyn DynArrayData>>);
81
82impl ArrayRef {
83 pub(crate) fn from_inner<D: DynArrayData>(inner: Arc<ArrayInner<D>>) -> Self {
85 Self(inner)
86 }
87
88 #[allow(clippy::inline_always)]
90 #[inline(always)]
91 pub(crate) fn dyn_array(&self) -> &dyn DynArrayData {
92 &self.0.data
93 }
94
95 #[allow(clippy::inline_always)]
97 #[inline(always)]
98 pub(crate) fn inner_mut(&mut self) -> Option<&mut ArrayInner<dyn DynArrayData>> {
99 Arc::get_mut(&mut self.0)
100 }
101
102 #[doc(hidden)]
105 pub fn addr(&self) -> usize {
106 Arc::as_ptr(&self.0).addr()
107 }
108
109 #[allow(dead_code)]
113 pub(crate) fn downcast_inner<V: VTable>(self) -> Result<Arc<ArrayInner<ArrayData<V>>>, Self> {
114 if self.0.data.as_any().is::<ArrayData<V>>() {
116 Ok(unsafe { self.downcast_inner_unchecked() })
117 } else {
118 Err(self)
119 }
120 }
121
122 #[allow(clippy::inline_always)]
127 #[inline(always)]
128 pub(crate) unsafe fn downcast_inner_unchecked<V: VTable>(
129 self,
130 ) -> Arc<ArrayInner<ArrayData<V>>> {
131 debug_assert!(self.0.data.as_any().is::<ArrayData<V>>());
132 let raw = Arc::into_raw(self.0);
136 unsafe { Arc::from_raw(raw.cast::<ArrayInner<ArrayData<V>>>()) }
138 }
139
140 pub fn ptr_eq(this: &ArrayRef, other: &ArrayRef) -> bool {
142 Arc::ptr_eq(&this.0, &other.0)
143 }
144}
145
146impl Debug for ArrayRef {
147 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
148 f.debug_struct("Array")
149 .field("encoding", &self.0.encoding_id)
150 .field("dtype", &self.0.dtype)
151 .field("len", &self.0.len)
152 .field("data", &self.0.data)
153 .finish()
154 }
155}
156
157impl ArrayHash for ArrayRef {
158 fn array_hash<H: Hasher>(&self, state: &mut H, accuracy: crate::EqMode) {
159 self.0.len.hash(state);
160 self.0.dtype.hash(state);
161 self.0.encoding_id.hash(state);
162 self.0.slots.len().hash(state);
163 for slot in &self.0.slots {
164 slot.array_hash(state, accuracy);
165 }
166 self.0
167 .data
168 .dyn_array_hash(state as &mut dyn Hasher, accuracy);
169 }
170}
171
172impl ArrayEq for ArrayRef {
173 fn array_eq(&self, other: &Self, accuracy: crate::EqMode) -> bool {
174 self.0.len == other.0.len
175 && self.0.dtype == other.0.dtype
176 && self.0.encoding_id == other.0.encoding_id
177 && self.0.slots.len() == other.0.slots.len()
178 && self
179 .0
180 .slots
181 .iter()
182 .zip(other.0.slots.iter())
183 .all(|(slot, other_slot)| slot.array_eq(other_slot, accuracy))
184 && self.0.data.dyn_array_eq(other, accuracy)
185 }
186}
187impl ArrayRef {
188 #[inline]
190 pub fn len(&self) -> usize {
191 self.0.len
192 }
193
194 #[inline]
196 pub fn is_empty(&self) -> bool {
197 self.0.len == 0
198 }
199
200 #[inline]
202 pub fn dtype(&self) -> &DType {
203 &self.0.dtype
204 }
205
206 #[inline]
208 pub fn encoding_id(&self) -> ArrayId {
209 self.0.encoding_id
210 }
211
212 pub fn slice(&self, range: Range<usize>) -> VortexResult<ArrayRef> {
214 let len = self.len();
215 let start = range.start;
216 let stop = range.end;
217
218 if start == 0 && stop == len {
219 return Ok(self.clone());
220 }
221
222 vortex_ensure!(start <= len, "OutOfBounds: start {start} > length {}", len);
223 vortex_ensure!(stop <= len, "OutOfBounds: stop {stop} > length {}", len);
224
225 vortex_ensure!(start <= stop, "start ({start}) must be <= stop ({stop})");
226
227 if start == stop {
228 return Ok(Canonical::empty(self.dtype()).into_array());
229 }
230
231 let sliced = SliceArray::try_new(self.clone(), range)?
232 .into_array()
233 .optimize()?;
234
235 if !sliced.is::<Constant>() {
237 self.statistics().with_iter(|iter| {
238 sliced.statistics().inherit(iter.filter(|(stat, value)| {
239 matches!(
240 stat,
241 Stat::IsConstant | Stat::IsSorted | Stat::IsStrictSorted
242 ) && value
243 .as_ref()
244 .as_exact()
245 .is_some_and(|v| matches!(v, ScalarValue::Bool(true)))
246 }));
247 });
248 }
249
250 Ok(sliced)
251 }
252
253 pub fn filter(&self, mask: Mask) -> VortexResult<ArrayRef> {
255 FilterArray::try_new(self.clone(), mask)?
256 .into_array()
257 .optimize()
258 }
259
260 pub fn take(&self, indices: ArrayRef) -> VortexResult<ArrayRef> {
262 DictArray::try_new(indices, self.clone())?
263 .into_array()
264 .optimize()
265 }
266
267 #[inline]
272 pub fn execute_scalar(&self, index: usize, ctx: &mut ExecutionCtx) -> VortexResult<Scalar> {
273 self.probe().execute_scalar(index, ctx)
274 }
275
276 #[inline]
289 pub fn probe(&self) -> ArrayProbe<'_> {
290 ArrayProbe::Once(self)
291 }
292
293 pub fn repeated_probe(&self) -> RepeatedArrayProbe {
308 RepeatedArrayProbe::new(self.clone())
309 }
310
311 #[inline]
316 pub fn is_valid(&self, index: usize, ctx: &mut ExecutionCtx) -> VortexResult<bool> {
317 self.probe().execute_is_valid(index, ctx)
318 }
319
320 #[inline]
323 pub fn is_invalid(&self, index: usize, ctx: &mut ExecutionCtx) -> VortexResult<bool> {
324 Ok(!self.is_valid(index, ctx)?)
325 }
326
327 pub fn all_valid(&self, ctx: &mut ExecutionCtx) -> VortexResult<bool> {
329 if self.is_empty() {
330 return Ok(true);
331 }
332
333 match self.validity()? {
334 Validity::NonNullable | Validity::AllValid => Ok(true),
335 Validity::AllInvalid => Ok(false),
336 Validity::Array(a) => Ok(a.statistics().compute_min::<bool>(ctx).unwrap_or(false)),
337 }
338 }
339
340 pub fn all_invalid(&self, ctx: &mut ExecutionCtx) -> VortexResult<bool> {
342 if self.is_empty() {
343 return Ok(true);
344 }
345
346 match self.validity()? {
347 Validity::NonNullable | Validity::AllValid => Ok(false),
348 Validity::AllInvalid => Ok(true),
349 Validity::Array(a) => Ok(!a.statistics().compute_max::<bool>(ctx).unwrap_or(true)),
350 }
351 }
352
353 pub fn valid_count(&self, ctx: &mut ExecutionCtx) -> VortexResult<usize> {
355 let len = self.len();
356 if let Precision::Exact(invalid_count) = self.statistics().get_as::<usize>(Stat::NullCount)
357 {
358 return Ok(len - invalid_count);
359 }
360
361 let count = match self.validity()? {
362 Validity::NonNullable | Validity::AllValid => len,
363 Validity::AllInvalid => 0,
364 Validity::Array(a) => {
365 let array_sum = sum(&a, ctx)?;
366 array_sum
367 .as_primitive()
368 .as_::<usize>()
369 .ok_or_else(|| vortex_err!("sum of validity array is null"))?
370 }
371 };
372 vortex_ensure!(count <= len, "Valid count exceeds array length");
373
374 self.statistics()
375 .set(Stat::NullCount, Precision::exact(len - count));
376
377 Ok(count)
378 }
379
380 pub fn invalid_count(&self, ctx: &mut ExecutionCtx) -> VortexResult<usize> {
382 Ok(self.len() - self.valid_count(ctx)?)
383 }
384
385 pub fn validity(&self) -> VortexResult<Validity> {
387 self.0.data.validity(self)
388 }
389
390 pub fn append_to_builder(
392 &self,
393 builder: &mut dyn ArrayBuilder,
394 ctx: &mut ExecutionCtx,
395 ) -> VortexResult<()> {
396 self.0.data.append_to_builder(self, builder, ctx)
397 }
398
399 pub fn statistics(&self) -> StatsSetRef<'_> {
401 self.0.stats.to_ref(self)
402 }
403
404 #[inline]
406 pub fn is<M: Matcher>(&self) -> bool {
407 M::matches(self)
408 }
409
410 #[inline]
412 pub fn as_<M: Matcher>(&self) -> M::Match<'_> {
413 self.as_opt::<M>().vortex_expect("Failed to downcast")
414 }
415
416 #[inline]
418 pub fn as_opt<M: Matcher>(&self) -> Option<M::Match<'_>> {
419 M::try_match(self)
420 }
421
422 pub fn try_downcast<V: VTable>(self) -> Result<Array<V>, ArrayRef> {
424 Array::<V>::try_from_array_ref(self)
425 }
426
427 pub fn downcast<V: VTable>(self) -> Array<V> {
433 Self::try_downcast(self)
434 .unwrap_or_else(|_| vortex_panic!("Failed to downcast to {}", type_name::<V>()))
435 }
436
437 pub fn as_typed<V: VTable>(&self) -> Option<ArrayView<'_, V>> {
439 let inner = self.0.data.as_any().downcast_ref::<ArrayData<V>>()?;
440 Some(unsafe { ArrayView::new_unchecked(self, &inner.data) })
441 }
442
443 #[inline]
448 pub(crate) unsafe fn as_typed_unchecked<V: VTable>(&self) -> ArrayView<'_, V> {
449 debug_assert!(self.is::<V>());
450 let inner = unsafe { &*ptr::from_ref(self.dyn_array()).cast::<ArrayData<V>>() };
453 unsafe { ArrayView::new_unchecked(self, &inner.data) }
455 }
456
457 pub fn as_constant(&self) -> Option<Scalar> {
459 self.as_opt::<Constant>().map(|a| a.scalar().clone())
460 }
461
462 pub fn nbytes(&self) -> u64 {
464 let mut nbytes = 0;
465 for array in self.depth_first_traversal() {
466 for buffer in array.buffers() {
467 nbytes += buffer.len() as u64;
468 }
469 }
470 nbytes
471 }
472
473 pub fn is_canonical(&self) -> bool {
475 self.is::<AnyCanonical>()
476 }
477
478 pub unsafe fn with_slot(
491 self,
492 slot_idx: usize,
493 replacement: ArrayRef,
494 ) -> VortexResult<ArrayRef> {
495 let mut slots: ArraySlots = self.slots().iter().cloned().collect();
496 let nslots = slots.len();
497 vortex_ensure!(
498 slot_idx < nslots,
499 "slot index {} out of bounds for array with {} slots",
500 slot_idx,
501 nslots
502 );
503 let existing = slots[slot_idx]
504 .as_ref()
505 .vortex_expect("with_slot cannot replace an absent slot");
506 vortex_ensure_eq!(
507 existing.dtype(),
508 replacement.dtype(),
509 "slot {} dtype changed during physical rewrite",
510 slot_idx
511 );
512 vortex_ensure_eq!(
513 existing.len(),
514 replacement.len(),
515 "slot {} len changed during physical rewrite",
516 slot_idx
517 );
518 slots[slot_idx] = Some(replacement);
519 unsafe { self.with_slots(slots) }
521 }
522
523 pub(crate) unsafe fn take_slot_unchecked(
535 mut self,
536 slot_idx: usize,
537 ) -> VortexResult<(ArrayRef, ArrayRef)> {
538 if let Some(inner) = Arc::get_mut(&mut self.0) {
539 let child = inner.slots[slot_idx]
540 .take()
541 .vortex_expect("take_slot_unchecked cannot take an absent slot");
542 return Ok((self, child));
543 }
544
545 let child = self.slots()[slot_idx]
548 .as_ref()
549 .vortex_expect("take_slot_unchecked cannot take an absent slot")
550 .clone();
551
552 let mut new_slots: ArraySlots = self.slots().iter().cloned().collect();
553 new_slots[slot_idx] = None;
554
555 let new_parent = unsafe { self.0.data.with_slots_unchecked(&self, new_slots) };
558 Ok((new_parent, child))
559 }
560
561 pub(crate) unsafe fn put_slot_unchecked(
569 mut self,
570 slot_idx: usize,
571 replacement: ArrayRef,
572 ) -> VortexResult<ArrayRef> {
573 if let Some(inner) = Arc::get_mut(&mut self.0) {
574 inner.slots[slot_idx] = Some(replacement);
575 return Ok(self);
576 }
577
578 let mut slots: ArraySlots = self.slots().iter().cloned().collect();
579 slots[slot_idx] = Some(replacement);
580 self.0.data.with_slots(&self, slots)
581 }
582
583 pub unsafe fn with_slots(self, slots: ArraySlots) -> VortexResult<ArrayRef> {
594 let old_slots = self.slots();
595 vortex_ensure_eq!(
596 old_slots.len(),
597 slots.len(),
598 "slot count changed during physical rewrite"
599 );
600 for (idx, (old_slot, new_slot)) in old_slots.iter().zip(slots.iter()).enumerate() {
601 vortex_ensure_eq!(
602 old_slot.is_some(),
603 new_slot.is_some(),
604 "slot {} presence changed during physical rewrite",
605 idx
606 );
607 if let (Some(old_slot), Some(new_slot)) = (old_slot.as_ref(), new_slot.as_ref()) {
608 vortex_ensure_eq!(
609 old_slot.dtype(),
610 new_slot.dtype(),
611 "slot {} dtype changed during physical rewrite",
612 idx
613 );
614 vortex_ensure_eq!(
615 old_slot.len(),
616 new_slot.len(),
617 "slot {} len changed during physical rewrite",
618 idx
619 );
620 }
621 }
622 self.0.data.with_slots(&self, slots)
623 }
624
625 pub unsafe fn with_buffers(
638 self,
639 buffers: impl IntoIterator<Item = BufferHandle>,
640 ) -> VortexResult<ArrayRef> {
641 let buffers = buffers.into_iter().collect::<Vec<_>>();
642 let nbuffers = self.nbuffers();
643 vortex_ensure_eq!(
644 nbuffers,
645 buffers.len(),
646 "buffer count changed during physical rewrite"
647 );
648 for (idx, (old_buffer, new_buffer)) in self
649 .buffer_handles()
650 .into_iter()
651 .zip(buffers.iter())
652 .enumerate()
653 {
654 vortex_ensure_eq!(
655 old_buffer.len(),
656 new_buffer.len(),
657 "buffer {} length changed during physical rewrite",
658 idx
659 );
660 }
661 self.0.data.with_buffers(&self, buffers)
662 }
663
664 pub fn reduce(&self) -> VortexResult<Option<ArrayRef>> {
665 self.0.data.reduce(self)
666 }
667
668 pub fn reduce_parent(
669 &self,
670 parent: &ArrayRef,
671 child_idx: usize,
672 ) -> VortexResult<Option<ArrayRef>> {
673 self.0.data.reduce_parent(self, parent, child_idx)
674 }
675
676 pub(crate) fn execute_encoding(self, ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
677 let inner = Arc::as_ptr(&self.0);
678 unsafe { (&*inner).data.execute(self, ctx) }
680 }
681
682 pub(crate) fn execute_encoding_unchecked(
688 self,
689 ctx: &mut ExecutionCtx,
690 ) -> VortexResult<ExecutionResult> {
691 let inner = Arc::as_ptr(&self.0);
692 unsafe { (&*inner).data.execute_unchecked(self, ctx) }
696 }
697
698 pub fn children_iter(&self) -> impl Iterator<Item = &ArrayRef> {
702 self.0.slots.iter().filter_map(|s| s.as_ref())
703 }
704
705 pub fn children(&self) -> Vec<ArrayRef> {
707 self.children_iter().cloned().collect()
708 }
709
710 pub fn nchildren(&self) -> usize {
712 self.children_iter().count()
713 }
714
715 pub fn nth_child(&self, idx: usize) -> Option<&ArrayRef> {
719 self.children_iter().nth(idx)
720 }
721
722 pub fn children_names(&self) -> Vec<String> {
725 self.0
726 .slots
727 .iter()
728 .enumerate()
729 .filter(|(_, s)| s.is_some())
730 .map(|(slot_idx, _)| self.slot_name(slot_idx))
731 .collect()
732 }
733
734 pub fn named_children(&self) -> Vec<(String, ArrayRef)> {
736 self.children_names()
737 .into_iter()
738 .zip(self.children_iter().cloned())
739 .collect()
740 }
741
742 pub fn buffers(&self) -> Vec<ByteBuffer> {
744 self.0.data.buffers(self)
745 }
746
747 pub fn buffer_handles(&self) -> Vec<BufferHandle> {
749 self.0.data.buffer_handles(self)
750 }
751
752 pub fn buffer_names(&self) -> Vec<String> {
754 self.0.data.buffer_names(self)
755 }
756
757 pub fn named_buffers(&self) -> Vec<(String, BufferHandle)> {
759 self.0.data.named_buffers(self)
760 }
761
762 pub fn nbuffers(&self) -> usize {
764 self.0.data.nbuffers(self)
765 }
766
767 pub fn slots(&self) -> &[Option<ArrayRef>] {
769 &self.0.slots
770 }
771
772 pub fn slot_name(&self, idx: usize) -> String {
774 self.0.data.slot_name(self, idx)
775 }
776
777 pub fn metadata_fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
779 self.0.data.metadata_fmt(f)
780 }
781
782 pub fn is_host(&self) -> bool {
784 for array in self.depth_first_traversal() {
785 if !array.buffer_handles().iter().all(BufferHandle::is_on_host) {
786 return false;
787 }
788 }
789 true
790 }
791
792 pub fn nbuffers_recursive(&self) -> usize {
796 self.children()
797 .iter()
798 .map(|c| c.nbuffers_recursive())
799 .sum::<usize>()
800 + self.nbuffers()
801 }
802
803 pub fn depth_first_traversal(&self) -> DepthFirstArrayIterator {
805 DepthFirstArrayIterator {
806 stack: vec![self.clone()],
807 }
808 }
809}
810
811impl IntoArray for ArrayRef {
812 #[allow(clippy::inline_always)]
813 #[inline(always)]
814 fn into_array(self) -> ArrayRef {
815 self
816 }
817}
818
819impl<V: VTable> Matcher for V {
820 type Match<'a> = ArrayView<'a, V>;
821
822 #[inline]
823 fn matches(array: &ArrayRef) -> bool {
824 array.0.data.as_any().is::<ArrayData<V>>()
825 }
826
827 #[inline]
828 fn try_match(array: &'_ ArrayRef) -> Option<ArrayView<'_, V>> {
829 let inner = array.0.data.as_any().downcast_ref::<ArrayData<V>>()?;
830 Some(unsafe { ArrayView::new_unchecked(array, &inner.data) })
832 }
833}