From d439c1d045fad972d2589d1e84bdc412abcde8aa Mon Sep 17 00:00:00 2001
From: julio4 <30329843+julio4@users.noreply.github.com>
Date: Fri, 24 Jan 2025 00:56:07 +0100
Subject: [PATCH 1/3] feat(corelib): iter::adapters::Filter
---
corelib/src/iter/adapters.cairo | 5 +++
corelib/src/iter/adapters/filter.cairo | 33 ++++++++++++++++++++
corelib/src/iter/traits/iterator.cairo | 42 ++++++++++++++++++++++++--
corelib/src/test/iter_test.cairo | 8 +++++
4 files changed, 86 insertions(+), 2 deletions(-)
create mode 100644 corelib/src/iter/adapters/filter.cairo
diff --git a/corelib/src/iter/adapters.cairo b/corelib/src/iter/adapters.cairo
index e938418f280..5a1a3853773 100644
--- a/corelib/src/iter/adapters.cairo
+++ b/corelib/src/iter/adapters.cairo
@@ -17,3 +17,8 @@ mod peekable;
#[allow(unused_imports)]
pub(crate) use peekable::peekable_iterator;
pub use peekable::{Peekable, PeekableTrait};
+
+mod filter;
+pub use filter::Filter;
+#[allow(unused_imports)]
+pub(crate) use filter::filter_iterator;
diff --git a/corelib/src/iter/adapters/filter.cairo b/corelib/src/iter/adapters/filter.cairo
new file mode 100644
index 00000000000..cb26d4c353d
--- /dev/null
+++ b/corelib/src/iter/adapters/filter.cairo
@@ -0,0 +1,33 @@
+/// An iterator that filters the elements of `iter` with `predicate`.
+///
+/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`filter`]: Iterator::filter
+#[must_use]
+#[derive(Drop, Clone)]
+pub struct Filter {
+ pub iter: I,
+ pub predicate: P,
+}
+
+pub fn filter_iterator(iter: I, predicate: P) -> Filter {
+ Filter { iter, predicate }
+}
+
+pub impl FilterIterator<
+ I,
+ P,
+ impl TIter: Iterator,
+ +core::ops::Fn
[Output: bool],
+ +Destruct,
+ +Destruct
,
+ +Copy,
+ +Copy,
+ +Destruct,
+> of Iterator> {
+ type Item = TIter::Item;
+ fn next(ref self: Filter) -> Option {
+ self.iter.find(self.predicate)
+ }
+}
diff --git a/corelib/src/iter/traits/iterator.cairo b/corelib/src/iter/traits/iterator.cairo
index 0bd351f48b0..a6c898e7ca3 100644
--- a/corelib/src/iter/traits/iterator.cairo
+++ b/corelib/src/iter/traits/iterator.cairo
@@ -1,6 +1,6 @@
use crate::iter::adapters::{
- Enumerate, Map, Peekable, Zip, enumerated_iterator, mapped_iterator, peekable_iterator,
- zipped_iterator,
+ Enumerate, Filter, Map, Zip, enumerated_iterator, filter_iterator, mapped_iterator,
+ peekable_iterator, zipped_iterator,
};
use crate::iter::traits::{Product, Sum};
@@ -364,6 +364,8 @@ pub trait Iterator {
/// // we can still use `iter`, as there are more elements.
/// assert_eq!(iter.next(), Option::Some(3));
/// ```
+ ///
+ /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`.
fn find<
P,
+core::ops::Fn[Output: bool],
@@ -385,6 +387,42 @@ pub trait Iterator {
}
}
+ /// Creates an iterator which uses a closure to determine if an element
+ /// should be yielded.
+ ///
+ /// Given an element the closure must return `true` or `false`. The returned
+ /// iterator will yield only the elements for which the closure returns
+ /// `true`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let a = array![0_u32, 1, 2];
+ ///
+ /// let mut iter = a.into_iter().filter(|x| x > 0);
+ ///
+ /// assert_eq!(iter.next(), Option::Some(1));
+ /// assert_eq!(iter.next(), Option::Some(2));
+ /// assert_eq!(iter.next(), Option::None);
+ /// ```
+ ///
+ /// Note that `iter.filter(f).next()` is equivalent to `iter.find(f)`.
+ #[inline]
+ fn filter<
+ P,
+ +core::ops::Fn[Output: bool],
+ +Destruct
,
+ +Destruct,
+ +Copy,
+ +Destruct,
+ >(
+ self: T, predicate: P,
+ ) -> Filter {
+ filter_iterator(self, predicate)
+ }
+
/// 'Zips up' two iterators into a single iterator of pairs.
///
/// `zip()` returns a new iterator that will iterate over two other
diff --git a/corelib/src/test/iter_test.cairo b/corelib/src/test/iter_test.cairo
index 2a176836b0a..4d522f00b93 100644
--- a/corelib/src/test/iter_test.cairo
+++ b/corelib/src/test/iter_test.cairo
@@ -121,3 +121,11 @@ fn test_iter_find() {
assert_eq!(iter.find(|x| *x == 2), Option::Some(2));
assert_eq!(iter.next(), Option::Some(3));
}
+
+#[test]
+fn test_iter_adapter_filter() {
+ let mut iter = array![0_u32, 1, 2].into_iter().filter(|x| x > 0);
+ assert_eq!(iter.next(), Option::Some(1));
+ assert_eq!(iter.next(), Option::Some(2));
+ assert_eq!(iter.next(), Option::None);
+}
From 695f5d276a75c5724f48ff2526c55e4bb7f623e7 Mon Sep 17 00:00:00 2001
From: julio4 <30329843+julio4@users.noreply.github.com>
Date: Mon, 27 Jan 2025 21:56:52 +0100
Subject: [PATCH 2/3] fix: filter takes snapshot iterator item
---
corelib/src/iter/adapters/filter.cairo | 3 +--
corelib/src/iter/traits/iterator.cairo | 9 ++++-----
corelib/src/test/iter_test.cairo | 2 +-
3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/corelib/src/iter/adapters/filter.cairo b/corelib/src/iter/adapters/filter.cairo
index cb26d4c353d..d4b578a3cb1 100644
--- a/corelib/src/iter/adapters/filter.cairo
+++ b/corelib/src/iter/adapters/filter.cairo
@@ -19,10 +19,9 @@ pub impl FilterIterator<
I,
P,
impl TIter: Iterator,
- +core::ops::Fn[Output: bool],
+ +core::ops::Fn
[Output: bool],
+Destruct,
+Destruct
,
- +Copy,
+Copy,
+Destruct,
> of Iterator> {
diff --git a/corelib/src/iter/traits/iterator.cairo b/corelib/src/iter/traits/iterator.cairo
index a6c898e7ca3..308432c787f 100644
--- a/corelib/src/iter/traits/iterator.cairo
+++ b/corelib/src/iter/traits/iterator.cairo
@@ -1,5 +1,5 @@
use crate::iter::adapters::{
- Enumerate, Filter, Map, Zip, enumerated_iterator, filter_iterator, mapped_iterator,
+ Enumerate, Filter, Map, Peekable, Zip, enumerated_iterator, filter_iterator, mapped_iterator,
peekable_iterator, zipped_iterator,
};
use crate::iter::traits::{Product, Sum};
@@ -388,7 +388,7 @@ pub trait Iterator {
}
/// Creates an iterator which uses a closure to determine if an element
- /// should be yielded.
+ /// should be yielded. The closure takes each element as a snapshot.
///
/// Given an element the closure must return `true` or `false`. The returned
/// iterator will yield only the elements for which the closure returns
@@ -401,7 +401,7 @@ pub trait Iterator {
/// ```
/// let a = array![0_u32, 1, 2];
///
- /// let mut iter = a.into_iter().filter(|x| x > 0);
+ /// let mut iter = a.into_iter().filter(|x| *x > 0);
///
/// assert_eq!(iter.next(), Option::Some(1));
/// assert_eq!(iter.next(), Option::Some(2));
@@ -412,10 +412,9 @@ pub trait Iterator {
#[inline]
fn filter<
P,
- +core::ops::Fn[Output: bool],
+ +core::ops::Fn
[Output: bool],
+Destruct
,
+Destruct,
- +Copy,
+Destruct,
>(
self: T, predicate: P,
diff --git a/corelib/src/test/iter_test.cairo b/corelib/src/test/iter_test.cairo
index 4d522f00b93..d3189a51d0e 100644
--- a/corelib/src/test/iter_test.cairo
+++ b/corelib/src/test/iter_test.cairo
@@ -124,7 +124,7 @@ fn test_iter_find() {
#[test]
fn test_iter_adapter_filter() {
- let mut iter = array![0_u32, 1, 2].into_iter().filter(|x| x > 0);
+ let mut iter = array![0_u32, 1, 2].into_iter().filter(|x| *x > 0);
assert_eq!(iter.next(), Option::Some(1));
assert_eq!(iter.next(), Option::Some(2));
assert_eq!(iter.next(), Option::None);
From c8fee23fc6a25d8f23558eb6eeb5fbd959cbbb5e Mon Sep 17 00:00:00 2001
From: julio4 <30329843+julio4@users.noreply.github.com>
Date: Tue, 28 Jan 2025 10:40:05 +0100
Subject: [PATCH 3/3] fix: FilterIterator don't copy predicate closure
---
corelib/src/iter/adapters/filter.cairo | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/corelib/src/iter/adapters/filter.cairo b/corelib/src/iter/adapters/filter.cairo
index d4b578a3cb1..896fad3c8fd 100644
--- a/corelib/src/iter/adapters/filter.cairo
+++ b/corelib/src/iter/adapters/filter.cairo
@@ -15,18 +15,17 @@ pub fn filter_iterator(iter: I, predicate: P) -> Filter {
Filter { iter, predicate }
}
-pub impl FilterIterator<
+impl FilterIterator<
I,
P,
impl TIter: Iterator,
+core::ops::Fn[Output: bool],
+Destruct,
+Destruct
,
- +Copy
,
+Destruct,
> of Iterator> {
type Item = TIter::Item;
fn next(ref self: Filter) -> Option {
- self.iter.find(self.predicate)
+ self.iter.find(@self.predicate)
}
}