1use std::any::Any;
5use std::mem::MaybeUninit;
6
7use vortex_buffer::BufferMut;
8use vortex_error::VortexExpect;
9use vortex_error::VortexResult;
10use vortex_error::vortex_ensure;
11use vortex_mask::Mask;
12
13use crate::ArrayRef;
14use crate::ExecutionCtx;
15use crate::IntoArray;
16use crate::LEGACY_SESSION;
17use crate::VortexSessionExecute;
18use crate::arrays::PrimitiveArray;
19use crate::builders::ArrayBuilder;
20use crate::builders::DEFAULT_BUILDER_CAPACITY;
21use crate::builders::LazyBitBufferBuilder;
22use crate::canonical::Canonical;
23#[expect(deprecated)]
24use crate::canonical::ToCanonical as _;
25use crate::dtype::DType;
26use crate::dtype::NativePType;
27use crate::dtype::Nullability;
28use crate::scalar::Scalar;
29
30pub struct PrimitiveBuilder<T> {
32 dtype: DType,
33 values: BufferMut<T>,
34 nulls: LazyBitBufferBuilder,
35}
36
37impl<T: NativePType> PrimitiveBuilder<T> {
38 pub fn new(nullability: Nullability) -> Self {
40 Self::with_capacity(nullability, DEFAULT_BUILDER_CAPACITY)
41 }
42
43 pub fn with_capacity(nullability: Nullability, capacity: usize) -> Self {
45 Self {
46 values: BufferMut::with_capacity(capacity),
47 nulls: LazyBitBufferBuilder::new(capacity),
48 dtype: DType::Primitive(T::PTYPE, nullability),
49 }
50 }
51
52 pub fn append_value(&mut self, value: T) {
54 self.values.push(value);
55 self.nulls.append_non_null();
56 }
57
58 pub fn append_n_values(&mut self, value: T, n: usize) {
60 self.values.push_n(value, n);
61 self.nulls.append_n_non_nulls(n);
62 }
63
64 pub fn values(&self) -> &[T] {
66 self.values.as_ref()
67 }
68
69 pub fn values_mut(&mut self) -> &mut [T] {
71 self.values.as_mut()
72 }
73
74 pub fn uninit_range(&mut self, len: usize) -> UninitRange<'_, T> {
108 assert_ne!(0, len, "cannot create an uninit range of length 0");
109
110 let current_len = self.values.len();
111 assert!(
112 current_len + len <= self.values.capacity(),
113 "uninit_range of len {len} exceeds builder with length {} and capacity {}",
114 current_len,
115 self.values.capacity()
116 );
117
118 UninitRange { len, builder: self }
119 }
120
121 pub fn finish_into_primitive(&mut self) -> PrimitiveArray {
123 let validity = self
124 .nulls
125 .finish_with_nullability(self.dtype().nullability());
126
127 PrimitiveArray::new(std::mem::take(&mut self.values).freeze(), validity)
128 }
129
130 pub fn extend_with_iterator(&mut self, iter: impl IntoIterator<Item = T>, mask: &Mask) {
132 self.values.extend(iter);
133 self.nulls.append_validity_mask(mask);
134 }
135
136 pub(crate) fn append_primitive_array(
137 &mut self,
138 array: &PrimitiveArray,
139 ctx: &mut ExecutionCtx,
140 ) -> VortexResult<()> {
141 debug_assert_eq!(
142 array.ptype(),
143 T::PTYPE,
144 "Cannot append primitive array with different ptype"
145 );
146
147 self.values.extend_from_slice(array.as_slice::<T>());
148 self.nulls.append_validity_mask(
149 &array
150 .as_ref()
151 .validity()
152 .vortex_expect("validity_mask")
153 .execute_mask(array.as_ref().len(), ctx)?,
154 );
155 Ok(())
156 }
157}
158
159impl<T: NativePType> ArrayBuilder for PrimitiveBuilder<T> {
160 fn as_any(&self) -> &dyn Any {
161 self
162 }
163
164 fn as_any_mut(&mut self) -> &mut dyn Any {
165 self
166 }
167
168 fn dtype(&self) -> &DType {
169 &self.dtype
170 }
171
172 fn len(&self) -> usize {
173 self.values.len()
174 }
175
176 fn append_zeros(&mut self, n: usize) {
177 self.values.push_n(T::default(), n);
178 self.nulls.append_n_non_nulls(n);
179 }
180
181 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
182 self.values.push_n(T::default(), n);
183 self.nulls.append_n_nulls(n);
184 }
185
186 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
187 vortex_ensure!(
188 scalar.dtype() == self.dtype(),
189 "PrimitiveBuilder expected scalar with dtype {}, got {}",
190 self.dtype(),
191 scalar.dtype()
192 );
193
194 if let Some(pv) = scalar.as_primitive().pvalue() {
195 self.append_value(pv.cast::<T>()?)
196 } else {
197 self.append_null()
198 }
199
200 Ok(())
201 }
202
203 unsafe fn extend_from_array_unchecked(&mut self, array: &ArrayRef) {
204 #[expect(deprecated)]
205 let array = array.to_primitive();
206
207 self.append_primitive_array(&array, &mut LEGACY_SESSION.create_execution_ctx())
208 .vortex_expect("Failed to append primitive array");
209 }
210
211 fn reserve_exact(&mut self, additional: usize) {
212 self.values.reserve(additional);
213 self.nulls.reserve_exact(additional);
214 }
215
216 unsafe fn set_validity_unchecked(&mut self, validity: Mask) {
217 self.nulls = LazyBitBufferBuilder::from_validity_mask(validity);
218 }
219
220 fn finish(&mut self) -> ArrayRef {
221 self.finish_into_primitive().into_array()
222 }
223
224 fn finish_into_canonical(&mut self) -> Canonical {
225 Canonical::Primitive(self.finish_into_primitive())
226 }
227}
228
229pub struct UninitRange<'a, T> {
231 len: usize,
235
236 builder: &'a mut PrimitiveBuilder<T>,
241}
242
243impl<T> UninitRange<'_, T> {
244 #[inline]
246 pub fn len(&self) -> usize {
247 self.len
248 }
249
250 #[inline]
252 pub fn is_empty(&self) -> bool {
253 self.len == 0
254 }
255
256 #[inline]
262 pub fn set_value(&mut self, index: usize, value: T) {
263 assert!(index < self.len, "index out of bounds");
264 let spare = self.builder.values.spare_capacity_mut();
265 spare[index] = MaybeUninit::new(value);
266 }
267
268 pub unsafe fn append_mask(&mut self, mask: &Mask) {
280 assert_eq!(
281 mask.len(),
282 self.len,
283 "Tried to append a mask to an `UninitRange` that was beyond the allowed range"
284 );
285
286 self.builder.nulls.append_validity_mask(mask);
291 }
292
293 pub fn set_validity_bit(&mut self, index: usize, v: bool) {
300 assert!(index < self.len, "set_bit index out of bounds");
301 let absolute_index = self.builder.values.len() + index;
304 self.builder.nulls.set_bit(absolute_index, v);
305 }
306
307 pub fn copy_from_slice(&mut self, local_offset: usize, src: &[T])
312 where
313 T: Copy,
314 {
315 debug_assert!(
316 local_offset + src.len() <= self.len,
317 "tried to copy a slice into a `UninitRange` past its boundary"
318 );
319
320 let uninit_src: &[MaybeUninit<T>] = unsafe { std::mem::transmute(src) };
322
323 let dst =
326 &mut self.builder.values.spare_capacity_mut()[local_offset..local_offset + src.len()];
327 dst.copy_from_slice(uninit_src);
328 }
329
330 pub unsafe fn slice_uninit_mut(&mut self, offset: usize, len: usize) -> &mut [MaybeUninit<T>] {
344 assert!(
345 offset + len <= self.len,
346 "slice_uninit_mut: offset {} + len {} exceeds range length {}",
347 offset,
348 len,
349 self.len
350 );
351 &mut self.builder.values.spare_capacity_mut()[offset..offset + len]
352 }
353
354 pub unsafe fn finish(self) {
368 let new_len = self.builder.values.len() + self.len;
370 unsafe { self.builder.values.set_len(new_len) };
371 }
372}
373
374#[cfg(test)]
375mod tests {
376 use vortex_error::VortexExpect;
377
378 use super::*;
379 use crate::VortexSessionExecute;
380 use crate::array_session;
381 use crate::assert_arrays_eq;
382
383 #[test]
388 fn test_multiple_uninit_ranges_correct_offsets() {
389 let mut ctx = array_session().create_execution_ctx();
390 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 10);
391
392 let mut range1 = builder.uninit_range(3);
394 range1.copy_from_slice(0, &[1, 2, 3]);
395
396 unsafe {
398 range1.finish();
399 }
400
401 assert_eq!(builder.values(), &[1, 2, 3]);
403
404 let mut range2 = builder.uninit_range(2);
406
407 range2.copy_from_slice(0, &[4, 5]);
409
410 unsafe {
412 range2.finish();
413 }
414
415 assert_eq!(builder.values(), &[1, 2, 3, 4, 5]);
417
418 let array = builder.finish_into_primitive();
419 assert_arrays_eq!(
420 array,
421 PrimitiveArray::from_iter([1i32, 2, 3, 4, 5]),
422 &mut ctx
423 );
424 }
425
426 #[test]
432 fn test_append_mask_on_uninit_range() {
433 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 5);
434 let mut range = builder.uninit_range(3);
435
436 let mask = Mask::from_iter([true, false, true]);
438
439 unsafe {
441 range.append_mask(&mask);
442 }
443
444 range.copy_from_slice(0, &[10, 20, 30]);
446
447 unsafe {
449 range.finish();
450 }
451
452 let array = builder.finish_into_primitive();
453 assert_eq!(array.len(), 3);
454 assert!(
456 !array
457 .execute_scalar(0, &mut array_session().create_execution_ctx())
458 .unwrap()
459 .is_null()
460 );
461 assert!(
462 array
463 .execute_scalar(1, &mut array_session().create_execution_ctx())
464 .unwrap()
465 .is_null()
466 );
467 assert!(
468 !array
469 .execute_scalar(2, &mut array_session().create_execution_ctx())
470 .unwrap()
471 .is_null()
472 );
473 }
474
475 #[test]
479 #[should_panic(
480 expected = "Tried to append a mask to an `UninitRange` that was beyond the allowed range"
481 )]
482 fn test_append_mask_wrong_length_panics() {
483 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 10);
484 let mut range = builder.uninit_range(5);
485
486 let wrong_mask = Mask::from_iter([true, false, true]);
488
489 unsafe {
491 range.append_mask(&wrong_mask);
492 }
493 }
494
495 #[test]
499 fn test_copy_from_slice_with_offsets() {
500 let mut ctx = array_session().create_execution_ctx();
501 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 10);
502 let mut range = builder.uninit_range(6);
503
504 range.copy_from_slice(0, &[1, 2]);
506 range.copy_from_slice(2, &[3, 4]);
507 range.copy_from_slice(4, &[5, 6]);
508
509 unsafe {
511 range.finish();
512 }
513
514 let array = builder.finish_into_primitive();
515 assert_arrays_eq!(
516 array,
517 PrimitiveArray::from_iter([1i32, 2, 3, 4, 5, 6]),
518 &mut ctx
519 );
520 }
521
522 #[test]
528 fn test_set_bit_relative_indexing() {
529 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 10);
530
531 builder.append_value(100);
533 builder.append_value(200);
534
535 let mut range = builder.uninit_range(3);
537
538 let initial_mask = Mask::from_iter([false, false, false]);
540 unsafe {
542 range.append_mask(&initial_mask);
543 }
544
545 range.set_validity_bit(0, true); range.set_validity_bit(2, true); range.copy_from_slice(0, &[10, 20, 30]);
552
553 unsafe {
555 range.finish();
556 }
557
558 let array = builder.finish_into_primitive();
559
560 assert_eq!(array.len(), 5);
562 assert_eq!(array.as_slice::<i32>(), &[100, 200, 10, 20, 30]);
563
564 assert!(
566 !array
567 .execute_scalar(0, &mut array_session().create_execution_ctx())
568 .unwrap()
569 .is_null()
570 ); assert!(
572 !array
573 .execute_scalar(1, &mut array_session().create_execution_ctx())
574 .unwrap()
575 .is_null()
576 ); assert!(
580 !array
581 .execute_scalar(2, &mut array_session().create_execution_ctx())
582 .unwrap()
583 .is_null()
584 ); assert!(
586 array
587 .execute_scalar(3, &mut array_session().create_execution_ctx())
588 .unwrap()
589 .is_null()
590 ); assert!(
592 !array
593 .execute_scalar(4, &mut array_session().create_execution_ctx())
594 .unwrap()
595 .is_null()
596 ); }
598
599 #[test]
601 #[should_panic(expected = "cannot create an uninit range of length 0")]
602 fn test_zero_length_uninit_range_panics() {
603 let mut builder = PrimitiveBuilder::<i32>::new(Nullability::NonNullable);
604 let _range = builder.uninit_range(0);
605 }
606
607 #[test]
609 #[should_panic(expected = "uninit_range of len 261 exceeds builder with length 0 and capacity")]
610 fn test_uninit_range_exceeds_capacity_panics() {
611 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 5);
612 let _range = builder.uninit_range(261);
613 }
614
615 #[test]
619 #[cfg(debug_assertions)]
620 #[should_panic(expected = "tried to copy a slice into a `UninitRange` past its boundary")]
621 fn test_copy_from_slice_out_of_bounds() {
622 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 10);
623 let mut range = builder.uninit_range(3);
624
625 range.copy_from_slice(1, &[1, 2, 3]);
627 }
628
629 #[test]
633 fn test_finish_unsafe_contract() {
634 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 5);
635 let mut range = builder.uninit_range(3);
636
637 let mask = Mask::from_iter([true, true, false]);
639 unsafe {
641 range.append_mask(&mask);
642 }
643
644 range.copy_from_slice(0, &[10, 20, 30]);
646
647 unsafe {
649 range.finish();
650 }
651
652 let array = builder.finish_into_primitive();
653 assert_eq!(array.len(), 3);
654 assert_eq!(array.as_slice::<i32>(), &[10, 20, 30]);
655 }
656
657 #[test]
658 fn test_append_scalar() {
659 use crate::dtype::DType;
660 use crate::scalar::Scalar;
661
662 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 10);
663
664 let scalar1 = Scalar::primitive(42i32, Nullability::Nullable);
666 builder.append_scalar(&scalar1).unwrap();
667
668 let scalar2 = Scalar::primitive(84i32, Nullability::Nullable);
670 builder.append_scalar(&scalar2).unwrap();
671
672 let null_scalar = Scalar::null(DType::Primitive(
674 crate::dtype::PType::I32,
675 Nullability::Nullable,
676 ));
677 builder.append_scalar(&null_scalar).unwrap();
678
679 let array = builder.finish_into_primitive();
680 assert_eq!(array.len(), 3);
681
682 let values = array.as_slice::<i32>();
684 assert_eq!(values[0], 42);
685 assert_eq!(values[1], 84);
686 let mut ctx = array_session().create_execution_ctx();
690 assert!(
691 array
692 .validity()
693 .vortex_expect("primitive validity should be derivable")
694 .execute_is_valid(0, &mut ctx)
695 .unwrap()
696 );
697 assert!(
698 array
699 .validity()
700 .vortex_expect("primitive validity should be derivable")
701 .execute_is_valid(1, &mut ctx)
702 .unwrap()
703 );
704 assert!(
705 !array
706 .validity()
707 .vortex_expect("primitive validity should be derivable")
708 .execute_is_valid(2, &mut ctx)
709 .unwrap()
710 );
711
712 let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 10);
714 let wrong_scalar = Scalar::from(true);
715 assert!(builder.append_scalar(&wrong_scalar).is_err());
716 }
717}