From ccc5081c3267130c7b736711bd917edd38eb2d8b Mon Sep 17 00:00:00 2001 From: aobatact Date: Wed, 26 May 2021 13:10:46 +0900 Subject: [PATCH 1/2] Add more FusedIterator Some Iterator is fused if the underlying Iterator is fused. (UniqueBy, Unique, InterleaveShortest, Product, MergeBy, FilterOk, FilterMapOk, Positions, Update) Combinations is fused. --- src/adaptors/mod.rs | 40 ++++++++++++++++++++++++- src/combinations.rs | 6 ++++ src/unique_impl.rs | 12 ++++++++ tests/quick.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index dfc68978f..23a41f0cb 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -15,7 +15,7 @@ pub use self::map::MapResults; pub use self::multi_product::*; use std::fmt; -use std::iter::{Fuse, Peekable, FromIterator}; +use std::iter::{Fuse, Peekable, FromIterator, FusedIterator}; use std::marker::PhantomData; use crate::size_hint; @@ -157,6 +157,11 @@ impl Iterator for InterleaveShortest } } +impl FusedIterator for InterleaveShortest + where I: FusedIterator, + J: FusedIterator +{} + #[derive(Clone, Debug)] /// An iterator adaptor that allows putting back a single /// item to the front of the iterator. @@ -361,6 +366,12 @@ impl Iterator for Product } } +impl FusedIterator for Product + where I: FusedIterator, + J: Clone + FusedIterator, + I::Item: Clone +{} + /// A “meta iterator adaptor”. Its closure receives a reference to the iterator /// and may pick off as many elements as it likes, to produce the next iterator element. /// @@ -588,6 +599,12 @@ impl Iterator for MergeBy } } +impl FusedIterator for MergeBy + where I: FusedIterator, + J: FusedIterator, + F: MergePredicate +{} + /// An iterator adaptor that borrows from a `Clone`-able iterator /// to only pick off elements while the predicate returns `true`. /// @@ -876,6 +893,11 @@ impl Iterator for FilterOk } } +impl FusedIterator for FilterOk + where I: FusedIterator>, + F: FnMut(&T) -> bool, +{} + /// An iterator adapter to filter and apply a transformation on values within a nested `Result::Ok`. /// /// See [`.filter_map_ok()`](crate::Itertools::filter_map_ok) for more information. @@ -947,6 +969,11 @@ impl Iterator for FilterMapOk } } +impl FusedIterator for FilterMapOk + where I: FusedIterator>, + F: FnMut(T) -> Option, +{} + /// An iterator adapter to get the positions of each element that matches a predicate. /// /// See [`.positions()`](crate::Itertools::positions) for more information. @@ -1006,6 +1033,11 @@ impl DoubleEndedIterator for Positions } } +impl FusedIterator for Positions + where I: FusedIterator, + F: FnMut(I::Item) -> bool, +{} + /// An iterator adapter to apply a mutating function to each element before yielding it. /// /// See [`.update()`](crate::Itertools::update) for more information. @@ -1081,3 +1113,9 @@ where } } } + +impl FusedIterator for Update +where + I: FusedIterator, + F: FnMut(&mut I::Item), +{} diff --git a/src/combinations.rs b/src/combinations.rs index 1ed04087b..a9a4041ce 100644 --- a/src/combinations.rs +++ b/src/combinations.rs @@ -1,4 +1,5 @@ use std::fmt; +use std::iter::FusedIterator; use super::lazy_buffer::LazyBuffer; use alloc::vec::Vec; @@ -122,3 +123,8 @@ impl Iterator for Combinations Some(self.indices.iter().map(|i| self.pool[*i].clone()).collect()) } } + +impl FusedIterator for Combinations + where I: Iterator, + I::Item: Clone +{} diff --git a/src/unique_impl.rs b/src/unique_impl.rs index 7073e8e2c..2240f36ed 100644 --- a/src/unique_impl.rs +++ b/src/unique_impl.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use std::collections::hash_map::{Entry}; use std::hash::Hash; use std::fmt; +use std::iter::FusedIterator; /// An iterator adapter to filter out duplicate elements. /// @@ -92,6 +93,12 @@ impl DoubleEndedIterator for UniqueBy } } +impl FusedIterator for UniqueBy + where I: FusedIterator, + V: Eq + Hash, + F: FnMut(&I::Item) -> V +{} + impl Iterator for Unique where I: Iterator, I::Item: Eq + Hash + Clone @@ -136,6 +143,11 @@ impl DoubleEndedIterator for Unique } } +impl FusedIterator for Unique + where I: FusedIterator, + I::Item: Eq + Hash + Clone +{} + /// An iterator adapter to filter out duplicate elements. /// /// See [`.unique()`](crate::Itertools::unique) for more information. diff --git a/tests/quick.rs b/tests/quick.rs index 7769cb432..0ea51ece1 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -1598,3 +1598,76 @@ quickcheck! { TestResult::from_bool(itertools::equal(x, y)) } } + + +fn is_fused(mut it: I) -> bool +{ + while let Some(_) = it.next() {} + for _ in 0..10{ + if it.next().is_some(){ + return false; + } + } + true +} + +quickcheck! { + fn fused_combination(a: Iter) -> bool + { + is_fused(a.clone().combinations(1)) && + is_fused(a.combinations(3)) + } + + fn fused_unique(a: Iter) -> bool + { + is_fused(a.fuse().unique()) + } + + fn fused_unique_by(a: Iter) -> bool + { + is_fused(a.fuse().unique_by(|x| x % 100)) + } + + fn fused_interleave_shortest(a: Iter, b: Iter) -> bool + { + !is_fused(a.clone().interleave_shortest(b.clone())) && + is_fused(a.fuse().interleave_shortest(b.fuse())) + } + + fn fused_product(a: Iter, b: Iter) -> bool + { + is_fused(a.fuse().cartesian_product(b.fuse())) + } + + fn fused_merge(a: Iter, b: Iter) -> bool + { + is_fused(a.fuse().merge(b.fuse())) + } + + fn fused_filter_ok(a: Iter) -> bool + { + is_fused(a.map(|x| if x % 2 == 0 {Ok(x)} else {Err(x)} ) + .filter_ok(|x| x % 3 == 0) + .fuse()) + } + + fn fused_filter_map_ok(a: Iter) -> bool + { + is_fused(a.map(|x| if x % 2 == 0 {Ok(x)} else {Err(x)} ) + .filter_map_ok(|x| if x % 3 == 0 {Some(x / 3)} else {None}) + .fuse()) + } + + fn fused_positions(a: Iter) -> bool + { + !is_fused(a.clone().positions(|x|x%2==0)) && + is_fused(a.fuse().positions(|x|x%2==0)) + } + + fn fused_update(a: Iter) -> bool + { + !is_fused(a.clone().update(|x|*x+=1)) && + is_fused(a.fuse().update(|x|*x+=1)) + } +} + From f9ccc345d1001d0c47515dec3067206e096f7f33 Mon Sep 17 00:00:00 2001 From: aobatact Date: Wed, 26 May 2021 15:38:02 +0900 Subject: [PATCH 2/2] Add more FusedIterator Mark FusedIterator to WhileSome, RcIter, PadUsing, TupleWindows, TupleCombinations, RepeatN, Powerset, CombinationsWithReplacement, WithPosition, KMergeBy --- src/adaptors/mod.rs | 5 +++++ src/combinations_with_replacement.rs | 7 +++++++ src/kmerge_impl.rs | 6 ++++++ src/pad_tail.rs | 8 +++++++- src/powerset.rs | 7 +++++++ src/rciter_impl.rs | 7 ++++++- src/repeatn.rs | 5 +++++ src/tuple_impl.rs | 7 +++++++ src/with_position.rs | 5 ++++- tests/quick.rs | 22 ++++++++++++++++++++++ 10 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 23a41f0cb..c3edc6487 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -728,6 +728,11 @@ impl Iterator for TupleCombinations } } +impl FusedIterator for TupleCombinations + where I: FusedIterator, + T: HasCombination, +{} + #[derive(Clone, Debug)] pub struct Tuple1Combination { iter: I, diff --git a/src/combinations_with_replacement.rs b/src/combinations_with_replacement.rs index 1f1bcf5b2..81b13f130 100644 --- a/src/combinations_with_replacement.rs +++ b/src/combinations_with_replacement.rs @@ -1,5 +1,6 @@ use alloc::vec::Vec; use std::fmt; +use std::iter::FusedIterator; use super::lazy_buffer::LazyBuffer; @@ -100,3 +101,9 @@ where } } } + +impl FusedIterator for CombinationsWithReplacement +where + I: Iterator, + I::Item: Clone, +{} diff --git a/src/kmerge_impl.rs b/src/kmerge_impl.rs index 36bfc5a8a..dce5b782c 100644 --- a/src/kmerge_impl.rs +++ b/src/kmerge_impl.rs @@ -2,6 +2,7 @@ use crate::size_hint; use crate::Itertools; use alloc::vec::Vec; +use std::iter::FusedIterator; use std::mem::replace; use std::fmt; @@ -219,3 +220,8 @@ impl Iterator for KMergeBy .unwrap_or((0, Some(0))) } } + +impl FusedIterator for KMergeBy + where I: Iterator, + F: KMergePredicate +{} diff --git a/src/pad_tail.rs b/src/pad_tail.rs index 18e666bad..03867cbf0 100644 --- a/src/pad_tail.rs +++ b/src/pad_tail.rs @@ -1,4 +1,4 @@ -use std::iter::Fuse; +use std::iter::{Fuse, FusedIterator}; use crate::size_hint; /// An iterator adaptor that pads a sequence to a minimum length by filling @@ -81,3 +81,9 @@ impl ExactSizeIterator for PadUsing where I: ExactSizeIterator, F: FnMut(usize) -> I::Item {} + + +impl FusedIterator for PadUsing + where I: FusedIterator, + F: FnMut(usize) -> I::Item +{} diff --git a/src/powerset.rs b/src/powerset.rs index ef17752b3..f50d860a2 100644 --- a/src/powerset.rs +++ b/src/powerset.rs @@ -1,4 +1,5 @@ use std::fmt; +use std::iter::FusedIterator; use std::usize; use alloc::vec::Vec; @@ -81,3 +82,9 @@ impl Iterator for Powerset } } } + +impl FusedIterator for Powerset + where + I: Iterator, + I::Item: Clone, +{} diff --git a/src/rciter_impl.rs b/src/rciter_impl.rs index 9122dadc9..782908e28 100644 --- a/src/rciter_impl.rs +++ b/src/rciter_impl.rs @@ -1,5 +1,5 @@ -use std::iter::IntoIterator; +use std::iter::{FusedIterator, IntoIterator}; use alloc::rc::Rc; use std::cell::RefCell; @@ -93,3 +93,8 @@ impl<'a, I> IntoIterator for &'a RcIter self.clone() } } + + +impl FusedIterator for RcIter + where I: FusedIterator +{} diff --git a/src/repeatn.rs b/src/repeatn.rs index 8bc485083..94a02651b 100644 --- a/src/repeatn.rs +++ b/src/repeatn.rs @@ -1,3 +1,4 @@ +use std::iter::FusedIterator; /// An iterator that produces *n* repetitions of an element. /// @@ -52,3 +53,7 @@ impl DoubleEndedIterator for RepeatN impl ExactSizeIterator for RepeatN where A: Clone {} + +impl FusedIterator for RepeatN + where A: Clone +{} diff --git a/src/tuple_impl.rs b/src/tuple_impl.rs index 82ecd8632..ca8b97c6a 100644 --- a/src/tuple_impl.rs +++ b/src/tuple_impl.rs @@ -1,6 +1,7 @@ //! Some iterator that produces tuples use std::iter::Fuse; +use std::iter::FusedIterator; use std::iter::Take; use std::iter::Cycle; use std::marker::PhantomData; @@ -187,6 +188,12 @@ impl Iterator for TupleWindows } } +impl FusedIterator for TupleWindows + where I: FusedIterator, + T: HomogeneousTuple + Clone, + T::Item: Clone +{} + /// An iterator over all windows,wrapping back to the first elements when the /// window would otherwise exceed the length of the iterator, producing tuples /// of a specific size. diff --git a/src/with_position.rs b/src/with_position.rs index c53b652c6..1388503d1 100644 --- a/src/with_position.rs +++ b/src/with_position.rs @@ -1,4 +1,4 @@ -use std::iter::{Fuse,Peekable}; +use std::iter::{Fuse,Peekable, FusedIterator}; /// An iterator adaptor that wraps each element in an [`Position`]. /// @@ -95,3 +95,6 @@ impl Iterator for WithPosition { impl ExactSizeIterator for WithPosition where I: ExactSizeIterator, { } + +impl FusedIterator for WithPosition +{} diff --git a/tests/quick.rs b/tests/quick.rs index 0ea51ece1..7e222a641 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -1618,6 +1618,18 @@ quickcheck! { is_fused(a.combinations(3)) } + fn fused_combination_with_replacement(a: Iter) -> bool + { + is_fused(a.clone().combinations_with_replacement(1)) && + is_fused(a.combinations_with_replacement(3)) + } + + fn fused_tuple_combination(a: Iter) -> bool + { + is_fused(a.clone().fuse().tuple_combinations::<(_,)>()) && + is_fused(a.fuse().tuple_combinations::<(_,_,_)>()) + } + fn fused_unique(a: Iter) -> bool { is_fused(a.fuse().unique()) @@ -1669,5 +1681,15 @@ quickcheck! { !is_fused(a.clone().update(|x|*x+=1)) && is_fused(a.fuse().update(|x|*x+=1)) } + + fn fused_tuple_windows(a: Iter) -> bool + { + is_fused(a.fuse().tuple_windows::<(_,_)>()) + } + + fn fused_pad_using(a: Iter) -> bool + { + is_fused(a.fuse().pad_using(100,|_|0)) + } }