Auto merge of #104455 - the8472:dont-drain-on-drop, r=Amanieu
Don't drain-on-drop in DrainFilter impls of various collections. This removes drain-on-drop behavior from various unstable DrainFilter impls (not yet for HashSet/Map) because that behavior [is problematic](https://github.com/rust-lang/rust/issues/43244#issuecomment-641638196) (because it can lead to panic-in-drop when user closures panic) and may become forbidden if [this draft RFC passes](https://github.com/rust-lang/rfcs/pull/3288). closes #101122 [ACP](https://github.com/rust-lang/libs-team/issues/136) affected tracking issues * #43244 * #70530 * #59618 Related hashbrown update: https://github.com/rust-lang/hashbrown/pull/374
This commit is contained in:
commit
6ee4265ca6
43 changed files with 449 additions and 577 deletions
17
Cargo.lock
17
Cargo.lock
|
@ -65,6 +65,12 @@ dependencies = [
|
||||||
"rand_xorshift",
|
"rand_xorshift",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "allocator-api2"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4f263788a35611fba42eb41ff811c5d0360c58b97402570312a350736e2542e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ammonia"
|
name = "ammonia"
|
||||||
version = "3.2.0"
|
version = "3.2.0"
|
||||||
|
@ -1522,6 +1528,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
|
checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash 0.8.2",
|
"ahash 0.8.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||||
|
dependencies = [
|
||||||
|
"allocator-api2",
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"rustc-std-workspace-alloc",
|
"rustc-std-workspace-alloc",
|
||||||
"rustc-std-workspace-core",
|
"rustc-std-workspace-core",
|
||||||
|
@ -4633,7 +4648,7 @@ dependencies = [
|
||||||
"core",
|
"core",
|
||||||
"dlmalloc",
|
"dlmalloc",
|
||||||
"fortanix-sgx-abi",
|
"fortanix-sgx-abi",
|
||||||
"hashbrown 0.13.1",
|
"hashbrown 0.14.0",
|
||||||
"hermit-abi 0.3.0",
|
"hermit-abi 0.3.0",
|
||||||
"libc",
|
"libc",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
#![feature(array_windows)]
|
#![feature(array_windows)]
|
||||||
#![feature(drain_filter)]
|
#![feature(extract_if)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
@ -1399,7 +1399,7 @@ impl HandlerInner {
|
||||||
!self.emitted_diagnostics.insert(diagnostic_hash)
|
!self.emitted_diagnostics.insert(diagnostic_hash)
|
||||||
};
|
};
|
||||||
|
|
||||||
diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
|
diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {});
|
||||||
|
|
||||||
self.emitter.emit_diagnostic(diagnostic);
|
self.emitter.emit_diagnostic(diagnostic);
|
||||||
if diagnostic.is_error() {
|
if diagnostic.is_error() {
|
||||||
|
|
|
@ -59,8 +59,6 @@ This API is completely unstable and subject to change.
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(control_flow_enum)]
|
#![feature(control_flow_enum)]
|
||||||
#![feature(drain_filter)]
|
|
||||||
#![feature(hash_drain_filter)]
|
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(is_sorted)]
|
#![feature(is_sorted)]
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
|
|
|
@ -753,20 +753,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.drain_filter(|error| {
|
errors.retain(|error| {
|
||||||
let Error::Invalid(
|
let Error::Invalid(
|
||||||
provided_idx,
|
provided_idx,
|
||||||
expected_idx,
|
expected_idx,
|
||||||
Compatibility::Incompatible(Some(e)),
|
Compatibility::Incompatible(Some(e)),
|
||||||
) = error else { return false };
|
) = error else { return true };
|
||||||
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
|
let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
|
||||||
let trace =
|
let trace =
|
||||||
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
|
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
|
||||||
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
|
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
|
||||||
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
|
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
false
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
// We're done if we found errors, but we already emitted them.
|
// We're done if we found errors, but we already emitted them.
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
#![feature(control_flow_enum)]
|
#![feature(control_flow_enum)]
|
||||||
#![feature(drain_filter)]
|
|
||||||
#![feature(option_as_slice)]
|
#![feature(option_as_slice)]
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(drain_filter)]
|
#![feature(extract_if)]
|
||||||
#![feature(generators)]
|
#![feature(generators)]
|
||||||
#![feature(iter_from_generator)]
|
#![feature(iter_from_generator)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
|
|
@ -425,7 +425,7 @@ impl<'tcx> Collector<'tcx> {
|
||||||
// can move them to the end of the list below.
|
// can move them to the end of the list below.
|
||||||
let mut existing = self
|
let mut existing = self
|
||||||
.libs
|
.libs
|
||||||
.drain_filter(|lib| {
|
.extract_if(|lib| {
|
||||||
if lib.name.as_str() == passed_lib.name {
|
if lib.name.as_str() == passed_lib.name {
|
||||||
// FIXME: This whole logic is questionable, whether modifiers are
|
// FIXME: This whole logic is questionable, whether modifiers are
|
||||||
// involved or not, library reordering and kind overriding without
|
// involved or not, library reordering and kind overriding without
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
#![feature(try_reserve_kind)]
|
#![feature(try_reserve_kind)]
|
||||||
#![feature(nonzero_ops)]
|
#![feature(nonzero_ops)]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(drain_filter)]
|
#![feature(extract_if)]
|
||||||
#![feature(intra_doc_pointers)]
|
#![feature(intra_doc_pointers)]
|
||||||
#![feature(yeet_expr)]
|
#![feature(yeet_expr)]
|
||||||
#![feature(result_option_inspect)]
|
#![feature(result_option_inspect)]
|
||||||
|
|
|
@ -237,7 +237,7 @@ pub fn suggest_constraining_type_params<'a>(
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut sized_constraints =
|
let mut sized_constraints =
|
||||||
constraints.drain_filter(|(_, def_id)| *def_id == tcx.lang_items().sized_trait());
|
constraints.extract_if(|(_, def_id)| *def_id == tcx.lang_items().sized_trait());
|
||||||
if let Some((constraint, def_id)) = sized_constraints.next() {
|
if let Some((constraint, def_id)) = sized_constraints.next() {
|
||||||
applicability = Applicability::MaybeIncorrect;
|
applicability = Applicability::MaybeIncorrect;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#![deny(rustc::untranslatable_diagnostic)]
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(drain_filter)]
|
|
||||||
#![feature(is_sorted)]
|
#![feature(is_sorted)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(map_try_insert)]
|
#![feature(map_try_insert)]
|
||||||
|
|
|
@ -436,13 +436,12 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
|
||||||
VarDebugInfoContents::Composite { ty: _, ref mut fragments } => {
|
VarDebugInfoContents::Composite { ty: _, ref mut fragments } => {
|
||||||
let mut new_fragments = Vec::new();
|
let mut new_fragments = Vec::new();
|
||||||
debug!(?fragments);
|
debug!(?fragments);
|
||||||
fragments
|
fragments.retain_mut(|fragment| {
|
||||||
.drain_filter(|fragment| {
|
if let Some(repl) =
|
||||||
if let Some(repl) =
|
|
||||||
self.replacements.replace_place(self.tcx, fragment.contents.as_ref())
|
self.replacements.replace_place(self.tcx, fragment.contents.as_ref())
|
||||||
{
|
{
|
||||||
fragment.contents = repl;
|
fragment.contents = repl;
|
||||||
false
|
true
|
||||||
} else if let Some(local) = fragment.contents.as_local()
|
} else if let Some(local) = fragment.contents.as_local()
|
||||||
&& let Some(frg) = self.gather_debug_info_fragments(local)
|
&& let Some(frg) = self.gather_debug_info_fragments(local)
|
||||||
{
|
{
|
||||||
|
@ -450,12 +449,11 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
|
||||||
f.projection.splice(0..0, fragment.projection.iter().copied());
|
f.projection.splice(0..0, fragment.projection.iter().copied());
|
||||||
f
|
f
|
||||||
}));
|
}));
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.for_each(drop);
|
|
||||||
debug!(?fragments);
|
debug!(?fragments);
|
||||||
debug!(?new_fragments);
|
debug!(?new_fragments);
|
||||||
fragments.extend(new_fragments);
|
fragments.extend(new_fragments);
|
||||||
|
|
|
@ -2494,7 +2494,7 @@ fn show_candidates(
|
||||||
for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
|
for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
|
||||||
path_strings.sort_by(|a, b| a.0.cmp(&b.0));
|
path_strings.sort_by(|a, b| a.0.cmp(&b.0));
|
||||||
let core_path_strings =
|
let core_path_strings =
|
||||||
path_strings.drain_filter(|p| p.0.starts_with("core::")).collect::<Vec<_>>();
|
path_strings.extract_if(|p| p.0.starts_with("core::")).collect::<Vec<_>>();
|
||||||
path_strings.extend(core_path_strings);
|
path_strings.extend(core_path_strings);
|
||||||
path_strings.dedup_by(|a, b| a.0 == b.0);
|
path_strings.dedup_by(|a, b| a.0 == b.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -496,7 +496,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
// Try to filter out intrinsics candidates, as long as we have
|
// Try to filter out intrinsics candidates, as long as we have
|
||||||
// some other candidates to suggest.
|
// some other candidates to suggest.
|
||||||
let intrinsic_candidates: Vec<_> = candidates
|
let intrinsic_candidates: Vec<_> = candidates
|
||||||
.drain_filter(|sugg| {
|
.extract_if(|sugg| {
|
||||||
let path = path_names_to_string(&sugg.path);
|
let path = path_names_to_string(&sugg.path);
|
||||||
path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")
|
path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(drain_filter)]
|
#![feature(extract_if)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(control_flow_enum)]
|
#![feature(control_flow_enum)]
|
||||||
#![feature(drain_filter)]
|
#![feature(extract_if)]
|
||||||
#![feature(hash_drain_filter)]
|
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
|
|
@ -354,7 +354,7 @@ pub fn normalize_param_env_or_error<'tcx>(
|
||||||
// This works fairly well because trait matching does not actually care about param-env
|
// This works fairly well because trait matching does not actually care about param-env
|
||||||
// TypeOutlives predicates - these are normally used by regionck.
|
// TypeOutlives predicates - these are normally used by regionck.
|
||||||
let outlives_predicates: Vec<_> = predicates
|
let outlives_predicates: Vec<_> = predicates
|
||||||
.drain_filter(|predicate| {
|
.extract_if(|predicate| {
|
||||||
matches!(
|
matches!(
|
||||||
predicate.kind().skip_binder(),
|
predicate.kind().skip_binder(),
|
||||||
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
|
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
|
||||||
|
|
|
@ -1170,11 +1170,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut deduped: SsoHashSet<_> = Default::default();
|
let mut deduped: SsoHashSet<_> = Default::default();
|
||||||
result.obligations.drain_filter(|projected_obligation| {
|
result.obligations.retain(|projected_obligation| {
|
||||||
if !deduped.insert(projected_obligation.clone()) {
|
if !deduped.insert(projected_obligation.clone()) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
false
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
if use_cache {
|
if use_cache {
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#![deny(rustc::untranslatable_diagnostic)]
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(drain_filter)]
|
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -385,7 +385,7 @@ pub fn clone_slim_100_and_clear(b: &mut Bencher) {
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn clone_slim_100_and_drain_all(b: &mut Bencher) {
|
pub fn clone_slim_100_and_drain_all(b: &mut Bencher) {
|
||||||
let src = slim_map(100);
|
let src = slim_map(100);
|
||||||
b.iter(|| src.clone().drain_filter(|_, _| true).count())
|
b.iter(|| src.clone().extract_if(|_, _| true).count())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
@ -393,7 +393,7 @@ pub fn clone_slim_100_and_drain_half(b: &mut Bencher) {
|
||||||
let src = slim_map(100);
|
let src = slim_map(100);
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut map = src.clone();
|
let mut map = src.clone();
|
||||||
assert_eq!(map.drain_filter(|i, _| i % 2 == 0).count(), 100 / 2);
|
assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2);
|
||||||
assert_eq!(map.len(), 100 / 2);
|
assert_eq!(map.len(), 100 / 2);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -456,7 +456,7 @@ pub fn clone_slim_10k_and_clear(b: &mut Bencher) {
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn clone_slim_10k_and_drain_all(b: &mut Bencher) {
|
pub fn clone_slim_10k_and_drain_all(b: &mut Bencher) {
|
||||||
let src = slim_map(10_000);
|
let src = slim_map(10_000);
|
||||||
b.iter(|| src.clone().drain_filter(|_, _| true).count())
|
b.iter(|| src.clone().extract_if(|_, _| true).count())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
@ -464,7 +464,7 @@ pub fn clone_slim_10k_and_drain_half(b: &mut Bencher) {
|
||||||
let src = slim_map(10_000);
|
let src = slim_map(10_000);
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut map = src.clone();
|
let mut map = src.clone();
|
||||||
assert_eq!(map.drain_filter(|i, _| i % 2 == 0).count(), 10_000 / 2);
|
assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 10_000 / 2);
|
||||||
assert_eq!(map.len(), 10_000 / 2);
|
assert_eq!(map.len(), 10_000 / 2);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -527,7 +527,7 @@ pub fn clone_fat_val_100_and_clear(b: &mut Bencher) {
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn clone_fat_val_100_and_drain_all(b: &mut Bencher) {
|
pub fn clone_fat_val_100_and_drain_all(b: &mut Bencher) {
|
||||||
let src = fat_val_map(100);
|
let src = fat_val_map(100);
|
||||||
b.iter(|| src.clone().drain_filter(|_, _| true).count())
|
b.iter(|| src.clone().extract_if(|_, _| true).count())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
@ -535,7 +535,7 @@ pub fn clone_fat_val_100_and_drain_half(b: &mut Bencher) {
|
||||||
let src = fat_val_map(100);
|
let src = fat_val_map(100);
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut map = src.clone();
|
let mut map = src.clone();
|
||||||
assert_eq!(map.drain_filter(|i, _| i % 2 == 0).count(), 100 / 2);
|
assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2);
|
||||||
assert_eq!(map.len(), 100 / 2);
|
assert_eq!(map.len(), 100 / 2);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub fn clone_100_and_clear(b: &mut Bencher) {
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn clone_100_and_drain_all(b: &mut Bencher) {
|
pub fn clone_100_and_drain_all(b: &mut Bencher) {
|
||||||
let src = slim_set(100);
|
let src = slim_set(100);
|
||||||
b.iter(|| src.clone().drain_filter(|_| true).count())
|
b.iter(|| src.clone().extract_if(|_| true).count())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
@ -77,7 +77,7 @@ pub fn clone_100_and_drain_half(b: &mut Bencher) {
|
||||||
let src = slim_set(100);
|
let src = slim_set(100);
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut set = src.clone();
|
let mut set = src.clone();
|
||||||
assert_eq!(set.drain_filter(|i| i % 2 == 0).count(), 100 / 2);
|
assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 100 / 2);
|
||||||
assert_eq!(set.len(), 100 / 2);
|
assert_eq!(set.len(), 100 / 2);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ pub fn clone_10k_and_clear(b: &mut Bencher) {
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn clone_10k_and_drain_all(b: &mut Bencher) {
|
pub fn clone_10k_and_drain_all(b: &mut Bencher) {
|
||||||
let src = slim_set(10_000);
|
let src = slim_set(10_000);
|
||||||
b.iter(|| src.clone().drain_filter(|_| true).count())
|
b.iter(|| src.clone().extract_if(|_| true).count())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
@ -148,7 +148,7 @@ pub fn clone_10k_and_drain_half(b: &mut Bencher) {
|
||||||
let src = slim_set(10_000);
|
let src = slim_set(10_000);
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut set = src.clone();
|
let mut set = src.clone();
|
||||||
assert_eq!(set.drain_filter(|i| i % 2 == 0).count(), 10_000 / 2);
|
assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 10_000 / 2);
|
||||||
assert_eq!(set.len(), 10_000 / 2);
|
assert_eq!(set.len(), 10_000 / 2);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Disabling on android for the time being
|
// Disabling on android for the time being
|
||||||
// See https://github.com/rust-lang/rust/issues/73535#event-3477699747
|
// See https://github.com/rust-lang/rust/issues/73535#event-3477699747
|
||||||
#![cfg(not(target_os = "android"))]
|
#![cfg(not(target_os = "android"))]
|
||||||
#![feature(btree_drain_filter)]
|
#![feature(btree_extract_if)]
|
||||||
#![feature(iter_next_chunk)]
|
#![feature(iter_next_chunk)]
|
||||||
#![feature(repr_simd)]
|
#![feature(repr_simd)]
|
||||||
#![feature(slice_partition_dedup)]
|
#![feature(slice_partition_dedup)]
|
||||||
|
|
|
@ -1132,7 +1132,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||||
K: Ord,
|
K: Ord,
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
{
|
{
|
||||||
self.drain_filter(|k, v| !f(k, v));
|
self.extract_if(|k, v| !f(k, v)).for_each(drop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves all elements from `other` into `self`, leaving `other` empty.
|
/// Moves all elements from `other` into `self`, leaving `other` empty.
|
||||||
|
@ -1395,40 +1395,37 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||||
/// The iterator also lets you mutate the value of each element in the
|
/// The iterator also lets you mutate the value of each element in the
|
||||||
/// closure, regardless of whether you choose to keep or remove it.
|
/// closure, regardless of whether you choose to keep or remove it.
|
||||||
///
|
///
|
||||||
/// If the iterator is only partially consumed or not consumed at all, each
|
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
|
||||||
/// of the remaining elements is still subjected to the closure, which may
|
/// or the iteration short-circuits, then the remaining elements will be retained.
|
||||||
/// change its value and, by returning `true`, have the element removed and
|
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
|
||||||
/// dropped.
|
|
||||||
///
|
///
|
||||||
/// It is unspecified how many more elements will be subjected to the
|
/// [`retain`]: BTreeMap::retain
|
||||||
/// closure if a panic occurs in the closure, or a panic occurs while
|
|
||||||
/// dropping an element, or if the `DrainFilter` value is leaked.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Splitting a map into even and odd keys, reusing the original map:
|
/// Splitting a map into even and odd keys, reusing the original map:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(btree_drain_filter)]
|
/// #![feature(btree_extract_if)]
|
||||||
/// use std::collections::BTreeMap;
|
/// use std::collections::BTreeMap;
|
||||||
///
|
///
|
||||||
/// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
|
/// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
|
||||||
/// let evens: BTreeMap<_, _> = map.drain_filter(|k, _v| k % 2 == 0).collect();
|
/// let evens: BTreeMap<_, _> = map.extract_if(|k, _v| k % 2 == 0).collect();
|
||||||
/// let odds = map;
|
/// let odds = map;
|
||||||
/// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]);
|
/// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]);
|
||||||
/// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]);
|
/// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]);
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F, A>
|
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A>
|
||||||
where
|
where
|
||||||
K: Ord,
|
K: Ord,
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
{
|
{
|
||||||
let (inner, alloc) = self.drain_filter_inner();
|
let (inner, alloc) = self.extract_if_inner();
|
||||||
DrainFilter { pred, inner, alloc }
|
ExtractIf { pred, inner, alloc }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn drain_filter_inner(&mut self) -> (DrainFilterInner<'_, K, V>, A)
|
pub(super) fn extract_if_inner(&mut self) -> (ExtractIfInner<'_, K, V>, A)
|
||||||
where
|
where
|
||||||
K: Ord,
|
K: Ord,
|
||||||
{
|
{
|
||||||
|
@ -1436,7 +1433,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||||
let (root, dormant_root) = DormantMutRef::new(root);
|
let (root, dormant_root) = DormantMutRef::new(root);
|
||||||
let front = root.borrow_mut().first_leaf_edge();
|
let front = root.borrow_mut().first_leaf_edge();
|
||||||
(
|
(
|
||||||
DrainFilterInner {
|
ExtractIfInner {
|
||||||
length: &mut self.length,
|
length: &mut self.length,
|
||||||
dormant_root: Some(dormant_root),
|
dormant_root: Some(dormant_root),
|
||||||
cur_leaf_edge: Some(front),
|
cur_leaf_edge: Some(front),
|
||||||
|
@ -1445,7 +1442,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
DrainFilterInner {
|
ExtractIfInner {
|
||||||
length: &mut self.length,
|
length: &mut self.length,
|
||||||
dormant_root: None,
|
dormant_root: None,
|
||||||
cur_leaf_edge: None,
|
cur_leaf_edge: None,
|
||||||
|
@ -1899,9 +1896,10 @@ impl<K, V> Default for Values<'_, K, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator produced by calling `drain_filter` on BTreeMap.
|
/// An iterator produced by calling `extract_if` on BTreeMap.
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
pub struct DrainFilter<
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
|
pub struct ExtractIf<
|
||||||
'a,
|
'a,
|
||||||
K,
|
K,
|
||||||
V,
|
V,
|
||||||
|
@ -1911,13 +1909,13 @@ pub struct DrainFilter<
|
||||||
F: 'a + FnMut(&K, &mut V) -> bool,
|
F: 'a + FnMut(&K, &mut V) -> bool,
|
||||||
{
|
{
|
||||||
pred: F,
|
pred: F,
|
||||||
inner: DrainFilterInner<'a, K, V>,
|
inner: ExtractIfInner<'a, K, V>,
|
||||||
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
|
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
|
||||||
alloc: A,
|
alloc: A,
|
||||||
}
|
}
|
||||||
/// Most of the implementation of DrainFilter are generic over the type
|
/// Most of the implementation of ExtractIf are generic over the type
|
||||||
/// of the predicate, thus also serving for BTreeSet::DrainFilter.
|
/// of the predicate, thus also serving for BTreeSet::ExtractIf.
|
||||||
pub(super) struct DrainFilterInner<'a, K, V> {
|
pub(super) struct ExtractIfInner<'a, K, V> {
|
||||||
/// Reference to the length field in the borrowed map, updated live.
|
/// Reference to the length field in the borrowed map, updated live.
|
||||||
length: &'a mut usize,
|
length: &'a mut usize,
|
||||||
/// Buried reference to the root field in the borrowed map.
|
/// Buried reference to the root field in the borrowed map.
|
||||||
|
@ -1929,30 +1927,20 @@ pub(super) struct DrainFilterInner<'a, K, V> {
|
||||||
cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
|
cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
impl<K, V, F, A: Allocator + Clone> Drop for DrainFilter<'_, K, V, F, A>
|
impl<K, V, F> fmt::Debug for ExtractIf<'_, K, V, F>
|
||||||
where
|
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.for_each(drop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
|
||||||
impl<K, V, F> fmt::Debug for DrainFilter<'_, K, V, F>
|
|
||||||
where
|
where
|
||||||
K: fmt::Debug,
|
K: fmt::Debug,
|
||||||
V: fmt::Debug,
|
V: fmt::Debug,
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_tuple("DrainFilter").field(&self.inner.peek()).finish()
|
f.debug_tuple("ExtractIf").field(&self.inner.peek()).finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
impl<K, V, F, A: Allocator + Clone> Iterator for DrainFilter<'_, K, V, F, A>
|
impl<K, V, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, F, A>
|
||||||
where
|
where
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
{
|
{
|
||||||
|
@ -1967,14 +1955,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K, V> DrainFilterInner<'a, K, V> {
|
impl<'a, K, V> ExtractIfInner<'a, K, V> {
|
||||||
/// Allow Debug implementations to predict the next element.
|
/// Allow Debug implementations to predict the next element.
|
||||||
pub(super) fn peek(&self) -> Option<(&K, &V)> {
|
pub(super) fn peek(&self) -> Option<(&K, &V)> {
|
||||||
let edge = self.cur_leaf_edge.as_ref()?;
|
let edge = self.cur_leaf_edge.as_ref()?;
|
||||||
edge.reborrow().next_kv().ok().map(Handle::into_kv)
|
edge.reborrow().next_kv().ok().map(Handle::into_kv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of a typical `DrainFilter::next` method, given the predicate.
|
/// Implementation of a typical `ExtractIf::next` method, given the predicate.
|
||||||
pub(super) fn next<F, A: Allocator + Clone>(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)>
|
pub(super) fn next<F, A: Allocator + Clone>(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)>
|
||||||
where
|
where
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
|
@ -2001,7 +1989,7 @@ impl<'a, K, V> DrainFilterInner<'a, K, V> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of a typical `DrainFilter::size_hint` method.
|
/// Implementation of a typical `ExtractIf::size_hint` method.
|
||||||
pub(super) fn size_hint(&self) -> (usize, Option<usize>) {
|
pub(super) fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
// In most of the btree iterators, `self.length` is the number of elements
|
// In most of the btree iterators, `self.length` is the number of elements
|
||||||
// yet to be visited. Here, it includes elements that were visited and that
|
// yet to be visited. Here, it includes elements that were visited and that
|
||||||
|
@ -2011,8 +1999,8 @@ impl<'a, K, V> DrainFilterInner<'a, K, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
impl<K, V, F> FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
|
impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
|
||||||
|
|
||||||
#[stable(feature = "btree_range", since = "1.17.0")]
|
#[stable(feature = "btree_range", since = "1.17.0")]
|
||||||
impl<'a, K, V> Iterator for Range<'a, K, V> {
|
impl<'a, K, V> Iterator for Range<'a, K, V> {
|
||||||
|
|
|
@ -941,13 +941,13 @@ fn test_retain() {
|
||||||
assert_eq!(map[&6], 60);
|
assert_eq!(map[&6], 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_drain_filter {
|
mod test_extract_if {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty() {
|
fn empty() {
|
||||||
let mut map: BTreeMap<i32, i32> = BTreeMap::new();
|
let mut map: BTreeMap<i32, i32> = BTreeMap::new();
|
||||||
map.drain_filter(|_, _| unreachable!("there's nothing to decide on"));
|
map.extract_if(|_, _| unreachable!("there's nothing to decide on")).for_each(drop);
|
||||||
assert_eq!(map.height(), None);
|
assert_eq!(map.height(), None);
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -957,7 +957,7 @@ mod test_drain_filter {
|
||||||
fn consumed_keeping_all() {
|
fn consumed_keeping_all() {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs);
|
let mut map = BTreeMap::from_iter(pairs);
|
||||||
assert!(map.drain_filter(|_, _| false).eq(iter::empty()));
|
assert!(map.extract_if(|_, _| false).eq(iter::empty()));
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -966,7 +966,7 @@ mod test_drain_filter {
|
||||||
fn consumed_removing_all() {
|
fn consumed_removing_all() {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||||
assert!(map.drain_filter(|_, _| true).eq(pairs));
|
assert!(map.extract_if(|_, _| true).eq(pairs));
|
||||||
assert!(map.is_empty());
|
assert!(map.is_empty());
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -977,7 +977,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs);
|
let mut map = BTreeMap::from_iter(pairs);
|
||||||
assert!(
|
assert!(
|
||||||
map.drain_filter(|_, v| {
|
map.extract_if(|_, v| {
|
||||||
*v += 6;
|
*v += 6;
|
||||||
false
|
false
|
||||||
})
|
})
|
||||||
|
@ -994,7 +994,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs);
|
let mut map = BTreeMap::from_iter(pairs);
|
||||||
assert!(
|
assert!(
|
||||||
map.drain_filter(|_, v| {
|
map.extract_if(|_, v| {
|
||||||
*v += 6;
|
*v += 6;
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
|
@ -1008,7 +1008,7 @@ mod test_drain_filter {
|
||||||
fn underfull_keeping_all() {
|
fn underfull_keeping_all() {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs);
|
let mut map = BTreeMap::from_iter(pairs);
|
||||||
map.drain_filter(|_, _| false);
|
map.extract_if(|_, _| false).for_each(drop);
|
||||||
assert!(map.keys().copied().eq(0..3));
|
assert!(map.keys().copied().eq(0..3));
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1018,7 +1018,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
for doomed in 0..3 {
|
for doomed in 0..3 {
|
||||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||||
map.drain_filter(|i, _| *i == doomed);
|
map.extract_if(|i, _| *i == doomed).for_each(drop);
|
||||||
assert_eq!(map.len(), 2);
|
assert_eq!(map.len(), 2);
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1029,7 +1029,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
for sacred in 0..3 {
|
for sacred in 0..3 {
|
||||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||||
map.drain_filter(|i, _| *i != sacred);
|
map.extract_if(|i, _| *i != sacred).for_each(drop);
|
||||||
assert!(map.keys().copied().eq(sacred..=sacred));
|
assert!(map.keys().copied().eq(sacred..=sacred));
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1039,7 +1039,7 @@ mod test_drain_filter {
|
||||||
fn underfull_removing_all() {
|
fn underfull_removing_all() {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs);
|
let mut map = BTreeMap::from_iter(pairs);
|
||||||
map.drain_filter(|_, _| true);
|
map.extract_if(|_, _| true).for_each(drop);
|
||||||
assert!(map.is_empty());
|
assert!(map.is_empty());
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1048,7 +1048,7 @@ mod test_drain_filter {
|
||||||
fn height_0_keeping_all() {
|
fn height_0_keeping_all() {
|
||||||
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs);
|
let mut map = BTreeMap::from_iter(pairs);
|
||||||
map.drain_filter(|_, _| false);
|
map.extract_if(|_, _| false).for_each(drop);
|
||||||
assert!(map.keys().copied().eq(0..node::CAPACITY));
|
assert!(map.keys().copied().eq(0..node::CAPACITY));
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1058,7 +1058,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
||||||
for doomed in 0..node::CAPACITY {
|
for doomed in 0..node::CAPACITY {
|
||||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||||
map.drain_filter(|i, _| *i == doomed);
|
map.extract_if(|i, _| *i == doomed).for_each(drop);
|
||||||
assert_eq!(map.len(), node::CAPACITY - 1);
|
assert_eq!(map.len(), node::CAPACITY - 1);
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1069,7 +1069,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
||||||
for sacred in 0..node::CAPACITY {
|
for sacred in 0..node::CAPACITY {
|
||||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||||
map.drain_filter(|i, _| *i != sacred);
|
map.extract_if(|i, _| *i != sacred).for_each(drop);
|
||||||
assert!(map.keys().copied().eq(sacred..=sacred));
|
assert!(map.keys().copied().eq(sacred..=sacred));
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1079,7 +1079,7 @@ mod test_drain_filter {
|
||||||
fn height_0_removing_all() {
|
fn height_0_removing_all() {
|
||||||
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
let pairs = (0..node::CAPACITY).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs);
|
let mut map = BTreeMap::from_iter(pairs);
|
||||||
map.drain_filter(|_, _| true);
|
map.extract_if(|_, _| true).for_each(drop);
|
||||||
assert!(map.is_empty());
|
assert!(map.is_empty());
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1087,7 +1087,7 @@ mod test_drain_filter {
|
||||||
#[test]
|
#[test]
|
||||||
fn height_0_keeping_half() {
|
fn height_0_keeping_half() {
|
||||||
let mut map = BTreeMap::from_iter((0..16).map(|i| (i, i)));
|
let mut map = BTreeMap::from_iter((0..16).map(|i| (i, i)));
|
||||||
assert_eq!(map.drain_filter(|i, _| *i % 2 == 0).count(), 8);
|
assert_eq!(map.extract_if(|i, _| *i % 2 == 0).count(), 8);
|
||||||
assert_eq!(map.len(), 8);
|
assert_eq!(map.len(), 8);
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1096,7 +1096,7 @@ mod test_drain_filter {
|
||||||
fn height_1_removing_all() {
|
fn height_1_removing_all() {
|
||||||
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
|
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs);
|
let mut map = BTreeMap::from_iter(pairs);
|
||||||
map.drain_filter(|_, _| true);
|
map.extract_if(|_, _| true).for_each(drop);
|
||||||
assert!(map.is_empty());
|
assert!(map.is_empty());
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1106,7 +1106,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
|
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
|
||||||
for doomed in 0..MIN_INSERTS_HEIGHT_1 {
|
for doomed in 0..MIN_INSERTS_HEIGHT_1 {
|
||||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||||
map.drain_filter(|i, _| *i == doomed);
|
map.extract_if(|i, _| *i == doomed).for_each(drop);
|
||||||
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_1 - 1);
|
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_1 - 1);
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1117,7 +1117,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
|
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
|
||||||
for sacred in 0..MIN_INSERTS_HEIGHT_1 {
|
for sacred in 0..MIN_INSERTS_HEIGHT_1 {
|
||||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||||
map.drain_filter(|i, _| *i != sacred);
|
map.extract_if(|i, _| *i != sacred).for_each(drop);
|
||||||
assert!(map.keys().copied().eq(sacred..=sacred));
|
assert!(map.keys().copied().eq(sacred..=sacred));
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1128,7 +1128,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
||||||
for doomed in (0..MIN_INSERTS_HEIGHT_2).step_by(12) {
|
for doomed in (0..MIN_INSERTS_HEIGHT_2).step_by(12) {
|
||||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||||
map.drain_filter(|i, _| *i == doomed);
|
map.extract_if(|i, _| *i == doomed).for_each(drop);
|
||||||
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_2 - 1);
|
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_2 - 1);
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1139,7 +1139,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
||||||
for sacred in (0..MIN_INSERTS_HEIGHT_2).step_by(12) {
|
for sacred in (0..MIN_INSERTS_HEIGHT_2).step_by(12) {
|
||||||
let mut map = BTreeMap::from_iter(pairs.clone());
|
let mut map = BTreeMap::from_iter(pairs.clone());
|
||||||
map.drain_filter(|i, _| *i != sacred);
|
map.extract_if(|i, _| *i != sacred).for_each(drop);
|
||||||
assert!(map.keys().copied().eq(sacred..=sacred));
|
assert!(map.keys().copied().eq(sacred..=sacred));
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1149,7 +1149,7 @@ mod test_drain_filter {
|
||||||
fn height_2_removing_all() {
|
fn height_2_removing_all() {
|
||||||
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
|
||||||
let mut map = BTreeMap::from_iter(pairs);
|
let mut map = BTreeMap::from_iter(pairs);
|
||||||
map.drain_filter(|_, _| true);
|
map.extract_if(|_, _| true).for_each(drop);
|
||||||
assert!(map.is_empty());
|
assert!(map.is_empty());
|
||||||
map.check();
|
map.check();
|
||||||
}
|
}
|
||||||
|
@ -1165,7 +1165,8 @@ mod test_drain_filter {
|
||||||
map.insert(b.spawn(Panic::InDrop), ());
|
map.insert(b.spawn(Panic::InDrop), ());
|
||||||
map.insert(c.spawn(Panic::Never), ());
|
map.insert(c.spawn(Panic::Never), ());
|
||||||
|
|
||||||
catch_unwind(move || drop(map.drain_filter(|dummy, _| dummy.query(true)))).unwrap_err();
|
catch_unwind(move || map.extract_if(|dummy, _| dummy.query(true)).for_each(drop))
|
||||||
|
.unwrap_err();
|
||||||
|
|
||||||
assert_eq!(a.queried(), 1);
|
assert_eq!(a.queried(), 1);
|
||||||
assert_eq!(b.queried(), 1);
|
assert_eq!(b.queried(), 1);
|
||||||
|
@ -1186,8 +1187,10 @@ mod test_drain_filter {
|
||||||
map.insert(b.spawn(Panic::InQuery), ());
|
map.insert(b.spawn(Panic::InQuery), ());
|
||||||
map.insert(c.spawn(Panic::InQuery), ());
|
map.insert(c.spawn(Panic::InQuery), ());
|
||||||
|
|
||||||
catch_unwind(AssertUnwindSafe(|| drop(map.drain_filter(|dummy, _| dummy.query(true)))))
|
catch_unwind(AssertUnwindSafe(|| {
|
||||||
.unwrap_err();
|
map.extract_if(|dummy, _| dummy.query(true)).for_each(drop)
|
||||||
|
}))
|
||||||
|
.unwrap_err();
|
||||||
|
|
||||||
assert_eq!(a.queried(), 1);
|
assert_eq!(a.queried(), 1);
|
||||||
assert_eq!(b.queried(), 1);
|
assert_eq!(b.queried(), 1);
|
||||||
|
@ -1214,7 +1217,7 @@ mod test_drain_filter {
|
||||||
map.insert(c.spawn(Panic::InQuery), ());
|
map.insert(c.spawn(Panic::InQuery), ());
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut it = map.drain_filter(|dummy, _| dummy.query(true));
|
let mut it = map.extract_if(|dummy, _| dummy.query(true));
|
||||||
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
|
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
|
||||||
// Iterator behaviour after a panic is explicitly unspecified,
|
// Iterator behaviour after a panic is explicitly unspecified,
|
||||||
// so this is just the current implementation:
|
// so this is just the current implementation:
|
||||||
|
@ -1657,8 +1660,8 @@ fn assert_sync() {
|
||||||
v.into_values()
|
v.into_values()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain_filter<T: Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
|
fn extract_if<T: Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ {
|
||||||
v.drain_filter(|_, _| false)
|
v.extract_if(|_, _| false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
|
fn iter<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
|
||||||
|
@ -1726,8 +1729,8 @@ fn assert_send() {
|
||||||
v.into_values()
|
v.into_values()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain_filter<T: Send + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
|
fn extract_if<T: Send + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
|
||||||
v.drain_filter(|_, _| false)
|
v.extract_if(|_, _| false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ {
|
fn iter<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ {
|
||||||
|
|
|
@ -999,7 +999,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
||||||
T: Ord,
|
T: Ord,
|
||||||
F: FnMut(&T) -> bool,
|
F: FnMut(&T) -> bool,
|
||||||
{
|
{
|
||||||
self.drain_filter(|v| !f(v));
|
self.extract_if(|v| !f(v)).for_each(drop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves all elements from `other` into `self`, leaving `other` empty.
|
/// Moves all elements from `other` into `self`, leaving `other` empty.
|
||||||
|
@ -1084,36 +1084,33 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
||||||
/// yielded. If the closure returns `false`, or panics, the element remains
|
/// yielded. If the closure returns `false`, or panics, the element remains
|
||||||
/// in the set and will not be yielded.
|
/// in the set and will not be yielded.
|
||||||
///
|
///
|
||||||
/// If the iterator is only partially consumed or not consumed at all, each
|
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
|
||||||
/// of the remaining elements is still subjected to the closure and removed
|
/// or the iteration short-circuits, then the remaining elements will be retained.
|
||||||
/// and dropped if it returns `true`.
|
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
|
||||||
///
|
|
||||||
/// It is unspecified how many more elements will be subjected to the
|
|
||||||
/// closure if a panic occurs in the closure, or if a panic occurs while
|
|
||||||
/// dropping an element, or if the `DrainFilter` itself is leaked.
|
|
||||||
///
|
///
|
||||||
|
/// [`retain`]: BTreeSet::retain
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Splitting a set into even and odd values, reusing the original set:
|
/// Splitting a set into even and odd values, reusing the original set:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(btree_drain_filter)]
|
/// #![feature(btree_extract_if)]
|
||||||
/// use std::collections::BTreeSet;
|
/// use std::collections::BTreeSet;
|
||||||
///
|
///
|
||||||
/// let mut set: BTreeSet<i32> = (0..8).collect();
|
/// let mut set: BTreeSet<i32> = (0..8).collect();
|
||||||
/// let evens: BTreeSet<_> = set.drain_filter(|v| v % 2 == 0).collect();
|
/// let evens: BTreeSet<_> = set.extract_if(|v| v % 2 == 0).collect();
|
||||||
/// let odds = set;
|
/// let odds = set;
|
||||||
/// assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![0, 2, 4, 6]);
|
/// assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![0, 2, 4, 6]);
|
||||||
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7]);
|
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7]);
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
pub fn drain_filter<'a, F>(&'a mut self, pred: F) -> DrainFilter<'a, T, F, A>
|
pub fn extract_if<'a, F>(&'a mut self, pred: F) -> ExtractIf<'a, T, F, A>
|
||||||
where
|
where
|
||||||
T: Ord,
|
T: Ord,
|
||||||
F: 'a + FnMut(&T) -> bool,
|
F: 'a + FnMut(&T) -> bool,
|
||||||
{
|
{
|
||||||
let (inner, alloc) = self.map.drain_filter_inner();
|
let (inner, alloc) = self.map.extract_if_inner();
|
||||||
DrainFilter { pred, inner, alloc }
|
ExtractIf { pred, inner, alloc }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an iterator that visits the elements in the `BTreeSet` in ascending
|
/// Gets an iterator that visits the elements in the `BTreeSet` in ascending
|
||||||
|
@ -1275,9 +1272,10 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet<T, A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator produced by calling `drain_filter` on BTreeSet.
|
/// An iterator produced by calling `extract_if` on BTreeSet.
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
pub struct DrainFilter<
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
|
pub struct ExtractIf<
|
||||||
'a,
|
'a,
|
||||||
T,
|
T,
|
||||||
F,
|
F,
|
||||||
|
@ -1287,34 +1285,24 @@ pub struct DrainFilter<
|
||||||
F: 'a + FnMut(&T) -> bool,
|
F: 'a + FnMut(&T) -> bool,
|
||||||
{
|
{
|
||||||
pred: F,
|
pred: F,
|
||||||
inner: super::map::DrainFilterInner<'a, T, SetValZST>,
|
inner: super::map::ExtractIfInner<'a, T, SetValZST>,
|
||||||
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
|
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
|
||||||
alloc: A,
|
alloc: A,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
impl<T, F, A: Allocator + Clone> Drop for DrainFilter<'_, T, F, A>
|
impl<T, F, A: Allocator + Clone> fmt::Debug for ExtractIf<'_, T, F, A>
|
||||||
where
|
|
||||||
F: FnMut(&T) -> bool,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.for_each(drop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
|
||||||
impl<T, F, A: Allocator + Clone> fmt::Debug for DrainFilter<'_, T, F, A>
|
|
||||||
where
|
where
|
||||||
T: fmt::Debug,
|
T: fmt::Debug,
|
||||||
F: FnMut(&T) -> bool,
|
F: FnMut(&T) -> bool,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_tuple("DrainFilter").field(&self.inner.peek().map(|(k, _)| k)).finish()
|
f.debug_tuple("ExtractIf").field(&self.inner.peek().map(|(k, _)| k)).finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
impl<'a, T, F, A: Allocator + Clone> Iterator for DrainFilter<'_, T, F, A>
|
impl<'a, T, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, F, A>
|
||||||
where
|
where
|
||||||
F: 'a + FnMut(&T) -> bool,
|
F: 'a + FnMut(&T) -> bool,
|
||||||
{
|
{
|
||||||
|
@ -1331,11 +1319,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "btree_drain_filter", issue = "70530")]
|
#[unstable(feature = "btree_extract_if", issue = "70530")]
|
||||||
impl<T, F, A: Allocator + Clone> FusedIterator for DrainFilter<'_, T, F, A> where
|
impl<T, F, A: Allocator + Clone> FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&T) -> bool {}
|
||||||
F: FnMut(&T) -> bool
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T: Ord, A: Allocator + Clone> Extend<T> for BTreeSet<T, A> {
|
impl<T: Ord, A: Allocator + Clone> Extend<T> for BTreeSet<T, A> {
|
||||||
|
|
|
@ -366,19 +366,19 @@ fn test_retain() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_drain_filter() {
|
fn test_extract_if() {
|
||||||
let mut x = BTreeSet::from([1]);
|
let mut x = BTreeSet::from([1]);
|
||||||
let mut y = BTreeSet::from([1]);
|
let mut y = BTreeSet::from([1]);
|
||||||
|
|
||||||
x.drain_filter(|_| true);
|
x.extract_if(|_| true).for_each(drop);
|
||||||
y.drain_filter(|_| false);
|
y.extract_if(|_| false).for_each(drop);
|
||||||
assert_eq!(x.len(), 0);
|
assert_eq!(x.len(), 0);
|
||||||
assert_eq!(y.len(), 1);
|
assert_eq!(y.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||||
fn test_drain_filter_drop_panic_leak() {
|
fn test_extract_if_drop_panic_leak() {
|
||||||
let a = CrashTestDummy::new(0);
|
let a = CrashTestDummy::new(0);
|
||||||
let b = CrashTestDummy::new(1);
|
let b = CrashTestDummy::new(1);
|
||||||
let c = CrashTestDummy::new(2);
|
let c = CrashTestDummy::new(2);
|
||||||
|
@ -387,7 +387,7 @@ fn test_drain_filter_drop_panic_leak() {
|
||||||
set.insert(b.spawn(Panic::InDrop));
|
set.insert(b.spawn(Panic::InDrop));
|
||||||
set.insert(c.spawn(Panic::Never));
|
set.insert(c.spawn(Panic::Never));
|
||||||
|
|
||||||
catch_unwind(move || drop(set.drain_filter(|dummy| dummy.query(true)))).ok();
|
catch_unwind(move || set.extract_if(|dummy| dummy.query(true)).for_each(drop)).ok();
|
||||||
|
|
||||||
assert_eq!(a.queried(), 1);
|
assert_eq!(a.queried(), 1);
|
||||||
assert_eq!(b.queried(), 1);
|
assert_eq!(b.queried(), 1);
|
||||||
|
@ -399,7 +399,7 @@ fn test_drain_filter_drop_panic_leak() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||||
fn test_drain_filter_pred_panic_leak() {
|
fn test_extract_if_pred_panic_leak() {
|
||||||
let a = CrashTestDummy::new(0);
|
let a = CrashTestDummy::new(0);
|
||||||
let b = CrashTestDummy::new(1);
|
let b = CrashTestDummy::new(1);
|
||||||
let c = CrashTestDummy::new(2);
|
let c = CrashTestDummy::new(2);
|
||||||
|
@ -408,7 +408,8 @@ fn test_drain_filter_pred_panic_leak() {
|
||||||
set.insert(b.spawn(Panic::InQuery));
|
set.insert(b.spawn(Panic::InQuery));
|
||||||
set.insert(c.spawn(Panic::InQuery));
|
set.insert(c.spawn(Panic::InQuery));
|
||||||
|
|
||||||
catch_unwind(AssertUnwindSafe(|| drop(set.drain_filter(|dummy| dummy.query(true))))).ok();
|
catch_unwind(AssertUnwindSafe(|| set.extract_if(|dummy| dummy.query(true)).for_each(drop)))
|
||||||
|
.ok();
|
||||||
|
|
||||||
assert_eq!(a.queried(), 1);
|
assert_eq!(a.queried(), 1);
|
||||||
assert_eq!(b.queried(), 1);
|
assert_eq!(b.queried(), 1);
|
||||||
|
@ -605,8 +606,8 @@ fn assert_sync() {
|
||||||
v.range(..)
|
v.range(..)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain_filter<T: Sync + Ord>(v: &mut BTreeSet<T>) -> impl Sync + '_ {
|
fn extract_if<T: Sync + Ord>(v: &mut BTreeSet<T>) -> impl Sync + '_ {
|
||||||
v.drain_filter(|_| false)
|
v.extract_if(|_| false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
|
fn difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
|
||||||
|
@ -644,8 +645,8 @@ fn assert_send() {
|
||||||
v.range(..)
|
v.range(..)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain_filter<T: Send + Ord>(v: &mut BTreeSet<T>) -> impl Send + '_ {
|
fn extract_if<T: Send + Ord>(v: &mut BTreeSet<T>) -> impl Send + '_ {
|
||||||
v.drain_filter(|_| false)
|
v.extract_if(|_| false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
|
fn difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
|
||||||
|
|
|
@ -1030,7 +1030,11 @@ impl<T, A: Allocator> LinkedList<T, A> {
|
||||||
/// If the closure returns false, the element will remain in the list and will not be yielded
|
/// If the closure returns false, the element will remain in the list and will not be yielded
|
||||||
/// by the iterator.
|
/// by the iterator.
|
||||||
///
|
///
|
||||||
/// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of
|
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
|
||||||
|
/// or the iteration short-circuits, then the remaining elements will be retained.
|
||||||
|
/// Use `extract_if().for_each(drop)` if you do not need the returned iterator.
|
||||||
|
///
|
||||||
|
/// Note that `extract_if` lets you mutate every element in the filter closure, regardless of
|
||||||
/// whether you choose to keep or remove it.
|
/// whether you choose to keep or remove it.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -1038,20 +1042,20 @@ impl<T, A: Allocator> LinkedList<T, A> {
|
||||||
/// Splitting a list into evens and odds, reusing the original list:
|
/// Splitting a list into evens and odds, reusing the original list:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(drain_filter)]
|
/// #![feature(extract_if)]
|
||||||
/// use std::collections::LinkedList;
|
/// use std::collections::LinkedList;
|
||||||
///
|
///
|
||||||
/// let mut numbers: LinkedList<u32> = LinkedList::new();
|
/// let mut numbers: LinkedList<u32> = LinkedList::new();
|
||||||
/// numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]);
|
/// numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]);
|
||||||
///
|
///
|
||||||
/// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<LinkedList<_>>();
|
/// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::<LinkedList<_>>();
|
||||||
/// let odds = numbers;
|
/// let odds = numbers;
|
||||||
///
|
///
|
||||||
/// assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![2, 4, 6, 8, 14]);
|
/// assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![2, 4, 6, 8, 14]);
|
||||||
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]);
|
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]);
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||||
pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
|
pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool,
|
F: FnMut(&mut T) -> bool,
|
||||||
{
|
{
|
||||||
|
@ -1059,7 +1063,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
|
||||||
let it = self.head;
|
let it = self.head;
|
||||||
let old_len = self.len;
|
let old_len = self.len;
|
||||||
|
|
||||||
DrainFilter { list: self, it, pred: filter, idx: 0, old_len }
|
ExtractIf { list: self, it, pred: filter, idx: 0, old_len }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1803,9 +1807,10 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator produced by calling `drain_filter` on LinkedList.
|
/// An iterator produced by calling `extract_if` on LinkedList.
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||||
pub struct DrainFilter<
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
|
pub struct ExtractIf<
|
||||||
'a,
|
'a,
|
||||||
T: 'a,
|
T: 'a,
|
||||||
F: 'a,
|
F: 'a,
|
||||||
|
@ -1820,8 +1825,8 @@ pub struct DrainFilter<
|
||||||
old_len: usize,
|
old_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||||
impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
|
impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool,
|
F: FnMut(&mut T) -> bool,
|
||||||
{
|
{
|
||||||
|
@ -1849,40 +1854,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||||
impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
|
impl<T: fmt::Debug, F> fmt::Debug for ExtractIf<'_, T, F>
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
|
||||||
struct DropGuard<'r, 'a, T, F, A: Allocator>(&'r mut DrainFilter<'a, T, F, A>)
|
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool;
|
|
||||||
|
|
||||||
impl<'r, 'a, T, F, A: Allocator> Drop for DropGuard<'r, 'a, T, F, A>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.0.for_each(drop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(item) = self.next() {
|
|
||||||
let guard = DropGuard(self);
|
|
||||||
drop(item);
|
|
||||||
mem::forget(guard);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
|
||||||
impl<T: fmt::Debug, F> fmt::Debug for DrainFilter<'_, T, F>
|
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool,
|
F: FnMut(&mut T) -> bool,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_tuple("DrainFilter").field(&self.list).finish()
|
f.debug_tuple("ExtractIf").field(&self.list).finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -540,10 +540,10 @@ fn test_show() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_test() {
|
fn extract_if_test() {
|
||||||
let mut m: LinkedList<u32> = LinkedList::new();
|
let mut m: LinkedList<u32> = LinkedList::new();
|
||||||
m.extend(&[1, 2, 3, 4, 5, 6]);
|
m.extend(&[1, 2, 3, 4, 5, 6]);
|
||||||
let deleted = m.drain_filter(|v| *v < 4).collect::<Vec<_>>();
|
let deleted = m.extract_if(|v| *v < 4).collect::<Vec<_>>();
|
||||||
|
|
||||||
check_links(&m);
|
check_links(&m);
|
||||||
|
|
||||||
|
@ -555,7 +555,7 @@ fn drain_filter_test() {
|
||||||
fn drain_to_empty_test() {
|
fn drain_to_empty_test() {
|
||||||
let mut m: LinkedList<u32> = LinkedList::new();
|
let mut m: LinkedList<u32> = LinkedList::new();
|
||||||
m.extend(&[1, 2, 3, 4, 5, 6]);
|
m.extend(&[1, 2, 3, 4, 5, 6]);
|
||||||
let deleted = m.drain_filter(|_| true).collect::<Vec<_>>();
|
let deleted = m.extract_if(|_| true).collect::<Vec<_>>();
|
||||||
|
|
||||||
check_links(&m);
|
check_links(&m);
|
||||||
|
|
||||||
|
@ -811,11 +811,11 @@ fn test_contains() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_empty() {
|
fn extract_if_empty() {
|
||||||
let mut list: LinkedList<i32> = LinkedList::new();
|
let mut list: LinkedList<i32> = LinkedList::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut iter = list.drain_filter(|_| true);
|
let mut iter = list.extract_if(|_| true);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||||
assert_eq!(iter.next(), None);
|
assert_eq!(iter.next(), None);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||||
|
@ -828,13 +828,13 @@ fn drain_filter_empty() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_zst() {
|
fn extract_if_zst() {
|
||||||
let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect();
|
let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect();
|
||||||
let initial_len = list.len();
|
let initial_len = list.len();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut iter = list.drain_filter(|_| true);
|
let mut iter = list.extract_if(|_| true);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
||||||
while let Some(_) = iter.next() {
|
while let Some(_) = iter.next() {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -851,14 +851,14 @@ fn drain_filter_zst() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_false() {
|
fn extract_if_false() {
|
||||||
let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
|
let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
|
||||||
|
|
||||||
let initial_len = list.len();
|
let initial_len = list.len();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut iter = list.drain_filter(|_| false);
|
let mut iter = list.extract_if(|_| false);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
||||||
for _ in iter.by_ref() {
|
for _ in iter.by_ref() {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -874,14 +874,14 @@ fn drain_filter_false() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_true() {
|
fn extract_if_true() {
|
||||||
let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
|
let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
|
||||||
|
|
||||||
let initial_len = list.len();
|
let initial_len = list.len();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut iter = list.drain_filter(|_| true);
|
let mut iter = list.extract_if(|_| true);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
||||||
while let Some(_) = iter.next() {
|
while let Some(_) = iter.next() {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -898,7 +898,7 @@ fn drain_filter_true() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_complex() {
|
fn extract_if_complex() {
|
||||||
{
|
{
|
||||||
// [+xxx++++++xxxxx++++x+x++]
|
// [+xxx++++++xxxxx++++x+x++]
|
||||||
let mut list = [
|
let mut list = [
|
||||||
|
@ -908,7 +908,7 @@ fn drain_filter_complex() {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<LinkedList<_>>();
|
.collect::<LinkedList<_>>();
|
||||||
|
|
||||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = list.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||||
|
|
||||||
|
@ -926,7 +926,7 @@ fn drain_filter_complex() {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<LinkedList<_>>();
|
.collect::<LinkedList<_>>();
|
||||||
|
|
||||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = list.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||||
|
|
||||||
|
@ -944,7 +944,7 @@ fn drain_filter_complex() {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<LinkedList<_>>();
|
.collect::<LinkedList<_>>();
|
||||||
|
|
||||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = list.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||||
|
|
||||||
|
@ -961,7 +961,7 @@ fn drain_filter_complex() {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<LinkedList<_>>();
|
.collect::<LinkedList<_>>();
|
||||||
|
|
||||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = list.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
||||||
|
|
||||||
|
@ -975,7 +975,7 @@ fn drain_filter_complex() {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<LinkedList<_>>();
|
.collect::<LinkedList<_>>();
|
||||||
|
|
||||||
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = list.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
||||||
|
|
||||||
|
@ -986,7 +986,7 @@ fn drain_filter_complex() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||||
fn drain_filter_drop_panic_leak() {
|
fn extract_if_drop_panic_leak() {
|
||||||
let d0 = CrashTestDummy::new(0);
|
let d0 = CrashTestDummy::new(0);
|
||||||
let d1 = CrashTestDummy::new(1);
|
let d1 = CrashTestDummy::new(1);
|
||||||
let d2 = CrashTestDummy::new(2);
|
let d2 = CrashTestDummy::new(2);
|
||||||
|
@ -1005,22 +1005,28 @@ fn drain_filter_drop_panic_leak() {
|
||||||
q.push_front(d1.spawn(Panic::InDrop));
|
q.push_front(d1.spawn(Panic::InDrop));
|
||||||
q.push_front(d0.spawn(Panic::Never));
|
q.push_front(d0.spawn(Panic::Never));
|
||||||
|
|
||||||
catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).unwrap_err();
|
catch_unwind(AssertUnwindSafe(|| q.extract_if(|_| true).for_each(drop))).unwrap_err();
|
||||||
|
|
||||||
assert_eq!(d0.dropped(), 1);
|
assert_eq!(d0.dropped(), 1);
|
||||||
assert_eq!(d1.dropped(), 1);
|
assert_eq!(d1.dropped(), 1);
|
||||||
|
assert_eq!(d2.dropped(), 0);
|
||||||
|
assert_eq!(d3.dropped(), 0);
|
||||||
|
assert_eq!(d4.dropped(), 0);
|
||||||
|
assert_eq!(d5.dropped(), 0);
|
||||||
|
assert_eq!(d6.dropped(), 0);
|
||||||
|
assert_eq!(d7.dropped(), 0);
|
||||||
|
drop(q);
|
||||||
assert_eq!(d2.dropped(), 1);
|
assert_eq!(d2.dropped(), 1);
|
||||||
assert_eq!(d3.dropped(), 1);
|
assert_eq!(d3.dropped(), 1);
|
||||||
assert_eq!(d4.dropped(), 1);
|
assert_eq!(d4.dropped(), 1);
|
||||||
assert_eq!(d5.dropped(), 1);
|
assert_eq!(d5.dropped(), 1);
|
||||||
assert_eq!(d6.dropped(), 1);
|
assert_eq!(d6.dropped(), 1);
|
||||||
assert_eq!(d7.dropped(), 1);
|
assert_eq!(d7.dropped(), 1);
|
||||||
assert!(q.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||||
fn drain_filter_pred_panic_leak() {
|
fn extract_if_pred_panic_leak() {
|
||||||
static mut DROPS: i32 = 0;
|
static mut DROPS: i32 = 0;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1045,7 +1051,7 @@ fn drain_filter_pred_panic_leak() {
|
||||||
q.push_front(D(0));
|
q.push_front(D(0));
|
||||||
|
|
||||||
catch_unwind(AssertUnwindSafe(|| {
|
catch_unwind(AssertUnwindSafe(|| {
|
||||||
drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }))
|
q.extract_if(|item| if item.0 >= 2 { panic!() } else { true }).for_each(drop)
|
||||||
}))
|
}))
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
|
|
|
@ -1,197 +0,0 @@
|
||||||
use crate::alloc::{Allocator, Global};
|
|
||||||
use core::mem::{ManuallyDrop, SizedTypeProperties};
|
|
||||||
use core::ptr;
|
|
||||||
use core::slice;
|
|
||||||
|
|
||||||
use super::Vec;
|
|
||||||
|
|
||||||
/// An iterator which uses a closure to determine if an element should be removed.
|
|
||||||
///
|
|
||||||
/// This struct is created by [`Vec::drain_filter`].
|
|
||||||
/// See its documentation for more.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(drain_filter)]
|
|
||||||
///
|
|
||||||
/// let mut v = vec![0, 1, 2];
|
|
||||||
/// let iter: std::vec::DrainFilter<'_, _, _> = v.drain_filter(|x| *x % 2 == 0);
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DrainFilter<
|
|
||||||
'a,
|
|
||||||
T,
|
|
||||||
F,
|
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
|
|
||||||
> where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
pub(super) vec: &'a mut Vec<T, A>,
|
|
||||||
/// The index of the item that will be inspected by the next call to `next`.
|
|
||||||
pub(super) idx: usize,
|
|
||||||
/// The number of items that have been drained (removed) thus far.
|
|
||||||
pub(super) del: usize,
|
|
||||||
/// The original length of `vec` prior to draining.
|
|
||||||
pub(super) old_len: usize,
|
|
||||||
/// The filter test predicate.
|
|
||||||
pub(super) pred: F,
|
|
||||||
/// A flag that indicates a panic has occurred in the filter test predicate.
|
|
||||||
/// This is used as a hint in the drop implementation to prevent consumption
|
|
||||||
/// of the remainder of the `DrainFilter`. Any unprocessed items will be
|
|
||||||
/// backshifted in the `vec`, but no further items will be dropped or
|
|
||||||
/// tested by the filter predicate.
|
|
||||||
pub(super) panic_flag: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
/// Returns a reference to the underlying allocator.
|
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
|
||||||
#[inline]
|
|
||||||
pub fn allocator(&self) -> &A {
|
|
||||||
self.vec.allocator()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Keep unyielded elements in the source `Vec`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(drain_filter)]
|
|
||||||
/// #![feature(drain_keep_rest)]
|
|
||||||
///
|
|
||||||
/// let mut vec = vec!['a', 'b', 'c'];
|
|
||||||
/// let mut drain = vec.drain_filter(|_| true);
|
|
||||||
///
|
|
||||||
/// assert_eq!(drain.next().unwrap(), 'a');
|
|
||||||
///
|
|
||||||
/// // This call keeps 'b' and 'c' in the vec.
|
|
||||||
/// drain.keep_rest();
|
|
||||||
///
|
|
||||||
/// // If we wouldn't call `keep_rest()`,
|
|
||||||
/// // `vec` would be empty.
|
|
||||||
/// assert_eq!(vec, ['b', 'c']);
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "drain_keep_rest", issue = "101122")]
|
|
||||||
pub fn keep_rest(self) {
|
|
||||||
// At this moment layout looks like this:
|
|
||||||
//
|
|
||||||
// _____________________/-- old_len
|
|
||||||
// / \
|
|
||||||
// [kept] [yielded] [tail]
|
|
||||||
// \_______/ ^-- idx
|
|
||||||
// \-- del
|
|
||||||
//
|
|
||||||
// Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
|
|
||||||
//
|
|
||||||
// 1. Move [tail] after [kept]
|
|
||||||
// 2. Update length of the original vec to `old_len - del`
|
|
||||||
// a. In case of ZST, this is the only thing we want to do
|
|
||||||
// 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
|
|
||||||
let mut this = ManuallyDrop::new(self);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// ZSTs have no identity, so we don't need to move them around.
|
|
||||||
if !T::IS_ZST && this.idx < this.old_len && this.del > 0 {
|
|
||||||
let ptr = this.vec.as_mut_ptr();
|
|
||||||
let src = ptr.add(this.idx);
|
|
||||||
let dst = src.sub(this.del);
|
|
||||||
let tail_len = this.old_len - this.idx;
|
|
||||||
src.copy_to(dst, tail_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_len = this.old_len - this.del;
|
|
||||||
this.vec.set_len(new_len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
|
||||||
impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
type Item = T;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<T> {
|
|
||||||
unsafe {
|
|
||||||
while self.idx < self.old_len {
|
|
||||||
let i = self.idx;
|
|
||||||
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
|
|
||||||
self.panic_flag = true;
|
|
||||||
let drained = (self.pred)(&mut v[i]);
|
|
||||||
self.panic_flag = false;
|
|
||||||
// Update the index *after* the predicate is called. If the index
|
|
||||||
// is updated prior and the predicate panics, the element at this
|
|
||||||
// index would be leaked.
|
|
||||||
self.idx += 1;
|
|
||||||
if drained {
|
|
||||||
self.del += 1;
|
|
||||||
return Some(ptr::read(&v[i]));
|
|
||||||
} else if self.del > 0 {
|
|
||||||
let del = self.del;
|
|
||||||
let src: *const T = &v[i];
|
|
||||||
let dst: *mut T = &mut v[i - del];
|
|
||||||
ptr::copy_nonoverlapping(src, dst, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
(0, Some(self.old_len - self.idx))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
|
||||||
impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
|
||||||
struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
drain: &'b mut DrainFilter<'a, T, F, A>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut T) -> bool,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
|
|
||||||
// This is a pretty messed up state, and there isn't really an
|
|
||||||
// obviously right thing to do. We don't want to keep trying
|
|
||||||
// to execute `pred`, so we just backshift all the unprocessed
|
|
||||||
// elements and tell the vec that they still exist. The backshift
|
|
||||||
// is required to prevent a double-drop of the last successfully
|
|
||||||
// drained item prior to a panic in the predicate.
|
|
||||||
let ptr = self.drain.vec.as_mut_ptr();
|
|
||||||
let src = ptr.add(self.drain.idx);
|
|
||||||
let dst = src.sub(self.drain.del);
|
|
||||||
let tail_len = self.drain.old_len - self.drain.idx;
|
|
||||||
src.copy_to(dst, tail_len);
|
|
||||||
}
|
|
||||||
self.drain.vec.set_len(self.drain.old_len - self.drain.del);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let backshift = BackshiftOnDrop { drain: self };
|
|
||||||
|
|
||||||
// Attempt to consume any remaining elements if the filter predicate
|
|
||||||
// has not yet panicked. We'll backshift any remaining elements
|
|
||||||
// whether we've already panicked or if the consumption here panics.
|
|
||||||
if !backshift.drain.panic_flag {
|
|
||||||
backshift.drain.for_each(drop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
121
library/alloc/src/vec/extract_if.rs
Normal file
121
library/alloc/src/vec/extract_if.rs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
use crate::alloc::{Allocator, Global};
|
||||||
|
use core::ptr;
|
||||||
|
use core::slice;
|
||||||
|
|
||||||
|
use super::Vec;
|
||||||
|
|
||||||
|
/// An iterator which uses a closure to determine if an element should be removed.
|
||||||
|
///
|
||||||
|
/// This struct is created by [`Vec::extract_if`].
|
||||||
|
/// See its documentation for more.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(extract_if)]
|
||||||
|
///
|
||||||
|
/// let mut v = vec![0, 1, 2];
|
||||||
|
/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
|
pub struct ExtractIf<
|
||||||
|
'a,
|
||||||
|
T,
|
||||||
|
F,
|
||||||
|
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
|
||||||
|
> where
|
||||||
|
F: FnMut(&mut T) -> bool,
|
||||||
|
{
|
||||||
|
pub(super) vec: &'a mut Vec<T, A>,
|
||||||
|
/// The index of the item that will be inspected by the next call to `next`.
|
||||||
|
pub(super) idx: usize,
|
||||||
|
/// The number of items that have been drained (removed) thus far.
|
||||||
|
pub(super) del: usize,
|
||||||
|
/// The original length of `vec` prior to draining.
|
||||||
|
pub(super) old_len: usize,
|
||||||
|
/// The filter test predicate.
|
||||||
|
pub(super) pred: F,
|
||||||
|
/// A flag that indicates a panic has occurred in the filter test predicate.
|
||||||
|
/// This is used as a hint in the drop implementation to prevent consumption
|
||||||
|
/// of the remainder of the `ExtractIf`. Any unprocessed items will be
|
||||||
|
/// backshifted in the `vec`, but no further items will be dropped or
|
||||||
|
/// tested by the filter predicate.
|
||||||
|
pub(super) panic_flag: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F, A: Allocator> ExtractIf<'_, T, F, A>
|
||||||
|
where
|
||||||
|
F: FnMut(&mut T) -> bool,
|
||||||
|
{
|
||||||
|
/// Returns a reference to the underlying allocator.
|
||||||
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
|
#[inline]
|
||||||
|
pub fn allocator(&self) -> &A {
|
||||||
|
self.vec.allocator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||||
|
impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
|
||||||
|
where
|
||||||
|
F: FnMut(&mut T) -> bool,
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<T> {
|
||||||
|
unsafe {
|
||||||
|
while self.idx < self.old_len {
|
||||||
|
let i = self.idx;
|
||||||
|
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
|
||||||
|
self.panic_flag = true;
|
||||||
|
let drained = (self.pred)(&mut v[i]);
|
||||||
|
self.panic_flag = false;
|
||||||
|
// Update the index *after* the predicate is called. If the index
|
||||||
|
// is updated prior and the predicate panics, the element at this
|
||||||
|
// index would be leaked.
|
||||||
|
self.idx += 1;
|
||||||
|
if drained {
|
||||||
|
self.del += 1;
|
||||||
|
return Some(ptr::read(&v[i]));
|
||||||
|
} else if self.del > 0 {
|
||||||
|
let del = self.del;
|
||||||
|
let src: *const T = &v[i];
|
||||||
|
let dst: *mut T = &mut v[i - del];
|
||||||
|
ptr::copy_nonoverlapping(src, dst, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(0, Some(self.old_len - self.idx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||||
|
impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A>
|
||||||
|
where
|
||||||
|
F: FnMut(&mut T) -> bool,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if self.idx < self.old_len && self.del > 0 {
|
||||||
|
// This is a pretty messed up state, and there isn't really an
|
||||||
|
// obviously right thing to do. We don't want to keep trying
|
||||||
|
// to execute `pred`, so we just backshift all the unprocessed
|
||||||
|
// elements and tell the vec that they still exist. The backshift
|
||||||
|
// is required to prevent a double-drop of the last successfully
|
||||||
|
// drained item prior to a panic in the predicate.
|
||||||
|
let ptr = self.vec.as_mut_ptr();
|
||||||
|
let src = ptr.add(self.idx);
|
||||||
|
let dst = src.sub(self.del);
|
||||||
|
let tail_len = self.old_len - self.idx;
|
||||||
|
src.copy_to(dst, tail_len);
|
||||||
|
}
|
||||||
|
self.vec.set_len(self.old_len - self.del);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,10 +71,10 @@ use crate::boxed::Box;
|
||||||
use crate::collections::TryReserveError;
|
use crate::collections::TryReserveError;
|
||||||
use crate::raw_vec::RawVec;
|
use crate::raw_vec::RawVec;
|
||||||
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||||
pub use self::drain_filter::DrainFilter;
|
pub use self::extract_if::ExtractIf;
|
||||||
|
|
||||||
mod drain_filter;
|
mod extract_if;
|
||||||
|
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||||
|
@ -2892,6 +2892,12 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||||
/// If the closure returns false, the element will remain in the vector and will not be yielded
|
/// If the closure returns false, the element will remain in the vector and will not be yielded
|
||||||
/// by the iterator.
|
/// by the iterator.
|
||||||
///
|
///
|
||||||
|
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
|
||||||
|
/// or the iteration short-circuits, then the remaining elements will be retained.
|
||||||
|
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
|
||||||
|
///
|
||||||
|
/// [`retain`]: Vec::retain
|
||||||
|
///
|
||||||
/// Using this method is equivalent to the following code:
|
/// Using this method is equivalent to the following code:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -2910,10 +2916,10 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||||
/// # assert_eq!(vec, vec![1, 4, 5]);
|
/// # assert_eq!(vec, vec![1, 4, 5]);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
|
/// But `extract_if` is easier to use. `extract_if` is also more efficient,
|
||||||
/// because it can backshift the elements of the array in bulk.
|
/// because it can backshift the elements of the array in bulk.
|
||||||
///
|
///
|
||||||
/// Note that `drain_filter` also lets you mutate every element in the filter closure,
|
/// Note that `extract_if` also lets you mutate every element in the filter closure,
|
||||||
/// regardless of whether you choose to keep or remove it.
|
/// regardless of whether you choose to keep or remove it.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -2921,17 +2927,17 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||||
/// Splitting an array into evens and odds, reusing the original allocation:
|
/// Splitting an array into evens and odds, reusing the original allocation:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(drain_filter)]
|
/// #![feature(extract_if)]
|
||||||
/// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
|
/// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
|
||||||
///
|
///
|
||||||
/// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
/// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
/// let odds = numbers;
|
/// let odds = numbers;
|
||||||
///
|
///
|
||||||
/// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
|
/// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
|
||||||
/// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
|
/// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||||
pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
|
pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut T) -> bool,
|
F: FnMut(&mut T) -> bool,
|
||||||
{
|
{
|
||||||
|
@ -2942,7 +2948,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||||
self.set_len(0);
|
self.set_len(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
|
ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ fn test_btree_map() {
|
||||||
|
|
||||||
require_send_sync(async {
|
require_send_sync(async {
|
||||||
let _v = None::<
|
let _v = None::<
|
||||||
alloc::collections::btree_map::DrainFilter<
|
alloc::collections::btree_map::ExtractIf<
|
||||||
'_,
|
'_,
|
||||||
&u32,
|
&u32,
|
||||||
&u32,
|
&u32,
|
||||||
|
@ -149,7 +149,7 @@ fn test_btree_set() {
|
||||||
});
|
});
|
||||||
|
|
||||||
require_send_sync(async {
|
require_send_sync(async {
|
||||||
let _v = None::<alloc::collections::btree_set::DrainFilter<'_, &u32, fn(&&u32) -> bool>>;
|
let _v = None::<alloc::collections::btree_set::ExtractIf<'_, &u32, fn(&&u32) -> bool>>;
|
||||||
async {}.await;
|
async {}.await;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -238,7 +238,7 @@ fn test_linked_list() {
|
||||||
/*
|
/*
|
||||||
require_send_sync(async {
|
require_send_sync(async {
|
||||||
let _v =
|
let _v =
|
||||||
None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>;
|
None::<alloc::collections::linked_list::ExtractIf<'_, &u32, fn(&mut &u32) -> bool>>;
|
||||||
async {}.await;
|
async {}.await;
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![feature(allocator_api)]
|
#![feature(allocator_api)]
|
||||||
#![feature(alloc_layout_extra)]
|
#![feature(alloc_layout_extra)]
|
||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(btree_drain_filter)]
|
#![feature(btree_extract_if)]
|
||||||
#![feature(cow_is_borrowed)]
|
#![feature(cow_is_borrowed)]
|
||||||
#![feature(const_cow_is_borrowed)]
|
#![feature(const_cow_is_borrowed)]
|
||||||
#![feature(const_heap)]
|
#![feature(const_heap)]
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
#![feature(const_ptr_write)]
|
#![feature(const_ptr_write)]
|
||||||
#![feature(const_try)]
|
#![feature(const_try)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(drain_filter)]
|
#![feature(extract_if)]
|
||||||
#![feature(exact_size_is_empty)]
|
#![feature(exact_size_is_empty)]
|
||||||
#![feature(linked_list_cursors)]
|
#![feature(linked_list_cursors)]
|
||||||
#![feature(map_try_insert)]
|
#![feature(map_try_insert)]
|
||||||
|
|
|
@ -1347,11 +1347,11 @@ fn overaligned_allocations() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_empty() {
|
fn extract_if_empty() {
|
||||||
let mut vec: Vec<i32> = vec![];
|
let mut vec: Vec<i32> = vec![];
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut iter = vec.drain_filter(|_| true);
|
let mut iter = vec.extract_if(|_| true);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||||
assert_eq!(iter.next(), None);
|
assert_eq!(iter.next(), None);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||||
|
@ -1363,12 +1363,12 @@ fn drain_filter_empty() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_zst() {
|
fn extract_if_zst() {
|
||||||
let mut vec = vec![(), (), (), (), ()];
|
let mut vec = vec![(), (), (), (), ()];
|
||||||
let initial_len = vec.len();
|
let initial_len = vec.len();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
{
|
{
|
||||||
let mut iter = vec.drain_filter(|_| true);
|
let mut iter = vec.extract_if(|_| true);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
||||||
while let Some(_) = iter.next() {
|
while let Some(_) = iter.next() {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -1385,13 +1385,13 @@ fn drain_filter_zst() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_false() {
|
fn extract_if_false() {
|
||||||
let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
|
||||||
let initial_len = vec.len();
|
let initial_len = vec.len();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
{
|
{
|
||||||
let mut iter = vec.drain_filter(|_| false);
|
let mut iter = vec.extract_if(|_| false);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
||||||
for _ in iter.by_ref() {
|
for _ in iter.by_ref() {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -1407,13 +1407,13 @@ fn drain_filter_false() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_true() {
|
fn extract_if_true() {
|
||||||
let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
|
||||||
let initial_len = vec.len();
|
let initial_len = vec.len();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
{
|
{
|
||||||
let mut iter = vec.drain_filter(|_| true);
|
let mut iter = vec.extract_if(|_| true);
|
||||||
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
|
||||||
while let Some(_) = iter.next() {
|
while let Some(_) = iter.next() {
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -1430,7 +1430,7 @@ fn drain_filter_true() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_complex() {
|
fn extract_if_complex() {
|
||||||
{
|
{
|
||||||
// [+xxx++++++xxxxx++++x+x++]
|
// [+xxx++++++xxxxx++++x+x++]
|
||||||
let mut vec = vec![
|
let mut vec = vec![
|
||||||
|
@ -1438,7 +1438,7 @@ fn drain_filter_complex() {
|
||||||
39,
|
39,
|
||||||
];
|
];
|
||||||
|
|
||||||
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||||
|
|
||||||
|
@ -1452,7 +1452,7 @@ fn drain_filter_complex() {
|
||||||
2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39,
|
2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39,
|
||||||
];
|
];
|
||||||
|
|
||||||
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||||
|
|
||||||
|
@ -1465,7 +1465,7 @@ fn drain_filter_complex() {
|
||||||
let mut vec =
|
let mut vec =
|
||||||
vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36];
|
vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36];
|
||||||
|
|
||||||
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
|
||||||
|
|
||||||
|
@ -1477,7 +1477,7 @@ fn drain_filter_complex() {
|
||||||
// [xxxxxxxxxx+++++++++++]
|
// [xxxxxxxxxx+++++++++++]
|
||||||
let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
|
let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
|
||||||
|
|
||||||
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
||||||
|
|
||||||
|
@ -1489,7 +1489,7 @@ fn drain_filter_complex() {
|
||||||
// [+++++++++++xxxxxxxxxx]
|
// [+++++++++++xxxxxxxxxx]
|
||||||
let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20];
|
let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20];
|
||||||
|
|
||||||
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||||
assert_eq!(removed.len(), 10);
|
assert_eq!(removed.len(), 10);
|
||||||
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
||||||
|
|
||||||
|
@ -1502,7 +1502,7 @@ fn drain_filter_complex() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(target_os = "emscripten"))]
|
#[cfg(not(target_os = "emscripten"))]
|
||||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||||
fn drain_filter_consumed_panic() {
|
fn extract_if_consumed_panic() {
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
@ -1537,9 +1537,9 @@ fn drain_filter_consumed_panic() {
|
||||||
}
|
}
|
||||||
c.index < 6
|
c.index < 6
|
||||||
};
|
};
|
||||||
let drain = data.drain_filter(filter);
|
let drain = data.extract_if(filter);
|
||||||
|
|
||||||
// NOTE: The DrainFilter is explicitly consumed
|
// NOTE: The ExtractIf is explicitly consumed
|
||||||
drain.for_each(drop);
|
drain.for_each(drop);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1555,7 +1555,7 @@ fn drain_filter_consumed_panic() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(target_os = "emscripten"))]
|
#[cfg(not(target_os = "emscripten"))]
|
||||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||||
fn drain_filter_unconsumed_panic() {
|
fn extract_if_unconsumed_panic() {
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
@ -1590,9 +1590,9 @@ fn drain_filter_unconsumed_panic() {
|
||||||
}
|
}
|
||||||
c.index < 6
|
c.index < 6
|
||||||
};
|
};
|
||||||
let _drain = data.drain_filter(filter);
|
let _drain = data.extract_if(filter);
|
||||||
|
|
||||||
// NOTE: The DrainFilter is dropped without being consumed
|
// NOTE: The ExtractIf is dropped without being consumed
|
||||||
});
|
});
|
||||||
|
|
||||||
let drop_counts = drop_counts.lock().unwrap();
|
let drop_counts = drop_counts.lock().unwrap();
|
||||||
|
@ -1604,40 +1604,11 @@ fn drain_filter_unconsumed_panic() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_unconsumed() {
|
fn extract_if_unconsumed() {
|
||||||
let mut vec = vec![1, 2, 3, 4];
|
let mut vec = vec![1, 2, 3, 4];
|
||||||
let drain = vec.drain_filter(|&mut x| x % 2 != 0);
|
let drain = vec.extract_if(|&mut x| x % 2 != 0);
|
||||||
drop(drain);
|
drop(drain);
|
||||||
assert_eq!(vec, [2, 4]);
|
assert_eq!(vec, [1, 2, 3, 4]);
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_drain_filter_keep_rest() {
|
|
||||||
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
|
|
||||||
let mut drain = v.drain_filter(|&mut x| x % 2 == 0);
|
|
||||||
assert_eq!(drain.next(), Some(0));
|
|
||||||
assert_eq!(drain.next(), Some(2));
|
|
||||||
|
|
||||||
drain.keep_rest();
|
|
||||||
assert_eq!(v, &[1, 3, 4, 5, 6]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_drain_filter_keep_rest_all() {
|
|
||||||
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
|
|
||||||
v.drain_filter(|_| true).keep_rest();
|
|
||||||
assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_drain_filter_keep_rest_none() {
|
|
||||||
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
|
|
||||||
let mut drain = v.drain_filter(|_| true);
|
|
||||||
|
|
||||||
drain.by_ref().for_each(drop);
|
|
||||||
|
|
||||||
drain.keep_rest();
|
|
||||||
assert_eq!(v, &[]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -21,7 +21,7 @@ libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-o
|
||||||
compiler_builtins = { version = "0.1.92" }
|
compiler_builtins = { version = "0.1.92" }
|
||||||
profiler_builtins = { path = "../profiler_builtins", optional = true }
|
profiler_builtins = { path = "../profiler_builtins", optional = true }
|
||||||
unwind = { path = "../unwind" }
|
unwind = { path = "../unwind" }
|
||||||
hashbrown = { version = "0.13", default-features = false, features = ['rustc-dep-of-std'] }
|
hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] }
|
||||||
std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
|
std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
|
||||||
|
|
||||||
# Dependencies of the `backtrace` crate
|
# Dependencies of the `backtrace` crate
|
||||||
|
|
|
@ -623,28 +623,27 @@ impl<K, V, S> HashMap<K, V, S> {
|
||||||
/// If the closure returns false, or panics, the element remains in the map and will not be
|
/// If the closure returns false, or panics, the element remains in the map and will not be
|
||||||
/// yielded.
|
/// yielded.
|
||||||
///
|
///
|
||||||
/// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of
|
/// Note that `extract_if` lets you mutate every value in the filter closure, regardless of
|
||||||
/// whether you choose to keep or remove it.
|
/// whether you choose to keep or remove it.
|
||||||
///
|
///
|
||||||
/// If the iterator is only partially consumed or not consumed at all, each of the remaining
|
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
|
||||||
/// elements will still be subjected to the closure and removed and dropped if it returns true.
|
/// or the iteration short-circuits, then the remaining elements will be retained.
|
||||||
|
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
|
||||||
///
|
///
|
||||||
/// It is unspecified how many more elements will be subjected to the closure
|
/// [`retain`]: HashMap::retain
|
||||||
/// if a panic occurs in the closure, or a panic occurs while dropping an element,
|
|
||||||
/// or if the `DrainFilter` value is leaked.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Splitting a map into even and odd keys, reusing the original map:
|
/// Splitting a map into even and odd keys, reusing the original map:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(hash_drain_filter)]
|
/// #![feature(hash_extract_if)]
|
||||||
/// use std::collections::HashMap;
|
/// use std::collections::HashMap;
|
||||||
///
|
///
|
||||||
/// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
|
/// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
|
||||||
/// let drained: HashMap<i32, i32> = map.drain_filter(|k, _v| k % 2 == 0).collect();
|
/// let extracted: HashMap<i32, i32> = map.extract_if(|k, _v| k % 2 == 0).collect();
|
||||||
///
|
///
|
||||||
/// let mut evens = drained.keys().copied().collect::<Vec<_>>();
|
/// let mut evens = extracted.keys().copied().collect::<Vec<_>>();
|
||||||
/// let mut odds = map.keys().copied().collect::<Vec<_>>();
|
/// let mut odds = map.keys().copied().collect::<Vec<_>>();
|
||||||
/// evens.sort();
|
/// evens.sort();
|
||||||
/// odds.sort();
|
/// odds.sort();
|
||||||
|
@ -654,12 +653,12 @@ impl<K, V, S> HashMap<K, V, S> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_lint_query_instability]
|
#[rustc_lint_query_instability]
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
|
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
{
|
{
|
||||||
DrainFilter { base: self.base.drain_filter(pred) }
|
ExtractIf { base: self.base.extract_if(pred) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retains only the elements specified by the predicate.
|
/// Retains only the elements specified by the predicate.
|
||||||
|
@ -1578,28 +1577,29 @@ impl<'a, K, V> Drain<'a, K, V> {
|
||||||
|
|
||||||
/// A draining, filtering iterator over the entries of a `HashMap`.
|
/// A draining, filtering iterator over the entries of a `HashMap`.
|
||||||
///
|
///
|
||||||
/// This `struct` is created by the [`drain_filter`] method on [`HashMap`].
|
/// This `struct` is created by the [`extract_if`] method on [`HashMap`].
|
||||||
///
|
///
|
||||||
/// [`drain_filter`]: HashMap::drain_filter
|
/// [`extract_if`]: HashMap::extract_if
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(hash_drain_filter)]
|
/// #![feature(hash_extract_if)]
|
||||||
///
|
///
|
||||||
/// use std::collections::HashMap;
|
/// use std::collections::HashMap;
|
||||||
///
|
///
|
||||||
/// let mut map = HashMap::from([
|
/// let mut map = HashMap::from([
|
||||||
/// ("a", 1),
|
/// ("a", 1),
|
||||||
/// ]);
|
/// ]);
|
||||||
/// let iter = map.drain_filter(|_k, v| *v % 2 == 0);
|
/// let iter = map.extract_if(|_k, v| *v % 2 == 0);
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
pub struct DrainFilter<'a, K, V, F>
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
|
pub struct ExtractIf<'a, K, V, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
{
|
{
|
||||||
base: base::DrainFilter<'a, K, V, F>,
|
base: base::ExtractIf<'a, K, V, F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mutable iterator over the values of a `HashMap`.
|
/// A mutable iterator over the values of a `HashMap`.
|
||||||
|
@ -2479,8 +2479,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
impl<K, V, F> Iterator for DrainFilter<'_, K, V, F>
|
impl<K, V, F> Iterator for ExtractIf<'_, K, V, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
{
|
{
|
||||||
|
@ -2496,16 +2496,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
impl<K, V, F> FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
|
impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
|
||||||
|
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
impl<'a, K, V, F> fmt::Debug for DrainFilter<'a, K, V, F>
|
impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&K, &mut V) -> bool,
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("DrainFilter").finish_non_exhaustive()
|
f.debug_struct("ExtractIf").finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -944,7 +944,7 @@ fn test_raw_entry() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_drain_filter {
|
mod test_extract_if {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::panic::{catch_unwind, AssertUnwindSafe};
|
use crate::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
|
@ -968,7 +968,7 @@ mod test_drain_filter {
|
||||||
#[test]
|
#[test]
|
||||||
fn empty() {
|
fn empty() {
|
||||||
let mut map: HashMap<i32, i32> = HashMap::new();
|
let mut map: HashMap<i32, i32> = HashMap::new();
|
||||||
map.drain_filter(|_, _| unreachable!("there's nothing to decide on"));
|
map.extract_if(|_, _| unreachable!("there's nothing to decide on")).for_each(drop);
|
||||||
assert!(map.is_empty());
|
assert!(map.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -976,7 +976,7 @@ mod test_drain_filter {
|
||||||
fn consuming_nothing() {
|
fn consuming_nothing() {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map: HashMap<_, _> = pairs.collect();
|
let mut map: HashMap<_, _> = pairs.collect();
|
||||||
assert!(map.drain_filter(|_, _| false).eq_sorted(crate::iter::empty()));
|
assert!(map.extract_if(|_, _| false).eq_sorted(crate::iter::empty()));
|
||||||
assert_eq!(map.len(), 3);
|
assert_eq!(map.len(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -984,7 +984,7 @@ mod test_drain_filter {
|
||||||
fn consuming_all() {
|
fn consuming_all() {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map: HashMap<_, _> = pairs.clone().collect();
|
let mut map: HashMap<_, _> = pairs.clone().collect();
|
||||||
assert!(map.drain_filter(|_, _| true).eq_sorted(pairs));
|
assert!(map.extract_if(|_, _| true).eq_sorted(pairs));
|
||||||
assert!(map.is_empty());
|
assert!(map.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -993,7 +993,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map: HashMap<_, _> = pairs.collect();
|
let mut map: HashMap<_, _> = pairs.collect();
|
||||||
assert!(
|
assert!(
|
||||||
map.drain_filter(|_, v| {
|
map.extract_if(|_, v| {
|
||||||
*v += 6;
|
*v += 6;
|
||||||
false
|
false
|
||||||
})
|
})
|
||||||
|
@ -1008,7 +1008,7 @@ mod test_drain_filter {
|
||||||
let pairs = (0..3).map(|i| (i, i));
|
let pairs = (0..3).map(|i| (i, i));
|
||||||
let mut map: HashMap<_, _> = pairs.collect();
|
let mut map: HashMap<_, _> = pairs.collect();
|
||||||
assert!(
|
assert!(
|
||||||
map.drain_filter(|_, v| {
|
map.extract_if(|_, v| {
|
||||||
*v += 6;
|
*v += 6;
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
|
@ -1034,14 +1034,15 @@ mod test_drain_filter {
|
||||||
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
|
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
catch_unwind(move || {
|
catch_unwind(move || {
|
||||||
drop(map.drain_filter(|_, _| {
|
map.extract_if(|_, _| {
|
||||||
PREDS.fetch_add(1, Ordering::SeqCst);
|
PREDS.fetch_add(1, Ordering::SeqCst);
|
||||||
true
|
true
|
||||||
}))
|
})
|
||||||
|
.for_each(drop)
|
||||||
})
|
})
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
assert_eq!(PREDS.load(Ordering::SeqCst), 3);
|
assert_eq!(PREDS.load(Ordering::SeqCst), 2);
|
||||||
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
|
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,10 +1061,11 @@ mod test_drain_filter {
|
||||||
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
|
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
catch_unwind(AssertUnwindSafe(|| {
|
catch_unwind(AssertUnwindSafe(|| {
|
||||||
drop(map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
|
map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
|
||||||
0 => true,
|
0 => true,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}))
|
})
|
||||||
|
.for_each(drop)
|
||||||
}))
|
}))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
|
@ -1088,7 +1090,7 @@ mod test_drain_filter {
|
||||||
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
|
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut it = map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
|
let mut it = map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
|
||||||
0 => true,
|
0 => true,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -262,25 +262,24 @@ impl<T, S> HashSet<T, S> {
|
||||||
/// If the closure returns false, the value will remain in the list and will not be yielded
|
/// If the closure returns false, the value will remain in the list and will not be yielded
|
||||||
/// by the iterator.
|
/// by the iterator.
|
||||||
///
|
///
|
||||||
/// If the iterator is only partially consumed or not consumed at all, each of the remaining
|
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
|
||||||
/// values will still be subjected to the closure and removed and dropped if it returns true.
|
/// or the iteration short-circuits, then the remaining elements will be retained.
|
||||||
|
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
|
||||||
///
|
///
|
||||||
/// It is unspecified how many more values will be subjected to the closure
|
/// [`retain`]: HashSet::retain
|
||||||
/// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the
|
|
||||||
/// `DrainFilter` itself is leaked.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Splitting a set into even and odd values, reusing the original set:
|
/// Splitting a set into even and odd values, reusing the original set:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(hash_drain_filter)]
|
/// #![feature(hash_extract_if)]
|
||||||
/// use std::collections::HashSet;
|
/// use std::collections::HashSet;
|
||||||
///
|
///
|
||||||
/// let mut set: HashSet<i32> = (0..8).collect();
|
/// let mut set: HashSet<i32> = (0..8).collect();
|
||||||
/// let drained: HashSet<i32> = set.drain_filter(|v| v % 2 == 0).collect();
|
/// let extracted: HashSet<i32> = set.extract_if(|v| v % 2 == 0).collect();
|
||||||
///
|
///
|
||||||
/// let mut evens = drained.into_iter().collect::<Vec<_>>();
|
/// let mut evens = extracted.into_iter().collect::<Vec<_>>();
|
||||||
/// let mut odds = set.into_iter().collect::<Vec<_>>();
|
/// let mut odds = set.into_iter().collect::<Vec<_>>();
|
||||||
/// evens.sort();
|
/// evens.sort();
|
||||||
/// odds.sort();
|
/// odds.sort();
|
||||||
|
@ -290,12 +289,12 @@ impl<T, S> HashSet<T, S> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_lint_query_instability]
|
#[rustc_lint_query_instability]
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
|
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, T, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&T) -> bool,
|
F: FnMut(&T) -> bool,
|
||||||
{
|
{
|
||||||
DrainFilter { base: self.base.drain_filter(pred) }
|
ExtractIf { base: self.base.extract_if(pred) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retains only the elements specified by the predicate.
|
/// Retains only the elements specified by the predicate.
|
||||||
|
@ -1312,27 +1311,27 @@ pub struct Drain<'a, K: 'a> {
|
||||||
|
|
||||||
/// A draining, filtering iterator over the items of a `HashSet`.
|
/// A draining, filtering iterator over the items of a `HashSet`.
|
||||||
///
|
///
|
||||||
/// This `struct` is created by the [`drain_filter`] method on [`HashSet`].
|
/// This `struct` is created by the [`extract_if`] method on [`HashSet`].
|
||||||
///
|
///
|
||||||
/// [`drain_filter`]: HashSet::drain_filter
|
/// [`extract_if`]: HashSet::extract_if
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(hash_drain_filter)]
|
/// #![feature(hash_extract_if)]
|
||||||
///
|
///
|
||||||
/// use std::collections::HashSet;
|
/// use std::collections::HashSet;
|
||||||
///
|
///
|
||||||
/// let mut a = HashSet::from([1, 2, 3]);
|
/// let mut a = HashSet::from([1, 2, 3]);
|
||||||
///
|
///
|
||||||
/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0);
|
/// let mut extract_ifed = a.extract_if(|v| v % 2 == 0);
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
pub struct DrainFilter<'a, K, F>
|
pub struct ExtractIf<'a, K, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&K) -> bool,
|
F: FnMut(&K) -> bool,
|
||||||
{
|
{
|
||||||
base: base::DrainFilter<'a, K, F>,
|
base: base::ExtractIf<'a, K, F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A lazy iterator producing elements in the intersection of `HashSet`s.
|
/// A lazy iterator producing elements in the intersection of `HashSet`s.
|
||||||
|
@ -1578,8 +1577,8 @@ impl<K: fmt::Debug> fmt::Debug for Drain<'_, K> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
impl<K, F> Iterator for DrainFilter<'_, K, F>
|
impl<K, F> Iterator for ExtractIf<'_, K, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&K) -> bool,
|
F: FnMut(&K) -> bool,
|
||||||
{
|
{
|
||||||
|
@ -1595,16 +1594,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
impl<K, F> FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {}
|
impl<K, F> FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {}
|
||||||
|
|
||||||
#[unstable(feature = "hash_drain_filter", issue = "59618")]
|
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||||
impl<'a, K, F> fmt::Debug for DrainFilter<'a, K, F>
|
impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F>
|
||||||
where
|
where
|
||||||
F: FnMut(&K) -> bool,
|
F: FnMut(&K) -> bool,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("DrainFilter").finish_non_exhaustive()
|
f.debug_struct("ExtractIf").finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -419,18 +419,18 @@ fn test_retain() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_drain_filter() {
|
fn test_extract_if() {
|
||||||
let mut x: HashSet<_> = [1].iter().copied().collect();
|
let mut x: HashSet<_> = [1].iter().copied().collect();
|
||||||
let mut y: HashSet<_> = [1].iter().copied().collect();
|
let mut y: HashSet<_> = [1].iter().copied().collect();
|
||||||
|
|
||||||
x.drain_filter(|_| true);
|
x.extract_if(|_| true).for_each(drop);
|
||||||
y.drain_filter(|_| false);
|
y.extract_if(|_| false).for_each(drop);
|
||||||
assert_eq!(x.len(), 0);
|
assert_eq!(x.len(), 0);
|
||||||
assert_eq!(y.len(), 1);
|
assert_eq!(y.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_drain_filter_drop_panic_leak() {
|
fn test_extract_if_drop_panic_leak() {
|
||||||
static PREDS: AtomicU32 = AtomicU32::new(0);
|
static PREDS: AtomicU32 = AtomicU32::new(0);
|
||||||
static DROPS: AtomicU32 = AtomicU32::new(0);
|
static DROPS: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
|
@ -447,19 +447,20 @@ fn test_drain_filter_drop_panic_leak() {
|
||||||
let mut set = (0..3).map(|i| D(i)).collect::<HashSet<_>>();
|
let mut set = (0..3).map(|i| D(i)).collect::<HashSet<_>>();
|
||||||
|
|
||||||
catch_unwind(move || {
|
catch_unwind(move || {
|
||||||
drop(set.drain_filter(|_| {
|
set.extract_if(|_| {
|
||||||
PREDS.fetch_add(1, Ordering::SeqCst);
|
PREDS.fetch_add(1, Ordering::SeqCst);
|
||||||
true
|
true
|
||||||
}))
|
})
|
||||||
|
.for_each(drop)
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
assert_eq!(PREDS.load(Ordering::SeqCst), 3);
|
assert_eq!(PREDS.load(Ordering::SeqCst), 2);
|
||||||
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
|
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_drain_filter_pred_panic_leak() {
|
fn test_extract_if_pred_panic_leak() {
|
||||||
static PREDS: AtomicU32 = AtomicU32::new(0);
|
static PREDS: AtomicU32 = AtomicU32::new(0);
|
||||||
static DROPS: AtomicU32 = AtomicU32::new(0);
|
static DROPS: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
|
@ -474,10 +475,11 @@ fn test_drain_filter_pred_panic_leak() {
|
||||||
let mut set: HashSet<_> = (0..3).map(|_| D).collect();
|
let mut set: HashSet<_> = (0..3).map(|_| D).collect();
|
||||||
|
|
||||||
catch_unwind(AssertUnwindSafe(|| {
|
catch_unwind(AssertUnwindSafe(|| {
|
||||||
drop(set.drain_filter(|_| match PREDS.fetch_add(1, Ordering::SeqCst) {
|
set.extract_if(|_| match PREDS.fetch_add(1, Ordering::SeqCst) {
|
||||||
0 => true,
|
0 => true,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}))
|
})
|
||||||
|
.for_each(drop)
|
||||||
}))
|
}))
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
|
|
|
@ -158,13 +158,13 @@ pub(crate) fn try_inline_glob(
|
||||||
.filter_map(|child| child.res.opt_def_id())
|
.filter_map(|child| child.res.opt_def_id())
|
||||||
.collect();
|
.collect();
|
||||||
let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports));
|
let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports));
|
||||||
items.drain_filter(|item| {
|
items.retain(|item| {
|
||||||
if let Some(name) = item.name {
|
if let Some(name) = item.name {
|
||||||
// If an item with the same type and name already exists,
|
// If an item with the same type and name already exists,
|
||||||
// it takes priority over the inlined stuff.
|
// it takes priority over the inlined stuff.
|
||||||
!inlined_names.insert((item.type_(), name))
|
inlined_names.insert((item.type_(), name))
|
||||||
} else {
|
} else {
|
||||||
false
|
true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Some(items)
|
Some(items)
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#![feature(array_methods)]
|
#![feature(array_methods)]
|
||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(drain_filter)]
|
|
||||||
#![feature(impl_trait_in_assoc_type)]
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
#![feature(lazy_cell)]
|
#![feature(lazy_cell)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//@revisions: stack tree
|
//@revisions: stack tree
|
||||||
//@[tree]compile-flags: -Zmiri-tree-borrows
|
//@[tree]compile-flags: -Zmiri-tree-borrows
|
||||||
//@compile-flags: -Zmiri-strict-provenance
|
//@compile-flags: -Zmiri-strict-provenance
|
||||||
#![feature(btree_drain_filter)]
|
#![feature(btree_extract_if)]
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ pub fn main() {
|
||||||
}
|
}
|
||||||
test_all_refs(&mut 13, b.values_mut());
|
test_all_refs(&mut 13, b.values_mut());
|
||||||
|
|
||||||
// Test forgetting the drain.
|
// Test forgetting the extractor.
|
||||||
let mut d = b.drain_filter(|_, i| *i < 30);
|
let mut d = b.extract_if(|_, i| *i < 30);
|
||||||
d.next().unwrap();
|
d.next().unwrap();
|
||||||
mem::forget(d);
|
mem::forget(d);
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||||
"adler",
|
"adler",
|
||||||
"ahash",
|
"ahash",
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
|
"allocator-api2", // FIXME: only appears in Cargo.lock due to https://github.com/rust-lang/cargo/issues/10801
|
||||||
"annotate-snippets",
|
"annotate-snippets",
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"ar_archive_writer",
|
"ar_archive_writer",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//check-pass
|
//check-pass
|
||||||
#![warn(unused)]
|
#![warn(unused)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(btree_drain_filter)]
|
#![feature(btree_extract_if)]
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
|
@ -14,14 +14,14 @@ fn main() {
|
||||||
map.insert("c", ());
|
map.insert("c", ());
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut it = map.drain_filter(|_, _| true);
|
let mut it = map.extract_if(|_, _| true);
|
||||||
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
|
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
|
||||||
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
|
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
|
||||||
assert!(matches!(result, Ok(None)));
|
assert!(matches!(result, Ok(None)));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut it = map.drain_filter(|_, _| true);
|
let mut it = map.extract_if(|_, _| true);
|
||||||
catch_unwind(AssertUnwindSafe(|| while let Some(_) = it.next() {})).unwrap_err();
|
catch_unwind(AssertUnwindSafe(|| while let Some(_) = it.next() {})).unwrap_err();
|
||||||
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
|
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
|
||||||
assert!(matches!(result, Ok(None)));
|
assert!(matches!(result, Ok(None)));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue