Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ca3a6f7

Browse files
committedJan 2, 2025
Add experimental Iterator::contains
1 parent eeeff9a commit ca3a6f7

File tree

5 files changed

+52
-0
lines changed

5 files changed

+52
-0
lines changed
 

‎library/core/src/iter/traits/iterator.rs

+33
Original file line numberDiff line numberDiff line change
@@ -2770,6 +2770,39 @@ pub trait Iterator {
27702770
self.try_fold((), check(f)) == ControlFlow::Break(())
27712771
}
27722772

2773+
/// Tests whether a value is contained in the iterator.
2774+
///
2775+
/// `contains()` is short-circuiting; in other words, it will stop processing
2776+
/// as soon as the function finds the item in the `Iterator`.
2777+
///
2778+
/// This method checks the whole iterator, which is O(n). If the iterator is a sorted
2779+
/// slice, [`binary_search`](slice::binary_search) may be faster. If this is an iterator
2780+
/// on collections that have a `.contains()` or `.contains_key()` method (such as
2781+
/// `HashMap` or `BtreeSet`, using those methods directly will be faster.
2782+
///
2783+
/// # Examples
2784+
/// Basic usage:
2785+
/// ```
2786+
/// #![feature(iter_contains)]
2787+
/// assert_eq!(true, [1, 2, 3].iter().contains(2));
2788+
/// assert_eq!(false, [1, 2, 3].iter().contains(5));
2789+
/// ```
2790+
/// [`Iterator::contains`] can be used where [`slice::contains`] cannot be used:
2791+
/// ```
2792+
/// #![feature(iter_contains)]
2793+
/// let s = [String::from("a"), String::from("b"), String::from("c")];
2794+
/// assert_eq!(s.iter().contains("b"), s.iter().any(|e| e == "b"));
2795+
/// ```
2796+
#[inline]
2797+
#[unstable(feature = "iter_contains", reason = "new API", issue = "127494")]
2798+
fn contains<Q: ?Sized>(&mut self, item: Q) -> bool
2799+
where
2800+
Q: PartialEq<Self::Item>,
2801+
Self: Sized,
2802+
{
2803+
self.any(|elem| item == elem)
2804+
}
2805+
27732806
/// Searches for an element of an iterator that satisfies a predicate.
27742807
///
27752808
/// `find()` takes a closure that returns `true` or `false`. It applies

‎library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
#![feature(internal_impls_macro)]
119119
#![feature(ip)]
120120
#![feature(is_ascii_octdigit)]
121+
#![feature(iter_contains)]
121122
#![feature(lazy_get)]
122123
#![feature(link_cfg)]
123124
#![feature(non_null_from_ref)]

‎library/core/src/str/iter.rs

+7
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,13 @@ impl Iterator for Bytes<'_> {
331331
self.0.any(f)
332332
}
333333

334+
fn contains<Q: ?Sized>(&mut self, item: Q) -> bool
335+
where
336+
Q: PartialEq<Self::Item>,
337+
{
338+
self.0.contains(item)
339+
}
340+
334341
#[inline]
335342
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
336343
where

‎library/core/tests/iter/traits/iterator.rs

+10
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,16 @@ fn test_any() {
271271
assert!(!v.iter().any(|&x| x > 100));
272272
assert!(!v[..0].iter().any(|_| panic!()));
273273
}
274+
#[test]
275+
fn test_iterator_contains() {
276+
let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]);
277+
assert_eq!(true, v.iter().contains(&3));
278+
assert_eq!(v.iter().contains(&3), v.iter().any(|&x| x == 3));
279+
assert_eq!(false, v.iter().contains(&10));
280+
assert_eq!(v.iter().contains(&10), v.iter().any(|&x| x == 10));
281+
assert_eq!(true, Iterator::contains(&mut (1isize..=5), 3));
282+
assert_eq!(false, Iterator::contains(&mut (1isize..=5), 10));
283+
}
274284

275285
#[test]
276286
fn test_find() {

‎library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#![feature(iter_array_chunks)]
4848
#![feature(iter_chain)]
4949
#![feature(iter_collect_into)]
50+
#![feature(iter_contains)]
5051
#![feature(iter_intersperse)]
5152
#![feature(iter_is_partitioned)]
5253
#![feature(iter_map_windows)]

0 commit comments

Comments
 (0)
Failed to load comments.