1use std::fmt::Display;
5use std::fmt::Formatter;
6use std::iter::repeat;
7
8use smallvec::smallvec;
9use vortex_buffer::Alignment;
10use vortex_buffer::Buffer;
11use vortex_buffer::BufferMut;
12use vortex_buffer::ByteBuffer;
13use vortex_buffer::ByteBufferMut;
14use vortex_error::VortexExpect;
15use vortex_error::VortexResult;
16use vortex_error::vortex_err;
17use vortex_error::vortex_panic;
18
19use crate::ArraySlots;
20use crate::ExecutionCtx;
21use crate::array::Array;
22use crate::array::ArrayParts;
23use crate::array::TypedArrayRef;
24use crate::arrays::BoolArray;
25use crate::arrays::Primitive;
26use crate::arrays::PrimitiveArray;
27use crate::dtype::DType;
28use crate::dtype::NativePType;
29use crate::dtype::Nullability;
30use crate::dtype::PType;
31use crate::match_each_native_ptype;
32use crate::validity::Validity;
33
34mod cast;
35mod conversion;
36mod patch;
37mod top_value;
38
39pub use patch::chunk_range;
40pub use patch::patch_chunk;
41
42use crate::ArrayRef;
43use crate::aggregate_fn::NumericalAggregateOpts;
44use crate::aggregate_fn::fns::min_max::min_max;
45use crate::array::child_to_validity;
46use crate::array::validity_to_child;
47use crate::array_slots;
48use crate::arrays::bool::BoolArrayExt;
49use crate::buffer::BufferHandle;
50use crate::builtins::ArrayBuiltins;
51
52#[array_slots(Primitive)]
53pub struct PrimitiveSlots {
54 #[slot(0)]
56 pub validity: Option<ArrayRef>,
57}
58
59#[derive(Clone, Debug)]
92pub struct PrimitiveData {
93 pub(super) ptype: PType,
94 pub(super) buffer: BufferHandle,
95}
96
97impl Display for PrimitiveData {
98 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
99 write!(f, "ptype: {}", self.ptype)
100 }
101}
102
103pub struct PrimitiveDataParts {
104 pub ptype: PType,
105 pub buffer: BufferHandle,
106 pub validity: Validity,
107}
108
109pub trait PrimitiveArrayExt: TypedArrayRef<Primitive> {
110 fn ptype(&self) -> PType {
111 match self.as_ref().dtype() {
112 DType::Primitive(ptype, _) => *ptype,
113 _ => unreachable!("PrimitiveArrayExt requires a primitive dtype"),
114 }
115 }
116
117 fn nullability(&self) -> Nullability {
118 match self.as_ref().dtype() {
119 DType::Primitive(_, nullability) => *nullability,
120 _ => unreachable!("PrimitiveArrayExt requires a primitive dtype"),
121 }
122 }
123
124 fn validity_child(&self) -> Option<&ArrayRef> {
125 self.as_ref().slots()[PrimitiveSlots::VALIDITY].as_ref()
126 }
127
128 fn validity(&self) -> Validity {
129 child_to_validity(
130 self.as_ref().slots()[PrimitiveSlots::VALIDITY].as_ref(),
131 self.nullability(),
132 )
133 }
134
135 fn buffer_handle(&self) -> &BufferHandle {
136 &self.buffer
137 }
138
139 fn reinterpret_cast(&self, ptype: PType) -> PrimitiveArray {
140 if self.ptype() == ptype {
141 return self.to_owned();
142 }
143
144 assert_eq!(
145 self.ptype().byte_width(),
146 ptype.byte_width(),
147 "can't reinterpret cast between integers of two different widths"
148 );
149
150 PrimitiveArray::from_buffer_handle(
151 self.buffer_handle().clone(),
152 ptype,
153 PrimitiveArrayExt::validity(self),
154 )
155 }
156
157 fn narrow(&self, ctx: &mut ExecutionCtx) -> VortexResult<PrimitiveArray> {
159 if !self.ptype().is_int() {
160 return Ok(self.to_owned());
161 }
162
163 let Some(min_max) = min_max(self.as_ref(), ctx, NumericalAggregateOpts::default())? else {
164 return Ok(PrimitiveArray::new(
165 Buffer::<u8>::zeroed(self.len()),
166 PrimitiveArrayExt::validity(self),
167 ));
168 };
169
170 let Ok(min) = min_max
173 .min
174 .cast(&PType::I64.into())
175 .and_then(|s| i64::try_from(&s))
176 else {
177 return Ok(self.to_owned());
178 };
179 let Ok(max) = min_max
180 .max
181 .cast(&PType::I64.into())
182 .and_then(|s| i64::try_from(&s))
183 else {
184 return Ok(self.to_owned());
185 };
186
187 let nullability = self.as_ref().dtype().nullability();
188
189 if min < 0 || max < 0 {
190 if min >= i8::MIN as i64 && max <= i8::MAX as i64 {
192 let result = self
193 .as_ref()
194 .cast(DType::Primitive(PType::I8, nullability))?
195 .execute::<PrimitiveArray>(ctx)?;
196 return Ok(result);
197 }
198
199 if min >= i16::MIN as i64 && max <= i16::MAX as i64 {
200 let result = self
201 .as_ref()
202 .cast(DType::Primitive(PType::I16, nullability))?
203 .execute::<PrimitiveArray>(ctx)?;
204 return Ok(result);
205 }
206
207 if min >= i32::MIN as i64 && max <= i32::MAX as i64 {
208 let result = self
209 .as_ref()
210 .cast(DType::Primitive(PType::I32, nullability))?
211 .execute::<PrimitiveArray>(ctx)?;
212 return Ok(result);
213 }
214 } else {
215 if max <= u8::MAX as i64 {
217 let result = self
218 .as_ref()
219 .cast(DType::Primitive(PType::U8, nullability))?
220 .execute::<PrimitiveArray>(ctx)?;
221 return Ok(result);
222 }
223
224 if max <= u16::MAX as i64 {
225 let result = self
226 .as_ref()
227 .cast(DType::Primitive(PType::U16, nullability))?
228 .execute::<PrimitiveArray>(ctx)?;
229 return Ok(result);
230 }
231
232 if max <= u32::MAX as i64 {
233 let result = self
234 .as_ref()
235 .cast(DType::Primitive(PType::U32, nullability))?
236 .execute::<PrimitiveArray>(ctx)?;
237 return Ok(result);
238 }
239 }
240
241 Ok(self.to_owned())
242 }
243}
244impl<T: TypedArrayRef<Primitive>> PrimitiveArrayExt for T {}
245
246impl PrimitiveData {
248 pub(super) fn make_slots(validity: &Validity, len: usize) -> ArraySlots {
250 smallvec![validity_to_child(validity, len)]
251 }
252
253 pub unsafe fn new_unchecked_from_handle(
260 handle: BufferHandle,
261 ptype: PType,
262 _validity: Validity,
263 ) -> Self {
264 Self {
265 ptype,
266 buffer: handle,
267 }
268 }
269
270 pub fn new<T: NativePType>(buffer: impl Into<Buffer<T>>, validity: Validity) -> Self {
277 let buffer = buffer.into();
278 Self::try_new(buffer, validity).vortex_expect("PrimitiveArray construction failed")
279 }
280
281 #[inline]
290 pub fn try_new<T: NativePType>(buffer: Buffer<T>, validity: Validity) -> VortexResult<Self> {
291 Self::validate(&buffer, &validity)?;
292
293 Ok(unsafe { Self::new_unchecked(buffer, validity) })
295 }
296
297 #[inline]
310 pub unsafe fn new_unchecked<T: NativePType>(buffer: Buffer<T>, _validity: Validity) -> Self {
311 #[cfg(debug_assertions)]
312 Self::validate(&buffer, &_validity)
313 .vortex_expect("[Debug Assertion]: Invalid `PrimitiveArray` parameters");
314
315 Self {
316 ptype: T::PTYPE,
317 buffer: BufferHandle::new_host(buffer.into_byte_buffer()),
318 }
319 }
320
321 #[inline]
325 pub fn validate<T: NativePType>(buffer: &Buffer<T>, validity: &Validity) -> VortexResult<()> {
326 if let Some(len) = validity.maybe_len()
327 && buffer.len() != len
328 {
329 return Err(vortex_err!(
330 InvalidArgument:
331 "Buffer and validity length mismatch: buffer={}, validity={}",
332 buffer.len(),
333 len
334 ));
335 }
336 Ok(())
337 }
338
339 pub fn empty<T: NativePType>(nullability: Nullability) -> Self {
340 Self::new(Buffer::<T>::empty(), nullability.into())
341 }
342}
343
344impl Array<Primitive> {
345 pub fn empty<T: NativePType>(nullability: Nullability) -> Self {
346 let dtype = DType::Primitive(T::PTYPE, nullability);
347 let len = 0;
348 let data = PrimitiveData::empty::<T>(nullability);
349 let slots = PrimitiveData::make_slots(&Validity::from(nullability), len);
350 unsafe {
351 Array::from_parts_unchecked(
352 ArrayParts::new(Primitive, dtype, len, data).with_slots(slots),
353 )
354 }
355 }
356
357 pub fn new<T: NativePType>(buffer: impl Into<Buffer<T>>, validity: Validity) -> Self {
363 let buffer = buffer.into();
364 let dtype = DType::Primitive(T::PTYPE, validity.nullability());
365 let len = buffer.len();
366 let slots = PrimitiveData::make_slots(&validity, len);
367 let data = PrimitiveData::new(buffer, validity);
368 unsafe {
369 Array::from_parts_unchecked(
370 ArrayParts::new(Primitive, dtype, len, data).with_slots(slots),
371 )
372 }
373 }
374
375 pub fn try_new<T: NativePType>(buffer: Buffer<T>, validity: Validity) -> VortexResult<Self> {
377 let dtype = DType::Primitive(T::PTYPE, validity.nullability());
378 let len = buffer.len();
379 let slots = PrimitiveData::make_slots(&validity, len);
380 let data = PrimitiveData::try_new(buffer, validity)?;
381 Ok(unsafe {
382 Array::from_parts_unchecked(
383 ArrayParts::new(Primitive, dtype, len, data).with_slots(slots),
384 )
385 })
386 }
387
388 pub unsafe fn new_unchecked<T: NativePType>(buffer: Buffer<T>, validity: Validity) -> Self {
394 let dtype = DType::Primitive(T::PTYPE, validity.nullability());
395 let len = buffer.len();
396 let slots = PrimitiveData::make_slots(&validity, len);
397 let data = unsafe { PrimitiveData::new_unchecked(buffer, validity) };
398 unsafe {
399 Array::from_parts_unchecked(
400 ArrayParts::new(Primitive, dtype, len, data).with_slots(slots),
401 )
402 }
403 }
404
405 pub unsafe fn new_unchecked_from_handle(
411 handle: BufferHandle,
412 ptype: PType,
413 validity: Validity,
414 ) -> Self {
415 let dtype = DType::Primitive(ptype, validity.nullability());
416 let len = handle.len() / ptype.byte_width();
417 let slots = PrimitiveData::make_slots(&validity, len);
418 let data = unsafe { PrimitiveData::new_unchecked_from_handle(handle, ptype, validity) };
419 unsafe {
420 Array::from_parts_unchecked(
421 ArrayParts::new(Primitive, dtype, len, data).with_slots(slots),
422 )
423 }
424 }
425
426 pub fn from_buffer_handle(handle: BufferHandle, ptype: PType, validity: Validity) -> Self {
428 let dtype = DType::Primitive(ptype, validity.nullability());
429 let len = handle.len() / ptype.byte_width();
430 let slots = PrimitiveData::make_slots(&validity, len);
431 let data = PrimitiveData::from_buffer_handle(handle, ptype, validity);
432 Array::try_from_parts(ArrayParts::new(Primitive, dtype, len, data).with_slots(slots))
433 .vortex_expect("PrimitiveData is always valid")
434 }
435
436 pub fn from_byte_buffer(buffer: ByteBuffer, ptype: PType, validity: Validity) -> Self {
438 let dtype = DType::Primitive(ptype, validity.nullability());
439 let len = buffer.len() / ptype.byte_width();
440 let slots = PrimitiveData::make_slots(&validity, len);
441 let data = PrimitiveData::from_byte_buffer(buffer, ptype, validity);
442 unsafe {
443 Array::from_parts_unchecked(
444 ArrayParts::new(Primitive, dtype, len, data).with_slots(slots),
445 )
446 }
447 }
448
449 pub fn from_values_byte_buffer(
451 valid_elems_buffer: ByteBuffer,
452 ptype: PType,
453 validity: Validity,
454 n_rows: usize,
455 ctx: &mut ExecutionCtx,
456 ) -> Self {
457 let dtype = DType::Primitive(ptype, validity.nullability());
458 let len = n_rows;
459 let slots = PrimitiveData::make_slots(&validity, len);
460 let data = PrimitiveData::from_values_byte_buffer(
461 valid_elems_buffer,
462 ptype,
463 validity,
464 n_rows,
465 ctx,
466 );
467 unsafe {
468 Array::from_parts_unchecked(
469 ArrayParts::new(Primitive, dtype, len, data).with_slots(slots),
470 )
471 }
472 }
473
474 pub fn validate<T: NativePType>(buffer: &Buffer<T>, validity: &Validity) -> VortexResult<()> {
476 PrimitiveData::validate(buffer, validity)
477 }
478
479 pub fn into_data_parts(self) -> PrimitiveDataParts {
480 let validity = PrimitiveArrayExt::validity(&self);
481 let ptype = PrimitiveArrayExt::ptype(&self);
482 let data = self.into_data();
483 PrimitiveDataParts {
484 ptype,
485 buffer: data.buffer,
486 validity,
487 }
488 }
489
490 pub fn map_each_with_validity<T, R, F>(self, ctx: &mut ExecutionCtx, f: F) -> VortexResult<Self>
491 where
492 T: NativePType,
493 R: NativePType,
494 F: FnMut((T, bool)) -> R,
495 {
496 let validity = PrimitiveArrayExt::validity(&self);
497 let data = self.into_data();
498 let buf_iter = data.to_buffer::<T>().into_iter();
499
500 let buffer = match &validity {
501 Validity::NonNullable | Validity::AllValid => {
502 Buffer::<R>::from_trusted_len_iter(buf_iter.zip(repeat(true)).map(f))
503 }
504 Validity::AllInvalid => {
505 Buffer::<R>::from_trusted_len_iter(buf_iter.zip(repeat(false)).map(f))
506 }
507 Validity::Array(val) => {
508 let val = val.clone().execute::<BoolArray>(ctx)?.into_bit_buffer();
509 Buffer::<R>::from_trusted_len_iter(buf_iter.zip(val.iter()).map(f))
510 }
511 };
512 Ok(PrimitiveArray::new(buffer, validity))
513 }
514}
515
516impl PrimitiveData {
517 pub fn len(&self) -> usize {
518 self.buffer.len() / self.ptype.byte_width()
519 }
520
521 pub fn is_empty(&self) -> bool {
523 self.buffer.is_empty()
524 }
525
526 pub fn ptype(&self) -> PType {
527 self.ptype
528 }
529
530 pub fn buffer_handle(&self) -> &BufferHandle {
532 &self.buffer
533 }
534
535 pub fn from_buffer_handle(handle: BufferHandle, ptype: PType, _validity: Validity) -> Self {
536 Self {
537 ptype,
538 buffer: handle,
539 }
540 }
541
542 pub fn from_byte_buffer(buffer: ByteBuffer, ptype: PType, validity: Validity) -> Self {
543 match_each_native_ptype!(ptype, |T| {
544 Self::new::<T>(Buffer::from_byte_buffer(buffer), validity)
545 })
546 }
547
548 pub fn from_values_byte_buffer(
550 valid_elems_buffer: ByteBuffer,
551 ptype: PType,
552 validity: Validity,
553 n_rows: usize,
554 ctx: &mut ExecutionCtx,
555 ) -> Self {
556 let byte_width = ptype.byte_width();
557 let alignment = Alignment::new(byte_width);
558 let buffer = match &validity {
559 Validity::AllValid | Validity::NonNullable => valid_elems_buffer.aligned(alignment),
560 Validity::AllInvalid => ByteBuffer::zeroed_aligned(n_rows * byte_width, alignment),
561 Validity::Array(is_valid) => {
562 let bool_array = is_valid
563 .clone()
564 .execute::<BoolArray>(ctx)
565 .vortex_expect("must be a bool array");
566 let bool_buffer = bool_array.bit_buffer_view();
567 let mut bytes = ByteBufferMut::zeroed_aligned(n_rows * byte_width, alignment);
568 for (i, valid_i) in bool_buffer.set_indices().enumerate() {
569 bytes[valid_i * byte_width..(valid_i + 1) * byte_width]
570 .copy_from_slice(&valid_elems_buffer[i * byte_width..(i + 1) * byte_width])
571 }
572 bytes.freeze()
573 }
574 };
575
576 Self::from_byte_buffer(buffer, ptype, validity)
577 }
578
579 pub fn to_buffer<T: NativePType>(&self) -> Buffer<T> {
583 if T::PTYPE != self.ptype() {
584 vortex_panic!(
585 "Attempted to get buffer of type {} from array of type {}",
586 T::PTYPE,
587 self.ptype()
588 )
589 }
590 Buffer::from_byte_buffer(self.buffer_handle().to_host_sync())
591 }
592
593 pub fn into_buffer<T: NativePType>(self) -> Buffer<T> {
595 if T::PTYPE != self.ptype() {
596 vortex_panic!(
597 "Attempted to get buffer of type {} from array of type {}",
598 T::PTYPE,
599 self.ptype()
600 )
601 }
602 Buffer::from_byte_buffer(self.buffer.into_host_sync())
603 }
604
605 pub fn into_buffer_mut<T: NativePType>(self) -> BufferMut<T> {
608 self.try_into_buffer_mut()
609 .unwrap_or_else(|buffer| BufferMut::<T>::copy_from(&buffer))
610 }
611
612 pub fn try_into_buffer_mut<T: NativePType>(self) -> Result<BufferMut<T>, Buffer<T>> {
617 if T::PTYPE != self.ptype() {
618 vortex_panic!(
619 "Attempted to get buffer_mut of type {} from array of type {}",
620 T::PTYPE,
621 self.ptype()
622 )
623 }
624 let buffer = Buffer::<T>::from_byte_buffer(self.buffer.into_host_sync());
625 buffer.try_into_mut()
626 }
627}