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) } }