Skip to content

Commit 7d786bd

Browse files
authored
Chore: Decimal vector cleanup (#5165)
Tracking Issue: #5028 Adds a bunch of missing methods plus reorganizes things to be in line with the other existing vectors. There's also no tests for decimal vectors at all but that can come later... --------- Signed-off-by: Connor Tsui <[email protected]>
1 parent cbbe407 commit 7d786bd

File tree

11 files changed

+377
-84
lines changed

11 files changed

+377
-84
lines changed

vortex-vector/src/decimal/generic.rs

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,54 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4+
//! Definition and implementation of [`DVector<D>`].
5+
46
use vortex_buffer::Buffer;
57
use vortex_dtype::{NativeDecimalType, PrecisionScale};
68
use vortex_error::{VortexExpect, VortexResult, vortex_bail};
79
use vortex_mask::Mask;
810

911
use crate::{DVectorMut, VectorOps};
1012

11-
/// A specifically typed decimal vector.
13+
/// An immutable vector of generic decimal values.
14+
///
15+
/// `DVector<D>` can be considered a borrowed / frozen version of [`DVectorMut<D>`], which is
16+
/// created via the [`freeze`](crate::VectorMutOps::freeze) method.
17+
///
18+
/// See the documentation for [`DVectorMut<D>`] for more information.
1219
#[derive(Debug, Clone)]
1320
pub struct DVector<D> {
21+
/// The precision and scale of each decimal in the decimal vector.
1422
pub(super) ps: PrecisionScale<D>,
23+
/// The buffer representing the vector decimal elements.
1524
pub(super) elements: Buffer<D>,
25+
/// The validity mask (where `true` represents an element is **not** null).
1626
pub(super) validity: Mask,
1727
}
1828

1929
impl<D: NativeDecimalType> DVector<D> {
20-
/// Try to create a new decimal vector from the given elements and validity.
30+
/// Creates a new [`DVector<D>`] from the given [`PrecisionScale`], elements buffer, and
31+
/// validity mask.
32+
///
33+
/// # Panics
34+
///
35+
/// Panics if:
36+
///
37+
/// - The lengths of the `elements` and `validity` do not match.
38+
/// - Any of the elements are out of bounds for the given [`PrecisionScale`].
39+
pub fn new(ps: PrecisionScale<D>, elements: Buffer<D>, validity: Mask) -> Self {
40+
Self::try_new(ps, elements, validity).vortex_expect("Failed to create `DVector`")
41+
}
42+
43+
/// Tries to create a new [`DVector<D>`] from the given [`PrecisionScale`], elements buffer, and
44+
/// validity mask.
2145
///
2246
/// # Errors
2347
///
24-
/// Returns an error if the precision/scale is invalid, the lengths of the elements
25-
/// and validity do not match, or any of the elements are out of bounds for the given
26-
/// precision/scale.
48+
/// Returns an error if:
49+
///
50+
/// - The lengths of the `elements` and `validity` do not match.
51+
/// - Any of the elements are out of bounds for the given [`PrecisionScale`].
2752
pub fn try_new(
2853
ps: PrecisionScale<D>,
2954
elements: Buffer<D>,
@@ -53,12 +78,15 @@ impl<D: NativeDecimalType> DVector<D> {
5378
})
5479
}
5580

56-
/// Create a new decimal vector from the given elements and validity without validation.
81+
/// Creates a new [`DVector<D>`] from the given [`PrecisionScale`], elements buffer, and
82+
/// validity mask, _without_ validation.
5783
///
5884
/// # Safety
5985
///
60-
/// The caller must ensure that the precision/scale is valid, the lengths of the elements
61-
/// and validity match, and all the elements are within bounds for the given precision/scale.
86+
/// The caller must ensure:
87+
///
88+
/// - The lengths of the elements and validity are equal.
89+
/// - All elements are in bounds for the given [`PrecisionScale`].
6290
pub unsafe fn new_unchecked(
6391
ps: PrecisionScale<D>,
6492
elements: Buffer<D>,
@@ -75,14 +103,42 @@ impl<D: NativeDecimalType> DVector<D> {
75103
}
76104
}
77105

106+
/// Decomposes the decimal vector into its constituent parts ([`PrecisionScale`], decimal
107+
/// buffer, and validity).
108+
pub fn into_parts(self) -> (PrecisionScale<D>, Buffer<D>, Mask) {
109+
(self.ps, self.elements, self.validity)
110+
}
111+
78112
/// Get the precision/scale of the decimal vector.
79113
pub fn precision_scale(&self) -> PrecisionScale<D> {
80114
self.ps
81115
}
82116

83-
/// Decomposes the decimal vector into its constituent parts (precision/scale, buffer and validity).
84-
pub fn into_parts(self) -> (PrecisionScale<D>, Buffer<D>, Mask) {
85-
(self.ps, self.elements, self.validity)
117+
/// Returns a reference to the underlying elements buffer containing the decimal data.
118+
pub fn elements(&self) -> &Buffer<D> {
119+
&self.elements
120+
}
121+
122+
/// Gets a nullable element at the given index, panicking on out-of-bounds.
123+
///
124+
/// If the element at the given index is null, returns `None`. Otherwise, returns `Some(x)`,
125+
/// where `x: D`.
126+
///
127+
/// Note that this `get` method is different from the standard library [`slice::get`], which
128+
/// returns `None` if the index is out of bounds. This method will panic if the index is out of
129+
/// bounds, and return `None` if the elements is null.
130+
///
131+
/// # Panics
132+
///
133+
/// Panics if the index is out of bounds.
134+
pub fn get(&self, index: usize) -> Option<&D> {
135+
self.validity.value(index).then(|| &self.elements[index])
136+
}
137+
}
138+
139+
impl<D: NativeDecimalType> AsRef<[D]> for DVector<D> {
140+
fn as_ref(&self) -> &[D] {
141+
&self.elements
86142
}
87143
}
88144

vortex-vector/src/decimal/generic_mut.rs

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,177 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4+
//! Definition and implementation of [`DVectorMut<D>`].
5+
46
use vortex_buffer::BufferMut;
5-
use vortex_dtype::{NativeDecimalType, PrecisionScale};
7+
use vortex_dtype::{DecimalDType, NativeDecimalType, PrecisionScale};
8+
use vortex_error::{VortexExpect, VortexResult, vortex_bail};
69
use vortex_mask::MaskMut;
710

811
use crate::{DVector, VectorMutOps, VectorOps};
912

1013
/// A specifically typed mutable decimal vector.
1114
#[derive(Debug, Clone)]
1215
pub struct DVectorMut<D> {
16+
/// The precision and scale of each decimal in the decimal vector.
1317
pub(super) ps: PrecisionScale<D>,
18+
/// The mutable buffer representing the vector decimal elements.
1419
pub(super) elements: BufferMut<D>,
20+
/// The validity mask (where `true` represents an element is **not** null).
1521
pub(super) validity: MaskMut,
1622
}
1723

24+
impl<D: NativeDecimalType> DVectorMut<D> {
25+
/// Creates a new [`DVectorMut<D>`] from the given [`PrecisionScale`], elements buffer, and
26+
/// validity mask.
27+
///
28+
/// # Panics
29+
///
30+
/// Panics if:
31+
///
32+
/// - The lengths of the `elements` and `validity` do not match.
33+
/// - Any of the elements are out of bounds for the given [`PrecisionScale`].
34+
pub fn new(ps: PrecisionScale<D>, elements: BufferMut<D>, validity: MaskMut) -> Self {
35+
Self::try_new(ps, elements, validity).vortex_expect("Failed to create `DVector`")
36+
}
37+
38+
/// Tries to create a new [`DVectorMut<D>`] from the given [`PrecisionScale`], elements buffer,
39+
/// and validity mask.
40+
///
41+
/// # Errors
42+
///
43+
/// Returns an error if:
44+
///
45+
/// - The lengths of the `elements` and `validity` do not match.
46+
/// - Any of the elements are out of bounds for the given [`PrecisionScale`].
47+
pub fn try_new(
48+
ps: PrecisionScale<D>,
49+
elements: BufferMut<D>,
50+
validity: MaskMut,
51+
) -> VortexResult<Self> {
52+
if elements.len() != validity.len() {
53+
vortex_bail!(
54+
"Elements length {} does not match validity length {}",
55+
elements.len(),
56+
validity.len()
57+
);
58+
}
59+
60+
// We assert that each element is within bounds for the given precision/scale.
61+
if !elements.iter().all(|e| ps.is_valid(*e)) {
62+
vortex_bail!(
63+
"One or more elements are out of bounds for precision {} and scale {}",
64+
ps.precision(),
65+
ps.scale()
66+
);
67+
}
68+
69+
Ok(Self {
70+
ps,
71+
elements,
72+
validity,
73+
})
74+
}
75+
76+
/// Creates a new [`DVectorMut<D>`] from the given [`PrecisionScale`], elements buffer, and
77+
/// validity mask, _without_ validation.
78+
///
79+
/// # Safety
80+
///
81+
/// The caller must ensure:
82+
///
83+
/// - The lengths of the elements and validity are equal.
84+
/// - All elements are in bounds for the given [`PrecisionScale`].
85+
pub unsafe fn new_unchecked(
86+
ps: PrecisionScale<D>,
87+
elements: BufferMut<D>,
88+
validity: MaskMut,
89+
) -> Self {
90+
if cfg!(debug_assertions) {
91+
Self::try_new(ps, elements, validity).vortex_expect("Failed to create `DVectorMut`")
92+
} else {
93+
Self {
94+
ps,
95+
elements,
96+
validity,
97+
}
98+
}
99+
}
100+
101+
/// Create a new mutable primitive vector with the given capacity.
102+
pub fn with_capacity(decimal_dtype: &DecimalDType, capacity: usize) -> Self {
103+
Self {
104+
ps: PrecisionScale::try_from(decimal_dtype)
105+
.vortex_expect("TODO(someone): This definitely should not be fallible"),
106+
elements: BufferMut::with_capacity(capacity),
107+
validity: MaskMut::with_capacity(capacity),
108+
}
109+
}
110+
111+
/// Decomposes the decimal vector into its constituent parts ([`PrecisionScale`], decimal
112+
/// buffer, and validity).
113+
pub fn into_parts(self) -> (PrecisionScale<D>, BufferMut<D>, MaskMut) {
114+
(self.ps, self.elements, self.validity)
115+
}
116+
117+
/// Get the precision/scale of the decimal vector.
118+
pub fn precision_scale(&self) -> PrecisionScale<D> {
119+
self.ps
120+
}
121+
122+
/// Returns a reference to the underlying elements buffer containing the decimal data.
123+
pub fn elements(&self) -> &BufferMut<D> {
124+
&self.elements
125+
}
126+
127+
/// Returns a mutable reference to the underlying elements buffer containing the decimal data.
128+
///
129+
/// # Safety
130+
///
131+
/// Modifying the elements buffer directly may violate the precision/scale constraints.
132+
/// The caller must ensure that any modifications maintain these invariants.
133+
pub unsafe fn elements_mut(&mut self) -> &mut BufferMut<D> {
134+
&mut self.elements
135+
}
136+
137+
/// Gets a nullable element at the given index, panicking on out-of-bounds.
138+
///
139+
/// If the element at the given index is null, returns `None`. Otherwise, returns `Some(x)`,
140+
/// where `x: D`.
141+
///
142+
/// Note that this `get` method is different from the standard library [`slice::get`], which
143+
/// returns `None` if the index is out of bounds. This method will panic if the index is out of
144+
/// bounds, and return `None` if the elements is null.
145+
///
146+
/// # Panics
147+
///
148+
/// Panics if the index is out of bounds.
149+
pub fn get(&self, index: usize) -> Option<&D> {
150+
self.validity.value(index).then(|| &self.elements[index])
151+
}
152+
153+
/// Appends a new element to the end of the vector.
154+
///
155+
/// # Errors
156+
///
157+
/// Returns an error if the value is out of bounds for the vector's precision/scale.
158+
pub fn try_push(&mut self, value: D) -> VortexResult<()> {
159+
if !self.ps.is_valid(value) {
160+
vortex_bail!("Value {:?} is out of bounds for {}", value, self.ps,);
161+
}
162+
163+
self.elements.push(value);
164+
self.validity.append_n(true, 1);
165+
Ok(())
166+
}
167+
}
168+
169+
impl<D: NativeDecimalType> AsRef<[D]> for DVectorMut<D> {
170+
fn as_ref(&self) -> &[D] {
171+
&self.elements
172+
}
173+
}
174+
18175
impl<D: NativeDecimalType> VectorMutOps for DVectorMut<D> {
19176
type Immutable = DVector<D>;
20177

vortex-vector/src/decimal/generic_mut_impl.rs

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)