Skip to content

add Iterator::contains #141994

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2826,6 +2826,43 @@ 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!([1, 2, 3].iter().contains(&2));
/// assert!(![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!(s.iter().contains("b"));
/// ```
#[inline]
#[unstable(feature = "iter_contains", issue = "127494")]
fn contains<Q>(&mut self, item: Q) -> bool
where
Q: PartialEq<Self::Item> + ?Sized,
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
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
#![feature(internal_impls_macro)]
#![feature(ip)]
#![feature(is_ascii_octdigit)]
#![feature(iter_contains)]
#![feature(lazy_get)]
#![feature(link_cfg)]
#![feature(offset_of_enum)]
Expand Down
8 changes: 8 additions & 0 deletions library/core/src/str/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,14 @@ impl Iterator for Bytes<'_> {
self.0.any(f)
}

#[inline]
fn contains<Q>(&mut self, item: Q) -> bool
where
Q: PartialEq<Self::Item> + ?Sized,
{
self.0.contains(item)
}

#[inline]
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where
Expand Down
11 changes: 11 additions & 0 deletions library/coretests/tests/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,17 @@ fn test_any() {
assert!(!v[..0].iter().any(|_| panic!()));
}

#[test]
fn test_iterator_contains() {
let v: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
assert!(v.iter().contains(&3));
assert_eq!(v.iter().contains(&3), v.iter().any(|&x| x == 3));
assert!(!v.iter().contains(&10));
assert_eq!(v.iter().contains(&10), v.iter().any(|&x| x == 10));
assert!(Iterator::contains(&mut (1..=5), 3));
assert!(!Iterator::contains(&mut (1..=5), 10));
}

#[test]
fn test_find() {
let v: &[isize] = &[1, 3, 9, 27, 103, 14, 11];
Expand Down
1 change: 1 addition & 0 deletions library/coretests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,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)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ fn augment_references_with_imports(
fn find_assignment_usage(name: &ast::NameLike) -> Option<ast::Expr> {
let bin_expr = name.syntax().ancestors().find_map(ast::BinExpr::cast)?;

if !bin_expr.lhs()?.syntax().descendants().contains(name.syntax()) {
if !Itertools::contains(&mut bin_expr.lhs()?.syntax().descendants(), name.syntax()) {
cov_mark::hit!(dont_assign_incorrect_ref);
return None;
}
Expand Down Expand Up @@ -444,7 +444,7 @@ fn find_method_call_expr_usage(name: &ast::NameLike) -> Option<ast::Expr> {
let method_call = name.syntax().ancestors().find_map(ast::MethodCallExpr::cast)?;
let receiver = method_call.receiver()?;

if !receiver.syntax().descendants().contains(name.syntax()) {
if !Itertools::contains(&mut receiver.syntax().descendants(), name.syntax()) {
return None;
}

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/suggestions/deref-path-method.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn main() {
let vec = Vec::new();
Vec::contains(&vec, &0);
//~^ ERROR no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope
//~^ ERROR `Vec<_, _>` is not an iterator
//~| HELP the function `contains` is implemented on `[_]`
}
7 changes: 5 additions & 2 deletions tests/ui/suggestions/deref-path-method.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0599]: no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope
error[E0599]: `Vec<_, _>` is not an iterator
--> $DIR/deref-path-method.rs:3:10
|
LL | Vec::contains(&vec, &0);
| ^^^^^^^^ function or associated item not found in `Vec<_, _>`
| ^^^^^^^^ `Vec<_, _>` is not an iterator
|
note: if you're trying to build a new `Vec<_, _>` consider using one of the following associated functions:
Vec::<T>::new
Expand All @@ -11,6 +11,9 @@ note: if you're trying to build a new `Vec<_, _>` consider using one of the foll
Vec::<T>::from_raw_parts
and 6 others
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
= note: the following trait bounds were not satisfied:
`Vec<_, _>: Iterator`
which is required by `&mut Vec<_, _>: Iterator`
help: the function `contains` is implemented on `[_]`
|
LL - Vec::contains(&vec, &0);
Expand Down
Loading