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