From 6d4e429e1c1f1ce256550176e252a1e819c2914b Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Thu, 1 Apr 2021 14:51:01 +0200 Subject: [PATCH 01/24] Impl dedup --- library/core/src/iter/adapters/dedup.rs | 177 +++++++++++++++++++++++ library/core/src/iter/adapters/mod.rs | 6 +- library/core/src/iter/mod.rs | 2 + library/core/src/iter/traits/iterator.rs | 88 +++++++++++ 4 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 library/core/src/iter/adapters/dedup.rs diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs new file mode 100644 index 0000000000000..f7b13589c292a --- /dev/null +++ b/library/core/src/iter/adapters/dedup.rs @@ -0,0 +1,177 @@ +use crate::mem::swap; + +/// An iterator that removes all but the first of consecutive elements in a +/// given iterator according to the [`PartialEq`] trait implementation. +/// +/// This `struct` is created by the [`dedup`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`dedup`]: Iterator::dedup +/// [`Iterator`]: trait.Iterator.html +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[derive(Debug, Clone, Copy)] +pub struct Dedup { + inner: I, + last: Option, +} + +impl Dedup { + pub(crate) const fn new(inner: I) -> Self { + Self { inner, last: None } + } +} + +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +impl Iterator for Dedup +where + I: Iterator, + T: PartialEq, +{ + type Item = T; + + fn next(&mut self) -> Option { + if self.last.is_none() { + self.last = self.inner.next(); + } + + let last_item = self.last.as_ref()?; + let mut next = loop { + let curr = self.inner.next(); + if let Some(curr_item) = &curr { + if last_item != curr_item { + break curr; + } + } else { + break None; + } + }; + + swap(&mut self.last, &mut next); + next + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.size_hint().1) + } +} + +/// An iterator that removes all but the first of consecutive elements in a +/// given iterator satisfying a given equality relation. +/// +/// This `struct` is created by the [`dedup_by`] method on [`Iterator`]. +/// See its documentation for more. +/// +/// [`dedup_by`]: Iterator::dedup_by +/// [`Iterator`]: trait.Iterator.html +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[derive(Debug, Clone, Copy)] +pub struct DedupBy { + inner: I, + same_bucket: F, + last: Option, +} + +impl DedupBy { + pub(crate) const fn new(inner: I, same_bucket: F) -> Self { + Self { + inner, + same_bucket, + last: None, + } + } +} + +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +impl Iterator for DedupBy +where + I: Iterator, + F: FnMut(&T, &T) -> bool, +{ + type Item = T; + + fn next(&mut self) -> Option { + if self.last.is_none() { + self.last = self.inner.next(); + } + + let last_item = self.last.as_ref()?; + let mut next = loop { + let curr = self.inner.next(); + if let Some(curr_item) = &curr { + if !(self.same_bucket)(last_item, curr_item) { + break curr; + } + } else { + break None; + } + }; + + swap(&mut self.last, &mut next); + next + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.size_hint().1) + } +} + +/// An iterator that removes all but the first of consecutive elements in a +/// given iterator that resolve to the same key. +/// +/// This `struct` is created by the [`dedup_by_key`] method on [`Iterator`]. +/// See its documentation for more. +/// +/// [`dedup_by_key`]: Iterator::dedup_by_key +/// [`Iterator`]: trait.Iterator.html +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[derive(Debug, Clone, Copy)] +pub struct DedupByKey { + inner: I, + key: F, + last: Option, +} + +impl DedupByKey { + pub(crate) const fn new(inner: I, key: F) -> Self { + Self { + inner, + key, + last: None, + } + } +} + +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +impl Iterator for DedupByKey +where + I: Iterator, + F: Fn(&T) -> K, + K: PartialEq, +{ + type Item = T; + + fn next(&mut self) -> Option { + if self.last.is_none() { + self.last = self.inner.next(); + } + + let last_item = self.last.as_ref()?; + let mut next = loop { + let curr = self.inner.next(); + if let Some(curr_item) = &curr { + if (self.key)(last_item) != (self.key)(curr_item) { + break curr; + } + } else { + break None; + } + }; + + swap(&mut self.last, &mut next); + next + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.size_hint().1) + } +} diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index bf4fabad32a37..8d0893a2b548e 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -7,6 +7,7 @@ mod chain; mod cloned; mod copied; mod cycle; +mod dedup; mod enumerate; mod filter; mod filter_map; @@ -66,7 +67,10 @@ pub use self::zip::TrustedRandomAccessNoCoerce; #[stable(feature = "iter_zip", since = "1.59.0")] pub use self::zip::zip; -/// This trait provides transitive access to source-stage in an iterator-adapter pipeline +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +pub use self::dedup::{Dedup, DedupBy, DedupByKey}; + +/// This trait provides transitive access to source-stage in an interator-adapter pipeline /// under the conditions that /// * the iterator source `S` itself implements `SourceIter` /// * there is a delegating implementation of this trait for each adapter in the pipeline between diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 9514466bd0c05..51bc7683e095f 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -425,6 +425,8 @@ pub use self::adapters::{ }; #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::adapters::{Intersperse, IntersperseWith}; +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +pub use self::adapters::{Dedup, DedupBy, DedupByKey}; pub(crate) use self::adapters::try_process; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index b2d08f4b0f67b..5edeb2f0e84c3 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -6,6 +6,7 @@ use super::super::try_process; use super::super::ByRefSized; use super::super::TrustedRandomAccessNoCoerce; use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; +use super::super::{Dedup, DedupBy, DedupByKey}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; use super::super::{ @@ -1689,6 +1690,93 @@ pub trait Iterator { Inspect::new(self, f) } + /// Removes all but the first of consecutive elements in the iterator according to the + /// [`PartialEq`] trait implementation. + /// + /// If the iterator is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// let vec = vec![1, 2, 2, 3, 2]; + /// + /// let mut iter = vec.into_iter().dedup(); + /// + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(3)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), None); + /// ``` + #[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] + #[inline] + fn dedup(self) -> Dedup + where + Self: Sized + { + Dedup::new(self) + } + + /// Removes all but the first of consecutive elements in the iterator satisfying a given equality + /// relation. + /// + /// The `same_bucket` function is passed a references to two elements from the iterator and + /// must determine if the elements compare equal. + /// + /// If the iterator is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// let vec = vec!["foo", "bar", "Bar", "baz", "bar"]; + /// + /// let mut iter = vec.into_iter().dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + /// + /// assert_eq!(iter.next(), Some("foo")); + /// assert_eq!(iter.next(), Some("bar")); + /// assert_eq!(iter.next(), Some("baz")); + /// assert_eq!(iter.next(), Some("bar")); + /// assert_eq!(iter.next(), None); + /// ``` + #[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] + #[inline] + fn dedup_by(self, same_bucket: F) -> DedupBy + where + Self: Sized, + F: Fn(&Self::Item, &Self::Item) -> bool, + { + DedupBy::new(self, same_bucket) + } + + /// Removes all but the first of consecutive elements in the iterator that + /// resolve to the same key. + /// + /// If the iterator is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// let vec = vec![10, 20, 21, 30, 20]; + /// + /// let mut iter = vec.into_iter().dedup_by_key(|&i| i / 10); + /// + /// assert_eq!(iter.next(), Some(10)); + /// assert_eq!(iter.next(), Some(20)); + /// assert_eq!(iter.next(), Some(30)); + /// assert_eq!(iter.next(), Some(20)); + /// assert_eq!(iter.next(), None); + /// ``` + #[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] + #[inline] + fn dedup_by_key(self, key: F) -> DedupByKey + where + Self: Sized, + F: Fn(&Self::Item) -> K, + K: PartialEq, + { + DedupByKey::new(self, key) + } + /// Borrows an iterator, rather than consuming it. /// /// This is useful to allow applying iterator adapters while still From bf425a09ef727a2c8d1975ef6ae7a673042f4ecf Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Thu, 1 Apr 2021 15:19:15 +0200 Subject: [PATCH 02/24] Update issue in unstable attributes --- library/core/src/iter/adapters/dedup.rs | 12 ++++++------ library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/mod.rs | 2 +- library/core/src/iter/traits/iterator.rs | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index f7b13589c292a..ae0c9c49d0f08 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -8,7 +8,7 @@ use crate::mem::swap; /// /// [`dedup`]: Iterator::dedup /// [`Iterator`]: trait.Iterator.html -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] pub struct Dedup { inner: I, @@ -21,7 +21,7 @@ impl Dedup { } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl Iterator for Dedup where I: Iterator, @@ -63,7 +63,7 @@ where /// /// [`dedup_by`]: Iterator::dedup_by /// [`Iterator`]: trait.Iterator.html -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] pub struct DedupBy { inner: I, @@ -81,7 +81,7 @@ impl DedupBy { } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl Iterator for DedupBy where I: Iterator, @@ -123,7 +123,7 @@ where /// /// [`dedup_by_key`]: Iterator::dedup_by_key /// [`Iterator`]: trait.Iterator.html -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] pub struct DedupByKey { inner: I, @@ -141,7 +141,7 @@ impl DedupByKey { } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl Iterator for DedupByKey where I: Iterator, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 8d0893a2b548e..e40b7e3dad44b 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -67,7 +67,7 @@ pub use self::zip::TrustedRandomAccessNoCoerce; #[stable(feature = "iter_zip", since = "1.59.0")] pub use self::zip::zip; -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] pub use self::dedup::{Dedup, DedupBy, DedupByKey}; /// This trait provides transitive access to source-stage in an interator-adapter pipeline diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 51bc7683e095f..fc2a3650d0f89 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -425,7 +425,7 @@ pub use self::adapters::{ }; #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::adapters::{Intersperse, IntersperseWith}; -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] pub use self::adapters::{Dedup, DedupBy, DedupByKey}; pub(crate) use self::adapters::try_process; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 5edeb2f0e84c3..b05a92569450b 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1708,7 +1708,7 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] + #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] fn dedup(self) -> Dedup where @@ -1738,7 +1738,7 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some("bar")); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] + #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] fn dedup_by(self, same_bucket: F) -> DedupBy where @@ -1766,7 +1766,7 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some(20)); /// assert_eq!(iter.next(), None); /// ``` - #[unstable(feature = "iter_dedup", reason = "recently added", issue = "none")] + #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] fn dedup_by_key(self, key: F) -> DedupByKey where From d59eb006906059ed17e44d652307a7293864c5fc Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Thu, 1 Apr 2021 15:29:20 +0200 Subject: [PATCH 03/24] Ran cargo fmt --- library/core/src/iter/adapters/dedup.rs | 12 ++---------- library/core/src/iter/mod.rs | 4 ++-- library/core/src/iter/traits/iterator.rs | 2 +- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index ae0c9c49d0f08..94bebdb6e9455 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -73,11 +73,7 @@ pub struct DedupBy { impl DedupBy { pub(crate) const fn new(inner: I, same_bucket: F) -> Self { - Self { - inner, - same_bucket, - last: None, - } + Self { inner, same_bucket, last: None } } } @@ -133,11 +129,7 @@ pub struct DedupByKey { impl DedupByKey { pub(crate) const fn new(inner: I, key: F) -> Self { - Self { - inner, - key, - last: None, - } + Self { inner, key, last: None } } } diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index fc2a3650d0f89..c0127683046fc 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -423,10 +423,10 @@ pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, Skip, SkipWhile, Take, TakeWhile, Zip, }; -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] -pub use self::adapters::{Intersperse, IntersperseWith}; #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] pub use self::adapters::{Dedup, DedupBy, DedupByKey}; +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +pub use self::adapters::{Intersperse, IntersperseWith}; pub(crate) use self::adapters::try_process; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index b05a92569450b..e08c6bc04e20b 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1712,7 +1712,7 @@ pub trait Iterator { #[inline] fn dedup(self) -> Dedup where - Self: Sized + Self: Sized, { Dedup::new(self) } From 5e243471f06ff83da1361a1a26a90a9bbf8ca381 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Thu, 1 Apr 2021 15:55:20 +0200 Subject: [PATCH 04/24] Added feature flag to doc tests --- library/core/src/iter/traits/iterator.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index e08c6bc04e20b..810f332e5c85f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1698,6 +1698,8 @@ pub trait Iterator { /// # Examples /// /// ``` + /// #![feature(iter_dedup)] + /// /// let vec = vec![1, 2, 2, 3, 2]; /// /// let mut iter = vec.into_iter().dedup(); @@ -1728,6 +1730,8 @@ pub trait Iterator { /// # Examples /// /// ``` + /// #![feature(iter_dedup)] + /// /// let vec = vec!["foo", "bar", "Bar", "baz", "bar"]; /// /// let mut iter = vec.into_iter().dedup_by(|a, b| a.eq_ignore_ascii_case(b)); @@ -1756,6 +1760,8 @@ pub trait Iterator { /// # Examples /// /// ``` + /// #![feature(iter_dedup)] + /// /// let vec = vec![10, 20, 21, 30, 20]; /// /// let mut iter = vec.into_iter().dedup_by_key(|&i| i / 10); From ca137db7e5c9adccb728049c42bd9b2f52e32910 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Thu, 1 Apr 2021 17:20:15 +0200 Subject: [PATCH 05/24] Changed trait bounds --- library/core/src/iter/traits/iterator.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 810f332e5c85f..49f8a7c44d2f4 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1715,6 +1715,7 @@ pub trait Iterator { fn dedup(self) -> Dedup where Self: Sized, + Self::Item: PartialEq, { Dedup::new(self) } @@ -1747,7 +1748,7 @@ pub trait Iterator { fn dedup_by(self, same_bucket: F) -> DedupBy where Self: Sized, - F: Fn(&Self::Item, &Self::Item) -> bool, + F: FnMut(&Self::Item, &Self::Item) -> bool, { DedupBy::new(self, same_bucket) } @@ -1777,7 +1778,7 @@ pub trait Iterator { fn dedup_by_key(self, key: F) -> DedupByKey where Self: Sized, - F: Fn(&Self::Item) -> K, + F: FnMut(&Self::Item) -> K, K: PartialEq, { DedupByKey::new(self, key) From 1ec9aa84e51daaf8b057049c5a7e6b5e07e4a1fd Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Thu, 1 Apr 2021 17:47:41 +0200 Subject: [PATCH 06/24] Forgot one --- library/core/src/iter/adapters/dedup.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 94bebdb6e9455..6c172ccb74eeb 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -137,7 +137,7 @@ impl DedupByKey { impl Iterator for DedupByKey where I: Iterator, - F: Fn(&T) -> K, + F: FnMut(&T) -> K, K: PartialEq, { type Item = T; From cc480ba5fd2f2912ede8c16793008065509d9f2f Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Thu, 1 Apr 2021 18:31:33 +0200 Subject: [PATCH 07/24] Moved initialization of last into contructor --- library/core/src/iter/adapters/dedup.rs | 51 ++++++++++++++----------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 6c172ccb74eeb..fff938f75ddc8 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -3,11 +3,10 @@ use crate::mem::swap; /// An iterator that removes all but the first of consecutive elements in a /// given iterator according to the [`PartialEq`] trait implementation. /// -/// This `struct` is created by the [`dedup`] method on [`Iterator`]. See its -/// documentation for more. +/// This `struct` is created by [`Iterator::dedup`]. +/// See its documentation for more. /// -/// [`dedup`]: Iterator::dedup -/// [`Iterator`]: trait.Iterator.html +/// [`Iterator::dedup`]: Iterator::dedup #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] pub struct Dedup { @@ -15,9 +14,13 @@ pub struct Dedup { last: Option, } -impl Dedup { - pub(crate) const fn new(inner: I) -> Self { - Self { inner, last: None } +impl Dedup +where + I: Iterator, +{ + pub(crate) fn new(inner: I) -> Self { + let mut inner = inner; + Self { last: inner.next(), inner } } } @@ -30,10 +33,6 @@ where type Item = T; fn next(&mut self) -> Option { - if self.last.is_none() { - self.last = self.inner.next(); - } - let last_item = self.last.as_ref()?; let mut next = loop { let curr = self.inner.next(); @@ -58,11 +57,10 @@ where /// An iterator that removes all but the first of consecutive elements in a /// given iterator satisfying a given equality relation. /// -/// This `struct` is created by the [`dedup_by`] method on [`Iterator`]. +/// This `struct` is created by [`Iterator::dedup_by`]. /// See its documentation for more. /// -/// [`dedup_by`]: Iterator::dedup_by -/// [`Iterator`]: trait.Iterator.html +/// [`Iterator::dedup_by`]: Iterator::dedup_by #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] pub struct DedupBy { @@ -71,9 +69,13 @@ pub struct DedupBy { last: Option, } -impl DedupBy { - pub(crate) const fn new(inner: I, same_bucket: F) -> Self { - Self { inner, same_bucket, last: None } +impl DedupBy +where + I: Iterator, +{ + pub(crate) fn new(inner: I, same_bucket: F) -> Self { + let mut inner = inner; + Self { last: inner.next(), inner, same_bucket } } } @@ -114,11 +116,10 @@ where /// An iterator that removes all but the first of consecutive elements in a /// given iterator that resolve to the same key. /// -/// This `struct` is created by the [`dedup_by_key`] method on [`Iterator`]. +/// This `struct` is created by [`Iterator::dedup_by_key`]. /// See its documentation for more. /// -/// [`dedup_by_key`]: Iterator::dedup_by_key -/// [`Iterator`]: trait.Iterator.html +/// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] pub struct DedupByKey { @@ -127,9 +128,13 @@ pub struct DedupByKey { last: Option, } -impl DedupByKey { - pub(crate) const fn new(inner: I, key: F) -> Self { - Self { inner, key, last: None } +impl DedupByKey +where + I: Iterator, +{ + pub(crate) fn new(inner: I, key: F) -> Self { + let mut inner = inner; + Self { last: inner.next(), inner, key } } } From 7d9b058b7a86da03d47f5bde1ff5b26cff523afa Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Thu, 1 Apr 2021 22:16:04 +0200 Subject: [PATCH 08/24] Actually removed checks this time --- library/core/src/iter/adapters/dedup.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index fff938f75ddc8..a3856e47e4946 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -88,10 +88,6 @@ where type Item = T; fn next(&mut self) -> Option { - if self.last.is_none() { - self.last = self.inner.next(); - } - let last_item = self.last.as_ref()?; let mut next = loop { let curr = self.inner.next(); @@ -148,10 +144,6 @@ where type Item = T; fn next(&mut self) -> Option { - if self.last.is_none() { - self.last = self.inner.next(); - } - let last_item = self.last.as_ref()?; let mut next = loop { let curr = self.inner.next(); From 87d7f9a456d690d77b2f030ca4171f2e75717582 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Fri, 2 Apr 2021 13:12:08 +0200 Subject: [PATCH 09/24] Better size_hint and documentation --- library/core/src/iter/adapters/dedup.rs | 12 +++++++++--- library/core/src/iter/traits/iterator.rs | 9 +++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index a3856e47e4946..49d79cac038c0 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -50,7 +50,9 @@ where } fn size_hint(&self) -> (usize, Option) { - (0, self.inner.size_hint().1) + let min = self.last.as_ref().map(|_| 1).unwrap_or(0); + let max = self.inner.size_hint().1; + (min, max) } } @@ -105,7 +107,9 @@ where } fn size_hint(&self) -> (usize, Option) { - (0, self.inner.size_hint().1) + let min = self.last.as_ref().map(|_| 1).unwrap_or(0); + let max = self.inner.size_hint().1; + (min, max) } } @@ -161,6 +165,8 @@ where } fn size_hint(&self) -> (usize, Option) { - (0, self.inner.size_hint().1) + let min = self.last.as_ref().map(|_| 1).unwrap_or(0); + let max = self.inner.size_hint().1; + (min, max) } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 49f8a7c44d2f4..2757608e49fc3 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1693,6 +1693,9 @@ pub trait Iterator { /// Removes all but the first of consecutive elements in the iterator according to the /// [`PartialEq`] trait implementation. /// + /// For an iterator yielding infinitely many consecutive duplicates, + /// this may result in an infinite loop. + /// /// If the iterator is sorted, this removes all duplicates. /// /// # Examples @@ -1726,6 +1729,9 @@ pub trait Iterator { /// The `same_bucket` function is passed a references to two elements from the iterator and /// must determine if the elements compare equal. /// + /// For an iterator yielding infinitely many consecutive duplicates, + /// this may result in an infinite loop. + /// /// If the iterator is sorted, this removes all duplicates. /// /// # Examples @@ -1756,6 +1762,9 @@ pub trait Iterator { /// Removes all but the first of consecutive elements in the iterator that /// resolve to the same key. /// + /// For an iterator yielding infinitely many consecutive duplicates, + /// this may result in an infinite loop. + /// /// If the iterator is sorted, this removes all duplicates. /// /// # Examples From 2e1beb11557f6af48f8312a2c068817b7d7e9729 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Fri, 2 Apr 2021 23:52:11 +0200 Subject: [PATCH 10/24] Fixed the (1, Some(0)) size_hint bug --- library/core/src/iter/adapters/dedup.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 49d79cac038c0..43652f903d9ce 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -50,9 +50,7 @@ where } fn size_hint(&self) -> (usize, Option) { - let min = self.last.as_ref().map(|_| 1).unwrap_or(0); - let max = self.inner.size_hint().1; - (min, max) + if self.last.is_some() { (1, self.inner.size_hint().1) } else { (0, Some(0)) } } } @@ -107,9 +105,7 @@ where } fn size_hint(&self) -> (usize, Option) { - let min = self.last.as_ref().map(|_| 1).unwrap_or(0); - let max = self.inner.size_hint().1; - (min, max) + if self.last.is_some() { (1, self.inner.size_hint().1) } else { (0, Some(0)) } } } @@ -165,8 +161,6 @@ where } fn size_hint(&self) -> (usize, Option) { - let min = self.last.as_ref().map(|_| 1).unwrap_or(0); - let max = self.inner.size_hint().1; - (min, max) + if self.last.is_some() { (1, self.inner.size_hint().1) } else { (0, Some(0)) } } } From d0f9feb0bead27331bdbc2d8e2ae6dcb67286811 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Sat, 3 Apr 2021 12:24:34 +0200 Subject: [PATCH 11/24] This should work --- library/core/src/iter/adapters/dedup.rs | 39 +++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 43652f903d9ce..ef02084b9ba8c 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -50,7 +50,18 @@ where } fn size_hint(&self) -> (usize, Option) { - if self.last.is_some() { (1, self.inner.size_hint().1) } else { (0, Some(0)) } + if self.last.is_some() { + // If we have a last item stored, the iterator can yield at most + // as many items at the inner iterator plus the stored one. Yet we + // can only guarantee that the iterator yields at least one more item + // since all other items in the inner iterator might be duplicates. + let (_, max) = self.inner.size_hint(); + (1, max.and_then(|k| k.checked_add(1))) + } else { + // If the last item we got from the inner iterator is `None`, + // the iterator is empty. + (0, Some(0)) + } } } @@ -105,7 +116,18 @@ where } fn size_hint(&self) -> (usize, Option) { - if self.last.is_some() { (1, self.inner.size_hint().1) } else { (0, Some(0)) } + if self.last.is_some() { + // If we have a last item stored, the iterator can yield at most + // as many items at the inner iterator plus the stored one. Yet we + // can only guarantee that the iterator yields at least one more item + // since all other items in the inner iterator might be duplicates. + let (_, max) = self.inner.size_hint(); + (1, max.and_then(|k| k.checked_add(1))) + } else { + // If the last item we got from the inner iterator is `None`, + // the iterator is empty. + (0, Some(0)) + } } } @@ -161,6 +183,17 @@ where } fn size_hint(&self) -> (usize, Option) { - if self.last.is_some() { (1, self.inner.size_hint().1) } else { (0, Some(0)) } + if self.last.is_some() { + // If we have a last item stored, the iterator can yield at most + // as many items at the inner iterator plus the stored one. Yet we + // can only guarantee that the iterator yields at least one more item + // since all other items in the inner iterator might be duplicates. + let (_, max) = self.inner.size_hint(); + (1, max.and_then(|k| k.checked_add(1))) + } else { + // If the last item we got from the inner iterator is `None`, + // the iterator is empty. + (0, Some(0)) + } } } From d1e6d2744c90fd60d49c7f90e77aaa52e6874efa Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Mon, 26 Apr 2021 17:18:42 +0200 Subject: [PATCH 12/24] Reduced code duplication and added impl for SourceIter and InPlaceIterable --- library/core/src/iter/adapters/dedup.rs | 206 ++++++++++------------- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/mod.rs | 2 +- library/core/src/iter/traits/iterator.rs | 14 +- 4 files changed, 97 insertions(+), 127 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index ef02084b9ba8c..dbcf9799f0f88 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -1,97 +1,121 @@ -use crate::mem::swap; +use crate::{ + iter::{InPlaceIterable, SourceIter}, + mem::swap, +}; -/// An iterator that removes all but the first of consecutive elements in a -/// given iterator according to the [`PartialEq`] trait implementation. +/// A wrapper type around a key function. /// -/// This `struct` is created by [`Iterator::dedup`]. +/// This struct acts like a function which given a key function returns true +/// if and only if both arguments evaluate to the same key. +/// +/// This `struct` is created by [`Iterator::dedup_by_key`]. /// See its documentation for more. /// -/// [`Iterator::dedup`]: Iterator::dedup +/// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] -pub struct Dedup { - inner: I, - last: Option, +pub struct ByKey { + key: F, +} + +impl ByKey { + pub(crate) fn new(key: F) -> Self { + Self { key } + } } -impl Dedup +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] +impl FnOnce<(&T, &T)> for ByKey where - I: Iterator, + F: FnMut(&T) -> K, + K: PartialEq, { - pub(crate) fn new(inner: I) -> Self { - let mut inner = inner; - Self { last: inner.next(), inner } + type Output = bool; + + extern "rust-call" fn call_once(mut self, args: (&T, &T)) -> Self::Output { + (self.key)(args.0) == (self.key)(args.1) } } #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -impl Iterator for Dedup +impl FnMut<(&T, &T)> for ByKey where - I: Iterator, - T: PartialEq, + F: FnMut(&T) -> K, + K: PartialEq, { - type Item = T; + extern "rust-call" fn call_mut(&mut self, args: (&T, &T)) -> Self::Output { + (self.key)(args.0) == (self.key)(args.1) + } +} - fn next(&mut self) -> Option { - let last_item = self.last.as_ref()?; - let mut next = loop { - let curr = self.inner.next(); - if let Some(curr_item) = &curr { - if last_item != curr_item { - break curr; - } - } else { - break None; - } - }; +/// A zero-sized type for checking partial equality. +/// +/// This struct acts exactly like the function [`PartialEq::eq`], but its +/// type is always known during compile time. +/// +/// This `struct` is created by [`Iterator::dedup`]. +/// See its documentation for more. +/// +/// [`Iterator::dedup`]: Iterator::dedup +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] +#[derive(Debug, Clone, Copy)] +pub struct ByPartialEq; - swap(&mut self.last, &mut next); - next +impl ByPartialEq { + pub(crate) fn new() -> Self { + Self } +} - fn size_hint(&self) -> (usize, Option) { - if self.last.is_some() { - // If we have a last item stored, the iterator can yield at most - // as many items at the inner iterator plus the stored one. Yet we - // can only guarantee that the iterator yields at least one more item - // since all other items in the inner iterator might be duplicates. - let (_, max) = self.inner.size_hint(); - (1, max.and_then(|k| k.checked_add(1))) - } else { - // If the last item we got from the inner iterator is `None`, - // the iterator is empty. - (0, Some(0)) - } +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] +impl FnOnce<(&T, &T)> for ByPartialEq { + type Output = bool; + + extern "rust-call" fn call_once(self, args: (&T, &T)) -> Self::Output { + args.0 == args.1 + } +} + +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] +impl FnMut<(&T, &T)> for ByPartialEq { + extern "rust-call" fn call_mut(&mut self, args: (&T, &T)) -> Self::Output { + args.0 == args.1 } } /// An iterator that removes all but the first of consecutive elements in a /// given iterator satisfying a given equality relation. /// -/// This `struct` is created by [`Iterator::dedup_by`]. -/// See its documentation for more. +/// This `struct` is created by [`Iterator::dedup`], [`Iterator::dedup_by`] +/// and [`Iterator::dedup_by_key`]. See its documentation for more. /// +/// [`Iterator::dedup`]: Iterator::dedup /// [`Iterator::dedup_by`]: Iterator::dedup_by +/// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] -pub struct DedupBy { +pub struct Dedup { inner: I, same_bucket: F, last: Option, } -impl DedupBy +impl Dedup where I: Iterator, { pub(crate) fn new(inner: I, same_bucket: F) -> Self { let mut inner = inner; - Self { last: inner.next(), inner, same_bucket } + Self { + last: inner.next(), + inner, + same_bucket, + } } } #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -impl Iterator for DedupBy +impl Iterator for Dedup where I: Iterator, F: FnMut(&T, &T) -> bool, @@ -116,84 +140,30 @@ where } fn size_hint(&self) -> (usize, Option) { - if self.last.is_some() { - // If we have a last item stored, the iterator can yield at most - // as many items at the inner iterator plus the stored one. Yet we - // can only guarantee that the iterator yields at least one more item - // since all other items in the inner iterator might be duplicates. - let (_, max) = self.inner.size_hint(); - (1, max.and_then(|k| k.checked_add(1))) - } else { - // If the last item we got from the inner iterator is `None`, - // the iterator is empty. - (0, Some(0)) - } + let min = self.last.as_ref().map(|_| 1).unwrap_or(0); + let max = self.inner.size_hint().1; + (min, max) } } -/// An iterator that removes all but the first of consecutive elements in a -/// given iterator that resolve to the same key. -/// -/// This `struct` is created by [`Iterator::dedup_by_key`]. -/// See its documentation for more. -/// -/// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -#[derive(Debug, Clone, Copy)] -pub struct DedupByKey { - inner: I, - key: F, - last: Option, -} - -impl DedupByKey +unsafe impl SourceIter for Dedup where - I: Iterator, + S: Iterator, + I: Iterator + SourceIter, { - pub(crate) fn new(inner: I, key: F) -> Self { - let mut inner = inner; - Self { last: inner.next(), inner, key } + type Source = S; + + unsafe fn as_inner(&mut self) -> &mut Self::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.inner) } } } #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -impl Iterator for DedupByKey +unsafe impl InPlaceIterable for Dedup where - I: Iterator, - F: FnMut(&T) -> K, - K: PartialEq, + I: InPlaceIterable, + F: FnMut(&T, &T) -> bool, { - type Item = T; - - fn next(&mut self) -> Option { - let last_item = self.last.as_ref()?; - let mut next = loop { - let curr = self.inner.next(); - if let Some(curr_item) = &curr { - if (self.key)(last_item) != (self.key)(curr_item) { - break curr; - } - } else { - break None; - } - }; - - swap(&mut self.last, &mut next); - next - } - - fn size_hint(&self) -> (usize, Option) { - if self.last.is_some() { - // If we have a last item stored, the iterator can yield at most - // as many items at the inner iterator plus the stored one. Yet we - // can only guarantee that the iterator yields at least one more item - // since all other items in the inner iterator might be duplicates. - let (_, max) = self.inner.size_hint(); - (1, max.and_then(|k| k.checked_add(1))) - } else { - // If the last item we got from the inner iterator is `None`, - // the iterator is empty. - (0, Some(0)) - } - } } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index e40b7e3dad44b..968e9b66f023d 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -68,7 +68,7 @@ pub use self::zip::TrustedRandomAccessNoCoerce; pub use self::zip::zip; #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -pub use self::dedup::{Dedup, DedupBy, DedupByKey}; +pub use self::dedup::{Dedup, ByKey, ByPartialEq}; /// This trait provides transitive access to source-stage in an interator-adapter pipeline /// under the conditions that diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index c0127683046fc..12ccf04ec5b3b 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -424,7 +424,7 @@ pub use self::adapters::{ Skip, SkipWhile, Take, TakeWhile, Zip, }; #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -pub use self::adapters::{Dedup, DedupBy, DedupByKey}; +pub use self::adapters::{Dedup, ByKey, ByPartialEq}; #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::adapters::{Intersperse, IntersperseWith}; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 2757608e49fc3..1c5da30c6f4cb 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -6,7 +6,7 @@ use super::super::try_process; use super::super::ByRefSized; use super::super::TrustedRandomAccessNoCoerce; use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; -use super::super::{Dedup, DedupBy, DedupByKey}; +use super::super::{Dedup, ByKey, ByPartialEq}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; use super::super::{ @@ -1715,12 +1715,12 @@ pub trait Iterator { /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] - fn dedup(self) -> Dedup + fn dedup(self) -> Dedup where Self: Sized, Self::Item: PartialEq, { - Dedup::new(self) + Dedup::new(self, ByPartialEq::new()) } /// Removes all but the first of consecutive elements in the iterator satisfying a given equality @@ -1751,12 +1751,12 @@ pub trait Iterator { /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] - fn dedup_by(self, same_bucket: F) -> DedupBy + fn dedup_by(self, same_bucket: F) -> Dedup where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> bool, { - DedupBy::new(self, same_bucket) + Dedup::new(self, same_bucket) } /// Removes all but the first of consecutive elements in the iterator that @@ -1784,13 +1784,13 @@ pub trait Iterator { /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] - fn dedup_by_key(self, key: F) -> DedupByKey + fn dedup_by_key(self, key: F) -> Dedup, Self::Item> where Self: Sized, F: FnMut(&Self::Item) -> K, K: PartialEq, { - DedupByKey::new(self, key) + Dedup::new(self, ByKey::new(key)) } /// Borrows an iterator, rather than consuming it. From 1a04987c094ce7db6b8121bacd33ebf156a0966a Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Mon, 26 Apr 2021 18:46:01 +0200 Subject: [PATCH 13/24] Run formatter --- library/core/src/iter/adapters/dedup.rs | 6 +----- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/mod.rs | 4 ++-- library/core/src/iter/traits/iterator.rs | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index dbcf9799f0f88..3f11a3e3cf534 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -106,11 +106,7 @@ where { pub(crate) fn new(inner: I, same_bucket: F) -> Self { let mut inner = inner; - Self { - last: inner.next(), - inner, - same_bucket, - } + Self { last: inner.next(), inner, same_bucket } } } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 968e9b66f023d..cb13a8de01a9f 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -68,7 +68,7 @@ pub use self::zip::TrustedRandomAccessNoCoerce; pub use self::zip::zip; #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -pub use self::dedup::{Dedup, ByKey, ByPartialEq}; +pub use self::dedup::{ByKey, ByPartialEq, Dedup}; /// This trait provides transitive access to source-stage in an interator-adapter pipeline /// under the conditions that diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 12ccf04ec5b3b..1cc8f915786cb 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -418,13 +418,13 @@ pub use self::adapters::StepBy; pub use self::adapters::TrustedRandomAccess; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::adapters::TrustedRandomAccessNoCoerce; +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] +pub use self::adapters::{ByKey, ByPartialEq, Dedup}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, Skip, SkipWhile, Take, TakeWhile, Zip, }; -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -pub use self::adapters::{Dedup, ByKey, ByPartialEq}; #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::adapters::{Intersperse, IntersperseWith}; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 1c5da30c6f4cb..5276f041a4cf1 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -5,7 +5,7 @@ use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; use super::super::ByRefSized; use super::super::TrustedRandomAccessNoCoerce; -use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; +use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{Dedup, ByKey, ByPartialEq}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; From 69b18f71117050b5e07c1aa96162539600cb4276 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Fri, 7 May 2021 15:13:53 +0200 Subject: [PATCH 14/24] Added more documentation --- library/core/src/iter/traits/iterator.rs | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 5276f041a4cf1..5a880c8dabf1f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1700,6 +1700,8 @@ pub trait Iterator { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// #![feature(iter_dedup)] /// @@ -1713,6 +1715,15 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), None); /// ``` + /// + /// Example of an infinite loop: + /// + /// ```no_run + /// #![feature(iter_dedup)] + /// + /// // this will never terminate + /// let _ = std::iter::repeat(2).dedup().next(); + /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] fn dedup(self) -> Dedup @@ -1736,6 +1747,8 @@ pub trait Iterator { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// #![feature(iter_dedup)] /// @@ -1749,6 +1762,15 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some("bar")); /// assert_eq!(iter.next(), None); /// ``` + /// + /// Example of an infinite loop: + /// + /// ```no_run + /// #![feature(iter_dedup)] + /// + /// // this will never terminate + /// let _ = std::iter::repeat(2).dedup_by(|a, b| a == b).next(); + /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] fn dedup_by(self, same_bucket: F) -> Dedup @@ -1769,6 +1791,8 @@ pub trait Iterator { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// #![feature(iter_dedup)] /// @@ -1782,6 +1806,15 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some(20)); /// assert_eq!(iter.next(), None); /// ``` + /// + /// Example of an infinite loop: + /// + /// ```no_run + /// #![feature(iter_dedup)] + /// + /// // this will never terminate + /// let _ = std::iter::repeat(2).dedup_by_key(|&n| n).next(); + /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] fn dedup_by_key(self, key: F) -> Dedup, Self::Item> From d8aebea65f83ffb639521ccc734c8920dd2eda0c Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Mon, 10 May 2021 22:49:26 +0200 Subject: [PATCH 15/24] Simplified type signature --- library/core/src/iter/adapters/dedup.rs | 27 +++++++++++++----------- library/core/src/iter/traits/iterator.rs | 6 +++--- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 3f11a3e3cf534..6516ec30780da 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -94,15 +94,18 @@ impl FnMut<(&T, &T)> for ByPartialEq { /// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] -pub struct Dedup { +pub struct Dedup +where + I: Iterator, +{ inner: I, same_bucket: F, - last: Option, + last: Option, } -impl Dedup +impl Dedup where - I: Iterator, + I: Iterator, { pub(crate) fn new(inner: I, same_bucket: F) -> Self { let mut inner = inner; @@ -111,12 +114,12 @@ where } #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -impl Iterator for Dedup +impl Iterator for Dedup where - I: Iterator, - F: FnMut(&T, &T) -> bool, + I: Iterator, + F: FnMut(&I::Item, &I::Item) -> bool, { - type Item = T; + type Item = I::Item; fn next(&mut self) -> Option { let last_item = self.last.as_ref()?; @@ -143,7 +146,7 @@ where } #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -unsafe impl SourceIter for Dedup +unsafe impl SourceIter for Dedup where S: Iterator, I: Iterator + SourceIter, @@ -157,9 +160,9 @@ where } #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -unsafe impl InPlaceIterable for Dedup +unsafe impl InPlaceIterable for Dedup where - I: InPlaceIterable, - F: FnMut(&T, &T) -> bool, + I: InPlaceIterable, + F: FnMut(&I::Item, &I::Item) -> bool, { } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 5a880c8dabf1f..9604935755aad 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1726,7 +1726,7 @@ pub trait Iterator { /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] - fn dedup(self) -> Dedup + fn dedup(self) -> Dedup where Self: Sized, Self::Item: PartialEq, @@ -1773,7 +1773,7 @@ pub trait Iterator { /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] - fn dedup_by(self, same_bucket: F) -> Dedup + fn dedup_by(self, same_bucket: F) -> Dedup where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> bool, @@ -1817,7 +1817,7 @@ pub trait Iterator { /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] - fn dedup_by_key(self, key: F) -> Dedup, Self::Item> + fn dedup_by_key(self, key: F) -> Dedup> where Self: Sized, F: FnMut(&Self::Item) -> K, From 5dec9ce19701fd8ca5f1a5b972a632f4c43d2b88 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Sat, 10 Jul 2021 19:54:53 +0200 Subject: [PATCH 16/24] Defer initial call to next + lots of inline tags --- library/core/src/iter/adapters/dedup.rs | 29 ++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 6516ec30780da..3aa6079955e4a 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -19,6 +19,7 @@ pub struct ByKey { } impl ByKey { + #[inline] pub(crate) fn new(key: F) -> Self { Self { key } } @@ -31,7 +32,7 @@ where K: PartialEq, { type Output = bool; - + #[inline] extern "rust-call" fn call_once(mut self, args: (&T, &T)) -> Self::Output { (self.key)(args.0) == (self.key)(args.1) } @@ -43,6 +44,7 @@ where F: FnMut(&T) -> K, K: PartialEq, { + #[inline] extern "rust-call" fn call_mut(&mut self, args: (&T, &T)) -> Self::Output { (self.key)(args.0) == (self.key)(args.1) } @@ -62,6 +64,7 @@ where pub struct ByPartialEq; impl ByPartialEq { + #[inline] pub(crate) fn new() -> Self { Self } @@ -70,7 +73,7 @@ impl ByPartialEq { #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl FnOnce<(&T, &T)> for ByPartialEq { type Output = bool; - + #[inline] extern "rust-call" fn call_once(self, args: (&T, &T)) -> Self::Output { args.0 == args.1 } @@ -78,6 +81,7 @@ impl FnOnce<(&T, &T)> for ByPartialEq { #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl FnMut<(&T, &T)> for ByPartialEq { + #[inline] extern "rust-call" fn call_mut(&mut self, args: (&T, &T)) -> Self::Output { args.0 == args.1 } @@ -93,23 +97,23 @@ impl FnMut<(&T, &T)> for ByPartialEq { /// [`Iterator::dedup_by`]: Iterator::dedup_by /// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub struct Dedup where I: Iterator, { inner: I, same_bucket: F, - last: Option, + last: Option>, } impl Dedup where I: Iterator, { + #[inline] pub(crate) fn new(inner: I, same_bucket: F) -> Self { - let mut inner = inner; - Self { last: inner.next(), inner, same_bucket } + Self { inner, same_bucket, last: None } } } @@ -121,8 +125,15 @@ where { type Item = I::Item; + #[inline] fn next(&mut self) -> Option { - let last_item = self.last.as_ref()?; + if self.last.is_none() { + self.last = Some(self.inner.next()) + } + + let last = self.last.as_mut().unwrap(); + let last_item = last.as_ref()?; + let mut next = loop { let curr = self.inner.next(); if let Some(curr_item) = &curr { @@ -134,10 +145,11 @@ where } }; - swap(&mut self.last, &mut next); + swap(last, &mut next); next } + #[inline] fn size_hint(&self) -> (usize, Option) { let min = self.last.as_ref().map(|_| 1).unwrap_or(0); let max = self.inner.size_hint().1; @@ -153,6 +165,7 @@ where { type Source = S; + #[inline] unsafe fn as_inner(&mut self) -> &mut Self::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.inner) } From 6cd757afab607b7cffe86a0d6896e99ccd6f7bd9 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Wed, 14 Jul 2021 16:39:22 +0200 Subject: [PATCH 17/24] Make use of `Option::unwrap_unchecked` and prevent user from contructing `ByPartialEq` --- library/core/src/iter/adapters/dedup.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 3aa6079955e4a..4148a82d8e231 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -1,7 +1,4 @@ -use crate::{ - iter::{InPlaceIterable, SourceIter}, - mem::swap, -}; +use crate::iter::{InPlaceIterable, SourceIter}; /// A wrapper type around a key function. /// @@ -61,6 +58,7 @@ where /// [`Iterator::dedup`]: Iterator::dedup #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] +#[non_exhaustive] pub struct ByPartialEq; impl ByPartialEq { @@ -131,9 +129,9 @@ where self.last = Some(self.inner.next()) } - let last = self.last.as_mut().unwrap(); + // Safety: the above if statement ensures that `self.last` is always `Some` + let last = unsafe { self.last.as_mut().unwrap_unchecked() }; let last_item = last.as_ref()?; - let mut next = loop { let curr = self.inner.next(); if let Some(curr_item) = &curr { @@ -145,7 +143,7 @@ where } }; - swap(last, &mut next); + crate::mem::swap(last, &mut next); next } From fcbff0425bbbb8d4850eead169f5c855158a9617 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Wed, 14 Jul 2021 18:01:37 +0200 Subject: [PATCH 18/24] Update library/core/src/iter/adapters/dedup.rs Co-authored-by: Cameron Steffen --- library/core/src/iter/adapters/dedup.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 4148a82d8e231..87cab5bf70336 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -149,8 +149,8 @@ where #[inline] fn size_hint(&self) -> (usize, Option) { - let min = self.last.as_ref().map(|_| 1).unwrap_or(0); - let max = self.inner.size_hint().1; + let min = matches!(self.last, Some(Some(_))).into(); + let max = self.inner.size_hint().1.map(|max| max + min); (min, max) } } From 9a906dd6d71d11623de7e749e4c9517e550ba77f Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Wed, 14 Jul 2021 18:10:55 +0200 Subject: [PATCH 19/24] Refactor `Dedup::next` as suggested by @camsteffen --- library/core/src/iter/adapters/dedup.rs | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 87cab5bf70336..7d32634365ede 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -125,26 +125,11 @@ where #[inline] fn next(&mut self) -> Option { - if self.last.is_none() { - self.last = Some(self.inner.next()) - } - - // Safety: the above if statement ensures that `self.last` is always `Some` - let last = unsafe { self.last.as_mut().unwrap_unchecked() }; + let Self { inner, last, same_bucket } = self; + let last = last.get_or_insert_with(|| inner.next()); let last_item = last.as_ref()?; - let mut next = loop { - let curr = self.inner.next(); - if let Some(curr_item) = &curr { - if !(self.same_bucket)(last_item, curr_item) { - break curr; - } - } else { - break None; - } - }; - - crate::mem::swap(last, &mut next); - next + let next = inner.find(|next_item| !(same_bucket)(last_item, next_item)); + crate::mem::replace(last, next) } #[inline] From 3fbbfdb8ba05ecb6f6cd473acd1e534f639d59cd Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Fri, 30 Jul 2021 17:17:21 +0200 Subject: [PATCH 20/24] whoops --- library/core/src/iter/traits/iterator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 9604935755aad..b98ca813b3a52 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -6,7 +6,7 @@ use super::super::try_process; use super::super::ByRefSized; use super::super::TrustedRandomAccessNoCoerce; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; -use super::super::{Dedup, ByKey, ByPartialEq}; +use super::super::{ByKey, ByPartialEq, Dedup}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; use super::super::{ From 9648fb51cec69a467bb2fc8b2ad3e963957cb409 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Tue, 25 Jan 2022 15:59:55 +0100 Subject: [PATCH 21/24] Update library/core/src/iter/adapters/dedup.rs Co-authored-by: Anders Kaseorg --- library/core/src/iter/adapters/dedup.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 7d32634365ede..f97b962b5cc68 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -128,7 +128,7 @@ where let Self { inner, last, same_bucket } = self; let last = last.get_or_insert_with(|| inner.next()); let last_item = last.as_ref()?; - let next = inner.find(|next_item| !(same_bucket)(last_item, next_item)); + let next = inner.find(|next_item| !(same_bucket)(next_item, last_item)); crate::mem::replace(last, next) } From 67d01d5f1a905d2fcad1f4b0bfab3cd0632046fd Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Sat, 26 Feb 2022 15:55:20 +0100 Subject: [PATCH 22/24] Fix inplace_iteration related impls --- library/core/src/iter/adapters/dedup.rs | 23 ++++++++--------------- library/core/src/iter/traits/iterator.rs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index f97b962b5cc68..137c9962af060 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -1,3 +1,5 @@ +#![unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] + use crate::iter::{InPlaceIterable, SourceIter}; /// A wrapper type around a key function. @@ -9,7 +11,6 @@ use crate::iter::{InPlaceIterable, SourceIter}; /// See its documentation for more. /// /// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] pub struct ByKey { key: F, @@ -22,7 +23,6 @@ impl ByKey { } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl FnOnce<(&T, &T)> for ByKey where F: FnMut(&T) -> K, @@ -35,7 +35,6 @@ where } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl FnMut<(&T, &T)> for ByKey where F: FnMut(&T) -> K, @@ -56,7 +55,6 @@ where /// See its documentation for more. /// /// [`Iterator::dedup`]: Iterator::dedup -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone, Copy)] #[non_exhaustive] pub struct ByPartialEq; @@ -68,7 +66,6 @@ impl ByPartialEq { } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl FnOnce<(&T, &T)> for ByPartialEq { type Output = bool; #[inline] @@ -77,7 +74,6 @@ impl FnOnce<(&T, &T)> for ByPartialEq { } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl FnMut<(&T, &T)> for ByPartialEq { #[inline] extern "rust-call" fn call_mut(&mut self, args: (&T, &T)) -> Self::Output { @@ -94,7 +90,6 @@ impl FnMut<(&T, &T)> for ByPartialEq { /// [`Iterator::dedup`]: Iterator::dedup /// [`Iterator::dedup_by`]: Iterator::dedup_by /// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[derive(Debug, Clone)] pub struct Dedup where @@ -115,7 +110,6 @@ where } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] impl Iterator for Dedup where I: Iterator, @@ -140,22 +134,21 @@ where } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -unsafe impl SourceIter for Dedup +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Dedup where - S: Iterator, - I: Iterator + SourceIter, + I: SourceIter + Iterator, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut Self::Source { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.inner) } } } -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] +#[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl InPlaceIterable for Dedup where I: InPlaceIterable, diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index b98ca813b3a52..d1557c8c830a6 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1690,8 +1690,8 @@ pub trait Iterator { Inspect::new(self, f) } - /// Removes all but the first of consecutive elements in the iterator according to the - /// [`PartialEq`] trait implementation. + /// Removes all but the first of consecutive repeated elements in the iterator + /// according to the [`PartialEq`] trait implementation. /// /// For an iterator yielding infinitely many consecutive duplicates, /// this may result in an infinite loop. @@ -1734,11 +1734,11 @@ pub trait Iterator { Dedup::new(self, ByPartialEq::new()) } - /// Removes all but the first of consecutive elements in the iterator satisfying a given equality - /// relation. + /// Removes all but the first of consecutive elements in the iterator + /// satisfying a given equality relation. /// - /// The `same_bucket` function is passed a references to two elements from the iterator and - /// must determine if the elements compare equal. + /// The `same_bucket` function is passed a references to two elements from + /// the iterator and must determine if the elements compare equal. /// /// For an iterator yielding infinitely many consecutive duplicates, /// this may result in an infinite loop. @@ -1781,8 +1781,8 @@ pub trait Iterator { Dedup::new(self, same_bucket) } - /// Removes all but the first of consecutive elements in the iterator that - /// resolve to the same key. + /// Removes all but the first of consecutive elements in the iterator + /// that resolve to the same key. /// /// For an iterator yielding infinitely many consecutive duplicates, /// this may result in an infinite loop. From a822aad9c7ff97938950f080cee369a36ff367e8 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Mon, 22 Aug 2022 01:17:39 +0200 Subject: [PATCH 23/24] Go back to separate iterators --- library/core/src/iter/adapters/dedup.rs | 188 ++++++++++++++++------- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/mod.rs | 4 +- library/core/src/iter/traits/iterator.rs | 14 +- 4 files changed, 139 insertions(+), 69 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index 137c9962af060..a16f31d23d5ee 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -2,127 +2,195 @@ use crate::iter::{InPlaceIterable, SourceIter}; -/// A wrapper type around a key function. -/// -/// This struct acts like a function which given a key function returns true -/// if and only if both arguments evaluate to the same key. +/// An iterator that removes all but the first of consecutive elements in a +/// given iterator according to the [`PartialEq`] trait implementation. /// -/// This `struct` is created by [`Iterator::dedup_by_key`]. +/// This `struct` is created by [`Iterator::dedup`]. /// See its documentation for more. /// -/// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key -#[derive(Debug, Clone, Copy)] -pub struct ByKey { - key: F, +/// [`Iterator::dedup`]: Iterator::dedup +#[derive(Debug, Clone)] +pub struct Dedup +where + I: Iterator, +{ + inner: I, + last: Option>, } -impl ByKey { +impl Dedup +where + I: Iterator, +{ #[inline] - pub(crate) fn new(key: F) -> Self { - Self { key } + pub(crate) fn new(inner: I) -> Self { + Self { inner, last: None } } } -impl FnOnce<(&T, &T)> for ByKey +impl Iterator for Dedup where - F: FnMut(&T) -> K, - K: PartialEq, + I: Iterator, + I::Item: PartialEq, { - type Output = bool; + type Item = I::Item; + #[inline] - extern "rust-call" fn call_once(mut self, args: (&T, &T)) -> Self::Output { - (self.key)(args.0) == (self.key)(args.1) + fn next(&mut self) -> Option { + let Self { inner, last } = self; + let last = last.get_or_insert_with(|| inner.next()); + let last_item = last.as_ref()?; + let next = inner.find(|next_item| next_item != last_item); + crate::mem::replace(last, next) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let min = matches!(self.last, Some(Some(_))).into(); + let max = self.inner.size_hint().1.map(|max| max + min); + (min, max) } } -impl FnMut<(&T, &T)> for ByKey +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Dedup where - F: FnMut(&T) -> K, - K: PartialEq, + I: SourceIter + Iterator, { + type Source = I::Source; + #[inline] - extern "rust-call" fn call_mut(&mut self, args: (&T, &T)) -> Self::Output { - (self.key)(args.0) == (self.key)(args.1) + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.inner) } } } -/// A zero-sized type for checking partial equality. -/// -/// This struct acts exactly like the function [`PartialEq::eq`], but its -/// type is always known during compile time. +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Dedup +where + I: Iterator, + I: InPlaceIterable, + I::Item: PartialEq, +{ +} + +/// An iterator that removes all but the first of consecutive elements in a +/// given iterator satisfying a given equality relation. /// -/// This `struct` is created by [`Iterator::dedup`]. +/// This `struct` is created by [`Iterator::dedup_by`]. /// See its documentation for more. /// -/// [`Iterator::dedup`]: Iterator::dedup -#[derive(Debug, Clone, Copy)] -#[non_exhaustive] -pub struct ByPartialEq; +/// [`Iterator::dedup_by`]: Iterator::dedup_by +#[derive(Debug, Clone)] +pub struct DedupBy +where + I: Iterator, +{ + inner: I, + same_bucket: F, + last: Option>, +} -impl ByPartialEq { +impl DedupBy +where + I: Iterator, +{ #[inline] - pub(crate) fn new() -> Self { - Self + pub(crate) fn new(inner: I, same_bucket: F) -> Self { + Self { inner, same_bucket, last: None } } } -impl FnOnce<(&T, &T)> for ByPartialEq { - type Output = bool; +impl Iterator for DedupBy +where + I: Iterator, + F: FnMut(&I::Item, &I::Item) -> bool, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + let Self { inner, last, same_bucket } = self; + let last = last.get_or_insert_with(|| inner.next()); + let last_item = last.as_ref()?; + let next = inner.find(|next_item| !(same_bucket)(next_item, last_item)); + crate::mem::replace(last, next) + } + #[inline] - extern "rust-call" fn call_once(self, args: (&T, &T)) -> Self::Output { - args.0 == args.1 + fn size_hint(&self) -> (usize, Option) { + let min = matches!(self.last, Some(Some(_))).into(); + let max = self.inner.size_hint().1.map(|max| max + min); + (min, max) } } -impl FnMut<(&T, &T)> for ByPartialEq { +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for DedupBy +where + I: SourceIter + Iterator, +{ + type Source = I::Source; + #[inline] - extern "rust-call" fn call_mut(&mut self, args: (&T, &T)) -> Self::Output { - args.0 == args.1 + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.inner) } } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for DedupBy +where + I: InPlaceIterable, + F: FnMut(&I::Item, &I::Item) -> bool, +{ +} + /// An iterator that removes all but the first of consecutive elements in a -/// given iterator satisfying a given equality relation. +/// given iterator that resolve to the same key. /// -/// This `struct` is created by [`Iterator::dedup`], [`Iterator::dedup_by`] -/// and [`Iterator::dedup_by_key`]. See its documentation for more. +/// This `struct` is created by [`Iterator::dedup_by_key`]. +/// See its documentation for more. /// -/// [`Iterator::dedup`]: Iterator::dedup -/// [`Iterator::dedup_by`]: Iterator::dedup_by /// [`Iterator::dedup_by_key`]: Iterator::dedup_by_key #[derive(Debug, Clone)] -pub struct Dedup +pub struct DedupByKey where I: Iterator, + F: FnMut(&I::Item) -> K, { inner: I, - same_bucket: F, + key: F, last: Option>, } -impl Dedup +impl DedupByKey where I: Iterator, + F: FnMut(&I::Item) -> K, { #[inline] - pub(crate) fn new(inner: I, same_bucket: F) -> Self { - Self { inner, same_bucket, last: None } + pub(crate) fn new(inner: I, key: F) -> Self { + Self { inner, key, last: None } } } -impl Iterator for Dedup +impl Iterator for DedupByKey where I: Iterator, - F: FnMut(&I::Item, &I::Item) -> bool, + F: FnMut(&I::Item) -> K, + K: PartialEq, { type Item = I::Item; #[inline] fn next(&mut self) -> Option { - let Self { inner, last, same_bucket } = self; + let Self { inner, last, key } = self; let last = last.get_or_insert_with(|| inner.next()); let last_item = last.as_ref()?; - let next = inner.find(|next_item| !(same_bucket)(next_item, last_item)); + let next = inner.find(|next_item| key(next_item) != key(last_item)); crate::mem::replace(last, next) } @@ -135,9 +203,10 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Dedup +unsafe impl SourceIter for DedupByKey where I: SourceIter + Iterator, + F: FnMut(&I::Item) -> K, { type Source = I::Source; @@ -149,9 +218,10 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Dedup +unsafe impl InPlaceIterable for DedupByKey where I: InPlaceIterable, - F: FnMut(&I::Item, &I::Item) -> bool, + F: FnMut(&I::Item) -> K, + K: PartialEq, { } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index cb13a8de01a9f..e40b7e3dad44b 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -68,7 +68,7 @@ pub use self::zip::TrustedRandomAccessNoCoerce; pub use self::zip::zip; #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -pub use self::dedup::{ByKey, ByPartialEq, Dedup}; +pub use self::dedup::{Dedup, DedupBy, DedupByKey}; /// This trait provides transitive access to source-stage in an interator-adapter pipeline /// under the conditions that diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 1cc8f915786cb..c0127683046fc 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -418,13 +418,13 @@ pub use self::adapters::StepBy; pub use self::adapters::TrustedRandomAccess; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::adapters::TrustedRandomAccessNoCoerce; -#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -pub use self::adapters::{ByKey, ByPartialEq, Dedup}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, Skip, SkipWhile, Take, TakeWhile, Zip, }; +#[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] +pub use self::adapters::{Dedup, DedupBy, DedupByKey}; #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::adapters::{Intersperse, IntersperseWith}; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d1557c8c830a6..d5b065bfb7320 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -5,8 +5,8 @@ use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; use super::super::ByRefSized; use super::super::TrustedRandomAccessNoCoerce; -use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; -use super::super::{ByKey, ByPartialEq, Dedup}; +use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; +use super::super::{Dedup, DedupBy, DedupByKey}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; use super::super::{ @@ -1726,12 +1726,12 @@ pub trait Iterator { /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] - fn dedup(self) -> Dedup + fn dedup(self) -> Dedup where Self: Sized, Self::Item: PartialEq, { - Dedup::new(self, ByPartialEq::new()) + Dedup::new(self) } /// Removes all but the first of consecutive elements in the iterator @@ -1773,7 +1773,7 @@ pub trait Iterator { /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] - fn dedup_by(self, same_bucket: F) -> Dedup + fn dedup_by(self, same_bucket: F) -> DedupBy where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> bool, @@ -1817,13 +1817,13 @@ pub trait Iterator { /// ``` #[unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] #[inline] - fn dedup_by_key(self, key: F) -> Dedup> + fn dedup_by_key(self, key: F) -> DedupByKey where Self: Sized, F: FnMut(&Self::Item) -> K, K: PartialEq, { - Dedup::new(self, ByKey::new(key)) + Dedup::new(self, key) } /// Borrows an iterator, rather than consuming it. From f57678c71e7e87e1a4ddf59b58da7cd210a12b46 Mon Sep 17 00:00:00 2001 From: Aaron Bies <48803074+slerpyyy@users.noreply.github.com> Date: Mon, 22 Aug 2022 10:42:15 +0200 Subject: [PATCH 24/24] Remove inplace_iteration traits because of ICE --- library/core/src/iter/adapters/dedup.rs | 71 ------------------------ library/core/src/iter/traits/iterator.rs | 4 +- 2 files changed, 2 insertions(+), 73 deletions(-) diff --git a/library/core/src/iter/adapters/dedup.rs b/library/core/src/iter/adapters/dedup.rs index a16f31d23d5ee..5113d8534e825 100644 --- a/library/core/src/iter/adapters/dedup.rs +++ b/library/core/src/iter/adapters/dedup.rs @@ -1,7 +1,5 @@ #![unstable(feature = "iter_dedup", reason = "recently added", issue = "83748")] -use crate::iter::{InPlaceIterable, SourceIter}; - /// An iterator that removes all but the first of consecutive elements in a /// given iterator according to the [`PartialEq`] trait implementation. /// @@ -52,29 +50,6 @@ where } } -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Dedup -where - I: SourceIter + Iterator, -{ - type Source = I::Source; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut I::Source { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.inner) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for Dedup -where - I: Iterator, - I: InPlaceIterable, - I::Item: PartialEq, -{ -} - /// An iterator that removes all but the first of consecutive elements in a /// given iterator satisfying a given equality relation. /// @@ -126,28 +101,6 @@ where } } -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for DedupBy -where - I: SourceIter + Iterator, -{ - type Source = I::Source; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut I::Source { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.inner) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for DedupBy -where - I: InPlaceIterable, - F: FnMut(&I::Item, &I::Item) -> bool, -{ -} - /// An iterator that removes all but the first of consecutive elements in a /// given iterator that resolve to the same key. /// @@ -201,27 +154,3 @@ where (min, max) } } - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for DedupByKey -where - I: SourceIter + Iterator, - F: FnMut(&I::Item) -> K, -{ - type Source = I::Source; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut I::Source { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - unsafe { SourceIter::as_inner(&mut self.inner) } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for DedupByKey -where - I: InPlaceIterable, - F: FnMut(&I::Item) -> K, - K: PartialEq, -{ -} diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d5b065bfb7320..6359989337287 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1778,7 +1778,7 @@ pub trait Iterator { Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> bool, { - Dedup::new(self, same_bucket) + DedupBy::new(self, same_bucket) } /// Removes all but the first of consecutive elements in the iterator @@ -1823,7 +1823,7 @@ pub trait Iterator { F: FnMut(&Self::Item) -> K, K: PartialEq, { - Dedup::new(self, key) + DedupByKey::new(self, key) } /// Borrows an iterator, rather than consuming it.