1use std::sync::Arc;
14
15use num_traits::ToPrimitive;
16use vortex_buffer::BufferAllocatorRef;
17use vortex_error::VortexExpect;
18use vortex_error::VortexResult;
19use vortex_error::vortex_ensure;
20use vortex_error::vortex_ensure_eq;
21use vortex_error::vortex_panic;
22
23use crate::ArrayRef;
24use crate::Canonical;
25use crate::ExecutionCtx;
26use crate::array::ArrayView;
27use crate::array::IntoArray;
28use crate::arrays::List;
29use crate::arrays::ListView;
30use crate::arrays::ListViewArray;
31use crate::arrays::PrimitiveArray;
32use crate::arrays::list::ListArraySlotsExt;
33use crate::arrays::listview::ListViewArrayExt;
34use crate::arrays::listview::ListViewArraySlotsExt;
35use crate::builders::ArrayBuilder;
36use crate::builders::ChildBuilder;
37use crate::builders::DEFAULT_BUILDER_CAPACITY;
38use crate::builders::PrimitiveBuilder;
39use crate::builders::UninitRange;
40use crate::builders::ValidityBuilder;
41use crate::dtype::DType;
42use crate::dtype::IntegerPType;
43use crate::dtype::Nullability;
44use crate::dtype::OffsetBuilderPType;
45use crate::match_each_integer_ptype;
46use crate::scalar::ListScalar;
47use crate::scalar::Scalar;
48
49pub struct ListViewBuilder<O: OffsetBuilderPType, S: OffsetBuilderPType> {
59 dtype: DType,
61
62 elements_builder: ChildBuilder,
64
65 offsets_builder: PrimitiveBuilder<O>,
67
68 sizes_builder: PrimitiveBuilder<S>,
70
71 nulls: ValidityBuilder,
73
74 zero_copy_to_list: bool,
81}
82
83impl<O: OffsetBuilderPType, S: OffsetBuilderPType> ListViewBuilder<O, S> {
84 #[deprecated(note = "use `new_in` with an explicit allocator")]
86 pub fn new(element_dtype: Arc<DType>, nullability: Nullability) -> Self {
87 Self::new_in(element_dtype, nullability, BufferAllocatorRef::static_ref())
88 }
89
90 pub fn new_in(
92 element_dtype: Arc<DType>,
93 nullability: Nullability,
94 allocator: &BufferAllocatorRef,
95 ) -> Self {
96 Self::with_capacity_in(
97 element_dtype,
98 nullability,
99 DEFAULT_BUILDER_CAPACITY * 2,
102 DEFAULT_BUILDER_CAPACITY,
103 allocator,
104 )
105 }
106
107 #[deprecated(note = "use `with_capacity_in` with an explicit allocator")]
115 pub fn with_capacity(
116 element_dtype: Arc<DType>,
117 nullability: Nullability,
118 elements_capacity: usize,
119 capacity: usize,
120 ) -> Self {
121 Self::with_capacity_in(
122 element_dtype,
123 nullability,
124 elements_capacity,
125 capacity,
126 BufferAllocatorRef::static_ref(),
127 )
128 }
129
130 pub fn with_capacity_in(
136 element_dtype: Arc<DType>,
137 nullability: Nullability,
138 elements_capacity: usize,
139 capacity: usize,
140 allocator: &BufferAllocatorRef,
141 ) -> Self {
142 let elements_builder =
143 ChildBuilder::with_capacity(&element_dtype, elements_capacity, allocator);
144
145 let offsets_builder =
146 PrimitiveBuilder::<O>::with_capacity_in(Nullability::NonNullable, capacity, allocator);
147 let sizes_builder =
148 PrimitiveBuilder::<S>::with_capacity_in(Nullability::NonNullable, capacity, allocator);
149
150 let nulls = ValidityBuilder::new(capacity, allocator);
151
152 Self {
153 dtype: DType::List(element_dtype, nullability),
154 elements_builder,
155 offsets_builder,
156 sizes_builder,
157 nulls,
158 zero_copy_to_list: true,
159 }
160 }
161
162 pub fn append_array_as_list(
169 &mut self,
170 array: &ArrayRef,
171 ctx: &mut ExecutionCtx,
172 ) -> VortexResult<()> {
173 vortex_ensure_eq!(array.dtype(), self.element_dtype());
174
175 let curr_offset = self.elements_builder.len();
176 let num_elements = array.len();
177
178 assert!(
181 ((curr_offset + num_elements) as u64) < O::max_value_as_u64(),
182 "appending this list would cause an offset overflow"
183 );
184
185 self.elements_builder.append_array(array, ctx)?;
186 self.nulls.append_non_null();
187
188 self.offsets_builder.append_value(
189 O::from_usize(curr_offset).vortex_expect("Failed to convert from usize to `O`"),
190 );
191 self.sizes_builder.append_value(
192 S::from_usize(num_elements).vortex_expect("Failed to convert from usize to `S`"),
193 );
194
195 Ok(())
196 }
197
198 pub fn append_value(&mut self, value: ListScalar) -> VortexResult<()> {
203 let Some(elements) = value.elements() else {
204 vortex_ensure!(
206 self.dtype.is_nullable(),
207 "Cannot append null value to non-nullable list builder"
208 );
209 self.append_null();
210 return Ok(());
211 };
212
213 let curr_offset = self.elements_builder.len();
214 let num_elements = elements.len();
215
216 assert!(
219 ((curr_offset + num_elements) as u64) < O::max_value_as_u64(),
220 "appending this list would cause an offset overflow"
221 );
222
223 for scalar in elements {
224 self.elements_builder.append_scalar(&scalar)?;
225 }
226 self.nulls.append_non_null();
227
228 self.offsets_builder.append_value(
229 O::from_usize(curr_offset).vortex_expect("Failed to convert from usize to `O`"),
230 );
231 self.sizes_builder.append_value(
232 S::from_usize(num_elements).vortex_expect("Failed to convert from usize to `S`"),
233 );
234
235 Ok(())
236 }
237
238 pub fn append_array_as_repeated_list(
248 &mut self,
249 array: &ArrayRef,
250 n: usize,
251 ctx: &mut ExecutionCtx,
252 ) -> VortexResult<()> {
253 vortex_ensure_eq!(array.dtype(), self.element_dtype());
254
255 if n == 0 {
256 return Ok(());
257 }
258
259 let curr_offset = self.elements_builder.len();
260 let num_elements = array.len();
261
262 assert!(
265 ((curr_offset + num_elements) as u64) < O::max_value_as_u64(),
266 "appending this list would cause an offset overflow"
267 );
268
269 self.elements_builder.append_array(array, ctx)?;
270
271 let offset =
272 O::from_usize(curr_offset).vortex_expect("Failed to convert from usize to `O`");
273 let size = S::from_usize(num_elements).vortex_expect("Failed to convert from usize to `S`");
274 self.offsets_builder.append_n_values(offset, n);
275 self.sizes_builder.append_n_values(size, n);
276 self.nulls.append_n_non_nulls(n);
277
278 if n > 1 && num_elements > 0 {
279 self.zero_copy_to_list = false;
280 }
281
282 Ok(())
283 }
284
285 pub fn finish_into_listview(&mut self) -> ListViewArray {
287 debug_assert_eq!(self.offsets_builder.len(), self.sizes_builder.len());
288 debug_assert_eq!(self.offsets_builder.len(), self.nulls.len());
289
290 let elements = self.elements_builder.finish();
291 let offsets = self.offsets_builder.finish();
292 let sizes = self.sizes_builder.finish();
293 let validity = self.nulls.finish_with_nullability(self.dtype.nullability());
294
295 let zero_copy_to_list = std::mem::replace(&mut self.zero_copy_to_list, true);
296
297 unsafe {
309 ListViewArray::new_unchecked(elements, offsets, sizes, validity)
310 .with_zero_copy_to_list(zero_copy_to_list)
311 }
312 }
313
314 pub fn element_dtype(&self) -> &DType {
317 let DType::List(element_dtype, ..) = &self.dtype else {
318 vortex_panic!("`ListViewBuilder` has an incorrect dtype: {}", self.dtype);
319 };
320
321 element_dtype
322 }
323
324 pub fn append_list_array(
331 &mut self,
332 array: ArrayView<'_, List>,
333 ctx: &mut ExecutionCtx,
334 ) -> VortexResult<()> {
335 if array.is_empty() {
336 return Ok(());
337 }
338
339 self.nulls.append_validity(array.validity()?, array.len());
340
341 let offsets = array.offsets().clone().execute::<PrimitiveArray>(ctx)?;
342 match_each_integer_ptype!(offsets.ptype(), |OffsetType| {
343 extend_from_list(
344 self,
345 array.elements(),
346 offsets.as_slice::<OffsetType>(),
347 ctx,
348 )?
349 });
350 Ok(())
351 }
352
353 pub fn append_listview_array(
364 &mut self,
365 array: ArrayView<'_, ListView>,
366 ctx: &mut ExecutionCtx,
367 ) -> VortexResult<()> {
368 if array.is_empty() {
369 return Ok(());
370 }
371
372 let len = array.len();
373
374 let offsets = array.offsets().clone().execute::<PrimitiveArray>(ctx)?;
381 let sizes = array.sizes().clone().execute::<PrimitiveArray>(ctx)?;
382
383 let (start, end) = if array.is_zero_copy_to_list() {
387 let last = len - 1;
388 (
389 metadata_at(&offsets, 0),
390 metadata_at(&offsets, last) + metadata_at(&sizes, last),
391 )
392 } else {
393 array.into_owned().referenced_element_bounds(ctx)?
394 };
395
396 self.zero_copy_to_list &= array.is_zero_copy_to_list();
399
400 self.nulls.append_validity(array.validity()?, len);
401
402 let elements_base = self.elements_builder.len();
404
405 assert!(
408 ((elements_base + (end - start)) as u64) < O::max_value_as_u64(),
409 "appending this list would cause an offset overflow"
410 );
411
412 if end > start {
413 self.elements_builder
414 .append_array(&array.elements().slice(start..end)?, ctx)?;
415 }
416
417 assert_eq!(
421 self.elements_builder.len(),
422 elements_base + (end - start),
423 "appending the referenced elements did not extend the child by the window's length"
424 );
425
426 self.offsets_builder.reserve_exact(len);
427 let offsets_range = self.offsets_builder.uninit_range(len);
428 match_each_integer_ptype!(offsets.ptype(), |A| {
429 extend_rebased_offsets::<O, A>(
430 offsets_range,
431 offsets.as_slice::<A>(),
432 start,
433 elements_base,
434 );
435 });
436
437 self.sizes_builder.reserve_exact(len);
438 let mut sizes_range = self.sizes_builder.uninit_range(len);
439 if sizes.ptype() == S::PTYPE {
440 sizes_range.copy_from_slice(0, sizes.as_slice::<S>());
442 unsafe { sizes_range.finish() };
445 } else {
446 match_each_integer_ptype!(sizes.ptype(), |A| {
447 extend_converted_sizes::<S, A>(sizes_range, sizes.as_slice::<A>());
448 });
449 }
450
451 Ok(())
452 }
453}
454
455impl<O: OffsetBuilderPType, S: OffsetBuilderPType> ArrayBuilder for ListViewBuilder<O, S> {
456 fn as_any(&self) -> &dyn std::any::Any {
457 self
458 }
459
460 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
461 self
462 }
463
464 fn dtype(&self) -> &DType {
465 &self.dtype
466 }
467
468 fn len(&self) -> usize {
469 self.offsets_builder.len()
470 }
471
472 fn append_zeros(&mut self, n: usize) {
473 debug_assert_eq!(self.offsets_builder.len(), self.sizes_builder.len());
474 debug_assert_eq!(self.offsets_builder.len(), self.nulls.len());
475
476 let curr_offset = self.elements_builder.len();
478
479 for _ in 0..n {
482 self.offsets_builder.append_value(
483 O::from_usize(curr_offset).vortex_expect("Failed to convert from usize to `O`"),
484 );
485 self.sizes_builder.append_value(S::zero());
486 }
487
488 self.nulls.append_n_non_nulls(n);
489 }
490
491 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
492 debug_assert_eq!(self.offsets_builder.len(), self.sizes_builder.len());
493 debug_assert_eq!(self.offsets_builder.len(), self.nulls.len());
494
495 let curr_offset = self.elements_builder.len();
497
498 for _ in 0..n {
500 self.offsets_builder.append_value(
501 O::from_usize(curr_offset).vortex_expect("Failed to convert from usize to `O`"),
502 );
503 self.sizes_builder.append_value(S::zero());
504 }
505
506 self.nulls.append_n_nulls(n);
508 }
509
510 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
511 vortex_ensure_eq!(
512 scalar.dtype(),
513 self.dtype(),
514 "ListViewBuilder received a scalar with the wrong dtype"
515 );
516
517 let list_scalar = scalar.as_list();
518 self.append_value(list_scalar)
519 }
520
521 fn reserve_exact(&mut self, capacity: usize) {
522 self.elements_builder.reserve_exact(capacity * 2);
523 self.offsets_builder.reserve_exact(capacity);
524 self.sizes_builder.reserve_exact(capacity);
525 self.nulls.reserve_exact(capacity);
526 }
527
528 fn finish(&mut self) -> ArrayRef {
529 self.finish_into_listview().into_array()
530 }
531
532 fn finish_into_canonical(&mut self, _ctx: &mut ExecutionCtx) -> Canonical {
533 Canonical::List(self.finish_into_listview())
534 }
535}
536
537fn extend_from_list<O, S, OffsetType>(
543 builder: &mut ListViewBuilder<O, S>,
544 elements: &ArrayRef,
545 offsets: &[OffsetType],
546 ctx: &mut ExecutionCtx,
547) -> VortexResult<()>
548where
549 O: OffsetBuilderPType,
550 S: OffsetBuilderPType,
551 OffsetType: IntegerPType,
552{
553 let num_lists = offsets.len() - 1;
554 let first: usize = offsets[0].as_();
555 let last: usize = offsets[num_lists].as_();
556
557 let elements_base = builder.elements_builder.len();
558
559 assert!(
562 ((elements_base + (last - first)) as u64) < O::max_value_as_u64(),
563 "appending this list would cause an offset overflow"
564 );
565
566 if last > first {
567 builder
568 .elements_builder
569 .append_array(&elements.slice(first..last)?, ctx)?;
570 }
571
572 builder.offsets_builder.reserve_exact(num_lists);
573 builder.sizes_builder.reserve_exact(num_lists);
574 let mut offsets_range = builder.offsets_builder.uninit_range(num_lists);
575 let mut sizes_range = builder.sizes_builder.uninit_range(num_lists);
576 for i in 0..num_lists {
577 let start: usize = offsets[i].as_();
578 let end: usize = offsets[i + 1].as_();
579 offsets_range.set_value(
580 i,
581 O::from_usize(start - first + elements_base)
582 .vortex_expect("Failed to convert from usize to `O`"),
583 );
584 sizes_range.set_value(
585 i,
586 S::from_usize(end - start).vortex_expect("Failed to convert from usize to `S`"),
587 );
588 }
589 unsafe { offsets_range.finish() };
592 unsafe { sizes_range.finish() };
593 Ok(())
594}
595
596fn metadata_at(metadata: &PrimitiveArray, index: usize) -> usize {
598 match_each_integer_ptype!(metadata.ptype(), |A| {
599 metadata.as_slice::<A>()[index]
600 .to_usize()
601 .vortex_expect("list view metadata must fit in a usize")
602 })
603}
604
605fn extend_rebased_offsets<O: OffsetBuilderPType, A: IntegerPType>(
611 mut range: UninitRange<O>,
612 offsets: &[A],
613 window_start: usize,
614 elements_base: usize,
615) {
616 debug_assert_eq!(range.len(), offsets.len());
617
618 for (i, &offset) in offsets.iter().enumerate() {
619 let offset = offset
620 .to_usize()
621 .vortex_expect("offsets must always fit in usize");
622 debug_assert!(
623 offset >= window_start,
624 "offset {offset} precedes the referenced window at {window_start}"
625 );
626 let rebased = O::from_usize(offset - window_start + elements_base)
627 .vortex_expect("rebased offset did not fit into the builder's offset type");
628 range.set_value(i, rebased);
629 }
630
631 unsafe { range.finish() };
634}
635
636fn extend_converted_sizes<S: OffsetBuilderPType, A: IntegerPType>(
640 mut range: UninitRange<S>,
641 sizes: &[A],
642) {
643 debug_assert_eq!(range.len(), sizes.len());
644
645 for (i, &size) in sizes.iter().enumerate() {
646 let size = S::from_usize(
647 size.to_usize()
648 .vortex_expect("sizes must always fit in usize"),
649 )
650 .vortex_expect("size did not fit into the builder's size type");
651 range.set_value(i, size);
652 }
653
654 unsafe { range.finish() };
657}
658
659#[cfg(test)]
660mod tests {
661 use std::sync::Arc;
662
663 use vortex_buffer::BufferAllocatorRef;
664 use vortex_buffer::buffer;
665 use vortex_error::VortexExpect;
666 use vortex_error::VortexResult;
667
668 use super::ListViewBuilder;
669 use crate::IntoArray;
670 use crate::VortexSessionExecute;
671 use crate::array_session;
672 use crate::arrays::ConstantArray;
673 use crate::arrays::ListArray;
674 use crate::arrays::ListViewArray;
675 use crate::arrays::listview::ListViewArrayExt;
676 use crate::arrays::listview::ListViewArraySlotsExt;
677 use crate::assert_arrays_eq;
678 use crate::builders::ArrayBuilder;
679 use crate::builders::listview::PrimitiveArray;
680 use crate::dtype::DType;
681 use crate::dtype::Nullability::NonNullable;
682 use crate::dtype::Nullability::Nullable;
683 use crate::dtype::PType::I32;
684 use crate::scalar::Scalar;
685 use crate::validity::Validity;
686
687 #[test]
688 fn test_empty() {
689 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
690 Arc::new(I32.into()),
691 NonNullable,
692 0,
693 0,
694 BufferAllocatorRef::static_ref(),
695 );
696
697 let listview = builder.finish();
698 assert_eq!(listview.len(), 0);
699 assert_eq!(
700 listview.dtype(),
701 &DType::List(Arc::new(I32.into()), NonNullable)
702 );
703 }
704
705 #[test]
706 fn test_basic_append_and_nulls() {
707 let mut ctx = array_session().create_execution_ctx();
708 let dtype: Arc<DType> = Arc::new(I32.into());
709 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
710 Arc::clone(&dtype),
711 Nullable,
712 0,
713 0,
714 BufferAllocatorRef::static_ref(),
715 );
716
717 builder
719 .append_value(
720 Scalar::list(
721 Arc::clone(&dtype),
722 vec![1i32.into(), 2i32.into(), 3i32.into()],
723 NonNullable,
724 )
725 .as_list(),
726 )
727 .unwrap();
728
729 builder
731 .append_value(Scalar::list_empty(Arc::clone(&dtype), NonNullable).as_list())
732 .unwrap();
733
734 builder.append_null();
736
737 builder
739 .append_value(
740 Scalar::list(dtype, vec![4i32.into(), 5i32.into()], NonNullable).as_list(),
741 )
742 .unwrap();
743
744 let listview = builder.finish_into_listview();
745 assert_eq!(listview.len(), 4);
746
747 assert_arrays_eq!(
749 listview.list_elements_at(0, &mut ctx).unwrap(),
750 PrimitiveArray::from_iter([1i32, 2, 3]),
751 &mut ctx
752 );
753
754 assert_eq!(listview.list_elements_at(1, &mut ctx).unwrap().len(), 0);
756
757 assert!(
759 !listview
760 .validity()
761 .vortex_expect("listview validity should be derivable")
762 .execute_is_valid(2, &mut ctx)
763 .unwrap()
764 );
765
766 assert_arrays_eq!(
768 listview.list_elements_at(3, &mut ctx).unwrap(),
769 PrimitiveArray::from_iter([4i32, 5]),
770 &mut ctx
771 );
772 let expected = ListArray::new(
773 buffer![1i32, 2, 3, 4, 5].into_array(),
774 buffer![0u32, 3, 3, 3, 5].into_array(),
775 Validity::from_iter([true, true, false, true]),
776 &mut ctx,
777 );
778 assert_arrays_eq!(listview, expected, &mut ctx);
779 }
780
781 #[test]
782 fn test_different_offset_size_types() {
783 let mut ctx = array_session().create_execution_ctx();
784 let dtype: Arc<DType> = Arc::new(I32.into());
786 let mut builder = ListViewBuilder::<u64, u32>::with_capacity_in(
787 Arc::clone(&dtype),
788 NonNullable,
789 0,
790 0,
791 BufferAllocatorRef::static_ref(),
792 );
793
794 builder
795 .append_value(
796 Scalar::list(
797 Arc::clone(&dtype),
798 vec![1i32.into(), 2i32.into()],
799 NonNullable,
800 )
801 .as_list(),
802 )
803 .unwrap();
804
805 builder
806 .append_value(
807 Scalar::list(
808 dtype,
809 vec![3i32.into(), 4i32.into(), 5i32.into()],
810 NonNullable,
811 )
812 .as_list(),
813 )
814 .unwrap();
815
816 let listview = builder.finish_into_listview();
817 assert_eq!(listview.len(), 2);
818
819 assert_arrays_eq!(
821 listview.list_elements_at(0, &mut ctx).unwrap(),
822 PrimitiveArray::from_iter([1i32, 2]),
823 &mut ctx
824 );
825
826 assert_arrays_eq!(
828 listview.list_elements_at(1, &mut ctx).unwrap(),
829 PrimitiveArray::from_iter([3i32, 4, 5]),
830 &mut ctx
831 );
832
833 let dtype2: Arc<DType> = Arc::new(I32.into());
835 let mut builder2 = ListViewBuilder::<i64, i32>::with_capacity_in(
836 Arc::clone(&dtype2),
837 NonNullable,
838 0,
839 0,
840 BufferAllocatorRef::static_ref(),
841 );
842
843 for i in 0..5 {
844 builder2
845 .append_value(
846 Scalar::list(Arc::clone(&dtype2), vec![(i * 10).into()], NonNullable).as_list(),
847 )
848 .unwrap();
849 }
850
851 let listview2 = builder2.finish_into_listview();
852 assert_eq!(listview2.len(), 5);
853
854 for i in 0..5i32 {
856 assert_arrays_eq!(
857 listview2.list_elements_at(i as usize, &mut ctx).unwrap(),
858 PrimitiveArray::from_iter([i * 10]),
859 &mut ctx
860 );
861 }
862 }
863
864 #[test]
865 fn test_builder_trait_methods() {
866 let mut ctx = array_session().create_execution_ctx();
867 let dtype: Arc<DType> = Arc::new(I32.into());
868 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
869 Arc::clone(&dtype),
870 Nullable,
871 0,
872 0,
873 BufferAllocatorRef::static_ref(),
874 );
875
876 builder.append_zeros(2);
878 assert_eq!(builder.len(), 2);
879
880 unsafe {
882 builder.append_nulls_unchecked(2);
883 }
884 assert_eq!(builder.len(), 4);
885
886 let list_scalar = Scalar::list(dtype, vec![10i32.into(), 20i32.into()], Nullable);
888 builder.append_scalar(&list_scalar).unwrap();
889 assert_eq!(builder.len(), 5);
890
891 let listview = builder.finish_into_listview();
892 assert_eq!(listview.len(), 5);
893
894 assert_eq!(listview.list_elements_at(0, &mut ctx).unwrap().len(), 0);
896 assert_eq!(listview.list_elements_at(1, &mut ctx).unwrap().len(), 0);
897
898 assert!(
900 !listview
901 .validity()
902 .vortex_expect("listview validity should be derivable")
903 .execute_is_valid(2, &mut ctx)
904 .unwrap()
905 );
906 assert!(
907 !listview
908 .validity()
909 .vortex_expect("listview validity should be derivable")
910 .execute_is_valid(3, &mut ctx)
911 .unwrap()
912 );
913
914 assert_arrays_eq!(
916 listview.list_elements_at(4, &mut ctx).unwrap(),
917 PrimitiveArray::from_iter([10i32, 20]),
918 &mut ctx
919 );
920 let expected = ListArray::new(
921 buffer![10i32, 20].into_array(),
922 buffer![0u32, 0, 0, 0, 0, 2].into_array(),
923 Validity::from_iter([true, true, false, false, true]),
924 &mut ctx,
925 );
926 assert_arrays_eq!(listview, expected, &mut ctx);
927 }
928
929 #[test]
930 fn test_extend_from_array() {
931 let mut ctx = array_session().create_execution_ctx();
932 let dtype: Arc<DType> = Arc::new(I32.into());
933
934 let source = ListArray::from_iter_opt_slow::<u32, _, Vec<i32>>(
936 [Some(vec![1, 2, 3]), None, Some(vec![4, 5])],
937 Arc::new(I32.into()),
938 )
939 .unwrap();
940
941 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
942 Arc::clone(&dtype),
943 Nullable,
944 0,
945 0,
946 BufferAllocatorRef::static_ref(),
947 );
948
949 builder
951 .append_value(Scalar::list(dtype, vec![0i32.into()], NonNullable).as_list())
952 .unwrap();
953
954 let source = source
956 .into_array()
957 .execute::<ListViewArray>(&mut ctx)
958 .unwrap();
959 builder
960 .append_listview_array(source.as_view(), &mut ctx)
961 .unwrap();
962
963 let empty_source = ListArray::from_iter_opt_slow::<u32, _, Vec<i32>>(
965 std::iter::empty::<Option<Vec<i32>>>(),
966 Arc::new(I32.into()),
967 )
968 .unwrap();
969 let empty_source = empty_source
970 .into_array()
971 .execute::<ListViewArray>(&mut ctx)
972 .unwrap();
973 builder
974 .append_listview_array(empty_source.as_view(), &mut ctx)
975 .unwrap();
976
977 let listview = builder.finish_into_listview();
978 assert_eq!(listview.len(), 4);
979
980 assert_arrays_eq!(
983 listview.list_elements_at(0, &mut ctx).unwrap(),
984 PrimitiveArray::from_iter([0i32]),
985 &mut ctx
986 );
987
988 assert_arrays_eq!(
990 listview.list_elements_at(1, &mut ctx).unwrap(),
991 PrimitiveArray::from_iter([1i32, 2, 3]),
992 &mut ctx
993 );
994
995 assert!(
997 !listview
998 .validity()
999 .vortex_expect("listview validity should be derivable")
1000 .execute_is_valid(2, &mut ctx)
1001 .unwrap()
1002 );
1003
1004 assert_arrays_eq!(
1006 listview.list_elements_at(3, &mut ctx).unwrap(),
1007 PrimitiveArray::from_iter([4i32, 5]),
1008 &mut ctx
1009 );
1010 let expected = ListArray::new(
1011 buffer![0i32, 1, 2, 3, 4, 5].into_array(),
1012 buffer![0u32, 1, 4, 4, 6].into_array(),
1013 Validity::from_iter([true, true, false, true]),
1014 &mut ctx,
1015 );
1016 assert_arrays_eq!(listview, expected, &mut ctx);
1017 }
1018
1019 #[test]
1020 fn test_append_list_array_grows_builder() -> VortexResult<()> {
1021 let mut ctx = array_session().create_execution_ctx();
1022 let dtype: Arc<DType> = Arc::new(I32.into());
1023
1024 let lists: Vec<Option<Vec<i32>>> =
1027 (0..100).map(|i| (i % 10 != 0).then(|| vec![i])).collect();
1028 let source = ListArray::from_iter_opt_slow::<u32, _, _>(lists.clone(), Arc::clone(&dtype))?;
1029
1030 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1031 Arc::clone(&dtype),
1032 Nullable,
1033 0,
1034 0,
1035 BufferAllocatorRef::static_ref(),
1036 );
1037 builder.append_list_array(source.as_view(), &mut ctx)?;
1038 builder.append_list_array(source.as_view(), &mut ctx)?;
1040
1041 let listview = builder.finish_into_listview();
1042 assert!(listview.is_zero_copy_to_list());
1043
1044 let expected = ListArray::from_iter_opt_slow::<u32, _, _>(
1045 lists.iter().cloned().chain(lists.iter().cloned()),
1046 dtype,
1047 )?;
1048 assert_arrays_eq!(listview, expected, &mut ctx);
1049
1050 Ok(())
1051 }
1052
1053 #[test]
1056 fn test_constant_list_append_keeps_one_copy_of_the_value() -> VortexResult<()> {
1057 let mut ctx = array_session().create_execution_ctx();
1058 let element_dtype: Arc<DType> = Arc::new(I32.into());
1059
1060 const ROWS: usize = 10_000;
1061 let fill = Scalar::list(
1062 Arc::clone(&element_dtype),
1063 vec![1i32.into(), 2i32.into(), 3i32.into()],
1064 NonNullable,
1065 );
1066 let constant = ConstantArray::new(fill, ROWS).into_array();
1067
1068 let mut builder = ListViewBuilder::<u64, u64>::with_capacity_in(
1069 element_dtype,
1070 NonNullable,
1071 0,
1072 0,
1073 BufferAllocatorRef::static_ref(),
1074 );
1075 constant.append_to_builder(&mut builder, &mut ctx)?;
1076 let listview = builder.finish_into_listview();
1077
1078 assert_eq!(listview.len(), ROWS);
1079 assert_eq!(
1080 listview.elements().len(),
1081 3,
1082 "the fill value should be stored once, not once per row",
1083 );
1084 assert!(!listview.is_zero_copy_to_list());
1085 assert_arrays_eq!(&listview.into_array(), &constant, &mut ctx);
1086
1087 Ok(())
1088 }
1089
1090 #[test]
1093 fn test_append_listview_array_trims_unreferenced_elements() -> VortexResult<()> {
1094 let mut ctx = array_session().create_execution_ctx();
1095 let dtype: Arc<DType> = Arc::new(I32.into());
1096
1097 let source = ListArray::from_iter_slow::<u32, _>(
1099 (0..5).map(|i| vec![2 * i, 2 * i + 1]),
1100 Arc::clone(&dtype),
1101 )?
1102 .into_array()
1103 .execute::<ListViewArray>(&mut ctx)?;
1104 let middle = source.slice(1..4)?.execute::<ListViewArray>(&mut ctx)?;
1105
1106 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1107 Arc::clone(&dtype),
1108 NonNullable,
1109 0,
1110 0,
1111 BufferAllocatorRef::static_ref(),
1112 );
1113 builder.append_listview_array(middle.as_view(), &mut ctx)?;
1114 builder.append_listview_array(middle.as_view(), &mut ctx)?;
1116 let listview = builder.finish_into_listview();
1117
1118 assert_eq!(
1119 listview.elements().len(),
1120 12,
1121 "only the six referenced elements of each append should have landed",
1122 );
1123 assert!(
1124 listview.is_zero_copy_to_list(),
1125 "trimming an exact source keeps the result exact",
1126 );
1127
1128 let expected = ListArray::from_iter_slow::<u32, _>(
1129 (1..4).chain(1..4).map(|i| vec![2 * i, 2 * i + 1]),
1130 dtype,
1131 )?;
1132 assert_arrays_eq!(listview, expected, &mut ctx);
1133
1134 Ok(())
1135 }
1136
1137 #[test]
1138 fn test_extend_from_array_overlapping_listview() {
1139 let mut ctx = array_session().create_execution_ctx();
1140 let dtype: Arc<DType> = Arc::new(I32.into());
1141
1142 let source = unsafe {
1147 ListViewArray::new_unchecked(
1148 buffer![10i32, 20, 30].into_array(),
1149 buffer![0u32, 1, 0].into_array(),
1150 buffer![2u8, 2, 1].into_array(),
1151 Validity::from_iter([true, false, true]),
1152 )
1153 };
1154 assert!(!source.is_zero_copy_to_list());
1155
1156 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1157 Arc::clone(&dtype),
1158 Nullable,
1159 0,
1160 0,
1161 BufferAllocatorRef::static_ref(),
1162 );
1163 builder
1164 .append_listview_array(source.as_view(), &mut ctx)
1165 .unwrap();
1166
1167 let listview = builder.finish_into_listview();
1168 assert_eq!(listview.len(), 3);
1169 assert!(!listview.is_zero_copy_to_list());
1171
1172 assert_arrays_eq!(
1173 listview.list_elements_at(0, &mut ctx).unwrap(),
1174 PrimitiveArray::from_iter([10i32, 20]),
1175 &mut ctx
1176 );
1177 assert!(
1178 !listview
1179 .validity()
1180 .vortex_expect("listview validity should be derivable")
1181 .execute_is_valid(1, &mut ctx)
1182 .unwrap()
1183 );
1184 assert_eq!(listview.size_at(1, &mut ctx), source.size_at(1, &mut ctx));
1186 assert_arrays_eq!(
1187 listview.list_elements_at(2, &mut ctx).unwrap(),
1188 PrimitiveArray::from_iter([10i32]),
1189 &mut ctx
1190 );
1191 let expected = ListArray::new(
1192 buffer![10i32, 20, 10].into_array(),
1193 buffer![0u32, 2, 2, 3].into_array(),
1194 Validity::from_iter([true, false, true]),
1195 &mut ctx,
1196 );
1197 assert_arrays_eq!(listview, expected, &mut ctx);
1198 }
1199
1200 #[test]
1201 fn test_error_append_null_to_non_nullable() {
1202 let dtype: Arc<DType> = Arc::new(I32.into());
1203 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1204 Arc::clone(&dtype),
1205 NonNullable,
1206 0,
1207 0,
1208 BufferAllocatorRef::static_ref(),
1209 );
1210
1211 let null_scalar = Scalar::null(DType::List(dtype, Nullable));
1213 let null_list = null_scalar.as_list();
1214
1215 let result = builder.append_value(null_list);
1217 assert!(result.is_err());
1218 assert!(
1219 result
1220 .unwrap_err()
1221 .to_string()
1222 .contains("null value to non-nullable")
1223 );
1224 }
1225
1226 #[test]
1227 fn test_append_array_as_list() {
1228 let dtype: Arc<DType> = Arc::new(I32.into());
1229 let mut ctx = array_session().create_execution_ctx();
1230 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1231 Arc::clone(&dtype),
1232 NonNullable,
1233 20,
1234 10,
1235 BufferAllocatorRef::static_ref(),
1236 );
1237
1238 let arr1 = buffer![1i32, 2, 3].into_array();
1240 builder.append_array_as_list(&arr1, &mut ctx).unwrap();
1241
1242 builder
1244 .append_value(
1245 Scalar::list(
1246 Arc::clone(&dtype),
1247 vec![10i32.into(), 11i32.into()],
1248 NonNullable,
1249 )
1250 .as_list(),
1251 )
1252 .unwrap();
1253
1254 let arr2 = buffer![4i32, 5].into_array();
1256 builder.append_array_as_list(&arr2, &mut ctx).unwrap();
1257
1258 let arr3 = buffer![0i32; 0].into_array();
1260 builder.append_array_as_list(&arr3, &mut ctx).unwrap();
1261
1262 builder
1264 .append_value(Scalar::list_empty(Arc::clone(&dtype), NonNullable).as_list())
1265 .unwrap();
1266
1267 let listview = builder.finish_into_listview();
1268 assert_eq!(listview.len(), 5);
1269
1270 assert_arrays_eq!(
1272 listview.elements(),
1273 PrimitiveArray::from_iter([1i32, 2, 3, 10, 11, 4, 5]),
1274 &mut ctx
1275 );
1276
1277 assert_arrays_eq!(
1279 listview.offsets(),
1280 PrimitiveArray::from_iter([0u32, 3, 5, 7, 7]),
1281 &mut ctx
1282 );
1283
1284 assert_arrays_eq!(
1286 listview.sizes(),
1287 PrimitiveArray::from_iter([3u32, 2, 2, 0, 0]),
1288 &mut ctx
1289 );
1290
1291 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1293 dtype,
1294 NonNullable,
1295 20,
1296 10,
1297 BufferAllocatorRef::static_ref(),
1298 );
1299 let wrong_dtype_arr = buffer![1i64, 2, 3].into_array();
1300 assert!(
1301 builder
1302 .append_array_as_list(&wrong_dtype_arr, &mut ctx)
1303 .is_err()
1304 );
1305 }
1306}