Skip to content

Commit f3fa13d

Browse files
committed
add nice-to-have vector methods to PVectorMut
Signed-off-by: Connor Tsui <[email protected]>
1 parent bd25e4a commit f3fa13d

File tree

7 files changed

+581
-86
lines changed

7 files changed

+581
-86
lines changed

vortex-buffer/src/bit/buf_mut.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ use crate::{BitBuffer, BufferMut, ByteBufferMut, buffer_mut};
3131
#[derive(Debug, Clone, Eq)]
3232
pub struct BitBufferMut {
3333
buffer: ByteBufferMut,
34+
/// Represents the offset of the bit buffer into the first byte.
35+
///
36+
/// This is always less than 8 (for when the bit buffer is not aligned to a byte).
3437
offset: usize,
3538
len: usize,
3639
}
@@ -162,6 +165,13 @@ impl BitBufferMut {
162165
self.buffer.reserve(additional_bytes);
163166
}
164167

168+
/// Clears the bit buffer (but keeps any allocated memory).
169+
pub fn clear(&mut self) {
170+
// Since there are no items we need to drop, we simply set the length to 0.
171+
self.len = 0;
172+
self.offset = 0;
173+
}
174+
165175
/// Set the bit at `index` to the given boolean value.
166176
///
167177
/// This operation is checked so if `index` exceeds the buffer length, this will panic.

vortex-mask/src/mask_mut.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::ops::Sub;
55
use std::sync::Arc;
66

77
use vortex_buffer::BitBufferMut;
8+
use vortex_error::vortex_panic;
89

910
use crate::Mask;
1011

@@ -56,6 +57,29 @@ impl MaskMut {
5657
})
5758
}
5859

60+
/// Returns the boolean value at a given index.
61+
///
62+
/// # Panics
63+
///
64+
/// Panics if the index is out of bounds.
65+
pub fn value(&self, index: usize) -> bool {
66+
match &self.0 {
67+
Inner::Empty { .. } => {
68+
vortex_panic!("index out of bounds: the length is 0 but the index is {index}")
69+
}
70+
Inner::Constant { value, len, .. } => {
71+
assert!(
72+
index < *len,
73+
"index out of bounds: the length is {} but the index is {index}",
74+
*len
75+
);
76+
77+
*value
78+
}
79+
Inner::Builder(bit_buffer) => bit_buffer.value(index),
80+
}
81+
}
82+
5983
/// Reserve capacity for at least `additional` more values to be appended.
6084
pub fn reserve(&mut self, additional: usize) {
6185
match &mut self.0 {
@@ -71,6 +95,39 @@ impl MaskMut {
7195
}
7296
}
7397

98+
/// Clears the mask.
99+
///
100+
/// Note that this method has no effect on the allocated capacity of the mask.
101+
pub fn clear(&mut self) {
102+
match &mut self.0 {
103+
Inner::Empty { .. } => {}
104+
Inner::Constant { capacity, .. } => {
105+
self.0 = Inner::Empty {
106+
capacity: *capacity,
107+
}
108+
}
109+
Inner::Builder(bit_buffer) => bit_buffer.clear(),
110+
};
111+
}
112+
113+
/// Shortens the mask, keeping the first `len` bits.
114+
///
115+
/// If `len` is greater or equal to the vector’s current length, this has no effect.
116+
///
117+
/// Note that this method has no effect on the allocated capacity of the mask.
118+
pub fn truncate(&mut self, len: usize) {
119+
let truncated_len = len;
120+
if truncated_len > self.len() {
121+
return;
122+
}
123+
124+
match &mut self.0 {
125+
Inner::Empty { .. } => {}
126+
Inner::Constant { len, .. } => *len = truncated_len.min(*len),
127+
Inner::Builder(bit_buffer) => bit_buffer.truncate(truncated_len),
128+
};
129+
}
130+
74131
/// Append n values to the mask.
75132
pub fn append_n(&mut self, new_value: bool, n: usize) {
76133
match &mut self.0 {

vortex-vector/src/primitive/from_iter.rs

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

vortex-vector/src/primitive/generic.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,76 @@ impl<T: NativePType> PVector<T> {
6868

6969
Self { elements, validity }
7070
}
71+
72+
/// Gets a nullable element at the given index, with bounds checking.
73+
///
74+
/// If the index is out of bounds, returns `None`. If the element at the given index is null,
75+
/// returns `Some(None)`. Otherwise, returns `Some(Some(x))`, where `x: T`.
76+
pub fn get_checked(&self, index: usize) -> Option<Option<T>> {
77+
(index < self.len()).then(|| {
78+
self.validity.value(index).then(|| {
79+
self.elements
80+
.get(index)
81+
.copied()
82+
.vortex_expect("length of elements was somehow incorrect")
83+
})
84+
})
85+
}
86+
87+
/// Gets a nullable element at the given index.
88+
///
89+
/// If the element at the given index is null, returns `None`. Otherwise, returns `Some(x)`,
90+
/// where `x: T`.
91+
///
92+
/// # Panics
93+
///
94+
/// Panics if the index is out of bounds.
95+
pub fn get(&self, index: usize) -> Option<T> {
96+
assert!(
97+
index < self.len(),
98+
"index out of bounds: the length is {} but the index is {index}",
99+
self.len()
100+
);
101+
102+
self.validity.value(index).then(|| {
103+
self.elements
104+
.get(index)
105+
.copied()
106+
.vortex_expect("length of elements was somehow incorrect")
107+
})
108+
}
109+
110+
/// Gets a nullable element at the given index, without checking bounds and without checking
111+
/// nullability.
112+
///
113+
/// The caller should ensure that the element at the given index is not null (though doing so
114+
/// will not cause undefined behavior).
115+
///
116+
/// # Safety
117+
///
118+
/// The caller must ensure that the index is within bounds.
119+
pub unsafe fn get_unchecked(&self, index: usize) -> T {
120+
debug_assert!(
121+
index < self.len(),
122+
"index out of bounds: the length is {} but the index is {index}",
123+
self.len()
124+
);
125+
126+
// SAFETY: The caller ensures that the index is in bounds.
127+
unsafe { *self.elements.get_unchecked(index) }
128+
}
129+
130+
/// Returns a slice over the internal buffer with elements of type `T`.
131+
///
132+
/// Note that this slice may contain garbage data where the [`validity()`] mask states that an
133+
/// element is invalid.
134+
///
135+
/// The caller should check the [`validity()`] before performing any operations.
136+
///
137+
/// [`validity()`]: Self::validity
138+
pub fn as_slice(&self) -> &[T] {
139+
self.elements.as_slice()
140+
}
71141
}
72142

73143
impl<T: NativePType> VectorOps for PVector<T> {

vortex-vector/src/primitive/generic_mut.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ use crate::{PVector, VectorMutOps, VectorOps};
1515
/// `T` is expected to be bound by [`NativePType`], which templates an internal [`BufferMut<T>`]
1616
/// that stores the elements of the vector.
1717
///
18-
/// `PVectorMut<T>` is the primary way to construct primitive vectors. It provides efficient methods
19-
/// for building vectors incrementally before converting them to an immutable [`PVector<T>`] using
20-
/// the [`freeze`](crate::VectorMutOps::freeze) method.
18+
/// [`PVectorMut<T>`] is the primary way to construct primitive vectors. It provides efficient
19+
/// methods for building vectors incrementally before converting them to an immutable [`PVector<T>`]
20+
/// using the [`freeze`](crate::VectorMutOps::freeze) method.
2121
///
2222
/// # Examples
2323
///

vortex-vector/src/primitive/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@ pub use generic_mut::PVectorMut;
2323
mod vector;
2424
pub use vector::PrimitiveVector;
2525

26+
mod pvector_impl;
2627
mod vector_mut;
2728
pub use vector_mut::PrimitiveVectorMut;
2829

29-
mod from_iter;
30-
3130
mod macros;
3231

3332
use vortex_dtype::NativePType;

0 commit comments

Comments
 (0)