vortex_vector/primitive/generic.rs
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! Definition and implementation of [`PVector<T>`].
5
6use std::fmt::Debug;
7use std::ops::BitAnd;
8use std::ops::RangeBounds;
9
10use vortex_buffer::Buffer;
11use vortex_dtype::NativePType;
12use vortex_error::VortexExpect;
13use vortex_error::VortexResult;
14use vortex_error::vortex_ensure;
15use vortex_mask::Mask;
16
17use crate::VectorOps;
18use crate::primitive::PScalar;
19use crate::primitive::PVectorMut;
20
21/// An immutable vector of generic primitive values.
22///
23/// `T` is expected to be bound by [`NativePType`], which templates an internal [`Buffer<T>`] that
24/// stores the elements of the vector.
25#[derive(Default, Debug, Clone)]
26pub struct PVector<T> {
27 /// The buffer representing the vector elements.
28 pub(super) elements: Buffer<T>,
29 /// The validity mask (where `true` represents an element is **not** null).
30 pub(super) validity: Mask,
31}
32
33impl<T> PVector<T> {
34 /// Creates a new [`PVector<T>`] from the given elements buffer and validity mask.
35 ///
36 /// # Panics
37 ///
38 /// Panics if the length of the validity mask does not match the length of the elements buffer.
39 pub fn new(elements: Buffer<T>, validity: Mask) -> Self {
40 Self::try_new(elements, validity).vortex_expect("Failed to create `PVector`")
41 }
42
43 /// Tries to create a new [`PVector<T>`] from the given elements buffer and validity mask.
44 ///
45 /// # Errors
46 ///
47 /// Returns an error if the length of the validity mask does not match the length of the
48 /// elements buffer.
49 pub fn try_new(elements: Buffer<T>, validity: Mask) -> VortexResult<Self> {
50 vortex_ensure!(
51 validity.len() == elements.len(),
52 "`PVector` validity mask must have the same length as elements"
53 );
54
55 Ok(Self { elements, validity })
56 }
57
58 /// Creates a new [`PVector<T>`] from the given elements buffer and validity mask without
59 /// validation.
60 ///
61 /// # Safety
62 ///
63 /// The caller must ensure that the validity mask has the same length as the elements buffer.
64 pub unsafe fn new_unchecked(elements: Buffer<T>, validity: Mask) -> Self {
65 if cfg!(debug_assertions) {
66 Self::new(elements, validity)
67 } else {
68 Self { elements, validity }
69 }
70 }
71
72 /// Decomposes the primitive vector into its constituent parts (buffer and validity).
73 pub fn into_parts(self) -> (Buffer<T>, Mask) {
74 (self.elements, self.validity)
75 }
76
77 /// Decomposes the primitive vector into its constituent parts by mutable reference.
78 ///
79 /// # Safety
80 ///
81 /// The caller must ensure that no other references to the internal parts exist while mutable
82 pub unsafe fn as_parts_mut(&mut self) -> (&mut Buffer<T>, &mut Mask) {
83 (&mut self.elements, &mut self.validity)
84 }
85
86 /// Gets a nullable element at the given index, panicking on out-of-bounds.
87 ///
88 /// If the element at the given index is null, returns `None`. Otherwise, returns `Some(x)`,
89 /// where `x: T`.
90 ///
91 /// Note that this `get` method is different from the standard library [`slice::get`], which
92 /// returns `None` if the index is out of bounds. This method will panic if the index is out of
93 /// bounds, and return `None` if the elements is null.
94 ///
95 /// # Panics
96 ///
97 /// Panics if the index is out of bounds.
98 pub fn get(&self, index: usize) -> Option<&T> {
99 self.validity.value(index).then(|| &self.elements[index])
100 }
101
102 /// Returns the internal [`Buffer`] of the [`PVector`].
103 ///
104 /// Note that the internal buffer may hold garbage data in place of nulls. That information is
105 /// tracked by the [`validity()`](Self::validity).
106 #[inline]
107 pub fn elements(&self) -> &Buffer<T> {
108 &self.elements
109 }
110}
111
112impl<T: NativePType> AsRef<[T]> for PVector<T> {
113 /// Returns an immutable slice over the internal buffer with elements of type `T`.
114 ///
115 /// Note that this slice may contain garbage data where the [`validity()`] mask states that an
116 /// element is invalid.
117 ///
118 /// The caller should check the [`validity()`] before performing any operations.
119 ///
120 /// [`validity()`]: crate::VectorOps::validity
121 #[inline]
122 fn as_ref(&self) -> &[T] {
123 self.elements.as_slice()
124 }
125}
126
127impl<T: NativePType> VectorOps for PVector<T> {
128 type Mutable = PVectorMut<T>;
129 type Scalar = PScalar<T>;
130
131 fn len(&self) -> usize {
132 self.elements.len()
133 }
134
135 fn validity(&self) -> &Mask {
136 &self.validity
137 }
138
139 fn mask_validity(&mut self, mask: &Mask) {
140 self.validity = self.validity.bitand(mask);
141 }
142
143 fn scalar_at(&self, index: usize) -> PScalar<T> {
144 assert!(index < self.len(), "Index out of bounds in `PVector`");
145 PScalar::<T>::new(self.validity.value(index).then(|| self.elements[index]))
146 }
147
148 fn slice(&self, range: impl RangeBounds<usize> + Clone + Debug) -> Self {
149 let elements = self.elements.slice(range.clone());
150 let validity = self.validity.slice(range);
151 Self::new(elements, validity)
152 }
153
154 fn clear(&mut self) {
155 self.elements.clear();
156 self.validity.clear();
157 }
158
159 /// Try to convert self into a mutable vector.
160 fn try_into_mut(self) -> Result<PVectorMut<T>, Self> {
161 let elements = match self.elements.try_into_mut() {
162 Ok(elements) => elements,
163 Err(elements) => {
164 return Err(Self {
165 elements,
166 validity: self.validity,
167 });
168 }
169 };
170
171 match self.validity.try_into_mut() {
172 Ok(validity_mut) => Ok(PVectorMut {
173 elements,
174 validity: validity_mut,
175 }),
176 Err(validity) => Err(Self {
177 elements: elements.freeze(),
178 validity,
179 }),
180 }
181 }
182
183 fn into_mut(self) -> PVectorMut<T> {
184 let elements = self.elements.into_mut();
185 let validity = self.validity.into_mut();
186
187 PVectorMut { elements, validity }
188 }
189}