Skip to content

Commit b645a51

Browse files
authored
Feature: Add IntoIter implementation for vectors (#5093)
Adds `IntoIter` impls for primitive and bool vector. Consolidates all the extend, from_iter, and (new) into_iter stuff into `iter.rs` files. The non-cosmetic changes are at the bottom of the `iter.rs` files. There is a world where we could use the internal `BufferIterator` types but this was way simpler. Signed-off-by: Connor Tsui <[email protected]>
1 parent 560aa17 commit b645a51

File tree

8 files changed

+319
-106
lines changed

8 files changed

+319
-106
lines changed
Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4-
//! [`FromIterator`] and related implementations for [`BoolVectorMut`].
4+
//! Iterator implementations for [`BoolVectorMut`].
55
66
use vortex_buffer::BitBufferMut;
77
use vortex_mask::MaskMut;
88

9-
use crate::BoolVectorMut;
9+
use crate::{BoolVectorMut, VectorMutOps};
1010

1111
impl FromIterator<Option<bool>> for BoolVectorMut {
1212
/// Creates a new [`BoolVectorMut`] from an iterator of `Option<bool>` values.
@@ -78,3 +78,63 @@ impl FromIterator<bool> for BoolVectorMut {
7878
}
7979
}
8080
}
81+
82+
/// Iterator over a [`BoolVectorMut`] that yields [`Option<bool>`] values.
83+
///
84+
/// This iterator is created by calling [`IntoIterator::into_iter`] on a [`BoolVectorMut`].
85+
///
86+
/// It consumes the mutable vector and iterates over the elements, yielding `None` for null values
87+
/// and `Some(value)` for valid values.
88+
pub struct BoolVectorMutIterator {
89+
/// The vector being iterated over.
90+
vector: BoolVectorMut,
91+
/// The current index into the vector.
92+
index: usize,
93+
}
94+
95+
impl Iterator for BoolVectorMutIterator {
96+
type Item = Option<bool>;
97+
98+
fn next(&mut self) -> Option<Self::Item> {
99+
(self.index < self.vector.len()).then(|| {
100+
let value = self
101+
.vector
102+
.validity
103+
.value(self.index)
104+
.then(|| self.vector.bits.value(self.index));
105+
self.index += 1;
106+
value
107+
})
108+
}
109+
110+
fn size_hint(&self) -> (usize, Option<usize>) {
111+
let remaining = self.vector.len() - self.index;
112+
(remaining, Some(remaining))
113+
}
114+
}
115+
116+
impl IntoIterator for BoolVectorMut {
117+
type Item = Option<bool>;
118+
type IntoIter = BoolVectorMutIterator;
119+
120+
/// Converts the mutable vector into an iterator over `Option<bool>` values.
121+
///
122+
/// This method consumes the `BoolVectorMut` and returns an iterator that yields `None` for
123+
/// null values and `Some(value)` for valid values.
124+
///
125+
/// # Examples
126+
///
127+
/// ```
128+
/// use vortex_vector::BoolVectorMut;
129+
///
130+
/// let vec = BoolVectorMut::from_iter([Some(true), None, Some(false), Some(true)]);
131+
/// let collected: Vec<_> = vec.into_iter().collect();
132+
/// assert_eq!(collected, vec![Some(true), None, Some(false), Some(true)]);
133+
/// ```
134+
fn into_iter(self) -> Self::IntoIter {
135+
BoolVectorMutIterator {
136+
vector: self,
137+
index: 0,
138+
}
139+
}
140+
}

vortex-vector/src/bool/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub use vector::BoolVector;
99
mod vector_mut;
1010
pub use vector_mut::BoolVectorMut;
1111

12-
mod from_iter;
12+
mod iter;
1313

1414
use crate::{Vector, VectorMut};
1515

vortex-vector/src/bool/vector_mut.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,41 @@ mod tests {
224224
let frozen = vec1.freeze();
225225
assert_eq!(frozen.validity().true_count(), 3);
226226
}
227+
228+
#[test]
229+
fn test_into_iter_roundtrip() {
230+
// Test that from_iter followed by into_iter preserves the data.
231+
let original_data = vec![
232+
Some(true),
233+
None,
234+
Some(false),
235+
Some(true),
236+
None,
237+
Some(false),
238+
None,
239+
Some(true),
240+
];
241+
242+
// Create vector from iterator.
243+
let vec = BoolVectorMut::from_iter(original_data.clone());
244+
245+
// Convert back to iterator and collect.
246+
let roundtrip: Vec<_> = vec.into_iter().collect();
247+
248+
// Should be identical.
249+
assert_eq!(roundtrip, original_data);
250+
251+
// Also test with all valid values.
252+
let all_valid = vec![true, false, true, false, true];
253+
let vec = BoolVectorMut::from_iter(all_valid.clone());
254+
let roundtrip: Vec<_> = vec.into_iter().collect();
255+
let expected: Vec<_> = all_valid.into_iter().map(Some).collect();
256+
assert_eq!(roundtrip, expected);
257+
258+
// Test with empty.
259+
let empty: Vec<Option<bool>> = vec![];
260+
let vec = BoolVectorMut::from_iter(empty.clone());
261+
let roundtrip: Vec<_> = vec.into_iter().collect();
262+
assert_eq!(roundtrip, empty);
263+
}
227264
}

vortex-vector/src/primitive/generic.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ impl<T: NativePType> PVector<T> {
6969
Self { elements, validity }
7070
}
7171

72+
/// Decomposes the primitive vector into its constituent parts.
73+
pub fn into_parts(self) -> (Buffer<T>, Mask) {
74+
(self.elements, self.validity)
75+
}
76+
7277
/// Gets a nullable element at the given index.
7378
///
7479
/// If the element at the given index is null, returns `None`. Otherwise, returns `Some(x)`,

vortex-vector/src/primitive/generic_mut.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ impl<T> PVectorMut<T> {
159159
validity: MaskMut::with_capacity(capacity),
160160
}
161161
}
162+
163+
/// Decomposes the primitive vector into its constituent parts.
164+
pub fn into_parts(self) -> (BufferMut<T>, MaskMut) {
165+
(self.elements, self.validity)
166+
}
162167
}
163168

164169
impl<T: NativePType> VectorMutOps for PVectorMut<T> {
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
//! Iterator implementations for [`PVectorMut`].
5+
6+
use vortex_dtype::NativePType;
7+
8+
use crate::{PVectorMut, VectorMutOps};
9+
10+
impl<T: NativePType> Extend<Option<T>> for PVectorMut<T> {
11+
/// Extends the vector from an iterator of optional values.
12+
///
13+
/// `None` values will be marked as null in the validity mask.
14+
///
15+
/// # Examples
16+
///
17+
/// ```
18+
/// use vortex_vector::{PVectorMut, VectorMutOps, VectorOps};
19+
///
20+
/// let mut vec = PVectorMut::from_iter([Some(1i32), None]);
21+
/// vec.extend([Some(3), None, Some(5)]);
22+
/// assert_eq!(vec.len(), 5);
23+
///
24+
/// let frozen = vec.freeze();
25+
/// assert_eq!(frozen.validity().true_count(), 3); // Only 3 non-null values.
26+
/// ```
27+
fn extend<I: IntoIterator<Item = Option<T>>>(&mut self, iter: I) {
28+
let iter = iter.into_iter();
29+
// Since we do not know the length of the iterator, we can only guess how much memory we
30+
// need to reserve. Note that these hints may be inaccurate.
31+
let (lower_bound, _) = iter.size_hint();
32+
33+
// We choose not to use the optional upper bound size hint to match the standard library.
34+
35+
self.reserve(lower_bound);
36+
37+
// We have to update validity per-element since it depends on Option variant.
38+
for opt_val in iter {
39+
match opt_val {
40+
Some(val) => {
41+
self.elements.push(val);
42+
self.validity.append_n(true, 1);
43+
}
44+
None => {
45+
self.elements.push(T::default());
46+
self.validity.append_n(false, 1);
47+
}
48+
}
49+
}
50+
}
51+
}
52+
53+
impl<T: NativePType> FromIterator<Option<T>> for PVectorMut<T> {
54+
/// Creates a new [`PVectorMut<T>`] from an iterator of `Option<T>` values.
55+
///
56+
/// `None` values will be marked as invalid in the validity mask.
57+
///
58+
/// Internally, this uses the [`Extend<Option<T>>`] trait implementation.
59+
fn from_iter<I>(iter: I) -> Self
60+
where
61+
I: IntoIterator<Item = Option<T>>,
62+
{
63+
let iter = iter.into_iter();
64+
65+
let mut vec = Self::with_capacity(iter.size_hint().0);
66+
vec.extend(iter);
67+
68+
vec
69+
}
70+
}
71+
72+
impl<T: NativePType> Extend<T> for PVectorMut<T> {
73+
/// Extends the vector from an iterator of values.
74+
///
75+
/// All values from the iterator will be marked as non-null in the validity mask.
76+
///
77+
/// Internally, this uses the [`Extend<T>`] trait implementation.
78+
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
79+
let start_len = self.len();
80+
81+
// Allow the `BufferMut` implementation to handle extending efficiently.
82+
self.elements.extend(iter);
83+
self.validity.append_n(true, self.len() - start_len);
84+
}
85+
}
86+
87+
impl<T: NativePType> FromIterator<T> for PVectorMut<T> {
88+
/// Creates a new [`PVectorMut<T>`] from an iterator of `T` values.
89+
///
90+
/// All values will be treated as non-null.
91+
///
92+
/// # Examples
93+
///
94+
/// ```
95+
/// use vortex_vector::{PVectorMut, VectorMutOps};
96+
///
97+
/// let mut vec = PVectorMut::from_iter([1i32, 2, 3, 4]);
98+
/// assert_eq!(vec.len(), 4);
99+
/// ```
100+
fn from_iter<I>(iter: I) -> Self
101+
where
102+
I: IntoIterator<Item = T>,
103+
{
104+
let iter = iter.into_iter();
105+
106+
let mut vec = Self::with_capacity(iter.size_hint().0);
107+
vec.extend(iter);
108+
109+
vec
110+
}
111+
}
112+
113+
/// Iterator over a [`PVectorMut<T>`] that yields [`Option<T>`] values.
114+
///
115+
/// This iterator is created by calling [`IntoIterator::into_iter`] on a [`PVectorMut<T>`].
116+
///
117+
/// It consumes the mutable vector and iterates over the elements, yielding `None` for null values
118+
/// and `Some(value)` for valid values.
119+
pub struct PVectorMutIterator<T: NativePType> {
120+
/// The vector being iterated over.
121+
vector: PVectorMut<T>,
122+
/// The current index into the vector.
123+
index: usize,
124+
}
125+
126+
impl<T: NativePType> Iterator for PVectorMutIterator<T> {
127+
type Item = Option<T>;
128+
129+
fn next(&mut self) -> Option<Self::Item> {
130+
(self.index < self.vector.len()).then(|| {
131+
let value = self
132+
.vector
133+
.validity
134+
.value(self.index)
135+
.then(|| self.vector.elements[self.index]);
136+
self.index += 1;
137+
value
138+
})
139+
}
140+
141+
fn size_hint(&self) -> (usize, Option<usize>) {
142+
let remaining = self.vector.len() - self.index;
143+
(remaining, Some(remaining))
144+
}
145+
}
146+
147+
impl<T: NativePType> IntoIterator for PVectorMut<T> {
148+
type Item = Option<T>;
149+
type IntoIter = PVectorMutIterator<T>;
150+
151+
/// Converts the mutable vector into an iterator over [`Option<T>`] values.
152+
///
153+
/// This method consumes the [`PVectorMut<T>`] and returns an iterator that yields `None` for
154+
/// null values and `Some(value)` for valid values.
155+
///
156+
/// # Examples
157+
///
158+
/// ```
159+
/// use vortex_vector::PVectorMut;
160+
///
161+
/// let vec = PVectorMut::<i32>::from_iter([Some(1), None, Some(3), Some(4)]);
162+
/// let collected: Vec<_> = vec.into_iter().collect();
163+
/// assert_eq!(collected, vec![Some(1), None, Some(3), Some(4)]);
164+
/// ```
165+
fn into_iter(self) -> Self::IntoIter {
166+
PVectorMutIterator {
167+
vector: self,
168+
index: 0,
169+
}
170+
}
171+
}

vortex-vector/src/primitive/mod.rs

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

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

0 commit comments

Comments
 (0)