Skip to content

Commit

Permalink
Merge #550
Browse files Browse the repository at this point in the history
550: Add More FusedIterator r=jswrenn a=aobatact

These Iterator is fused if the underlying Iterator is fused.
-  `FilterOk`
-  `FilterMapOk`
- `InterleaveShortest`
- `KMergeBy`
- `MergeBy`
- `PadUsing`
- `Positions`
- `Product` 
- `RcIter`
- `TupleWindows`
- `Unique`
- `UniqueBy`
-  `Update`
- `WhileSome`

These is fused even though the underlying Iterator is not fused.
- `Combinations` 
- `CombinationsWithReplacement`
- `Powerset`
- `RepeatN`
- `WithPosition` 

`FusedIterator` can be added to these structs.

Related  #55, #152, #531, #533

I separate the pull request with #548 because these Iterator are sure to be fused because it was documented, but I'm not 100% sure that the structs in this PR is actually fused. (Though I believe it is.)

Co-authored-by: aobatact <aobatact144@gmail.com>
  • Loading branch information
bors[bot] and aobatact committed Jun 8, 2021
2 parents a9e367f + f9ccc34 commit eedea19
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 4 deletions.
45 changes: 44 additions & 1 deletion src/adaptors/mod.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -157,6 +157,11 @@ impl<I, J> Iterator for InterleaveShortest<I, J>
}
}

impl<I, J> FusedIterator for InterleaveShortest<I, J>
where I: FusedIterator,
J: FusedIterator<Item = I::Item>
{}

#[derive(Clone, Debug)]
/// An iterator adaptor that allows putting back a single
/// item to the front of the iterator.
Expand Down Expand Up @@ -361,6 +366,12 @@ impl<I, J> Iterator for Product<I, J>
}
}

impl<I, J> FusedIterator for Product<I, J>
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.
///
Expand Down Expand Up @@ -588,6 +599,12 @@ impl<I, J, F> Iterator for MergeBy<I, J, F>
}
}

impl<I, J, F> FusedIterator for MergeBy<I, J, F>
where I: FusedIterator,
J: FusedIterator<Item = I::Item>,
F: MergePredicate<I::Item>
{}

/// An iterator adaptor that borrows from a `Clone`-able iterator
/// to only pick off elements while the predicate returns `true`.
///
Expand Down Expand Up @@ -711,6 +728,11 @@ impl<I, T> Iterator for TupleCombinations<I, T>
}
}

impl<I, T> FusedIterator for TupleCombinations<I, T>
where I: FusedIterator,
T: HasCombination<I>,
{}

#[derive(Clone, Debug)]
pub struct Tuple1Combination<I> {
iter: I,
Expand Down Expand Up @@ -876,6 +898,11 @@ impl<I, F, T, E> Iterator for FilterOk<I, F>
}
}

impl<I, F, T, E> FusedIterator for FilterOk<I, F>
where I: FusedIterator<Item = Result<T, E>>,
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.
Expand Down Expand Up @@ -947,6 +974,11 @@ impl<I, F, T, U, E> Iterator for FilterMapOk<I, F>
}
}

impl<I, F, T, U, E> FusedIterator for FilterMapOk<I, F>
where I: FusedIterator<Item = Result<T, E>>,
F: FnMut(T) -> Option<U>,
{}

/// An iterator adapter to get the positions of each element that matches a predicate.
///
/// See [`.positions()`](crate::Itertools::positions) for more information.
Expand Down Expand Up @@ -1006,6 +1038,11 @@ impl<I, F> DoubleEndedIterator for Positions<I, F>
}
}

impl<I, F> FusedIterator for Positions<I, F>
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.
Expand Down Expand Up @@ -1081,3 +1118,9 @@ where
}
}
}

impl<I, F> FusedIterator for Update<I, F>
where
I: FusedIterator,
F: FnMut(&mut I::Item),
{}
6 changes: 6 additions & 0 deletions src/combinations.rs
@@ -1,4 +1,5 @@
use std::fmt;
use std::iter::FusedIterator;

use super::lazy_buffer::LazyBuffer;
use alloc::vec::Vec;
Expand Down Expand Up @@ -122,3 +123,8 @@ impl<I> Iterator for Combinations<I>
Some(self.indices.iter().map(|i| self.pool[*i].clone()).collect())
}
}

impl<I> FusedIterator for Combinations<I>
where I: Iterator,
I::Item: Clone
{}
7 changes: 7 additions & 0 deletions 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;

Expand Down Expand Up @@ -100,3 +101,9 @@ where
}
}
}

impl<I> FusedIterator for CombinationsWithReplacement<I>
where
I: Iterator,
I::Item: Clone,
{}
6 changes: 6 additions & 0 deletions src/kmerge_impl.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -219,3 +220,8 @@ impl<I, F> Iterator for KMergeBy<I, F>
.unwrap_or((0, Some(0)))
}
}

impl<I, F> FusedIterator for KMergeBy<I, F>
where I: Iterator,
F: KMergePredicate<I::Item>
{}
8 changes: 7 additions & 1 deletion 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
Expand Down Expand Up @@ -81,3 +81,9 @@ impl<I, F> ExactSizeIterator for PadUsing<I, F>
where I: ExactSizeIterator,
F: FnMut(usize) -> I::Item
{}


impl<I, F> FusedIterator for PadUsing<I, F>
where I: FusedIterator,
F: FnMut(usize) -> I::Item
{}
7 changes: 7 additions & 0 deletions src/powerset.rs
@@ -1,4 +1,5 @@
use std::fmt;
use std::iter::FusedIterator;
use std::usize;
use alloc::vec::Vec;

Expand Down Expand Up @@ -81,3 +82,9 @@ impl<I> Iterator for Powerset<I>
}
}
}

impl<I> FusedIterator for Powerset<I>
where
I: Iterator,
I::Item: Clone,
{}
7 changes: 6 additions & 1 deletion 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;

Expand Down Expand Up @@ -93,3 +93,8 @@ impl<'a, I> IntoIterator for &'a RcIter<I>
self.clone()
}
}


impl<A, I> FusedIterator for RcIter<I>
where I: FusedIterator<Item = A>
{}
5 changes: 5 additions & 0 deletions src/repeatn.rs
@@ -1,3 +1,4 @@
use std::iter::FusedIterator;

/// An iterator that produces *n* repetitions of an element.
///
Expand Down Expand Up @@ -52,3 +53,7 @@ impl<A> DoubleEndedIterator for RepeatN<A>
impl<A> ExactSizeIterator for RepeatN<A>
where A: Clone
{}

impl<A> FusedIterator for RepeatN<A>
where A: Clone
{}
7 changes: 7 additions & 0 deletions 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;
Expand Down Expand Up @@ -187,6 +188,12 @@ impl<I, T> Iterator for TupleWindows<I, T>
}
}

impl<I, T> FusedIterator for TupleWindows<I, T>
where I: FusedIterator<Item = T::Item>,
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.
Expand Down
12 changes: 12 additions & 0 deletions src/unique_impl.rs
Expand Up @@ -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.
///
Expand Down Expand Up @@ -92,6 +93,12 @@ impl<I, V, F> DoubleEndedIterator for UniqueBy<I, V, F>
}
}

impl<I, V, F> FusedIterator for UniqueBy<I, V, F>
where I: FusedIterator,
V: Eq + Hash,
F: FnMut(&I::Item) -> V
{}

impl<I> Iterator for Unique<I>
where I: Iterator,
I::Item: Eq + Hash + Clone
Expand Down Expand Up @@ -136,6 +143,11 @@ impl<I> DoubleEndedIterator for Unique<I>
}
}

impl<I> FusedIterator for Unique<I>
where I: FusedIterator,
I::Item: Eq + Hash + Clone
{}

/// An iterator adapter to filter out duplicate elements.
///
/// See [`.unique()`](crate::Itertools::unique) for more information.
Expand Down
5 changes: 4 additions & 1 deletion 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`].
///
Expand Down Expand Up @@ -95,3 +95,6 @@ impl<I: Iterator> Iterator for WithPosition<I> {
impl<I> ExactSizeIterator for WithPosition<I>
where I: ExactSizeIterator,
{ }

impl<I: Iterator> FusedIterator for WithPosition<I>
{}
95 changes: 95 additions & 0 deletions tests/quick.rs
Expand Up @@ -1598,3 +1598,98 @@ quickcheck! {
TestResult::from_bool(itertools::equal(x, y))
}
}


fn is_fused<I: Iterator>(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<i16>) -> bool
{
is_fused(a.clone().combinations(1)) &&
is_fused(a.combinations(3))
}

fn fused_combination_with_replacement(a: Iter<i16>) -> bool
{
is_fused(a.clone().combinations_with_replacement(1)) &&
is_fused(a.combinations_with_replacement(3))
}

fn fused_tuple_combination(a: Iter<i16>) -> bool
{
is_fused(a.clone().fuse().tuple_combinations::<(_,)>()) &&
is_fused(a.fuse().tuple_combinations::<(_,_,_)>())
}

fn fused_unique(a: Iter<i16>) -> bool
{
is_fused(a.fuse().unique())
}

fn fused_unique_by(a: Iter<i16>) -> bool
{
is_fused(a.fuse().unique_by(|x| x % 100))
}

fn fused_interleave_shortest(a: Iter<i16>, b: Iter<i16>) -> bool
{
!is_fused(a.clone().interleave_shortest(b.clone())) &&
is_fused(a.fuse().interleave_shortest(b.fuse()))
}

fn fused_product(a: Iter<i16>, b: Iter<i16>) -> bool
{
is_fused(a.fuse().cartesian_product(b.fuse()))
}

fn fused_merge(a: Iter<i16>, b: Iter<i16>) -> bool
{
is_fused(a.fuse().merge(b.fuse()))
}

fn fused_filter_ok(a: Iter<i16>) -> 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<i16>) -> 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<i16>) -> bool
{
!is_fused(a.clone().positions(|x|x%2==0)) &&
is_fused(a.fuse().positions(|x|x%2==0))
}

fn fused_update(a: Iter<i16>) -> bool
{
!is_fused(a.clone().update(|x|*x+=1)) &&
is_fused(a.fuse().update(|x|*x+=1))
}

fn fused_tuple_windows(a: Iter<i16>) -> bool
{
is_fused(a.fuse().tuple_windows::<(_,_)>())
}

fn fused_pad_using(a: Iter<i16>) -> bool
{
is_fused(a.fuse().pad_using(100,|_|0))
}
}

0 comments on commit eedea19

Please sign in to comment.