-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
108f945
commit e4b89ee
Showing
4 changed files
with
401 additions
and
224 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
//! Idiomatic iterators for [`Array`](crate::Array) | ||
use arrow_buffer::NullBuffer; | ||
|
||
use crate::array::PointArray; | ||
use crate::scalar::Point; | ||
use crate::trait_::ArrayAccessor; | ||
use crate::ArrayBase; | ||
|
||
/// An iterator that returns Some(T) or None, that can be used on any [`ArrayAccessor`] | ||
/// | ||
/// # Performance | ||
/// | ||
/// [`ArrayIter`] provides an idiomatic way to iterate over an array, however, this | ||
/// comes at the cost of performance. In particular the interleaved handling of | ||
/// the null mask is often sub-optimal. | ||
/// | ||
/// If performing an infallible operation, it is typically faster to perform the operation | ||
/// on every index of the array, and handle the null mask separately. For [`PrimitiveArray`] | ||
/// this functionality is provided by [`compute::unary`] | ||
/// | ||
/// If performing a fallible operation, it isn't possible to perform the operation independently | ||
/// of the null mask, as this might result in a spurious failure on a null index. However, | ||
/// there are more efficient ways to iterate over just the non-null indices, this functionality | ||
/// is provided by [`compute::try_unary`] | ||
/// | ||
/// [`PrimitiveArray`]: crate::PrimitiveArray | ||
/// [`compute::unary`]: https://docs.rs/arrow/latest/arrow/compute/fn.unary.html | ||
/// [`compute::try_unary`]: https://docs.rs/arrow/latest/arrow/compute/fn.try_unary.html | ||
#[derive(Debug)] | ||
pub struct PointArrayIter<'a> { | ||
array: &'a PointArray, | ||
logical_nulls: Option<NullBuffer>, | ||
current: usize, | ||
current_end: usize, | ||
} | ||
|
||
impl<'a> PointArrayIter<'a> { | ||
/// create a new iterator | ||
pub fn new(array: &'a PointArray) -> Self { | ||
let len = array.len(); | ||
let logical_nulls = array.nulls().cloned(); | ||
PointArrayIter { | ||
array, | ||
logical_nulls, | ||
current: 0, | ||
current_end: len, | ||
} | ||
} | ||
|
||
#[inline] | ||
fn is_null(&self, idx: usize) -> bool { | ||
self.logical_nulls | ||
.as_ref() | ||
.map(|x| x.is_null(idx)) | ||
.unwrap_or_default() | ||
} | ||
} | ||
|
||
impl<'a> Iterator for PointArrayIter<'a> { | ||
type Item = Option<Point<'a>>; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<Self::Item> { | ||
if self.current == self.current_end { | ||
None | ||
} else if self.is_null(self.current) { | ||
self.current += 1; | ||
Some(None) | ||
} else { | ||
let old = self.current; | ||
self.current += 1; | ||
// Safety: | ||
// we just checked bounds in `self.current_end == self.current` | ||
// this is safe on the premise that this struct is initialized with | ||
// current = array.len() | ||
// and that current_end is ever only decremented | ||
unsafe { Some(Some(self.array.value_unchecked(old))) } | ||
} | ||
} | ||
|
||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
( | ||
self.array.len() - self.current, | ||
Some(self.array.len() - self.current), | ||
) | ||
} | ||
} | ||
|
||
impl DoubleEndedIterator for PointArrayIter<'_> { | ||
fn next_back(&mut self) -> Option<Self::Item> { | ||
if self.current_end == self.current { | ||
None | ||
} else { | ||
self.current_end -= 1; | ||
Some(if self.is_null(self.current_end) { | ||
None | ||
} else { | ||
// Safety: | ||
// we just checked bounds in `self.current_end == self.current` | ||
// this is safe on the premise that this struct is initialized with | ||
// current = array.len() | ||
// and that current_end is ever only decremented | ||
unsafe { Some(self.array.value_unchecked(self.current_end)) } | ||
}) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.