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;
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 allocator = self.values.allocator().clone();
142 let values = std::mem::replace(&mut self.values, allocator.with_capacity(0)).freeze();
143 PrimitiveArray::new(values, validity)
144 }
145
146 pub fn extend_with_iterator(&mut self, iter: impl IntoIterator<Item = T>, mask: &Mask) {
148 self.values.extend(iter);
149 self.nulls.append_validity_mask(mask);
150 }
151
152 pub(crate) fn append_primitive_array(
153 &mut self,
154 array: &PrimitiveArray,
155 ctx: &mut ExecutionCtx,
156 ) -> VortexResult<()> {
157 debug_assert_eq!(
158 array.ptype(),
159 T::PTYPE,
160 "Cannot append primitive array with different ptype"
161 );
162
163 self.values.extend_from_slice(array.as_slice::<T>());
164 self.nulls.append_validity_mask(
165 &array
166 .as_ref()
167 .validity()
168 .vortex_expect("validity_mask")
169 .execute_mask(array.as_ref().len(), ctx)?,
170 );
171 Ok(())
172 }
173}
174
175impl<T: NativePType> ArrayBuilder for PrimitiveBuilder<T> {
176 fn as_any(&self) -> &dyn Any {
177 self
178 }
179
180 fn as_any_mut(&mut self) -> &mut dyn Any {
181 self
182 }
183
184 fn dtype(&self) -> &DType {
185 &self.dtype
186 }
187
188 fn len(&self) -> usize {
189 self.values.len()
190 }
191
192 fn append_zeros(&mut self, n: usize) {
193 self.values.push_n(T::default(), n);
194 self.nulls.append_n_non_nulls(n);
195 }
196
197 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
198 self.values.push_n(T::default(), n);
199 self.nulls.append_n_nulls(n);
200 }
201
202 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
203 vortex_ensure!(
204 scalar.dtype() == self.dtype(),
205 "PrimitiveBuilder expected scalar with dtype {}, got {}",
206 self.dtype(),
207 scalar.dtype()
208 );
209
210 if let Some(pv) = scalar.as_primitive().pvalue() {
211 self.append_value(pv.cast::<T>()?)
212 } else {
213 self.append_null()
214 }
215
216 Ok(())
217 }
218
219 fn reserve_exact(&mut self, additional: usize) {
220 self.values.reserve(additional);
221 self.nulls.reserve_exact(additional);
222 }
223
224 fn finish(&mut self) -> ArrayRef {
225 self.finish_into_primitive().into_array()
226 }
227
228 fn finish_into_canonical(&mut self, _ctx: &mut ExecutionCtx) -> Canonical {
229 Canonical::Primitive(self.finish_into_primitive())
230 }
231}
232
233pub struct UninitRange<'a, T> {
235 len: usize,
239
240 builder: &'a mut PrimitiveBuilder<T>,
245}
246
247impl<T> UninitRange<'_, T> {
248 #[inline]
250 pub fn len(&self) -> usize {
251 self.len
252 }
253
254 #[inline]
256 pub fn is_empty(&self) -> bool {
257 self.len == 0
258 }
259
260 #[inline]
266 pub fn set_value(&mut self, index: usize, value: T) {
267 assert!(index < self.len, "index out of bounds");
268 let spare = self.builder.values.spare_capacity_mut();
269 spare[index] = MaybeUninit::new(value);
270 }
271
272 pub unsafe fn append_mask(&mut self, mask: &Mask) {
284 assert_eq!(
285 mask.len(),
286 self.len,
287 "Tried to append a mask to an `UninitRange` that was beyond the allowed range"
288 );
289
290 self.builder.nulls.append_validity_mask(mask);
295 }
296
297 pub fn set_validity_bit(&mut self, index: usize, v: bool) {
304 assert!(index < self.len, "set_bit index out of bounds");
305 let absolute_index = self.builder.values.len() + index;
308 self.builder.nulls.set_bit(absolute_index, v);
309 }
310
311 pub fn copy_from_slice(&mut self, local_offset: usize, src: &[T])
316 where
317 T: Copy,
318 {
319 debug_assert!(
320 local_offset + src.len() <= self.len,
321 "tried to copy a slice into a `UninitRange` past its boundary"
322 );
323
324 let uninit_src: &[MaybeUninit<T>] = unsafe { std::mem::transmute(src) };
326
327 let dst =
330 &mut self.builder.values.spare_capacity_mut()[local_offset..local_offset + src.len()];
331 dst.copy_from_slice(uninit_src);
332 }
333
334 pub unsafe fn slice_uninit_mut(&mut self, offset: usize, len: usize) -> &mut [MaybeUninit<T>] {
348 assert!(
349 offset + len <= self.len,
350 "slice_uninit_mut: offset {} + len {} exceeds range length {}",
351 offset,
352 len,
353 self.len
354 );
355 &mut self.builder.values.spare_capacity_mut()[offset..offset + len]
356 }
357
358 pub unsafe fn finish(self) {
372 let new_len = self.builder.values.len() + self.len;
374 unsafe { self.builder.values.set_len(new_len) };
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use vortex_error::VortexExpect;
381
382 use super::*;
383 use crate::VortexSessionExecute;
384 use crate::array_session;
385 use crate::assert_arrays_eq;
386
387 #[test]
392 fn test_multiple_uninit_ranges_correct_offsets() {
393 let mut ctx = array_session().create_execution_ctx();
394 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
395 Nullability::NonNullable,
396 10,
397 BufferAllocatorRef::static_ref(),
398 );
399
400 let mut range1 = builder.uninit_range(3);
402 range1.copy_from_slice(0, &[1, 2, 3]);
403
404 unsafe {
406 range1.finish();
407 }
408
409 assert_eq!(builder.values(), &[1, 2, 3]);
411
412 let mut range2 = builder.uninit_range(2);
414
415 range2.copy_from_slice(0, &[4, 5]);
417
418 unsafe {
420 range2.finish();
421 }
422
423 assert_eq!(builder.values(), &[1, 2, 3, 4, 5]);
425
426 let array = builder.finish_into_primitive();
427 assert_arrays_eq!(
428 array,
429 PrimitiveArray::from_iter([1i32, 2, 3, 4, 5]),
430 &mut ctx
431 );
432 }
433
434 #[test]
440 fn test_append_mask_on_uninit_range() {
441 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
442 Nullability::Nullable,
443 5,
444 BufferAllocatorRef::static_ref(),
445 );
446 let mut range = builder.uninit_range(3);
447
448 let mask = Mask::from_iter([true, false, true]);
450
451 unsafe {
453 range.append_mask(&mask);
454 }
455
456 range.copy_from_slice(0, &[10, 20, 30]);
458
459 unsafe {
461 range.finish();
462 }
463
464 let array = builder.finish_into_primitive();
465 assert_eq!(array.len(), 3);
466 assert!(
468 !array
469 .execute_scalar(0, &mut array_session().create_execution_ctx())
470 .unwrap()
471 .is_null()
472 );
473 assert!(
474 array
475 .execute_scalar(1, &mut array_session().create_execution_ctx())
476 .unwrap()
477 .is_null()
478 );
479 assert!(
480 !array
481 .execute_scalar(2, &mut array_session().create_execution_ctx())
482 .unwrap()
483 .is_null()
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 }
695
696 #[test]
697 fn test_append_scalar() {
698 use crate::dtype::DType;
699 use crate::scalar::Scalar;
700
701 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
702 Nullability::Nullable,
703 10,
704 BufferAllocatorRef::static_ref(),
705 );
706
707 let scalar1 = Scalar::primitive(42i32, Nullability::Nullable);
709 builder.append_scalar(&scalar1).unwrap();
710
711 let scalar2 = Scalar::primitive(84i32, Nullability::Nullable);
713 builder.append_scalar(&scalar2).unwrap();
714
715 let null_scalar = Scalar::null(DType::Primitive(
717 crate::dtype::PType::I32,
718 Nullability::Nullable,
719 ));
720 builder.append_scalar(&null_scalar).unwrap();
721
722 let array = builder.finish_into_primitive();
723 assert_eq!(array.len(), 3);
724
725 let values = array.as_slice::<i32>();
727 assert_eq!(values[0], 42);
728 assert_eq!(values[1], 84);
729 let mut ctx = array_session().create_execution_ctx();
733 assert!(
734 array
735 .validity()
736 .vortex_expect("primitive validity should be derivable")
737 .execute_is_valid(0, &mut ctx)
738 .unwrap()
739 );
740 assert!(
741 array
742 .validity()
743 .vortex_expect("primitive validity should be derivable")
744 .execute_is_valid(1, &mut ctx)
745 .unwrap()
746 );
747 assert!(
748 !array
749 .validity()
750 .vortex_expect("primitive validity should be derivable")
751 .execute_is_valid(2, &mut ctx)
752 .unwrap()
753 );
754
755 let mut builder = PrimitiveBuilder::<i32>::with_capacity_in(
757 Nullability::NonNullable,
758 10,
759 BufferAllocatorRef::static_ref(),
760 );
761 let wrong_scalar = Scalar::from(true);
762 assert!(builder.append_scalar(&wrong_scalar).is_err());
763 }
764}