diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 91c3a4b29b539..b3e959cd82282 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2770,6 +2770,39 @@ pub trait Iterator { self.try_fold((), check(f)) == ControlFlow::Break(()) } + /// Returns `true` if the iterator contains a value. + /// + /// `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 e31957a1fa703..bd271e5b1f600 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -118,6 +118,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/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 830debe02ea2b..a22b9b48c15f7 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -289,6 +289,16 @@ macro_rules! iterator { false } + fn contains(&mut self, item: Q) -> bool + where + Q: PartialEq, + Self: Sized, + { + // specialize + self.any(|elem|item == elem) + + } + // We override the default implementation, which uses `try_fold`, // because this simple implementation generates less LLVM IR and is // faster to compile. 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/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs index e31d2e15b6d7e..06edf2d16b43b 100644 --- a/library/core/tests/iter/traits/iterator.rs +++ b/library/core/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 (1..=5), 3)); + assert_eq!(false, Iterator::contains(&mut (1..=5), 10)); +} #[test] fn test_find() {