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 }
481
482 #[test]
486 #[should_panic(
487 expected = "Tried to append a mask to an `UninitRange` that was beyond the allowed range"
488 )]
489 fn test_append_mask_wrong_length_panics() {
490 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
491 Nullability::Nullable,
492 10,
493 BufferAllocatorRef::static_ref(),
494 );
495 let mut range = builder.uninit_range(5);
496
497 let wrong_mask = Mask::from_iter([true, false, true]);
499
500 unsafe {
502 range.append_mask(&wrong_mask);
503 }
504 }
505
506 #[test]
510 fn test_copy_from_slice_with_offsets() {
511 let mut ctx = array_session().create_execution_ctx();
512 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
513 Nullability::NonNullable,
514 10,
515 BufferAllocatorRef::static_ref(),
516 );
517 let mut range = builder.uninit_range(6);
518
519 range.copy_from_slice(0, &[1, 2]);
521 range.copy_from_slice(2, &[3, 4]);
522 range.copy_from_slice(4, &[5, 6]);
523
524 unsafe {
526 range.finish();
527 }
528
529 let array = builder.finish_into_primitive();
530 assert_arrays_eq!(
531 array,
532 PrimitiveArray::from_iter([1i32, 2, 3, 4, 5, 6]),
533 &mut ctx
534 );
535 }
536
537 #[test]
543 fn test_set_bit_relative_indexing() {
544 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
545 Nullability::Nullable,
546 10,
547 BufferAllocatorRef::static_ref(),
548 );
549
550 builder.append_value(100);
552 builder.append_value(200);
553
554 let mut range = builder.uninit_range(3);
556
557 let initial_mask = Mask::from_iter([false, false, false]);
559 unsafe {
561 range.append_mask(&initial_mask);
562 }
563
564 range.set_validity_bit(0, true); range.set_validity_bit(2, true); range.copy_from_slice(0, &[10, 20, 30]);
571
572 unsafe {
574 range.finish();
575 }
576
577 let array = builder.finish_into_primitive();
578
579 assert_eq!(array.len(), 5);
581 assert_eq!(array.as_slice::<i32>(), &[100, 200, 10, 20, 30]);
582
583 assert!(
585 !array
586 .execute_scalar(0, &mut array_session().create_execution_ctx())
587 .unwrap()
588 .is_null()
589 ); assert!(
591 !array
592 .execute_scalar(1, &mut array_session().create_execution_ctx())
593 .unwrap()
594 .is_null()
595 ); assert!(
599 !array
600 .execute_scalar(2, &mut array_session().create_execution_ctx())
601 .unwrap()
602 .is_null()
603 ); assert!(
605 array
606 .execute_scalar(3, &mut array_session().create_execution_ctx())
607 .unwrap()
608 .is_null()
609 ); assert!(
611 !array
612 .execute_scalar(4, &mut array_session().create_execution_ctx())
613 .unwrap()
614 .is_null()
615 ); }
617
618 #[test]
620 #[should_panic(expected = "cannot create an uninit range of length 0")]
621 fn test_zero_length_uninit_range_panics() {
622 let mut builder = PrimitiveBuilder::<i32>::new_in(
623 Nullability::NonNullable,
624 BufferAllocatorRef::static_ref(),
625 );
626 let _range = builder.uninit_range(0);
627 }
628
629 #[test]
631 #[should_panic(expected = "uninit_range of len 261 exceeds builder with length 0 and capacity")]
632 fn test_uninit_range_exceeds_capacity_panics() {
633 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
634 Nullability::NonNullable,
635 5,
636 BufferAllocatorRef::static_ref(),
637 );
638 let _range = builder.uninit_range(261);
639 }
640
641 #[test]
645 #[cfg(debug_assertions)]
646 #[should_panic(expected = "tried to copy a slice into a `UninitRange` past its boundary")]
647 fn test_copy_from_slice_out_of_bounds() {
648 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
649 Nullability::NonNullable,
650 10,
651 BufferAllocatorRef::static_ref(),
652 );
653 let mut range = builder.uninit_range(3);
654
655 range.copy_from_slice(1, &[1, 2, 3]);
657 }
658
659 #[test]
663 fn test_finish_unsafe_contract() {
664 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
665 Nullability::Nullable,
666 5,
667 BufferAllocatorRef::static_ref(),
668 );
669 let mut range = builder.uninit_range(3);
670
671 let mask = Mask::from_iter([true, true, false]);
673 unsafe {
675 range.append_mask(&mask);
676 }
677
678 range.copy_from_slice(0, &[10, 20, 30]);
680
681 unsafe {
683 range.finish();
684 }
685
686 let array = builder.finish_into_primitive();
687 assert_eq!(array.len(), 3);
688 assert_eq!(array.as_slice::<i32>(), &[10, 20, 30]);
689 }
690
691 #[test]
692 fn test_append_scalar() {
693 use crate::dtype::DType;
694 use crate::scalar::Scalar;
695
696 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
697 Nullability::Nullable,
698 10,
699 BufferAllocatorRef::static_ref(),
700 );
701
702 let scalar1 = Scalar::primitive(42i32, Nullability::Nullable);
704 builder.append_scalar(&scalar1).unwrap();
705
706 let scalar2 = Scalar::primitive(84i32, Nullability::Nullable);
708 builder.append_scalar(&scalar2).unwrap();
709
710 let null_scalar = Scalar::null(DType::Primitive(
712 crate::dtype::PType::I32,
713 Nullability::Nullable,
714 ));
715 builder.append_scalar(&null_scalar).unwrap();
716
717 let array = builder.finish_into_primitive();
718 assert_eq!(array.len(), 3);
719
720 let values = array.as_slice::<i32>();
722 assert_eq!(values[0], 42);
723 assert_eq!(values[1], 84);
724 let mut ctx = array_session().create_execution_ctx();
728 assert!(
729 array
730 .validity()
731 .vortex_expect("primitive validity should be derivable")
732 .execute_is_valid(0, &mut ctx)
733 .unwrap()
734 );
735 assert!(
736 array
737 .validity()
738 .vortex_expect("primitive validity should be derivable")
739 .execute_is_valid(1, &mut ctx)
740 .unwrap()
741 );
742 assert!(
743 !array
744 .validity()
745 .vortex_expect("primitive validity should be derivable")
746 .execute_is_valid(2, &mut ctx)
747 .unwrap()
748 );
749
750 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
752 Nullability::NonNullable,
753 10,
754 BufferAllocatorRef::static_ref(),
755 );
756 let wrong_scalar = Scalar::from(true);
757 assert!(builder.append_scalar(&wrong_scalar).is_err());
758 }
759}