1use std::any::Any;
5use std::mem::MaybeUninit;
6
7use vortex_buffer::BufferAllocatorRef;
8use vortex_buffer::BufferMut;
9use vortex_error::VortexExpect;
10use vortex_error::VortexResult;
11use vortex_error::vortex_ensure_eq;
12use vortex_mask::Mask;
13
14use crate::ArrayRef;
15use crate::ExecutionCtx;
16use crate::IntoArray;
17use crate::arrays::PrimitiveArray;
18use crate::builders::ArrayBuilder;
19use crate::builders::DEFAULT_BUILDER_CAPACITY;
20use crate::builders::LazyBitBufferBuilder;
21use crate::canonical::Canonical;
22use crate::dtype::DType;
23use crate::dtype::NativePType;
24use crate::dtype::Nullability;
25use crate::scalar::Scalar;
26
27pub struct PrimitiveBuilder<T> {
29 dtype: DType,
30 values: BufferMut<T>,
31 nulls: LazyBitBufferBuilder,
32}
33
34impl<T: NativePType> PrimitiveBuilder<T> {
35 #[deprecated(note = "use `new_in` with an explicit allocator")]
37 pub fn new(nullability: Nullability) -> Self {
38 Self::new_in(nullability, BufferAllocatorRef::static_ref())
39 }
40
41 pub fn new_in(nullability: Nullability, allocator: &BufferAllocatorRef) -> Self {
43 Self::with_capacity_in(nullability, DEFAULT_BUILDER_CAPACITY, allocator)
44 }
45
46 #[deprecated(note = "use `with_capacity_in` with an explicit allocator")]
48 pub fn with_capacity(nullability: Nullability, capacity: usize) -> Self {
49 Self::with_capacity_in(nullability, capacity, BufferAllocatorRef::static_ref())
50 }
51
52 pub fn with_capacity_in(
54 nullability: Nullability,
55 capacity: usize,
56 allocator: &BufferAllocatorRef,
57 ) -> Self {
58 Self {
59 values: BufferMut::with_capacity_in(capacity, allocator.clone()),
60 nulls: LazyBitBufferBuilder::new(capacity, allocator.clone()),
61 dtype: DType::Primitive(T::PTYPE, nullability),
62 }
63 }
64
65 pub fn append_value(&mut self, value: T) {
67 self.values.push(value);
68 self.nulls.append_non_null();
69 }
70
71 pub fn append_n_values(&mut self, value: T, n: usize) {
73 self.values.push_n(value, n);
74 self.nulls.append_n_non_nulls(n);
75 }
76
77 pub fn values(&self) -> &[T] {
79 self.values.as_ref()
80 }
81
82 pub fn values_mut(&mut self) -> &mut [T] {
84 self.values.as_mut()
85 }
86
87 pub fn uninit_range(&mut self, len: usize) -> UninitRange<'_, T> {
122 assert_ne!(0, len, "cannot create an uninit range of length 0");
123
124 let current_len = self.values.len();
125 assert!(
126 current_len + len <= self.values.capacity(),
127 "uninit_range of len {len} exceeds builder with length {} and capacity {}",
128 current_len,
129 self.values.capacity()
130 );
131
132 UninitRange { len, builder: self }
133 }
134
135 pub fn finish_into_primitive(&mut self) -> PrimitiveArray {
137 let validity = self
138 .nulls
139 .finish_with_nullability(self.dtype().nullability());
140
141 let values = self.values.take().freeze();
142 PrimitiveArray::new(values, validity)
143 }
144
145 pub fn extend_with_iterator(&mut self, iter: impl IntoIterator<Item = T>, mask: &Mask) {
147 self.values.extend(iter);
148 self.nulls.append_validity_mask(mask);
149 }
150
151 pub(crate) fn append_primitive_array(
152 &mut self,
153 array: &PrimitiveArray,
154 ctx: &mut ExecutionCtx,
155 ) -> VortexResult<()> {
156 debug_assert_eq!(
157 array.ptype(),
158 T::PTYPE,
159 "Cannot append primitive array with different ptype"
160 );
161
162 self.values.extend_from_slice(array.as_slice::<T>());
163 self.nulls.append_validity_mask(
164 &array
165 .as_ref()
166 .validity()
167 .vortex_expect("validity_mask")
168 .execute_mask(array.as_ref().len(), ctx)?,
169 );
170 Ok(())
171 }
172}
173
174impl<T: NativePType> ArrayBuilder for PrimitiveBuilder<T> {
175 fn as_any(&self) -> &dyn Any {
176 self
177 }
178
179 fn as_any_mut(&mut self) -> &mut dyn Any {
180 self
181 }
182
183 fn dtype(&self) -> &DType {
184 &self.dtype
185 }
186
187 fn len(&self) -> usize {
188 self.values.len()
189 }
190
191 fn append_zeros(&mut self, n: usize) {
192 self.values.push_n(T::default(), n);
193 self.nulls.append_n_non_nulls(n);
194 }
195
196 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
197 self.values.push_n(T::default(), n);
198 self.nulls.append_n_nulls(n);
199 }
200
201 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
202 vortex_ensure_eq!(
203 scalar.dtype(),
204 self.dtype(),
205 "PrimitiveBuilder received a scalar with the wrong dtype"
206 );
207
208 if let Some(pv) = scalar.as_primitive().pvalue() {
209 self.append_value(pv.cast::<T>()?)
210 } else {
211 self.append_null()
212 }
213
214 Ok(())
215 }
216
217 fn reserve_exact(&mut self, additional: usize) {
218 self.values.reserve(additional);
219 self.nulls.reserve_exact(additional);
220 }
221
222 fn finish(&mut self) -> ArrayRef {
223 self.finish_into_primitive().into_array()
224 }
225
226 fn finish_into_canonical(&mut self, _ctx: &mut ExecutionCtx) -> Canonical {
227 Canonical::Primitive(self.finish_into_primitive())
228 }
229}
230
231pub struct UninitRange<'a, T> {
233 len: usize,
237
238 builder: &'a mut PrimitiveBuilder<T>,
243}
244
245impl<T> UninitRange<'_, T> {
246 #[inline]
248 pub fn len(&self) -> usize {
249 self.len
250 }
251
252 #[inline]
254 pub fn is_empty(&self) -> bool {
255 self.len == 0
256 }
257
258 #[inline]
264 pub fn set_value(&mut self, index: usize, value: T) {
265 assert!(index < self.len, "index out of bounds");
266 let spare = self.builder.values.spare_capacity_mut();
267 spare[index] = MaybeUninit::new(value);
268 }
269
270 pub unsafe fn append_mask(&mut self, mask: &Mask) {
282 assert_eq!(
283 mask.len(),
284 self.len,
285 "Tried to append a mask to an `UninitRange` that was beyond the allowed range"
286 );
287
288 self.builder.nulls.append_validity_mask(mask);
293 }
294
295 pub fn set_validity_bit(&mut self, index: usize, v: bool) {
302 assert!(index < self.len, "set_bit index out of bounds");
303 let absolute_index = self.builder.values.len() + index;
306 self.builder.nulls.set_bit(absolute_index, v);
307 }
308
309 pub fn copy_from_slice(&mut self, local_offset: usize, src: &[T])
314 where
315 T: Copy,
316 {
317 debug_assert!(
318 local_offset + src.len() <= self.len,
319 "tried to copy a slice into a `UninitRange` past its boundary"
320 );
321
322 let dst =
325 &mut self.builder.values.spare_capacity_mut()[local_offset..local_offset + src.len()];
326 dst.write_copy_of_slice(src);
327 }
328
329 pub unsafe fn slice_uninit_mut(&mut self, offset: usize, len: usize) -> &mut [MaybeUninit<T>] {
343 assert!(
344 offset + len <= self.len,
345 "slice_uninit_mut: offset {} + len {} exceeds range length {}",
346 offset,
347 len,
348 self.len
349 );
350 &mut self.builder.values.spare_capacity_mut()[offset..offset + len]
351 }
352
353 pub unsafe fn finish(self) {
367 let new_len = self.builder.values.len() + self.len;
369 unsafe { self.builder.values.set_len(new_len) };
370 }
371}
372
373#[cfg(test)]
374mod tests {
375 use vortex_error::VortexExpect;
376
377 use super::*;
378 use crate::VortexSessionExecute;
379 use crate::array_session;
380 use crate::assert_arrays_eq;
381
382 #[test]
387 fn test_multiple_uninit_ranges_correct_offsets() {
388 let mut ctx = array_session().create_execution_ctx();
389 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
390 Nullability::NonNullable,
391 10,
392 BufferAllocatorRef::static_ref(),
393 );
394
395 let mut range1 = builder.uninit_range(3);
397 range1.copy_from_slice(0, &[1, 2, 3]);
398
399 unsafe {
401 range1.finish();
402 }
403
404 assert_eq!(builder.values(), &[1, 2, 3]);
406
407 let mut range2 = builder.uninit_range(2);
409
410 range2.copy_from_slice(0, &[4, 5]);
412
413 unsafe {
415 range2.finish();
416 }
417
418 assert_eq!(builder.values(), &[1, 2, 3, 4, 5]);
420
421 let array = builder.finish_into_primitive();
422 assert_arrays_eq!(
423 array,
424 PrimitiveArray::from_iter([1i32, 2, 3, 4, 5]),
425 &mut ctx
426 );
427 }
428
429 #[test]
435 fn test_append_mask_on_uninit_range() {
436 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
437 Nullability::Nullable,
438 5,
439 BufferAllocatorRef::static_ref(),
440 );
441 let mut range = builder.uninit_range(3);
442
443 let mask = Mask::from_iter([true, false, true]);
445
446 unsafe {
448 range.append_mask(&mask);
449 }
450
451 range.copy_from_slice(0, &[10, 20, 30]);
453
454 unsafe {
456 range.finish();
457 }
458
459 let array = builder.finish_into_primitive();
460 assert_eq!(array.len(), 3);
461 assert!(
463 !array
464 .execute_scalar(0, &mut array_session().create_execution_ctx())
465 .unwrap()
466 .is_null()
467 );
468 assert!(
469 array
470 .execute_scalar(1, &mut array_session().create_execution_ctx())
471 .unwrap()
472 .is_null()
473 );
474 assert!(
475 !array
476 .execute_scalar(2, &mut array_session().create_execution_ctx())
477 .unwrap()
478 .is_null()
479 );
480 assert_arrays_eq!(
481 array,
482 PrimitiveArray::from_option_iter([Some(10i32), None, Some(30)]),
483 &mut array_session().create_execution_ctx()
484 );
485 }
486
487 #[test]
491 #[should_panic(
492 expected = "Tried to append a mask to an `UninitRange` that was beyond the allowed range"
493 )]
494 fn test_append_mask_wrong_length_panics() {
495 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
496 Nullability::Nullable,
497 10,
498 BufferAllocatorRef::static_ref(),
499 );
500 let mut range = builder.uninit_range(5);
501
502 let wrong_mask = Mask::from_iter([true, false, true]);
504
505 unsafe {
507 range.append_mask(&wrong_mask);
508 }
509 }
510
511 #[test]
515 fn test_copy_from_slice_with_offsets() {
516 let mut ctx = array_session().create_execution_ctx();
517 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
518 Nullability::NonNullable,
519 10,
520 BufferAllocatorRef::static_ref(),
521 );
522 let mut range = builder.uninit_range(6);
523
524 range.copy_from_slice(0, &[1, 2]);
526 range.copy_from_slice(2, &[3, 4]);
527 range.copy_from_slice(4, &[5, 6]);
528
529 unsafe {
531 range.finish();
532 }
533
534 let array = builder.finish_into_primitive();
535 assert_arrays_eq!(
536 array,
537 PrimitiveArray::from_iter([1i32, 2, 3, 4, 5, 6]),
538 &mut ctx
539 );
540 }
541
542 #[test]
548 fn test_set_bit_relative_indexing() {
549 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
550 Nullability::Nullable,
551 10,
552 BufferAllocatorRef::static_ref(),
553 );
554
555 builder.append_value(100);
557 builder.append_value(200);
558
559 let mut range = builder.uninit_range(3);
561
562 let initial_mask = Mask::from_iter([false, false, false]);
564 unsafe {
566 range.append_mask(&initial_mask);
567 }
568
569 range.set_validity_bit(0, true); range.set_validity_bit(2, true); range.copy_from_slice(0, &[10, 20, 30]);
576
577 unsafe {
579 range.finish();
580 }
581
582 let array = builder.finish_into_primitive();
583
584 assert_eq!(array.len(), 5);
586 assert_eq!(array.as_slice::<i32>(), &[100, 200, 10, 20, 30]);
587
588 assert!(
590 !array
591 .execute_scalar(0, &mut array_session().create_execution_ctx())
592 .unwrap()
593 .is_null()
594 ); assert!(
596 !array
597 .execute_scalar(1, &mut array_session().create_execution_ctx())
598 .unwrap()
599 .is_null()
600 ); assert!(
604 !array
605 .execute_scalar(2, &mut array_session().create_execution_ctx())
606 .unwrap()
607 .is_null()
608 ); assert!(
610 array
611 .execute_scalar(3, &mut array_session().create_execution_ctx())
612 .unwrap()
613 .is_null()
614 ); assert!(
616 !array
617 .execute_scalar(4, &mut array_session().create_execution_ctx())
618 .unwrap()
619 .is_null()
620 ); }
622
623 #[test]
625 #[should_panic(expected = "cannot create an uninit range of length 0")]
626 fn test_zero_length_uninit_range_panics() {
627 let mut builder = PrimitiveBuilder::<i32>::new_in(
628 Nullability::NonNullable,
629 BufferAllocatorRef::static_ref(),
630 );
631 let _range = builder.uninit_range(0);
632 }
633
634 #[test]
636 #[should_panic(expected = "uninit_range of len 261 exceeds builder with length 0 and capacity")]
637 fn test_uninit_range_exceeds_capacity_panics() {
638 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
639 Nullability::NonNullable,
640 5,
641 BufferAllocatorRef::static_ref(),
642 );
643 let _range = builder.uninit_range(261);
644 }
645
646 #[test]
650 #[cfg(debug_assertions)]
651 #[should_panic(expected = "tried to copy a slice into a `UninitRange` past its boundary")]
652 fn test_copy_from_slice_out_of_bounds() {
653 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
654 Nullability::NonNullable,
655 10,
656 BufferAllocatorRef::static_ref(),
657 );
658 let mut range = builder.uninit_range(3);
659
660 range.copy_from_slice(1, &[1, 2, 3]);
662 }
663
664 #[test]
668 fn test_finish_unsafe_contract() {
669 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
670 Nullability::Nullable,
671 5,
672 BufferAllocatorRef::static_ref(),
673 );
674 let mut range = builder.uninit_range(3);
675
676 let mask = Mask::from_iter([true, true, false]);
678 unsafe {
680 range.append_mask(&mask);
681 }
682
683 range.copy_from_slice(0, &[10, 20, 30]);
685
686 unsafe {
688 range.finish();
689 }
690
691 let array = builder.finish_into_primitive();
692 assert_eq!(array.len(), 3);
693 assert_eq!(array.as_slice::<i32>(), &[10, 20, 30]);
694 assert_arrays_eq!(
695 array,
696 PrimitiveArray::from_option_iter([Some(10i32), Some(20), None]),
697 &mut array_session().create_execution_ctx()
698 );
699 }
700
701 #[test]
702 fn test_append_scalar() {
703 use crate::dtype::DType;
704 use crate::scalar::Scalar;
705
706 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
707 Nullability::Nullable,
708 10,
709 BufferAllocatorRef::static_ref(),
710 );
711
712 let scalar1 = Scalar::primitive(42i32, Nullability::Nullable);
714 builder.append_scalar(&scalar1).unwrap();
715
716 let scalar2 = Scalar::primitive(84i32, Nullability::Nullable);
718 builder.append_scalar(&scalar2).unwrap();
719
720 let null_scalar = Scalar::null(DType::Primitive(
722 crate::dtype::PType::I32,
723 Nullability::Nullable,
724 ));
725 builder.append_scalar(&null_scalar).unwrap();
726
727 let array = builder.finish_into_primitive();
728 assert_eq!(array.len(), 3);
729
730 let values = array.as_slice::<i32>();
732 assert_eq!(values[0], 42);
733 assert_eq!(values[1], 84);
734 let mut ctx = array_session().create_execution_ctx();
738 assert!(
739 array
740 .validity()
741 .vortex_expect("primitive validity should be derivable")
742 .execute_is_valid(0, &mut ctx)
743 .unwrap()
744 );
745 assert!(
746 array
747 .validity()
748 .vortex_expect("primitive validity should be derivable")
749 .execute_is_valid(1, &mut ctx)
750 .unwrap()
751 );
752 assert!(
753 !array
754 .validity()
755 .vortex_expect("primitive validity should be derivable")
756 .execute_is_valid(2, &mut ctx)
757 .unwrap()
758 );
759
760 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
762 Nullability::NonNullable,
763 10,
764 BufferAllocatorRef::static_ref(),
765 );
766 let wrong_scalar = Scalar::from(true);
767 assert!(builder.append_scalar(&wrong_scalar).is_err());
768 }
769}