From 36c9eadbeb7d5a205cd41268b5cd95429dec32a8 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Mon, 12 Dec 2022 13:40:25 +0100 Subject: Upgrade itertools to 0.10.5 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update rust/crates/itertools For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md Test: TreeHugger Change-Id: I04ecd1d5827d6d1822997f324e6bac8e8bd8ea83 --- src/adaptors/coalesce.rs | 4 +- src/adaptors/mod.rs | 14 +-- src/adaptors/multi_product.rs | 4 +- src/combinations_with_replacement.rs | 4 +- src/concat_impl.rs | 3 +- src/duplicates_impl.rs | 1 - src/either_or_both.rs | 49 ++++++++ src/exactly_one_err.rs | 4 +- src/extrema_set.rs | 48 ++++++++ src/flatten_ok.rs | 33 +++-- src/free.rs | 26 ++-- src/groupbylazy.rs | 12 +- src/grouping_map.rs | 7 +- src/impl_macros.rs | 1 + src/intersperse.rs | 5 +- src/kmerge_impl.rs | 8 +- src/lazy_buffer.rs | 20 ++- src/lib.rs | 230 +++++++++++++++++++++++++++++++---- src/merge_join.rs | 4 +- src/multipeek_impl.rs | 10 +- src/pad_tail.rs | 2 +- src/peeking_take_while.rs | 2 +- src/permutations.rs | 7 +- src/rciter_impl.rs | 1 - src/size_hint.rs | 16 +-- src/tuple_impl.rs | 2 +- src/unique_impl.rs | 7 +- src/unziptuple.rs | 8 +- src/ziptuple.rs | 1 + 29 files changed, 401 insertions(+), 132 deletions(-) create mode 100644 src/extrema_set.rs (limited to 'src') diff --git a/src/adaptors/coalesce.rs b/src/adaptors/coalesce.rs index b1aff6e..3df7cc5 100644 --- a/src/adaptors/coalesce.rs +++ b/src/adaptors/coalesce.rs @@ -3,6 +3,7 @@ use std::iter::FusedIterator; use crate::size_hint; +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct CoalesceBy where I: Iterator, @@ -86,7 +87,6 @@ impl, T> FusedIterator for Coalesc /// An iterator adaptor that may join together adjacent elements. /// /// See [`.coalesce()`](crate::Itertools::coalesce) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub type Coalesce = CoalesceBy::Item>; impl CoalescePredicate for F @@ -113,7 +113,6 @@ where /// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function. /// /// See [`.dedup_by()`](crate::Itertools::dedup_by) or [`.dedup()`](crate::Itertools::dedup) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub type DedupBy = CoalesceBy, ::Item>; #[derive(Clone)] @@ -186,7 +185,6 @@ where /// /// See [`.dedup_by_with_count()`](crate::Itertools::dedup_by_with_count) or /// [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub type DedupByWithCount = CoalesceBy, (usize, ::Item)>; diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 2010f53..1695bbd 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -35,9 +35,7 @@ pub struct Interleave { /// Create an iterator that interleaves elements in `i` and `j`. /// -/// [`IntoIterator`] enabled version of `i.interleave(j)`. -/// -/// See [`.interleave()`](crate::Itertools::interleave) for more information. +/// [`IntoIterator`] enabled version of `[Itertools::interleave]`. pub fn interleave(i: I, j: J) -> Interleave<::IntoIter, ::IntoIter> where I: IntoIterator, J: IntoIterator @@ -210,7 +208,7 @@ impl PutBack /// If a value is already in the put back slot, it is overwritten. #[inline] pub fn put_back(&mut self, x: I::Item) { - self.top = Some(x) + self.top = Some(x); } } @@ -329,12 +327,7 @@ impl Iterator for Product } Some(x) => x }; - match self.a_cur { - None => None, - Some(ref a) => { - Some((a.clone(), elt_b)) - } - } + self.a_cur.as_ref().map(|a| (a.clone(), elt_b)) } fn size_hint(&self) -> (usize, Option) { @@ -492,7 +485,6 @@ impl MergePredicate for MergeLte { /// Iterator element type is `I::Item`. /// /// See [`.merge()`](crate::Itertools::merge_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub type Merge = MergeBy; /// Create an iterator that merges elements in `i` and `j`. diff --git a/src/adaptors/multi_product.rs b/src/adaptors/multi_product.rs index 30650ed..0b38406 100644 --- a/src/adaptors/multi_product.rs +++ b/src/adaptors/multi_product.rs @@ -40,7 +40,7 @@ pub fn multi_cartesian_product(iters: H) -> MultiProduct< where I: Iterator + Clone, I::Item: Clone @@ -50,7 +50,7 @@ struct MultiProductIter iter_orig: I, } -/// Holds the current state during an iteration of a MultiProduct. +/// Holds the current state during an iteration of a `MultiProduct`. #[derive(Debug)] enum MultiProductIterState { StartOfIter, diff --git a/src/combinations_with_replacement.rs b/src/combinations_with_replacement.rs index 81b13f1..0fec967 100644 --- a/src/combinations_with_replacement.rs +++ b/src/combinations_with_replacement.rs @@ -64,7 +64,7 @@ where // If this is the first iteration, return early if self.first { // In empty edge cases, stop iterating immediately - return if self.indices.len() != 0 && !self.pool.get_next() { + return if !(self.indices.is_empty() || self.pool.get_next()) { None // Otherwise, yield the initial state } else { @@ -92,7 +92,7 @@ where // We need to update the rightmost non-max value // and all those to the right for indices_index in increment_from..self.indices.len() { - self.indices[indices_index] = increment_value + self.indices[indices_index] = increment_value; } Some(self.current()) } diff --git a/src/concat_impl.rs b/src/concat_impl.rs index 450f7fc..f022ec9 100644 --- a/src/concat_impl.rs +++ b/src/concat_impl.rs @@ -18,5 +18,6 @@ pub fn concat(iterable: I) -> I::Item where I: IntoIterator, I::Item: Extend<<::Item as IntoIterator>::Item> + IntoIterator + Default { - iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_else(<_>::default) + #[allow(deprecated)] //TODO: once msrv hits 1.51. replace `fold1` with `reduce` + iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_default() } diff --git a/src/duplicates_impl.rs b/src/duplicates_impl.rs index 640d481..28eda44 100644 --- a/src/duplicates_impl.rs +++ b/src/duplicates_impl.rs @@ -188,7 +188,6 @@ mod private { /// An iterator adapter to filter for duplicate elements. /// /// See [`.duplicates_by()`](crate::Itertools::duplicates_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub type DuplicatesBy = private::DuplicatesBy>; /// Create a new `DuplicatesBy` iterator. diff --git a/src/either_or_both.rs b/src/either_or_both.rs index 28d1df7..ef3985f 100644 --- a/src/either_or_both.rs +++ b/src/either_or_both.rs @@ -164,6 +164,33 @@ impl EitherOrBoth { } } + /// Returns a tuple consisting of the `l` and `r` in `Both(l, r)`, if present. + /// Otherwise, returns the wrapped value for the present element, and the supplied + /// value for the other. The first (`l`) argument is used for a missing `Left` + /// value. The second (`r`) argument is used for a missing `Right` value. + /// + /// Arguments passed to `or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use [`or_else`], + /// which is lazily evaluated. + /// + /// [`or_else`]: EitherOrBoth::or_else + /// + /// # Examples + /// + /// ``` + /// # use itertools::EitherOrBoth; + /// assert_eq!(EitherOrBoth::Both("tree", 1).or("stone", 5), ("tree", 1)); + /// assert_eq!(EitherOrBoth::Left("tree").or("stone", 5), ("tree", 5)); + /// assert_eq!(EitherOrBoth::Right(1).or("stone", 5), ("stone", 1)); + /// ``` + pub fn or(self, l: A, r: B) -> (A, B) { + match self { + Left(inner_l) => (inner_l, r), + Right(inner_r) => (l, inner_r), + Both(inner_l, inner_r) => (inner_l, inner_r), + } + } + /// Returns a tuple consisting of the `l` and `r` in `Both(l, r)`, if present. /// Otherwise, returns the wrapped value for the present element, and the [`default`](Default::default) /// for the other. @@ -178,6 +205,28 @@ impl EitherOrBoth { EitherOrBoth::Both(l, r) => (l, r), } } + + /// Returns a tuple consisting of the `l` and `r` in `Both(l, r)`, if present. + /// Otherwise, returns the wrapped value for the present element, and computes the + /// missing value with the supplied closure. The first argument (`l`) is used for a + /// missing `Left` value. The second argument (`r`) is used for a missing `Right` value. + /// + /// # Examples + /// + /// ``` + /// # use itertools::EitherOrBoth; + /// let k = 10; + /// assert_eq!(EitherOrBoth::Both("tree", 1).or_else(|| "stone", || 2 * k), ("tree", 1)); + /// assert_eq!(EitherOrBoth::Left("tree").or_else(|| "stone", || 2 * k), ("tree", 20)); + /// assert_eq!(EitherOrBoth::Right(1).or_else(|| "stone", || 2 * k), ("stone", 1)); + /// ``` + pub fn or_else A, R: FnOnce() -> B>(self, l: L, r: R) -> (A, B) { + match self { + Left(inner_l) => (inner_l, r()), + Right(inner_r) => (l(), inner_r), + Both(inner_l, inner_r) => (inner_l, inner_r), + } + } } impl EitherOrBoth { diff --git a/src/exactly_one_err.rs b/src/exactly_one_err.rs index 63485c9..c54ae77 100644 --- a/src/exactly_one_err.rs +++ b/src/exactly_one_err.rs @@ -11,10 +11,10 @@ use crate::size_hint; /// Iterator returned for the error case of `IterTools::exactly_one()` /// This iterator yields exactly the same elements as the input iterator. /// -/// During the execution of exactly_one the iterator must be mutated. This wrapper +/// During the execution of `exactly_one` the iterator must be mutated. This wrapper /// effectively "restores" the state of the input iterator when it's handed back. /// -/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not +/// This is very similar to `PutBackN` except this iterator only supports 0-2 elements and does not /// use a `Vec`. #[derive(Clone)] pub struct ExactlyOneError diff --git a/src/extrema_set.rs b/src/extrema_set.rs new file mode 100644 index 0000000..ae12836 --- /dev/null +++ b/src/extrema_set.rs @@ -0,0 +1,48 @@ +use std::cmp::Ordering; + +/// Implementation guts for `min_set`, `min_set_by`, and `min_set_by_key`. +pub fn min_set_impl( + mut it: I, + mut key_for: F, + mut compare: Compare, +) -> Vec +where + I: Iterator, + F: FnMut(&I::Item) -> K, + Compare: FnMut(&I::Item, &I::Item, &K, &K) -> Ordering, +{ + match it.next() { + None => Vec::new(), + Some(element) => { + let mut current_key = key_for(&element); + let mut result = vec![element]; + it.for_each(|element| { + let key = key_for(&element); + match compare(&element, &result[0], &key, ¤t_key) { + Ordering::Less => { + result.clear(); + result.push(element); + current_key = key; + } + Ordering::Equal => { + result.push(element); + } + Ordering::Greater => {} + } + }); + result + } + } +} + +/// Implementation guts for `ax_set`, `max_set_by`, and `max_set_by_key`. +pub fn max_set_impl(it: I, key_for: F, mut compare: Compare) -> Vec +where + I: Iterator, + F: FnMut(&I::Item) -> K, + Compare: FnMut(&I::Item, &I::Item, &K, &K) -> Ordering, +{ + min_set_impl(it, key_for, |it1, it2, key1, key2| { + compare(it2, it1, key2, key1) + }) +} diff --git a/src/flatten_ok.rs b/src/flatten_ok.rs index d46bbde..21ae1f7 100644 --- a/src/flatten_ok.rs +++ b/src/flatten_ok.rs @@ -44,11 +44,11 @@ where if let Some(inner) = &mut self.inner_front { if let Some(item) = inner.next() { return Some(Ok(item)); - } else { - // This is necessary for the iterator to implement `FusedIterator` - // with only the orginal iterator being fused. - self.inner_front = None; } + + // This is necessary for the iterator to implement `FusedIterator` + // with only the original iterator being fused. + self.inner_front = None; } match self.iter.next() { @@ -59,11 +59,11 @@ where if let Some(inner) = &mut self.inner_back { if let Some(item) = inner.next() { return Some(Ok(item)); - } else { - // This is necessary for the iterator to implement `FusedIterator` - // with only the orginal iterator being fused. - self.inner_back = None; } + + // This is necessary for the iterator to implement `FusedIterator` + // with only the original iterator being fused. + self.inner_back = None; } else { return None; } @@ -103,11 +103,11 @@ where if let Some(inner) = &mut self.inner_back { if let Some(item) = inner.next_back() { return Some(Ok(item)); - } else { - // This is necessary for the iterator to implement `FusedIterator` - // with only the orginal iterator being fused. - self.inner_back = None; } + + // This is necessary for the iterator to implement `FusedIterator` + // with only the original iterator being fused. + self.inner_back = None; } match self.iter.next_back() { @@ -118,11 +118,11 @@ where if let Some(inner) = &mut self.inner_front { if let Some(item) = inner.next_back() { return Some(Ok(item)); - } else { - // This is necessary for the iterator to implement `FusedIterator` - // with only the orginal iterator being fused. - self.inner_front = None; } + + // This is necessary for the iterator to implement `FusedIterator` + // with only the original iterator being fused. + self.inner_front = None; } else { return None; } @@ -138,7 +138,6 @@ where T: IntoIterator, T::IntoIter: Clone, { - #[inline] clone_fields!(iter, inner_front, inner_back); } diff --git a/src/free.rs b/src/free.rs index 6674030..19e3e28 100644 --- a/src/free.rs +++ b/src/free.rs @@ -105,18 +105,23 @@ pub fn rev(iterable: I) -> iter::Rev iterable.into_iter().rev() } -/// Iterate `i` and `j` in lock step. +/// Converts the arguments to iterators and zips them. /// /// [`IntoIterator`] enabled version of [`Iterator::zip`]. +/// +/// ## Example /// /// ``` /// use itertools::zip; /// -/// let data = [1, 2, 3, 4, 5]; -/// for (a, b) in zip(&data, &data[1..]) { -/// /* loop body */ +/// let mut result: Vec<(i32, char)> = Vec::new(); +/// +/// for (a, b) in zip(&[1, 2, 3, 4, 5], &['a', 'b', 'c']) { +/// result.push((*a, *b)); /// } +/// assert_eq!(result, vec![(1, 'a'),(2, 'b'),(3, 'c')]); /// ``` +#[deprecated(note="Use [std::iter::zip](https://doc.rust-lang.org/std/iter/fn.zip.html) instead", since="0.10.4")] pub fn zip(i: I, j: J) -> Zip where I: IntoIterator, J: IntoIterator @@ -124,16 +129,21 @@ pub fn zip(i: I, j: J) -> Zip i.into_iter().zip(j) } -/// Create an iterator that first iterates `i` and then `j`. + +/// Takes two iterables and creates a new iterator over both in sequence. /// /// [`IntoIterator`] enabled version of [`Iterator::chain`]. /// +/// ## Example /// ``` /// use itertools::chain; +/// +/// let mut result:Vec = Vec::new(); /// -/// for elt in chain(&[1, 2, 3], &[4]) { -/// /* loop body */ +/// for element in chain(&[1, 2, 3], &[4]) { +/// result.push(*element); /// } +/// assert_eq!(result, vec![1, 2, 3, 4]); /// ``` pub fn chain(i: I, j: J) -> iter::Chain<::IntoIter, ::IntoIter> where I: IntoIterator, @@ -239,7 +249,7 @@ pub fn min(iterable: I) -> Option } -/// Combine all iterator elements into one String, seperated by `sep`. +/// Combine all iterator elements into one String, separated by `sep`. /// /// [`IntoIterator`] enabled version of [`Itertools::join`]. /// diff --git a/src/groupbylazy.rs b/src/groupbylazy.rs index 91c52ea..a5a321d 100644 --- a/src/groupbylazy.rs +++ b/src/groupbylazy.rs @@ -1,13 +1,13 @@ use std::cell::{Cell, RefCell}; use alloc::vec::{self, Vec}; -/// A trait to unify FnMut for GroupBy with the chunk key in IntoChunks +/// A trait to unify `FnMut` for `GroupBy` with the chunk key in `IntoChunks` trait KeyFunction { type Key; fn call_mut(&mut self, arg: A) -> Self::Key; } -impl<'a, A, K, F: ?Sized> KeyFunction for F +impl KeyFunction for F where F: FnMut(A) -> K { type Key = K; @@ -18,7 +18,7 @@ impl<'a, A, K, F: ?Sized> KeyFunction for F } -/// ChunkIndex acts like the grouping key function for IntoChunks +/// `ChunkIndex` acts like the grouping key function for `IntoChunks` #[derive(Debug)] struct ChunkIndex { size: usize, @@ -37,7 +37,7 @@ impl ChunkIndex { } } -impl<'a, A> KeyFunction for ChunkIndex { +impl KeyFunction for ChunkIndex { type Key = usize; #[inline(always)] fn call_mut(&mut self, _arg: A) -> Self::Key { @@ -330,7 +330,7 @@ impl GroupBy /// `client`: Index of group fn drop_group(&self, client: usize) { - self.inner.borrow_mut().drop_group(client) + self.inner.borrow_mut().drop_group(client); } } @@ -482,7 +482,7 @@ impl IntoChunks /// `client`: Index of chunk fn drop_group(&self, client: usize) { - self.inner.borrow_mut().drop_group(client) + self.inner.borrow_mut().drop_group(client); } } diff --git a/src/grouping_map.rs b/src/grouping_map.rs index be22ec8..bb5b582 100644 --- a/src/grouping_map.rs +++ b/src/grouping_map.rs @@ -39,7 +39,6 @@ pub fn new(iter: I) -> GroupingMap /// `GroupingMapBy` is an intermediate struct for efficient group-and-fold operations. /// /// See [`GroupingMap`] for more informations. -#[must_use = "GroupingMapBy is lazy and do nothing unless consumed"] pub type GroupingMapBy = GroupingMap>; /// `GroupingMap` is an intermediate struct for efficient group-and-fold operations. @@ -290,7 +289,7 @@ impl GroupingMap where F: FnMut(&K, &V) -> CK, CK: Ord, { - self.max_by(|key, v1, v2| f(key, &v1).cmp(&f(key, &v2))) + self.max_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2))) } /// Groups elements from the `GroupingMap` source by key and finds the minimum of each group. @@ -368,7 +367,7 @@ impl GroupingMap where F: FnMut(&K, &V) -> CK, CK: Ord, { - self.min_by(|key, v1, v2| f(key, &v1).cmp(&f(key, &v2))) + self.min_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2))) } /// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of @@ -481,7 +480,7 @@ impl GroupingMap where F: FnMut(&K, &V) -> CK, CK: Ord, { - self.minmax_by(|key, v1, v2| f(key, &v1).cmp(&f(key, &v2))) + self.minmax_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2))) } /// Groups elements from the `GroupingMap` source by key and sums them. diff --git a/src/impl_macros.rs b/src/impl_macros.rs index 5772bae..a029843 100644 --- a/src/impl_macros.rs +++ b/src/impl_macros.rs @@ -15,6 +15,7 @@ macro_rules! debug_fmt_fields { macro_rules! clone_fields { ($($field:ident),*) => { + #[inline] // TODO is this sensible? fn clone(&self) -> Self { Self { $($field: self.$field.clone(),)* diff --git a/src/intersperse.rs b/src/intersperse.rs index 2c660d4..10a3a53 100644 --- a/src/intersperse.rs +++ b/src/intersperse.rs @@ -55,7 +55,7 @@ pub struct IntersperseWith peek: Option, } -/// Create a new IntersperseWith iterator +/// Create a new `IntersperseWith` iterator pub fn intersperse_with(iter: I, elt: ElemF) -> IntersperseWith where I: Iterator, { @@ -107,8 +107,7 @@ impl Iterator for IntersperseWith self.iter.fold(accum, |accum, x| { let accum = f(accum, element.generate()); - let accum = f(accum, x); - accum + f(accum, x) }) } } diff --git a/src/kmerge_impl.rs b/src/kmerge_impl.rs index bd56b03..509d5fc 100644 --- a/src/kmerge_impl.rs +++ b/src/kmerge_impl.rs @@ -80,7 +80,7 @@ fn sift_down(heap: &mut [T], index: usize, mut less_than: S) // that wouldn't be predicted if present while child + 1 < heap.len() { // pick the smaller of the two children - // use aritmethic to avoid an unpredictable branch + // use arithmetic to avoid an unpredictable branch child += less_than(&heap[child+1], &heap[child]) as usize; // sift down is done if we are already in order @@ -104,7 +104,6 @@ fn sift_down(heap: &mut [T], index: usize, mut less_than: S) /// Iterator element type is `I::Item`. /// /// See [`.kmerge()`](crate::Itertools::kmerge) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub type KMerge = KMergeBy; pub trait KMergePredicate { @@ -129,7 +128,7 @@ implbool> KMergePredicate for F { /// Create an iterator that merges elements of the contained iterators using /// the ordering function. /// -/// Equivalent to `iterable.into_iter().kmerge()`. +/// [`IntoIterator`] enabled version of [`Itertools::kmerge`]. /// /// ``` /// use itertools::kmerge; @@ -170,7 +169,7 @@ impl fmt::Debug for KMergeBy /// Create an iterator that merges elements of the contained iterators. /// -/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`. +/// [`IntoIterator`] enabled version of [`Itertools::kmerge_by`]. pub fn kmerge_by(iterable: I, mut less_than: F) -> KMergeBy<::IntoIter, F> where I: IntoIterator, @@ -214,6 +213,7 @@ impl Iterator for KMergeBy } fn size_hint(&self) -> (usize, Option) { + #[allow(deprecated)] //TODO: once msrv hits 1.51. replace `fold1` with `reduce` self.heap.iter() .map(|i| i.size_hint()) .fold1(size_hint::add) diff --git a/src/lazy_buffer.rs b/src/lazy_buffer.rs index fa514ec..ca24062 100644 --- a/src/lazy_buffer.rs +++ b/src/lazy_buffer.rs @@ -28,16 +28,12 @@ where if self.done { return false; } - let next_item = self.it.next(); - match next_item { - Some(x) => { - self.buffer.push(x); - true - } - None => { - self.done = true; - false - } + if let Some(x) = self.it.next() { + self.buffer.push(x); + true + } else { + self.done = true; + false } } @@ -61,7 +57,7 @@ where { type Output = as Index>::Output; - fn index(&self, _index: J) -> &Self::Output { - self.buffer.index(_index) + fn index(&self, index: J) -> &Self::Output { + self.buffer.index(index) } } diff --git a/src/lib.rs b/src/lib.rs index df95e19..f919688 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -197,6 +197,8 @@ mod combinations_with_replacement; mod exactly_one_err; mod diff; mod flatten_ok; +#[cfg(feature = "use_std")] +mod extrema_set; mod format; #[cfg(feature = "use_std")] mod grouping_map; @@ -387,7 +389,7 @@ macro_rules! izip { /// let with_macro: Chain, Take>>, slice::Iter<_>> = /// chain![once(&0), repeat(&1).take(2), &[2, 3, 5],]; /// -/// // ...is equivalant to this: +/// // ...is equivalent to this: /// let with_method: Chain, Take>>, slice::Iter<_>> = /// once(&0) /// .chain(repeat(&1).take(2)) @@ -778,7 +780,7 @@ pub trait Itertools : Iterator { /// the original iterator. /// /// **Note:** If the iterator is clonable, prefer using that instead - /// of using this method. It is likely to be more efficient. + /// of using this method. Cloning is likely to be more efficient. /// /// Iterator element type is `Self::Item`. /// @@ -904,7 +906,7 @@ pub trait Itertools : Iterator { /// a series of `Result::Ok` values. `Result::Err` values are unchanged. /// /// This is useful when you have some common error type for your crate and - /// need to propogate it upwards, but the `Result::Ok` case needs to be flattened. + /// need to propagate it upwards, but the `Result::Ok` case needs to be flattened. /// /// ``` /// use itertools::Itertools; @@ -913,7 +915,7 @@ pub trait Itertools : Iterator { /// let it = input.iter().cloned().flatten_ok(); /// itertools::assert_equal(it.clone(), vec![Ok(0), Ok(1), Err(false), Ok(2), Ok(3)]); /// - /// // This can also be used to propogate errors when collecting. + /// // This can also be used to propagate errors when collecting. /// let output_result: Result, bool> = it.collect(); /// assert_eq!(output_result, Err(false)); /// ``` @@ -1109,7 +1111,7 @@ pub trait Itertools : Iterator { /// ``` #[cfg(feature = "use_alloc")] fn multi_cartesian_product(self) -> MultiProduct<::IntoIter> - where Self: Iterator + Sized, + where Self: Sized, Self::Item: IntoIterator, ::IntoIter: Clone, ::Item: Clone @@ -1746,12 +1748,10 @@ pub trait Itertools : Iterator { fn find_position

(&mut self, mut pred: P) -> Option<(usize, Self::Item)> where P: FnMut(&Self::Item) -> bool { - let mut index = 0usize; - for elt in self { + for (index, elt) in self.enumerate() { if pred(&elt) { return Some((index, elt)); } - index += 1; } None } @@ -1795,7 +1795,7 @@ pub trait Itertools : Iterator { Some(if predicate(&first) { first } else { - self.find(|x| predicate(&x)).unwrap_or(first) + self.find(|x| predicate(x)).unwrap_or(first) }) } /// Returns `true` if the given item is present in this iterator. @@ -1953,7 +1953,7 @@ pub trait Itertools : Iterator { where F: FnMut(Self::Item), Self: Sized, { - self.for_each(f) + self.for_each(f); } /// Combine all an iterator's elements into one element by using [`Extend`]. @@ -2271,7 +2271,7 @@ pub trait Itertools : Iterator { /// ``` /// /// Which, for non-associative functions, will typically produce a different - /// result than the linear call tree used by `fold1`: + /// result than the linear call tree used by [`Iterator::reduce`]: /// /// ```text /// 1 2 3 4 5 6 7 @@ -2279,7 +2279,7 @@ pub trait Itertools : Iterator { /// └─f─f─f─f─f─f /// ``` /// - /// If `f` is associative, prefer the normal `fold1` instead. + /// If `f` is associative, prefer the normal [`Iterator::reduce`] instead. /// /// ``` /// use itertools::Itertools; @@ -2692,7 +2692,6 @@ pub trait Itertools : Iterator { /// itertools::assert_equal(oldest_people_first, /// vec!["Jill", "Jack", "Jane", "John"]); /// ``` - /// ``` #[cfg(feature = "use_alloc")] fn sorted_by_cached_key(self, f: F) -> VecIntoIter where @@ -2902,6 +2901,194 @@ pub trait Itertools : Iterator { grouping_map::new(grouping_map::MapForGrouping::new(self, key_mapper)) } + /// Return all minimum elements of an iterator. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().min_set(), Vec::<&i32>::new()); + /// + /// let a = [1]; + /// assert_eq!(a.iter().min_set(), vec![&1]); + /// + /// let a = [1, 2, 3, 4, 5]; + /// assert_eq!(a.iter().min_set(), vec![&1]); + /// + /// let a = [1, 1, 1, 1]; + /// assert_eq!(a.iter().min_set(), vec![&1, &1, &1, &1]); + /// ``` + /// + /// The elements can be floats but no particular result is guaranteed + /// if an element is NaN. + #[cfg(feature = "use_std")] + fn min_set(self) -> Vec + where Self: Sized, Self::Item: Ord + { + extrema_set::min_set_impl(self, |_| (), |x, y, _, _| x.cmp(y)) + } + + /// Return all minimum elements of an iterator, as determined by + /// the specified function. + /// + /// # Examples + /// + /// ``` + /// # use std::cmp::Ordering; + /// use itertools::Itertools; + /// + /// let a: [(i32, i32); 0] = []; + /// assert_eq!(a.iter().min_set_by(|_, _| Ordering::Equal), Vec::<&(i32, i32)>::new()); + /// + /// let a = [(1, 2)]; + /// assert_eq!(a.iter().min_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), vec![&(1, 2)]); + /// + /// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)]; + /// assert_eq!(a.iter().min_set_by(|&&(_,k1), &&(_,k2)| k1.cmp(&k2)), vec![&(1, 2), &(2, 2)]); + /// + /// let a = [(1, 2), (1, 3), (1, 4), (1, 5)]; + /// assert_eq!(a.iter().min_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]); + /// ``` + /// + /// The elements can be floats but no particular result is guaranteed + /// if an element is NaN. + #[cfg(feature = "use_std")] + fn min_set_by(self, mut compare: F) -> Vec + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering + { + extrema_set::min_set_impl( + self, + |_| (), + |x, y, _, _| compare(x, y) + ) + } + + /// Return all minimum elements of an iterator, as determined by + /// the specified function. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [(i32, i32); 0] = []; + /// assert_eq!(a.iter().min_set_by_key(|_| ()), Vec::<&(i32, i32)>::new()); + /// + /// let a = [(1, 2)]; + /// assert_eq!(a.iter().min_set_by_key(|&&(k,_)| k), vec![&(1, 2)]); + /// + /// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)]; + /// assert_eq!(a.iter().min_set_by_key(|&&(_, k)| k), vec![&(1, 2), &(2, 2)]); + /// + /// let a = [(1, 2), (1, 3), (1, 4), (1, 5)]; + /// assert_eq!(a.iter().min_set_by_key(|&&(k, _)| k), vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]); + /// ``` + /// + /// The elements can be floats but no particular result is guaranteed + /// if an element is NaN. + #[cfg(feature = "use_std")] + fn min_set_by_key(self, key: F) -> Vec + where Self: Sized, K: Ord, F: FnMut(&Self::Item) -> K + { + extrema_set::min_set_impl(self, key, |_, _, kx, ky| kx.cmp(ky)) + } + + /// Return all maximum elements of an iterator. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().max_set(), Vec::<&i32>::new()); + /// + /// let a = [1]; + /// assert_eq!(a.iter().max_set(), vec![&1]); + /// + /// let a = [1, 2, 3, 4, 5]; + /// assert_eq!(a.iter().max_set(), vec![&5]); + /// + /// let a = [1, 1, 1, 1]; + /// assert_eq!(a.iter().max_set(), vec![&1, &1, &1, &1]); + /// ``` + /// + /// The elements can be floats but no particular result is guaranteed + /// if an element is NaN. + #[cfg(feature = "use_std")] + fn max_set(self) -> Vec + where Self: Sized, Self::Item: Ord + { + extrema_set::max_set_impl(self, |_| (), |x, y, _, _| x.cmp(y)) + } + + /// Return all maximum elements of an iterator, as determined by + /// the specified function. + /// + /// # Examples + /// + /// ``` + /// # use std::cmp::Ordering; + /// use itertools::Itertools; + /// + /// let a: [(i32, i32); 0] = []; + /// assert_eq!(a.iter().max_set_by(|_, _| Ordering::Equal), Vec::<&(i32, i32)>::new()); + /// + /// let a = [(1, 2)]; + /// assert_eq!(a.iter().max_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), vec![&(1, 2)]); + /// + /// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)]; + /// assert_eq!(a.iter().max_set_by(|&&(_,k1), &&(_,k2)| k1.cmp(&k2)), vec![&(3, 9), &(5, 9)]); + /// + /// let a = [(1, 2), (1, 3), (1, 4), (1, 5)]; + /// assert_eq!(a.iter().max_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]); + /// ``` + /// + /// The elements can be floats but no particular result is guaranteed + /// if an element is NaN. + #[cfg(feature = "use_std")] + fn max_set_by(self, mut compare: F) -> Vec + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering + { + extrema_set::max_set_impl( + self, + |_| (), + |x, y, _, _| compare(x, y) + ) + } + + /// Return all minimum elements of an iterator, as determined by + /// the specified function. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [(i32, i32); 0] = []; + /// assert_eq!(a.iter().max_set_by_key(|_| ()), Vec::<&(i32, i32)>::new()); + /// + /// let a = [(1, 2)]; + /// assert_eq!(a.iter().max_set_by_key(|&&(k,_)| k), vec![&(1, 2)]); + /// + /// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)]; + /// assert_eq!(a.iter().max_set_by_key(|&&(_, k)| k), vec![&(3, 9), &(5, 9)]); + /// + /// let a = [(1, 2), (1, 3), (1, 4), (1, 5)]; + /// assert_eq!(a.iter().max_set_by_key(|&&(k, _)| k), vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]); + /// ``` + /// + /// The elements can be floats but no particular result is guaranteed + /// if an element is NaN. + #[cfg(feature = "use_std")] + fn max_set_by_key(self, key: F) -> Vec + where Self: Sized, K: Ord, F: FnMut(&Self::Item) -> K + { + extrema_set::max_set_impl(self, key, |_, _, kx, ky| kx.cmp(ky)) + } + /// Return the minimum and maximum elements in the iterator. /// /// The return type `MinMaxResult` is an enum of three variants: @@ -3157,7 +3344,7 @@ pub trait Itertools : Iterator { /// be equal to `ypos`. /// /// On an iterator of length `n`, `position_minmax` does `1.5 * n` - /// comparisons, and so is faster than calling `positon_min` and + /// comparisons, and so is faster than calling `position_min` and /// `position_max` separately which does `2 * n` comparisons. /// /// For the minimum, if several elements are equally minimum, the @@ -3478,8 +3665,7 @@ impl Itertools for T where T: Iterator { } /// (elements pairwise equal and sequences of the same length), /// `false` otherwise. /// -/// This is an [`IntoIterator`] enabled function that is similar to the standard -/// library method [`Iterator::eq`]. +/// [`IntoIterator`] enabled version of [`Iterator::eq`]. /// /// ``` /// assert!(itertools::equal(vec![1, 2, 3], 1..4)); @@ -3490,17 +3676,7 @@ pub fn equal(a: I, b: J) -> bool J: IntoIterator, I::Item: PartialEq { - let mut ia = a.into_iter(); - let mut ib = b.into_iter(); - loop { - match ia.next() { - Some(x) => match ib.next() { - Some(y) => if x != y { return false; }, - None => return false, - }, - None => return ib.next().is_none() - } - } + a.into_iter().eq(b) } /// Assert that two iterables produce equal sequences, with the same diff --git a/src/merge_join.rs b/src/merge_join.rs index 4c0048f..f2fbdea 100644 --- a/src/merge_join.rs +++ b/src/merge_join.rs @@ -4,10 +4,12 @@ use std::fmt; use super::adaptors::{PutBack, put_back}; use crate::either_or_both::EitherOrBoth; +#[cfg(doc)] +use crate::Itertools; /// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order. /// -/// See [`.merge_join_by()`](crate::Itertools::merge_join_by) for more information. +/// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`]. pub fn merge_join_by(left: I, right: J, cmp_fn: F) -> MergeJoinBy where I: IntoIterator, diff --git a/src/multipeek_impl.rs b/src/multipeek_impl.rs index 5917681..8b49c69 100644 --- a/src/multipeek_impl.rs +++ b/src/multipeek_impl.rs @@ -2,6 +2,8 @@ use std::iter::Fuse; use alloc::collections::VecDeque; use crate::size_hint; use crate::PeekingNext; +#[cfg(doc)] +use crate::Itertools; /// See [`multipeek()`] for more information. #[derive(Clone, Debug)] @@ -15,6 +17,8 @@ pub struct MultiPeek /// An iterator adaptor that allows the user to peek at multiple `.next()` /// values without advancing the base iterator. +/// +/// [`IntoIterator`] enabled version of [`Itertools::multipeek`]. pub fn multipeek(iterable: I) -> MultiPeek where I: IntoIterator { @@ -67,10 +71,8 @@ impl PeekingNext for MultiPeek if let Some(r) = self.peek() { if !accept(r) { return None } } - } else { - if let Some(r) = self.buf.get(0) { - if !accept(r) { return None } - } + } else if let Some(r) = self.buf.get(0) { + if !accept(r) { return None } } self.next() } diff --git a/src/pad_tail.rs b/src/pad_tail.rs index de57ee4..248a432 100644 --- a/src/pad_tail.rs +++ b/src/pad_tail.rs @@ -23,7 +23,7 @@ where debug_fmt_fields!(PadUsing, iter, min, pos); } -/// Create a new **PadUsing** iterator. +/// Create a new `PadUsing` iterator. pub fn pad_using(iter: I, min: usize, filler: F) -> PadUsing where I: Iterator, F: FnMut(usize) -> I::Item diff --git a/src/peeking_take_while.rs b/src/peeking_take_while.rs index cd0945a..b3a9c5c 100644 --- a/src/peeking_take_while.rs +++ b/src/peeking_take_while.rs @@ -90,7 +90,7 @@ where debug_fmt_fields!(PeekingTakeWhile, iter); } -/// Create a PeekingTakeWhile +/// Create a `PeekingTakeWhile` pub fn peeking_take_while(iter: &mut I, f: F) -> PeekingTakeWhile where I: Iterator, { diff --git a/src/permutations.rs b/src/permutations.rs index 3080f9d..d03b852 100644 --- a/src/permutations.rs +++ b/src/permutations.rs @@ -113,19 +113,15 @@ where Some(indices.map(|i| vals[i].clone()).collect()) } - PermutationState::Complete(CompleteState::Start { .. }) => None, PermutationState::Complete(CompleteState::Ongoing { ref indices, ref cycles }) => { let k = cycles.len(); - Some(indices[0..k].iter().map(|&i| vals[i].clone()).collect()) }, - PermutationState::Empty => None + PermutationState::Complete(CompleteState::Start { .. }) | PermutationState::Empty => None } } fn count(self) -> usize { - let Permutations { vals, state } = self; - fn from_complete(complete_state: CompleteState) -> usize { match complete_state.remaining() { CompleteStateRemaining::Known(count) => count, @@ -135,6 +131,7 @@ where } } + let Permutations { vals, state } = self; match state { PermutationState::StartUnknownLen { k } => { let n = vals.len() + vals.it.count(); diff --git a/src/rciter_impl.rs b/src/rciter_impl.rs index 782908e..7298350 100644 --- a/src/rciter_impl.rs +++ b/src/rciter_impl.rs @@ -51,7 +51,6 @@ pub fn rciter(iterable: I) -> RcIter } impl Clone for RcIter { - #[inline] clone_fields!(rciter); } diff --git a/src/size_hint.rs b/src/size_hint.rs index 1168eca..71ea141 100644 --- a/src/size_hint.rs +++ b/src/size_hint.rs @@ -1,14 +1,14 @@ -//! Arithmetic on **Iterator** *.size_hint()* values. +//! Arithmetic on `Iterator.size_hint()` values. //! use std::usize; use std::cmp; use std::u32; -/// **SizeHint** is the return type of **Iterator::size_hint()**. +/// `SizeHint` is the return type of `Iterator::size_hint()`. pub type SizeHint = (usize, Option); -/// Add **SizeHint** correctly. +/// Add `SizeHint` correctly. #[inline] pub fn add(a: SizeHint, b: SizeHint) -> SizeHint { let min = a.0.saturating_add(b.0); @@ -20,7 +20,7 @@ pub fn add(a: SizeHint, b: SizeHint) -> SizeHint { (min, max) } -/// Add **x** correctly to a **SizeHint**. +/// Add `x` correctly to a `SizeHint`. #[inline] pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint { let (mut low, mut hi) = sh; @@ -29,7 +29,7 @@ pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint { (low, hi) } -/// Sbb **x** correctly to a **SizeHint**. +/// Subtract `x` correctly from a `SizeHint`. #[inline] #[allow(dead_code)] pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint { @@ -40,7 +40,7 @@ pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint { } -/// Multiply **SizeHint** correctly +/// Multiply `SizeHint` correctly /// /// ```ignore /// use std::usize; @@ -66,7 +66,7 @@ pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint { (low, hi) } -/// Multiply **x** correctly with a **SizeHint**. +/// Multiply `x` correctly with a `SizeHint`. #[inline] pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint { let (mut low, mut hi) = sh; @@ -75,7 +75,7 @@ pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint { (low, hi) } -/// Raise `base` correctly by a **`SizeHint`** exponent. +/// Raise `base` correctly by a `SizeHint` exponent. #[inline] pub fn pow_scalar_base(base: usize, exp: SizeHint) -> SizeHint { let exp_low = cmp::min(exp.0, u32::MAX as usize) as u32; diff --git a/src/tuple_impl.rs b/src/tuple_impl.rs index d914e03..06b5c13 100644 --- a/src/tuple_impl.rs +++ b/src/tuple_impl.rs @@ -162,8 +162,8 @@ pub fn tuple_windows(mut iter: I) -> TupleWindows } TupleWindows { - last, iter, + last, } } diff --git a/src/unique_impl.rs b/src/unique_impl.rs index 2240f36..4e81e78 100644 --- a/src/unique_impl.rs +++ b/src/unique_impl.rs @@ -1,6 +1,5 @@ - use std::collections::HashMap; -use std::collections::hash_map::{Entry}; +use std::collections::hash_map::Entry; use std::hash::Hash; use std::fmt; use std::iter::FusedIterator; @@ -12,7 +11,9 @@ use std::iter::FusedIterator; #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct UniqueBy { iter: I, - // Use a hashmap for the entry API + // Use a Hashmap for the Entry API in order to prevent hashing twice. + // This can maybe be replaced with a HashSet once `get_or_insert_with` + // or a proper Entry API for Hashset is stable and meets this msrv used: HashMap, f: F, } diff --git a/src/unziptuple.rs b/src/unziptuple.rs index f468f05..7af29ec 100644 --- a/src/unziptuple.rs +++ b/src/unziptuple.rs @@ -39,11 +39,11 @@ macro_rules! impl_unzip_iter { #[allow(non_snake_case)] impl, $($T, $FromT: Default + Extend<$T>),* > MultiUnzip<($($FromT,)*)> for IT { fn multiunzip(self) -> ($($FromT,)*) { - // This implementation mirrors the logic of Iterator::unzip as close as possible. - // Unfortunately a lot of the used api there is still unstable represented by - // the commented out parts that follow. + // This implementation mirrors the logic of Iterator::unzip resp. Extend for (A, B) as close as possible. + // Unfortunately a lot of the used api there is still unstable (https://github.com/rust-lang/rust/issues/72631). // - // https://doc.rust-lang.org/src/core/iter/traits/iterator.rs.html#2816-2844 + // Iterator::unzip: https://doc.rust-lang.org/src/core/iter/traits/iterator.rs.html#2825-2865 + // Extend for (A, B): https://doc.rust-lang.org/src/core/iter/traits/collect.rs.html#370-411 let mut res = ($($FromT::default(),)*); let ($($FromT,)*) = &mut res; diff --git a/src/ziptuple.rs b/src/ziptuple.rs index b7902ae..6d3a584 100644 --- a/src/ziptuple.rs +++ b/src/ziptuple.rs @@ -36,6 +36,7 @@ pub struct Zip { /// /// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); /// ``` +/// [`izip!()`]: crate::izip pub fn multizip(t: U) -> Zip where Zip: From, Zip: Iterator, -- cgit v1.2.3