Skip to main content

vortex_array/arrays/primitive/vtable/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::sync::Arc;
5
6use kernel::PARENT_KERNELS;
7use vortex_error::VortexExpect;
8use vortex_error::VortexResult;
9use vortex_error::vortex_bail;
10use vortex_error::vortex_ensure;
11use vortex_error::vortex_panic;
12
13use crate::ArrayRef;
14use crate::EmptyMetadata;
15use crate::ExecutionCtx;
16use crate::ExecutionResult;
17use crate::arrays::PrimitiveArray;
18use crate::buffer::BufferHandle;
19use crate::dtype::DType;
20use crate::dtype::PType;
21use crate::serde::ArrayChildren;
22use crate::validity::Validity;
23use crate::vtable;
24use crate::vtable::Array;
25use crate::vtable::VTable;
26use crate::vtable::ValidityVTableFromValidityHelper;
27use crate::vtable::validity_nchildren;
28use crate::vtable::validity_to_child;
29mod kernel;
30mod operations;
31mod validity;
32
33use std::hash::Hash;
34use std::hash::Hasher;
35
36use vortex_buffer::Alignment;
37use vortex_session::VortexSession;
38
39use crate::Precision;
40use crate::arrays::primitive::compute::rules::RULES;
41use crate::hash::ArrayEq;
42use crate::hash::ArrayHash;
43use crate::stats::StatsSetRef;
44use crate::vtable::ArrayId;
45
46vtable!(Primitive);
47
48impl VTable for Primitive {
49    type Array = PrimitiveArray;
50
51    type Metadata = EmptyMetadata;
52    type OperationsVTable = Self;
53    type ValidityVTable = ValidityVTableFromValidityHelper;
54
55    fn vtable(_array: &Self::Array) -> &Self {
56        &Primitive
57    }
58
59    fn id(&self) -> ArrayId {
60        Self::ID
61    }
62
63    fn len(array: &PrimitiveArray) -> usize {
64        array.buffer_handle().len() / array.ptype().byte_width()
65    }
66
67    fn dtype(array: &PrimitiveArray) -> &DType {
68        &array.dtype
69    }
70
71    fn stats(array: &PrimitiveArray) -> StatsSetRef<'_> {
72        array.stats_set.to_ref(array.as_ref())
73    }
74
75    fn array_hash<H: Hasher>(array: &PrimitiveArray, state: &mut H, precision: Precision) {
76        array.dtype.hash(state);
77        array.buffer.array_hash(state, precision);
78        array.validity.array_hash(state, precision);
79    }
80
81    fn array_eq(array: &PrimitiveArray, other: &PrimitiveArray, precision: Precision) -> bool {
82        array.dtype == other.dtype
83            && array.buffer.array_eq(&other.buffer, precision)
84            && array.validity.array_eq(&other.validity, precision)
85    }
86
87    fn nbuffers(_array: &PrimitiveArray) -> usize {
88        1
89    }
90
91    fn buffer(array: &PrimitiveArray, idx: usize) -> BufferHandle {
92        match idx {
93            0 => array.buffer_handle().clone(),
94            _ => vortex_panic!("PrimitiveArray buffer index {idx} out of bounds"),
95        }
96    }
97
98    fn buffer_name(_array: &PrimitiveArray, idx: usize) -> Option<String> {
99        match idx {
100            0 => Some("values".to_string()),
101            _ => None,
102        }
103    }
104
105    fn nchildren(array: &PrimitiveArray) -> usize {
106        validity_nchildren(&array.validity)
107    }
108
109    fn child(array: &PrimitiveArray, idx: usize) -> ArrayRef {
110        match idx {
111            0 => validity_to_child(&array.validity, array.len())
112                .vortex_expect("PrimitiveArray child index out of bounds"),
113            _ => vortex_panic!("PrimitiveArray child index {idx} out of bounds"),
114        }
115    }
116
117    fn child_name(_array: &PrimitiveArray, _idx: usize) -> String {
118        "validity".to_string()
119    }
120
121    fn metadata(_array: &PrimitiveArray) -> VortexResult<Self::Metadata> {
122        Ok(EmptyMetadata)
123    }
124
125    fn serialize(_metadata: Self::Metadata) -> VortexResult<Option<Vec<u8>>> {
126        Ok(Some(vec![]))
127    }
128
129    fn deserialize(
130        _bytes: &[u8],
131        _dtype: &DType,
132        _len: usize,
133        _buffers: &[BufferHandle],
134        _session: &VortexSession,
135    ) -> VortexResult<Self::Metadata> {
136        Ok(EmptyMetadata)
137    }
138
139    fn build(
140        dtype: &DType,
141        len: usize,
142        _metadata: &Self::Metadata,
143        buffers: &[BufferHandle],
144        children: &dyn ArrayChildren,
145    ) -> VortexResult<PrimitiveArray> {
146        if buffers.len() != 1 {
147            vortex_bail!("Expected 1 buffer, got {}", buffers.len());
148        }
149        let buffer = buffers[0].clone();
150
151        let validity = if children.is_empty() {
152            Validity::from(dtype.nullability())
153        } else if children.len() == 1 {
154            let validity = children.get(0, &Validity::DTYPE, len)?;
155            Validity::Array(validity)
156        } else {
157            vortex_bail!("Expected 0 or 1 child, got {}", children.len());
158        };
159
160        let ptype = PType::try_from(dtype)?;
161
162        vortex_ensure!(
163            buffer.is_aligned_to(Alignment::new(ptype.byte_width())),
164            "Misaligned buffer cannot be used to build PrimitiveArray of {ptype}"
165        );
166
167        if buffer.len() != ptype.byte_width() * len {
168            vortex_bail!(
169                "Buffer length {} does not match expected length {} for {}, {}",
170                buffer.len(),
171                ptype.byte_width() * len,
172                ptype.byte_width(),
173                len,
174            );
175        }
176
177        vortex_ensure!(
178            buffer.is_aligned_to(Alignment::new(ptype.byte_width())),
179            "PrimitiveArray::build: Buffer (align={}) must be aligned to {}",
180            buffer.alignment(),
181            ptype.byte_width()
182        );
183
184        // SAFETY: checked ahead of time
185        unsafe {
186            Ok(PrimitiveArray::new_unchecked_from_handle(
187                buffer, ptype, validity,
188            ))
189        }
190    }
191
192    fn with_children(array: &mut Self::Array, children: Vec<ArrayRef>) -> VortexResult<()> {
193        vortex_ensure!(
194            children.len() <= 1,
195            "PrimitiveArray can have at most 1 child (validity), got {}",
196            children.len()
197        );
198
199        array.validity = if children.is_empty() {
200            Validity::from(array.dtype().nullability())
201        } else {
202            Validity::Array(children.into_iter().next().vortex_expect("checked"))
203        };
204
205        Ok(())
206    }
207
208    fn execute(array: Arc<Array<Self>>, _ctx: &mut ExecutionCtx) -> VortexResult<ExecutionResult> {
209        Ok(ExecutionResult::done(array))
210    }
211
212    fn reduce_parent(
213        array: &Array<Self>,
214        parent: &ArrayRef,
215        child_idx: usize,
216    ) -> VortexResult<Option<ArrayRef>> {
217        RULES.evaluate(array, parent, child_idx)
218    }
219
220    fn execute_parent(
221        array: &Array<Self>,
222        parent: &ArrayRef,
223        child_idx: usize,
224        ctx: &mut ExecutionCtx,
225    ) -> VortexResult<Option<ArrayRef>> {
226        PARENT_KERNELS.execute(array, parent, child_idx, ctx)
227    }
228}
229
230#[derive(Clone, Debug)]
231pub struct Primitive;
232
233impl Primitive {
234    pub const ID: ArrayId = ArrayId::new_ref("vortex.primitive");
235}