Skip to content

Commit ec4e1ca

Browse files
authored
Rollup merge of rust-lang#133265 - the8472:extract-if-ranges, r=cuviper
Add a range argument to vec.extract_if tracking issue: rust-lang#43244 This adds the range argument requested in rust-lang#43244 (comment)
2 parents b9e001f + 44790c4 commit ec4e1ca

File tree

11 files changed

+105
-72
lines changed

11 files changed

+105
-72
lines changed

compiler/rustc_errors/src/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1569,18 +1569,18 @@ impl DiagCtxtInner {
15691569
debug!(?diagnostic);
15701570
debug!(?self.emitted_diagnostics);
15711571

1572-
let already_emitted_sub = |sub: &mut Subdiag| {
1572+
let not_yet_emitted = |sub: &mut Subdiag| {
15731573
debug!(?sub);
15741574
if sub.level != OnceNote && sub.level != OnceHelp {
1575-
return false;
1575+
return true;
15761576
}
15771577
let mut hasher = StableHasher::new();
15781578
sub.hash(&mut hasher);
15791579
let diagnostic_hash = hasher.finish();
15801580
debug!(?diagnostic_hash);
1581-
!self.emitted_diagnostics.insert(diagnostic_hash)
1581+
self.emitted_diagnostics.insert(diagnostic_hash)
15821582
};
1583-
diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {});
1583+
diagnostic.children.retain_mut(not_yet_emitted);
15841584
if already_emitted {
15851585
let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`";
15861586
diagnostic.sub(Note, msg, MultiSpan::new());

compiler/rustc_lint/src/non_ascii_idents.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ impl EarlyLintPass for NonAsciiIdents {
205205
(IdentifierType::Not_NFKC, "Not_NFKC"),
206206
] {
207207
let codepoints: Vec<_> =
208-
chars.extract_if(|(_, ty)| *ty == Some(id_ty)).collect();
208+
chars.extract_if(.., |(_, ty)| *ty == Some(id_ty)).collect();
209209
if codepoints.is_empty() {
210210
continue;
211211
}
@@ -217,7 +217,7 @@ impl EarlyLintPass for NonAsciiIdents {
217217
}
218218

219219
let remaining = chars
220-
.extract_if(|(c, _)| !GeneralSecurityProfile::identifier_allowed(*c))
220+
.extract_if(.., |(c, _)| !GeneralSecurityProfile::identifier_allowed(*c))
221221
.collect::<Vec<_>>();
222222
if !remaining.is_empty() {
223223
cx.emit_span_lint(UNCOMMON_CODEPOINTS, sp, IdentifierUncommonCodepoints {

compiler/rustc_metadata/src/native_libs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ impl<'tcx> Collector<'tcx> {
544544
// can move them to the end of the list below.
545545
let mut existing = self
546546
.libs
547-
.extract_if(|lib| {
547+
.extract_if(.., |lib| {
548548
if lib.name.as_str() == passed_lib.name {
549549
// FIXME: This whole logic is questionable, whether modifiers are
550550
// involved or not, library reordering and kind overriding without

compiler/rustc_middle/src/ty/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ pub fn suggest_constraining_type_params<'a>(
309309
let Some(param) = param else { return false };
310310

311311
{
312-
let mut sized_constraints = constraints.extract_if(|(_, def_id, _)| {
312+
let mut sized_constraints = constraints.extract_if(.., |(_, def_id, _)| {
313313
def_id.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Sized))
314314
});
315315
if let Some((_, def_id, _)) = sized_constraints.next() {

compiler/rustc_resolve/src/diagnostics.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2817,11 +2817,11 @@ fn show_candidates(
28172817
path_strings.sort_by(|a, b| a.0.cmp(&b.0));
28182818
path_strings.dedup_by(|a, b| a.0 == b.0);
28192819
let core_path_strings =
2820-
path_strings.extract_if(|p| p.0.starts_with("core::")).collect::<Vec<_>>();
2820+
path_strings.extract_if(.., |p| p.0.starts_with("core::")).collect::<Vec<_>>();
28212821
let std_path_strings =
2822-
path_strings.extract_if(|p| p.0.starts_with("std::")).collect::<Vec<_>>();
2822+
path_strings.extract_if(.., |p| p.0.starts_with("std::")).collect::<Vec<_>>();
28232823
let foreign_crate_path_strings =
2824-
path_strings.extract_if(|p| !p.0.starts_with("crate::")).collect::<Vec<_>>();
2824+
path_strings.extract_if(.., |p| !p.0.starts_with("crate::")).collect::<Vec<_>>();
28252825

28262826
// We list the `crate` local paths first.
28272827
// Then we list the `std`/`core` paths.

compiler/rustc_resolve/src/late/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
629629
// Try to filter out intrinsics candidates, as long as we have
630630
// some other candidates to suggest.
631631
let intrinsic_candidates: Vec<_> = candidates
632-
.extract_if(|sugg| {
632+
.extract_if(.., |sugg| {
633633
let path = path_names_to_string(&sugg.path);
634634
path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")
635635
})

compiler/rustc_trait_selection/src/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ pub fn normalize_param_env_or_error<'tcx>(
447447
// This works fairly well because trait matching does not actually care about param-env
448448
// TypeOutlives predicates - these are normally used by regionck.
449449
let outlives_predicates: Vec<_> = predicates
450-
.extract_if(|predicate| {
450+
.extract_if(.., |predicate| {
451451
matches!(predicate.kind().skip_binder(), ty::ClauseKind::TypeOutlives(..))
452452
})
453453
.collect();

library/alloc/src/collections/linked_list.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -1939,9 +1939,7 @@ pub struct ExtractIf<
19391939
T: 'a,
19401940
F: 'a,
19411941
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
1942-
> where
1943-
F: FnMut(&mut T) -> bool,
1944-
{
1942+
> {
19451943
list: &'a mut LinkedList<T, A>,
19461944
it: Option<NonNull<Node<T>>>,
19471945
pred: F,
@@ -1979,10 +1977,7 @@ where
19791977
}
19801978

19811979
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
1982-
impl<T: fmt::Debug, F> fmt::Debug for ExtractIf<'_, T, F>
1983-
where
1984-
F: FnMut(&mut T) -> bool,
1985-
{
1980+
impl<T: fmt::Debug, F> fmt::Debug for ExtractIf<'_, T, F> {
19861981
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19871982
f.debug_tuple("ExtractIf").field(&self.list).finish()
19881983
}

library/alloc/src/vec/extract_if.rs

+25-25
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use core::ops::{Range, RangeBounds};
12
use core::{ptr, slice};
23

34
use super::Vec;
@@ -14,7 +15,7 @@ use crate::alloc::{Allocator, Global};
1415
/// #![feature(extract_if)]
1516
///
1617
/// let mut v = vec![0, 1, 2];
17-
/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0);
18+
/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0);
1819
/// ```
1920
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
2021
#[derive(Debug)]
@@ -24,24 +25,32 @@ pub struct ExtractIf<
2425
T,
2526
F,
2627
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
27-
> where
28-
F: FnMut(&mut T) -> bool,
29-
{
30-
pub(super) vec: &'a mut Vec<T, A>,
28+
> {
29+
vec: &'a mut Vec<T, A>,
3130
/// The index of the item that will be inspected by the next call to `next`.
32-
pub(super) idx: usize,
31+
idx: usize,
32+
/// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`.
33+
end: usize,
3334
/// The number of items that have been drained (removed) thus far.
34-
pub(super) del: usize,
35+
del: usize,
3536
/// The original length of `vec` prior to draining.
36-
pub(super) old_len: usize,
37+
old_len: usize,
3738
/// The filter test predicate.
38-
pub(super) pred: F,
39+
pred: F,
3940
}
4041

41-
impl<T, F, A: Allocator> ExtractIf<'_, T, F, A>
42-
where
43-
F: FnMut(&mut T) -> bool,
44-
{
42+
impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> {
43+
pub(super) fn new<R: RangeBounds<usize>>(vec: &'a mut Vec<T, A>, pred: F, range: R) -> Self {
44+
let old_len = vec.len();
45+
let Range { start, end } = slice::range(range, ..old_len);
46+
47+
// Guard against the vec getting leaked (leak amplification)
48+
unsafe {
49+
vec.set_len(0);
50+
}
51+
ExtractIf { vec, idx: start, del: 0, end, old_len, pred }
52+
}
53+
4554
/// Returns a reference to the underlying allocator.
4655
#[unstable(feature = "allocator_api", issue = "32838")]
4756
#[inline]
@@ -59,7 +68,7 @@ where
5968

6069
fn next(&mut self) -> Option<T> {
6170
unsafe {
62-
while self.idx < self.old_len {
71+
while self.idx < self.end {
6372
let i = self.idx;
6473
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
6574
let drained = (self.pred)(&mut v[i]);
@@ -82,24 +91,15 @@ where
8291
}
8392

8493
fn size_hint(&self) -> (usize, Option<usize>) {
85-
(0, Some(self.old_len - self.idx))
94+
(0, Some(self.end - self.idx))
8695
}
8796
}
8897

8998
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
90-
impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A>
91-
where
92-
F: FnMut(&mut T) -> bool,
93-
{
99+
impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> {
94100
fn drop(&mut self) {
95101
unsafe {
96102
if self.idx < self.old_len && self.del > 0 {
97-
// This is a pretty messed up state, and there isn't really an
98-
// obviously right thing to do. We don't want to keep trying
99-
// to execute `pred`, so we just backshift all the unprocessed
100-
// elements and tell the vec that they still exist. The backshift
101-
// is required to prevent a double-drop of the last successfully
102-
// drained item prior to a panic in the predicate.
103103
let ptr = self.vec.as_mut_ptr();
104104
let src = ptr.add(self.idx);
105105
let dst = src.sub(self.del);

library/alloc/src/vec/mod.rs

+28-15
Original file line numberDiff line numberDiff line change
@@ -3615,12 +3615,15 @@ impl<T, A: Allocator> Vec<T, A> {
36153615
Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
36163616
}
36173617

3618-
/// Creates an iterator which uses a closure to determine if an element should be removed.
3618+
/// Creates an iterator which uses a closure to determine if element in the range should be removed.
36193619
///
36203620
/// If the closure returns true, then the element is removed and yielded.
36213621
/// If the closure returns false, the element will remain in the vector and will not be yielded
36223622
/// by the iterator.
36233623
///
3624+
/// Only elements that fall in the provided range are considered for extraction, but any elements
3625+
/// after the range will still have to be moved if any element has been extracted.
3626+
///
36243627
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
36253628
/// or the iteration short-circuits, then the remaining elements will be retained.
36263629
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
@@ -3630,10 +3633,12 @@ impl<T, A: Allocator> Vec<T, A> {
36303633
/// Using this method is equivalent to the following code:
36313634
///
36323635
/// ```
3636+
/// # use std::cmp::min;
36333637
/// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
36343638
/// # let mut vec = vec![1, 2, 3, 4, 5, 6];
3635-
/// let mut i = 0;
3636-
/// while i < vec.len() {
3639+
/// # let range = 1..4;
3640+
/// let mut i = range.start;
3641+
/// while i < min(vec.len(), range.end) {
36373642
/// if some_predicate(&mut vec[i]) {
36383643
/// let val = vec.remove(i);
36393644
/// // your code here
@@ -3648,8 +3653,12 @@ impl<T, A: Allocator> Vec<T, A> {
36483653
/// But `extract_if` is easier to use. `extract_if` is also more efficient,
36493654
/// because it can backshift the elements of the array in bulk.
36503655
///
3651-
/// Note that `extract_if` also lets you mutate every element in the filter closure,
3652-
/// regardless of whether you choose to keep or remove it.
3656+
/// Note that `extract_if` also lets you mutate the elements passed to the filter closure,
3657+
/// regardless of whether you choose to keep or remove them.
3658+
///
3659+
/// # Panics
3660+
///
3661+
/// If `range` is out of bounds.
36533662
///
36543663
/// # Examples
36553664
///
@@ -3659,25 +3668,29 @@ impl<T, A: Allocator> Vec<T, A> {
36593668
/// #![feature(extract_if)]
36603669
/// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
36613670
///
3662-
/// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
3671+
/// let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>();
36633672
/// let odds = numbers;
36643673
///
36653674
/// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
36663675
/// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
36673676
/// ```
3677+
///
3678+
/// Using the range argument to only process a part of the vector:
3679+
///
3680+
/// ```
3681+
/// #![feature(extract_if)]
3682+
/// let mut items = vec![0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2];
3683+
/// let ones = items.extract_if(7.., |x| *x == 1).collect::<Vec<_>>();
3684+
/// assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]);
3685+
/// assert_eq!(ones.len(), 3);
3686+
/// ```
36683687
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
3669-
pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A>
3688+
pub fn extract_if<F, R>(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A>
36703689
where
36713690
F: FnMut(&mut T) -> bool,
3691+
R: RangeBounds<usize>,
36723692
{
3673-
let old_len = self.len();
3674-
3675-
// Guard against us getting leaked (leak amplification)
3676-
unsafe {
3677-
self.set_len(0);
3678-
}
3679-
3680-
ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter }
3693+
ExtractIf::new(self, filter, range)
36813694
}
36823695
}
36833696

0 commit comments

Comments
 (0)