vortex_vector/decimal/generic.rs
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! Definition and implementation of [`DVector<D>`].
5
6use std::fmt::Debug;
7use std::ops::BitAnd;
8use std::ops::RangeBounds;
9
10use vortex_buffer::Buffer;
11use vortex_dtype::NativeDecimalType;
12use vortex_dtype::PrecisionScale;
13use vortex_error::VortexExpect;
14use vortex_error::VortexResult;
15use vortex_error::vortex_bail;
16use vortex_mask::Mask;
17
18use crate::VectorOps;
19use crate::decimal::DScalar;
20use crate::decimal::DVectorMut;
21
22/// An immutable vector of generic decimal values.
23///
24/// `D` is bound by [`NativeDecimalType`], which can be one of the native integer types (`i8`,
25/// `i16`, `i32`, `i64`, `i128`) or `i256`. `D` is used to store the decimal values.
26///
27/// The decimal vector maintains a [`PrecisionScale<D>`] that defines the precision (total number of
28/// digits) and scale (digits after the decimal point) for all values in the vector.
29#[derive(Debug, Clone)]
30pub struct DVector<D> {
31 /// The precision and scale of each decimal in the decimal vector.
32 pub(super) ps: PrecisionScale<D>,
33 /// The buffer representing the vector decimal elements.
34 pub(super) elements: Buffer<D>,
35 /// The validity mask (where `true` represents an element is **not** null).
36 pub(super) validity: Mask,
37}
38
39impl<D: NativeDecimalType> DVector<D> {
40 /// Creates a new [`DVector<D>`] from the given [`PrecisionScale`], elements buffer, and
41 /// validity mask.
42 ///
43 /// # Panics
44 ///
45 /// Panics if:
46 ///
47 /// - The lengths of the `elements` and `validity` do not match.
48 /// - Any of the elements are out of bounds for the given [`PrecisionScale`].
49 pub fn new(ps: PrecisionScale<D>, elements: Buffer<D>, validity: Mask) -> Self {
50 Self::try_new(ps, elements, validity).vortex_expect("Failed to create `DVector`")
51 }
52
53 /// Tries to create a new [`DVector<D>`] from the given [`PrecisionScale`], elements buffer, and
54 /// validity mask.
55 ///
56 /// # Errors
57 ///
58 /// Returns an error if:
59 ///
60 /// - The lengths of the `elements` and `validity` do not match.
61 /// - Any of the elements are out of bounds for the given [`PrecisionScale`].
62 pub fn try_new(
63 ps: PrecisionScale<D>,
64 elements: Buffer<D>,
65 validity: Mask,
66 ) -> VortexResult<Self> {
67 if elements.len() != validity.len() {
68 vortex_bail!(
69 "Elements length {} does not match validity length {}",
70 elements.len(),
71 validity.len()
72 );
73 }
74
75 // We assert that each element is within bounds for the given precision/scale.
76 if !elements.iter().all(|e| ps.is_valid(*e)) {
77 vortex_bail!(
78 "One or more elements are out of bounds for precision {} and scale {}",
79 ps.precision(),
80 ps.scale()
81 );
82 }
83
84 Ok(Self {
85 ps,
86 elements,
87 validity,
88 })
89 }
90
91 /// Creates a new [`DVector<D>`] from the given [`PrecisionScale`], elements buffer, and
92 /// validity mask, _without_ validation.
93 ///
94 /// # Safety
95 ///
96 /// The caller must ensure:
97 ///
98 /// - The lengths of the elements and validity are equal.
99 /// - All elements are in bounds for the given [`PrecisionScale`].
100 pub unsafe fn new_unchecked(
101 ps: PrecisionScale<D>,
102 elements: Buffer<D>,
103 validity: Mask,
104 ) -> Self {
105 if cfg!(debug_assertions) {
106 Self::try_new(ps, elements, validity).vortex_expect("Failed to create `DVector`")
107 } else {
108 Self {
109 ps,
110 elements,
111 validity,
112 }
113 }
114 }
115
116 /// Decomposes the decimal vector into its constituent parts ([`PrecisionScale`], decimal
117 /// buffer, and validity).
118 pub fn into_parts(self) -> (PrecisionScale<D>, Buffer<D>, Mask) {
119 (self.ps, self.elements, self.validity)
120 }
121
122 /// Get the precision/scale of the decimal vector.
123 pub fn precision_scale(&self) -> PrecisionScale<D> {
124 self.ps
125 }
126
127 /// Returns the precision of the decimal vector.
128 pub fn precision(&self) -> u8 {
129 self.ps.precision()
130 }
131
132 /// Returns the scale of the decimal vector.
133 pub fn scale(&self) -> i8 {
134 self.ps.scale()
135 }
136
137 /// Returns a reference to the underlying elements buffer containing the decimal data.
138 pub fn elements(&self) -> &Buffer<D> {
139 &self.elements
140 }
141
142 /// Gets a nullable element at the given index, panicking on out-of-bounds.
143 ///
144 /// If the element at the given index is null, returns `None`. Otherwise, returns `Some(x)`,
145 /// where `x: D`.
146 ///
147 /// Note that this `get` method is different from the standard library [`slice::get`], which
148 /// returns `None` if the index is out of bounds. This method will panic if the index is out of
149 /// bounds, and return `None` if the elements is null.
150 ///
151 /// # Panics
152 ///
153 /// Panics if the index is out of bounds.
154 pub fn get(&self, index: usize) -> Option<&D> {
155 self.validity.value(index).then(|| &self.elements[index])
156 }
157}
158
159impl<D: NativeDecimalType> AsRef<[D]> for DVector<D> {
160 fn as_ref(&self) -> &[D] {
161 &self.elements
162 }
163}
164
165impl<D: NativeDecimalType> VectorOps for DVector<D> {
166 type Mutable = DVectorMut<D>;
167 type Scalar = DScalar<D>;
168
169 fn len(&self) -> usize {
170 self.elements.len()
171 }
172
173 fn validity(&self) -> &Mask {
174 &self.validity
175 }
176
177 fn mask_validity(&mut self, mask: &Mask) {
178 self.validity = self.validity.bitand(mask);
179 }
180
181 fn scalar_at(&self, index: usize) -> DScalar<D> {
182 assert!(index < self.len());
183
184 let is_valid = self.validity.value(index);
185 let value = is_valid.then(|| self.elements[index]);
186
187 // SAFETY: We have already checked the validity on construction of the vector
188 unsafe { DScalar::<D>::new_unchecked(self.ps, value) }
189 }
190
191 fn slice(&self, range: impl RangeBounds<usize> + Clone + Debug) -> Self {
192 let elements = self.elements.slice(range.clone());
193 let validity = self.validity.slice(range);
194 Self {
195 ps: self.ps,
196 elements,
197 validity,
198 }
199 }
200
201 fn clear(&mut self) {
202 self.elements.clear();
203 self.validity.clear();
204 }
205
206 fn try_into_mut(self) -> Result<DVectorMut<D>, Self> {
207 let elements = match self.elements.try_into_mut() {
208 Ok(elements) => elements,
209 Err(elements) => {
210 return Err(Self {
211 ps: self.ps,
212 elements,
213 validity: self.validity,
214 });
215 }
216 };
217
218 match self.validity.try_into_mut() {
219 Ok(validity_mut) => Ok(DVectorMut {
220 ps: self.ps,
221 elements,
222 validity: validity_mut,
223 }),
224 Err(validity) => Err(Self {
225 ps: self.ps,
226 elements: elements.freeze(),
227 validity,
228 }),
229 }
230 }
231
232 fn into_mut(self) -> DVectorMut<D> {
233 DVectorMut {
234 ps: self.ps,
235 elements: self.elements.into_mut(),
236 validity: self.validity.into_mut(),
237 }
238 }
239}