vortex_array/arrays/primitive/array/
mod.rs1use std::iter;
5
6use vortex_buffer::Alignment;
7use vortex_buffer::Buffer;
8use vortex_buffer::BufferMut;
9use vortex_buffer::ByteBuffer;
10use vortex_buffer::ByteBufferMut;
11use vortex_error::VortexExpect;
12use vortex_error::VortexResult;
13use vortex_error::vortex_err;
14
15use crate::ToCanonical;
16use crate::dtype::DType;
17use crate::dtype::NativePType;
18use crate::dtype::Nullability;
19use crate::dtype::PType;
20use crate::match_each_native_ptype;
21use crate::stats::ArrayStats;
22use crate::validity::Validity;
23use crate::vtable::ValidityHelper;
24
25mod accessor;
26mod cast;
27mod conversion;
28mod patch;
29mod top_value;
30
31pub use patch::chunk_range;
32pub use patch::patch_chunk;
33
34use crate::buffer::BufferHandle;
35
36#[derive(Clone, Debug)]
72pub struct PrimitiveArray {
73 pub(super) dtype: DType,
74 pub(super) buffer: BufferHandle,
75 pub(super) validity: Validity,
76 pub(super) stats_set: ArrayStats,
77}
78
79pub struct PrimitiveArrayParts {
80 pub ptype: PType,
81 pub buffer: BufferHandle,
82 pub validity: Validity,
83}
84
85impl PrimitiveArray {
87 pub unsafe fn new_unchecked_from_handle(
94 handle: BufferHandle,
95 ptype: PType,
96 validity: Validity,
97 ) -> Self {
98 Self {
99 buffer: handle,
100 dtype: DType::Primitive(ptype, validity.nullability()),
101 validity,
102 stats_set: ArrayStats::default(),
103 }
104 }
105
106 pub fn new<T: NativePType>(buffer: impl Into<Buffer<T>>, validity: Validity) -> Self {
113 let buffer = buffer.into();
114 Self::try_new(buffer, validity).vortex_expect("PrimitiveArray construction failed")
115 }
116
117 #[inline]
126 pub fn try_new<T: NativePType>(buffer: Buffer<T>, validity: Validity) -> VortexResult<Self> {
127 Self::validate(&buffer, &validity)?;
128
129 Ok(unsafe { Self::new_unchecked(buffer, validity) })
131 }
132
133 #[inline]
146 pub unsafe fn new_unchecked<T: NativePType>(buffer: Buffer<T>, validity: Validity) -> Self {
147 #[cfg(debug_assertions)]
148 Self::validate(&buffer, &validity)
149 .vortex_expect("[Debug Assertion]: Invalid `PrimitiveArray` parameters");
150
151 Self {
152 dtype: DType::Primitive(T::PTYPE, validity.nullability()),
153 buffer: BufferHandle::new_host(buffer.into_byte_buffer()),
154 validity,
155 stats_set: Default::default(),
156 }
157 }
158
159 #[inline]
163 pub fn validate<T: NativePType>(buffer: &Buffer<T>, validity: &Validity) -> VortexResult<()> {
164 if let Some(len) = validity.maybe_len()
165 && buffer.len() != len
166 {
167 return Err(vortex_err!(
168 InvalidArgument:
169 "Buffer and validity length mismatch: buffer={}, validity={}",
170 buffer.len(),
171 len
172 ));
173 }
174 Ok(())
175 }
176
177 pub fn empty<T: NativePType>(nullability: Nullability) -> Self {
178 Self::new(Buffer::<T>::empty(), nullability.into())
179 }
180}
181
182impl PrimitiveArray {
183 pub fn into_parts(self) -> PrimitiveArrayParts {
185 let ptype = self.ptype();
186 PrimitiveArrayParts {
187 ptype,
188 buffer: self.buffer,
189 validity: self.validity,
190 }
191 }
192}
193
194impl PrimitiveArray {
195 pub fn ptype(&self) -> PType {
196 self.dtype().as_ptype()
197 }
198
199 pub fn buffer_handle(&self) -> &BufferHandle {
201 &self.buffer
202 }
203
204 pub fn from_buffer_handle(handle: BufferHandle, ptype: PType, validity: Validity) -> Self {
205 let dtype = DType::Primitive(ptype, validity.nullability());
206 Self {
207 buffer: handle,
208 dtype,
209 validity,
210 stats_set: ArrayStats::default(),
211 }
212 }
213
214 pub fn from_byte_buffer(buffer: ByteBuffer, ptype: PType, validity: Validity) -> Self {
215 match_each_native_ptype!(ptype, |T| {
216 Self::new::<T>(Buffer::from_byte_buffer(buffer), validity)
217 })
218 }
219
220 pub fn from_values_byte_buffer(
222 valid_elems_buffer: ByteBuffer,
223 ptype: PType,
224 validity: Validity,
225 n_rows: usize,
226 ) -> Self {
227 let byte_width = ptype.byte_width();
228 let alignment = Alignment::new(byte_width);
229 let buffer = match &validity {
230 Validity::AllValid | Validity::NonNullable => valid_elems_buffer.aligned(alignment),
231 Validity::AllInvalid => ByteBuffer::zeroed_aligned(n_rows * byte_width, alignment),
232 Validity::Array(is_valid) => {
233 let bool_array = is_valid.to_bool();
234 let bool_buffer = bool_array.to_bit_buffer();
235 let mut bytes = ByteBufferMut::zeroed_aligned(n_rows * byte_width, alignment);
236 for (i, valid_i) in bool_buffer.set_indices().enumerate() {
237 bytes[valid_i * byte_width..(valid_i + 1) * byte_width]
238 .copy_from_slice(&valid_elems_buffer[i * byte_width..(i + 1) * byte_width])
239 }
240 bytes.freeze()
241 }
242 };
243
244 Self::from_byte_buffer(buffer, ptype, validity)
245 }
246
247 pub fn map_each<T, R, F>(self, f: F) -> PrimitiveArray
254 where
255 T: NativePType,
256 R: NativePType,
257 F: FnMut(T) -> R,
258 {
259 let validity = self.validity().clone();
260 let buffer = match self.try_into_buffer_mut() {
261 Ok(buffer_mut) => buffer_mut.map_each_in_place(f),
262 Err(buffer) => BufferMut::from_iter(buffer.iter().copied().map(f)),
263 };
264 PrimitiveArray::new(buffer.freeze(), validity)
265 }
266
267 pub fn map_each_with_validity<T, R, F>(self, f: F) -> VortexResult<PrimitiveArray>
272 where
273 T: NativePType,
274 R: NativePType,
275 F: FnMut((T, bool)) -> R,
276 {
277 let validity = self.validity();
278
279 let buf_iter = self.to_buffer::<T>().into_iter();
280
281 let buffer = match &validity {
282 Validity::NonNullable | Validity::AllValid => {
283 BufferMut::<R>::from_iter(buf_iter.zip(iter::repeat(true)).map(f))
284 }
285 Validity::AllInvalid => {
286 BufferMut::<R>::from_iter(buf_iter.zip(iter::repeat(false)).map(f))
287 }
288 Validity::Array(val) => {
289 let val = val.to_bool().into_bit_buffer();
290 BufferMut::<R>::from_iter(buf_iter.zip(val.iter()).map(f))
291 }
292 };
293 Ok(PrimitiveArray::new(buffer.freeze(), validity.clone()))
294 }
295}