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 }
700
701 #[test]
702 fn test_basic_append_and_nulls() {
703 let mut ctx = array_session().create_execution_ctx();
704 let dtype: Arc<DType> = Arc::new(I32.into());
705 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
706 Arc::clone(&dtype),
707 Nullable,
708 0,
709 0,
710 BufferAllocatorRef::static_ref(),
711 );
712
713 builder
715 .append_value(
716 Scalar::list(
717 Arc::clone(&dtype),
718 vec![1i32.into(), 2i32.into(), 3i32.into()],
719 NonNullable,
720 )
721 .as_list(),
722 )
723 .unwrap();
724
725 builder
727 .append_value(Scalar::list_empty(Arc::clone(&dtype), NonNullable).as_list())
728 .unwrap();
729
730 builder.append_null();
732
733 builder
735 .append_value(
736 Scalar::list(dtype, vec![4i32.into(), 5i32.into()], NonNullable).as_list(),
737 )
738 .unwrap();
739
740 let listview = builder.finish_into_listview();
741 assert_eq!(listview.len(), 4);
742
743 assert_arrays_eq!(
745 listview.list_elements_at(0).unwrap(),
746 PrimitiveArray::from_iter([1i32, 2, 3]),
747 &mut ctx
748 );
749
750 assert_eq!(listview.list_elements_at(1).unwrap().len(), 0);
752
753 assert!(
755 !listview
756 .validity()
757 .vortex_expect("listview validity should be derivable")
758 .execute_is_valid(2, &mut ctx)
759 .unwrap()
760 );
761
762 assert_arrays_eq!(
764 listview.list_elements_at(3).unwrap(),
765 PrimitiveArray::from_iter([4i32, 5]),
766 &mut ctx
767 );
768 }
769
770 #[test]
771 fn test_different_offset_size_types() {
772 let mut ctx = array_session().create_execution_ctx();
773 let dtype: Arc<DType> = Arc::new(I32.into());
775 let mut builder = ListViewBuilder::<u64, u32>::with_capacity_in(
776 Arc::clone(&dtype),
777 NonNullable,
778 0,
779 0,
780 BufferAllocatorRef::static_ref(),
781 );
782
783 builder
784 .append_value(
785 Scalar::list(
786 Arc::clone(&dtype),
787 vec![1i32.into(), 2i32.into()],
788 NonNullable,
789 )
790 .as_list(),
791 )
792 .unwrap();
793
794 builder
795 .append_value(
796 Scalar::list(
797 dtype,
798 vec![3i32.into(), 4i32.into(), 5i32.into()],
799 NonNullable,
800 )
801 .as_list(),
802 )
803 .unwrap();
804
805 let listview = builder.finish_into_listview();
806 assert_eq!(listview.len(), 2);
807
808 assert_arrays_eq!(
810 listview.list_elements_at(0).unwrap(),
811 PrimitiveArray::from_iter([1i32, 2]),
812 &mut ctx
813 );
814
815 assert_arrays_eq!(
817 listview.list_elements_at(1).unwrap(),
818 PrimitiveArray::from_iter([3i32, 4, 5]),
819 &mut ctx
820 );
821
822 let dtype2: Arc<DType> = Arc::new(I32.into());
824 let mut builder2 = ListViewBuilder::<i64, i32>::with_capacity_in(
825 Arc::clone(&dtype2),
826 NonNullable,
827 0,
828 0,
829 BufferAllocatorRef::static_ref(),
830 );
831
832 for i in 0..5 {
833 builder2
834 .append_value(
835 Scalar::list(Arc::clone(&dtype2), vec![(i * 10).into()], NonNullable).as_list(),
836 )
837 .unwrap();
838 }
839
840 let listview2 = builder2.finish_into_listview();
841 assert_eq!(listview2.len(), 5);
842
843 for i in 0..5i32 {
845 assert_arrays_eq!(
846 listview2.list_elements_at(i as usize).unwrap(),
847 PrimitiveArray::from_iter([i * 10]),
848 &mut ctx
849 );
850 }
851 }
852
853 #[test]
854 fn test_builder_trait_methods() {
855 let mut ctx = array_session().create_execution_ctx();
856 let dtype: Arc<DType> = Arc::new(I32.into());
857 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
858 Arc::clone(&dtype),
859 Nullable,
860 0,
861 0,
862 BufferAllocatorRef::static_ref(),
863 );
864
865 builder.append_zeros(2);
867 assert_eq!(builder.len(), 2);
868
869 unsafe {
871 builder.append_nulls_unchecked(2);
872 }
873 assert_eq!(builder.len(), 4);
874
875 let list_scalar = Scalar::list(dtype, vec![10i32.into(), 20i32.into()], Nullable);
877 builder.append_scalar(&list_scalar).unwrap();
878 assert_eq!(builder.len(), 5);
879
880 let listview = builder.finish_into_listview();
881 assert_eq!(listview.len(), 5);
882
883 assert_eq!(listview.list_elements_at(0).unwrap().len(), 0);
885 assert_eq!(listview.list_elements_at(1).unwrap().len(), 0);
886
887 assert!(
889 !listview
890 .validity()
891 .vortex_expect("listview validity should be derivable")
892 .execute_is_valid(2, &mut ctx)
893 .unwrap()
894 );
895 assert!(
896 !listview
897 .validity()
898 .vortex_expect("listview validity should be derivable")
899 .execute_is_valid(3, &mut ctx)
900 .unwrap()
901 );
902
903 assert_arrays_eq!(
905 listview.list_elements_at(4).unwrap(),
906 PrimitiveArray::from_iter([10i32, 20]),
907 &mut ctx
908 );
909 }
910
911 #[test]
912 fn test_extend_from_array() {
913 let mut ctx = array_session().create_execution_ctx();
914 let dtype: Arc<DType> = Arc::new(I32.into());
915
916 let source = ListArray::from_iter_opt_slow::<u32, _, Vec<i32>>(
918 [Some(vec![1, 2, 3]), None, Some(vec![4, 5])],
919 Arc::new(I32.into()),
920 )
921 .unwrap();
922
923 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
924 Arc::clone(&dtype),
925 Nullable,
926 0,
927 0,
928 BufferAllocatorRef::static_ref(),
929 );
930
931 builder
933 .append_value(Scalar::list(dtype, vec![0i32.into()], NonNullable).as_list())
934 .unwrap();
935
936 let source = source
938 .into_array()
939 .execute::<ListViewArray>(&mut ctx)
940 .unwrap();
941 builder
942 .append_listview_array(source.as_view(), &mut ctx)
943 .unwrap();
944
945 let empty_source = ListArray::from_iter_opt_slow::<u32, _, Vec<i32>>(
947 std::iter::empty::<Option<Vec<i32>>>(),
948 Arc::new(I32.into()),
949 )
950 .unwrap();
951 let empty_source = empty_source
952 .into_array()
953 .execute::<ListViewArray>(&mut ctx)
954 .unwrap();
955 builder
956 .append_listview_array(empty_source.as_view(), &mut ctx)
957 .unwrap();
958
959 let listview = builder.finish_into_listview();
960 assert_eq!(listview.len(), 4);
961
962 assert_arrays_eq!(
965 listview.list_elements_at(0).unwrap(),
966 PrimitiveArray::from_iter([0i32]),
967 &mut ctx
968 );
969
970 assert_arrays_eq!(
972 listview.list_elements_at(1).unwrap(),
973 PrimitiveArray::from_iter([1i32, 2, 3]),
974 &mut ctx
975 );
976
977 assert!(
979 !listview
980 .validity()
981 .vortex_expect("listview validity should be derivable")
982 .execute_is_valid(2, &mut ctx)
983 .unwrap()
984 );
985
986 assert_arrays_eq!(
988 listview.list_elements_at(3).unwrap(),
989 PrimitiveArray::from_iter([4i32, 5]),
990 &mut ctx
991 );
992 }
993
994 #[test]
995 fn test_append_list_array_grows_builder() -> VortexResult<()> {
996 let mut ctx = array_session().create_execution_ctx();
997 let dtype: Arc<DType> = Arc::new(I32.into());
998
999 let lists: Vec<Option<Vec<i32>>> =
1002 (0..100).map(|i| (i % 10 != 0).then(|| vec![i])).collect();
1003 let source = ListArray::from_iter_opt_slow::<u32, _, _>(lists.clone(), Arc::clone(&dtype))?;
1004
1005 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1006 Arc::clone(&dtype),
1007 Nullable,
1008 0,
1009 0,
1010 BufferAllocatorRef::static_ref(),
1011 );
1012 builder.append_list_array(source.as_view(), &mut ctx)?;
1013 builder.append_list_array(source.as_view(), &mut ctx)?;
1015
1016 let listview = builder.finish_into_listview();
1017 assert!(listview.is_zero_copy_to_list());
1018
1019 let expected = ListArray::from_iter_opt_slow::<u32, _, _>(
1020 lists.iter().cloned().chain(lists.iter().cloned()),
1021 dtype,
1022 )?;
1023 assert_arrays_eq!(listview, expected, &mut ctx);
1024
1025 Ok(())
1026 }
1027
1028 #[test]
1031 fn test_constant_list_append_keeps_one_copy_of_the_value() -> VortexResult<()> {
1032 let mut ctx = array_session().create_execution_ctx();
1033 let element_dtype: Arc<DType> = Arc::new(I32.into());
1034
1035 const ROWS: usize = 10_000;
1036 let fill = Scalar::list(
1037 Arc::clone(&element_dtype),
1038 vec![1i32.into(), 2i32.into(), 3i32.into()],
1039 NonNullable,
1040 );
1041 let constant = ConstantArray::new(fill, ROWS).into_array();
1042
1043 let mut builder = ListViewBuilder::<u64, u64>::with_capacity_in(
1044 element_dtype,
1045 NonNullable,
1046 0,
1047 0,
1048 BufferAllocatorRef::static_ref(),
1049 );
1050 constant.append_to_builder(&mut builder, &mut ctx)?;
1051 let listview = builder.finish_into_listview();
1052
1053 assert_eq!(listview.len(), ROWS);
1054 assert_eq!(
1055 listview.elements().len(),
1056 3,
1057 "the fill value should be stored once, not once per row",
1058 );
1059 assert!(!listview.is_zero_copy_to_list());
1060 assert_arrays_eq!(&listview.into_array(), &constant, &mut ctx);
1061
1062 Ok(())
1063 }
1064
1065 #[test]
1068 fn test_append_listview_array_trims_unreferenced_elements() -> VortexResult<()> {
1069 let mut ctx = array_session().create_execution_ctx();
1070 let dtype: Arc<DType> = Arc::new(I32.into());
1071
1072 let source = ListArray::from_iter_slow::<u32, _>(
1074 (0..5).map(|i| vec![2 * i, 2 * i + 1]),
1075 Arc::clone(&dtype),
1076 )?
1077 .into_array()
1078 .execute::<ListViewArray>(&mut ctx)?;
1079 let middle = source.slice(1..4)?.execute::<ListViewArray>(&mut ctx)?;
1080
1081 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1082 Arc::clone(&dtype),
1083 NonNullable,
1084 0,
1085 0,
1086 BufferAllocatorRef::static_ref(),
1087 );
1088 builder.append_listview_array(middle.as_view(), &mut ctx)?;
1089 builder.append_listview_array(middle.as_view(), &mut ctx)?;
1091 let listview = builder.finish_into_listview();
1092
1093 assert_eq!(
1094 listview.elements().len(),
1095 12,
1096 "only the six referenced elements of each append should have landed",
1097 );
1098 assert!(
1099 listview.is_zero_copy_to_list(),
1100 "trimming an exact source keeps the result exact",
1101 );
1102
1103 let expected = ListArray::from_iter_slow::<u32, _>(
1104 (1..4).chain(1..4).map(|i| vec![2 * i, 2 * i + 1]),
1105 dtype,
1106 )?;
1107 assert_arrays_eq!(listview, expected, &mut ctx);
1108
1109 Ok(())
1110 }
1111
1112 #[test]
1113 fn test_extend_from_array_overlapping_listview() {
1114 let mut ctx = array_session().create_execution_ctx();
1115 let dtype: Arc<DType> = Arc::new(I32.into());
1116
1117 let source = unsafe {
1122 ListViewArray::new_unchecked(
1123 buffer![10i32, 20, 30].into_array(),
1124 buffer![0u32, 1, 0].into_array(),
1125 buffer![2u8, 2, 1].into_array(),
1126 Validity::from_iter([true, false, true]),
1127 )
1128 };
1129 assert!(!source.is_zero_copy_to_list());
1130
1131 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1132 Arc::clone(&dtype),
1133 Nullable,
1134 0,
1135 0,
1136 BufferAllocatorRef::static_ref(),
1137 );
1138 builder
1139 .append_listview_array(source.as_view(), &mut ctx)
1140 .unwrap();
1141
1142 let listview = builder.finish_into_listview();
1143 assert_eq!(listview.len(), 3);
1144 assert!(!listview.is_zero_copy_to_list());
1146
1147 assert_arrays_eq!(
1148 listview.list_elements_at(0).unwrap(),
1149 PrimitiveArray::from_iter([10i32, 20]),
1150 &mut ctx
1151 );
1152 assert!(
1153 !listview
1154 .validity()
1155 .vortex_expect("listview validity should be derivable")
1156 .execute_is_valid(1, &mut ctx)
1157 .unwrap()
1158 );
1159 assert_eq!(listview.size_at(1), source.size_at(1));
1161 assert_arrays_eq!(
1162 listview.list_elements_at(2).unwrap(),
1163 PrimitiveArray::from_iter([10i32]),
1164 &mut ctx
1165 );
1166 }
1167
1168 #[test]
1169 fn test_error_append_null_to_non_nullable() {
1170 let dtype: Arc<DType> = Arc::new(I32.into());
1171 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1172 Arc::clone(&dtype),
1173 NonNullable,
1174 0,
1175 0,
1176 BufferAllocatorRef::static_ref(),
1177 );
1178
1179 let null_scalar = Scalar::null(DType::List(dtype, Nullable));
1181 let null_list = null_scalar.as_list();
1182
1183 let result = builder.append_value(null_list);
1185 assert!(result.is_err());
1186 assert!(
1187 result
1188 .unwrap_err()
1189 .to_string()
1190 .contains("null value to non-nullable")
1191 );
1192 }
1193
1194 #[test]
1195 fn test_append_array_as_list() {
1196 let dtype: Arc<DType> = Arc::new(I32.into());
1197 let mut ctx = array_session().create_execution_ctx();
1198 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1199 Arc::clone(&dtype),
1200 NonNullable,
1201 20,
1202 10,
1203 BufferAllocatorRef::static_ref(),
1204 );
1205
1206 let arr1 = buffer![1i32, 2, 3].into_array();
1208 builder.append_array_as_list(&arr1, &mut ctx).unwrap();
1209
1210 builder
1212 .append_value(
1213 Scalar::list(
1214 Arc::clone(&dtype),
1215 vec![10i32.into(), 11i32.into()],
1216 NonNullable,
1217 )
1218 .as_list(),
1219 )
1220 .unwrap();
1221
1222 let arr2 = buffer![4i32, 5].into_array();
1224 builder.append_array_as_list(&arr2, &mut ctx).unwrap();
1225
1226 let arr3 = buffer![0i32; 0].into_array();
1228 builder.append_array_as_list(&arr3, &mut ctx).unwrap();
1229
1230 builder
1232 .append_value(Scalar::list_empty(Arc::clone(&dtype), NonNullable).as_list())
1233 .unwrap();
1234
1235 let listview = builder.finish_into_listview();
1236 assert_eq!(listview.len(), 5);
1237
1238 assert_arrays_eq!(
1240 listview.elements(),
1241 PrimitiveArray::from_iter([1i32, 2, 3, 10, 11, 4, 5]),
1242 &mut ctx
1243 );
1244
1245 assert_arrays_eq!(
1247 listview.offsets(),
1248 PrimitiveArray::from_iter([0u32, 3, 5, 7, 7]),
1249 &mut ctx
1250 );
1251
1252 assert_arrays_eq!(
1254 listview.sizes(),
1255 PrimitiveArray::from_iter([3u32, 2, 2, 0, 0]),
1256 &mut ctx
1257 );
1258
1259 let mut builder = ListViewBuilder::<u32, u32>::with_capacity_in(
1261 dtype,
1262 NonNullable,
1263 20,
1264 10,
1265 BufferAllocatorRef::static_ref(),
1266 );
1267 let wrong_dtype_arr = buffer![1i64, 2, 3].into_array();
1268 assert!(
1269 builder
1270 .append_array_as_list(&wrong_dtype_arr, &mut ctx)
1271 .is_err()
1272 );
1273 }
1274}