From d7b8f46909e5b0c3f7d7d2ed22f1e9467c028197 Mon Sep 17 00:00:00 2001 From: Dominic Gerhauser Date: Thu, 2 Jan 2025 10:54:23 +0100 Subject: [PATCH] Add experimental Iterator::contains --- library/core/src/iter/traits/iterator.rs | 33 +++++++++++++++++++ library/core/src/lib.rs | 1 + library/core/src/str/iter.rs | 7 ++++ .../coretests/tests/iter/traits/iterator.rs | 10 ++++++ library/coretests/tests/lib.rs | 1 + 5 files changed, 52 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 10ae43ac3fcd5..daaceb5ddcee0 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2779,6 +2779,39 @@ pub trait Iterator { self.try_fold((), check(f)) == ControlFlow::Break(()) } + /// Tests whether a value is contained in the iterator. + /// + /// `contains()` is short-circuiting; in other words, it will stop processing + /// as soon as the function finds the item in the `Iterator`. + /// + /// This method checks the whole iterator, which is O(n). If the iterator is a sorted + /// slice, [`binary_search`](slice::binary_search) may be faster. If this is an iterator + /// on collections that have a `.contains()` or `.contains_key()` method (such as + /// `HashMap` or `BtreeSet`), using those methods directly will be faster. + /// + /// # Examples + /// Basic usage: + /// ``` + /// #![feature(iter_contains)] + /// assert_eq!(true, [1, 2, 3].iter().contains(2)); + /// assert_eq!(false, [1, 2, 3].iter().contains(5)); + /// ``` + /// [`Iterator::contains`] can be used where [`slice::contains`] cannot be used: + /// ``` + /// #![feature(iter_contains)] + /// let s = [String::from("a"), String::from("b"), String::from("c")]; + /// assert_eq!(s.iter().contains("b"), s.iter().any(|e| e == "b")); + /// ``` + #[inline] + #[unstable(feature = "iter_contains", reason = "new API", issue = "127494")] + fn contains(&mut self, item: Q) -> bool + where + Q: PartialEq, + Self: Sized, + { + self.any(|elem| item == elem) + } + /// Searches for an element of an iterator that satisfies a predicate. /// /// `find()` takes a closure that returns `true` or `false`. It applies diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6e058069756f0..8b1c3686b668e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -122,6 +122,7 @@ #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] +#![feature(iter_contains)] #![feature(lazy_get)] #![feature(link_cfg)] #![feature(non_null_from_ref)] diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 425c4eaee28ee..77fb1955ee153 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -331,6 +331,13 @@ impl Iterator for Bytes<'_> { self.0.any(f) } + fn contains(&mut self, item: Q) -> bool + where + Q: PartialEq, + { + self.0.contains(item) + } + #[inline] fn find

(&mut self, predicate: P) -> Option where diff --git a/library/coretests/tests/iter/traits/iterator.rs b/library/coretests/tests/iter/traits/iterator.rs index e31d2e15b6d7e..bfe2b4c82c64e 100644 --- a/library/coretests/tests/iter/traits/iterator.rs +++ b/library/coretests/tests/iter/traits/iterator.rs @@ -271,6 +271,16 @@ fn test_any() { assert!(!v.iter().any(|&x| x > 100)); assert!(!v[..0].iter().any(|_| panic!())); } +#[test] +fn test_iterator_contains() { + let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); + assert_eq!(true, v.iter().contains(&3)); + assert_eq!(v.iter().contains(&3), v.iter().any(|&x| x == 3)); + assert_eq!(false, v.iter().contains(&10)); + assert_eq!(v.iter().contains(&10), v.iter().any(|&x| x == 10)); + assert_eq!(true, Iterator::contains(&mut (1isize..=5), 3)); + assert_eq!(false, Iterator::contains(&mut (1isize..=5), 10)); +} #[test] fn test_find() { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 79022fec8a20c..826f922b6ef0d 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -49,6 +49,7 @@ #![feature(iter_array_chunks)] #![feature(iter_chain)] #![feature(iter_collect_into)] +#![feature(iter_contains)] #![feature(iter_intersperse)] #![feature(iter_is_partitioned)] #![feature(iter_map_windows)]