Skip to content

Commit 349241e

Browse files
committed
Auto merge of #101183 - Dylan-DPC:rollup-6kewixv, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #95376 (Add `vec::Drain{,Filter}::keep_rest`) - #100092 (Fall back when relating two opaques by substs in MIR typeck) - #101019 (Suggest returning closure as `impl Fn`) - #101022 (Erase late bound regions before comparing types in `suggest_dereferences`) - #101101 (interpret: make read-pointer-as-bytes a CTFE-only error with extra information) - #101123 (Remove `register_attr` feature) - #101175 (Don't --bless in pre-push hook) - #101176 (rustdoc: remove unused CSS selectors for `.table-display`) - #101180 (Add another MaybeUninit array test with const) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents e4f52f0 + ea763b8 commit 349241e

File tree

4 files changed

+190
-3
lines changed

4 files changed

+190
-3
lines changed

alloc/src/vec/drain.rs

+72-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::alloc::{Allocator, Global};
22
use core::fmt;
33
use core::iter::{FusedIterator, TrustedLen};
4-
use core::mem;
4+
use core::mem::{self, ManuallyDrop};
55
use core::ptr::{self, NonNull};
66
use core::slice::{self};
77

@@ -65,6 +65,77 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
6565
pub fn allocator(&self) -> &A {
6666
unsafe { self.vec.as_ref().allocator() }
6767
}
68+
69+
/// Keep unyielded elements in the source `Vec`.
70+
///
71+
/// # Examples
72+
///
73+
/// ```
74+
/// #![feature(drain_keep_rest)]
75+
///
76+
/// let mut vec = vec!['a', 'b', 'c'];
77+
/// let mut drain = vec.drain(..);
78+
///
79+
/// assert_eq!(drain.next().unwrap(), 'a');
80+
///
81+
/// // This call keeps 'b' and 'c' in the vec.
82+
/// drain.keep_rest();
83+
///
84+
/// // If we wouldn't call `keep_rest()`,
85+
/// // `vec` would be empty.
86+
/// assert_eq!(vec, ['b', 'c']);
87+
/// ```
88+
#[unstable(feature = "drain_keep_rest", issue = "101122")]
89+
pub fn keep_rest(self) {
90+
// At this moment layout looks like this:
91+
//
92+
// [head] [yielded by next] [unyielded] [yielded by next_back] [tail]
93+
// ^-- start \_________/-- unyielded_len \____/-- self.tail_len
94+
// ^-- unyielded_ptr ^-- tail
95+
//
96+
// Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`.
97+
// Here we want to
98+
// 1. Move [unyielded] to `start`
99+
// 2. Move [tail] to a new start at `start + len(unyielded)`
100+
// 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)`
101+
// a. In case of ZST, this is the only thing we want to do
102+
// 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
103+
let mut this = ManuallyDrop::new(self);
104+
105+
unsafe {
106+
let source_vec = this.vec.as_mut();
107+
108+
let start = source_vec.len();
109+
let tail = this.tail_start;
110+
111+
let unyielded_len = this.iter.len();
112+
let unyielded_ptr = this.iter.as_slice().as_ptr();
113+
114+
// ZSTs have no identity, so we don't need to move them around.
115+
let needs_move = mem::size_of::<T>() != 0;
116+
117+
if needs_move {
118+
let start_ptr = source_vec.as_mut_ptr().add(start);
119+
120+
// memmove back unyielded elements
121+
if unyielded_ptr != start_ptr {
122+
let src = unyielded_ptr;
123+
let dst = start_ptr;
124+
125+
ptr::copy(src, dst, unyielded_len);
126+
}
127+
128+
// memmove back untouched tail
129+
if tail != (start + unyielded_len) {
130+
let src = source_vec.as_ptr().add(tail);
131+
let dst = start_ptr.add(unyielded_len);
132+
ptr::copy(src, dst, this.tail_len);
133+
}
134+
}
135+
136+
source_vec.set_len(start + unyielded_len + this.tail_len);
137+
}
138+
}
68139
}
69140

70141
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]

alloc/src/vec/drain_filter.rs

+58-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::alloc::{Allocator, Global};
2-
use core::ptr::{self};
3-
use core::slice::{self};
2+
use core::mem::{self, ManuallyDrop};
3+
use core::ptr;
4+
use core::slice;
45

56
use super::Vec;
67

@@ -54,6 +55,61 @@ where
5455
pub fn allocator(&self) -> &A {
5556
self.vec.allocator()
5657
}
58+
59+
/// Keep unyielded elements in the source `Vec`.
60+
///
61+
/// # Examples
62+
///
63+
/// ```
64+
/// #![feature(drain_filter)]
65+
/// #![feature(drain_keep_rest)]
66+
///
67+
/// let mut vec = vec!['a', 'b', 'c'];
68+
/// let mut drain = vec.drain_filter(|_| true);
69+
///
70+
/// assert_eq!(drain.next().unwrap(), 'a');
71+
///
72+
/// // This call keeps 'b' and 'c' in the vec.
73+
/// drain.keep_rest();
74+
///
75+
/// // If we wouldn't call `keep_rest()`,
76+
/// // `vec` would be empty.
77+
/// assert_eq!(vec, ['b', 'c']);
78+
/// ```
79+
#[unstable(feature = "drain_keep_rest", issue = "101122")]
80+
pub fn keep_rest(self) {
81+
// At this moment layout looks like this:
82+
//
83+
// _____________________/-- old_len
84+
// / \
85+
// [kept] [yielded] [tail]
86+
// \_______/ ^-- idx
87+
// \-- del
88+
//
89+
// Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
90+
//
91+
// 1. Move [tail] after [kept]
92+
// 2. Update length of the original vec to `old_len - del`
93+
// a. In case of ZST, this is the only thing we want to do
94+
// 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
95+
let mut this = ManuallyDrop::new(self);
96+
97+
unsafe {
98+
// ZSTs have no identity, so we don't need to move them around.
99+
let needs_move = mem::size_of::<T>() != 0;
100+
101+
if needs_move && this.idx < this.old_len && this.del > 0 {
102+
let ptr = this.vec.as_mut_ptr();
103+
let src = ptr.add(this.idx);
104+
let dst = src.sub(this.del);
105+
let tail_len = this.old_len - this.idx;
106+
src.copy_to(dst, tail_len);
107+
}
108+
109+
let new_len = this.old_len - this.del;
110+
this.vec.set_len(new_len);
111+
}
112+
}
57113
}
58114

59115
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]

alloc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#![feature(bench_black_box)]
4545
#![feature(strict_provenance)]
4646
#![feature(once_cell)]
47+
#![feature(drain_keep_rest)]
4748

4849
use std::collections::hash_map::DefaultHasher;
4950
use std::hash::{Hash, Hasher};

alloc/tests/vec.rs

+59
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,36 @@ fn test_drain_leak() {
839839
assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]);
840840
}
841841

842+
#[test]
843+
fn test_drain_keep_rest() {
844+
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
845+
let mut drain = v.drain(1..6);
846+
assert_eq!(drain.next(), Some(1));
847+
assert_eq!(drain.next_back(), Some(5));
848+
assert_eq!(drain.next(), Some(2));
849+
850+
drain.keep_rest();
851+
assert_eq!(v, &[0, 3, 4, 6]);
852+
}
853+
854+
#[test]
855+
fn test_drain_keep_rest_all() {
856+
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
857+
v.drain(1..6).keep_rest();
858+
assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]);
859+
}
860+
861+
#[test]
862+
fn test_drain_keep_rest_none() {
863+
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
864+
let mut drain = v.drain(1..6);
865+
866+
drain.by_ref().for_each(drop);
867+
868+
drain.keep_rest();
869+
assert_eq!(v, &[0, 6]);
870+
}
871+
842872
#[test]
843873
fn test_splice() {
844874
let mut v = vec![1, 2, 3, 4, 5];
@@ -1533,6 +1563,35 @@ fn drain_filter_unconsumed() {
15331563
assert_eq!(vec, [2, 4]);
15341564
}
15351565

1566+
#[test]
1567+
fn test_drain_filter_keep_rest() {
1568+
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
1569+
let mut drain = v.drain_filter(|&mut x| x % 2 == 0);
1570+
assert_eq!(drain.next(), Some(0));
1571+
assert_eq!(drain.next(), Some(2));
1572+
1573+
drain.keep_rest();
1574+
assert_eq!(v, &[1, 3, 4, 5, 6]);
1575+
}
1576+
1577+
#[test]
1578+
fn test_drain_filter_keep_rest_all() {
1579+
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
1580+
v.drain_filter(|_| true).keep_rest();
1581+
assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6]);
1582+
}
1583+
1584+
#[test]
1585+
fn test_drain_filter_keep_rest_none() {
1586+
let mut v = vec![0, 1, 2, 3, 4, 5, 6];
1587+
let mut drain = v.drain_filter(|_| true);
1588+
1589+
drain.by_ref().for_each(drop);
1590+
1591+
drain.keep_rest();
1592+
assert_eq!(v, &[]);
1593+
}
1594+
15361595
#[test]
15371596
fn test_reserve_exact() {
15381597
// This is all the same as test_reserve

0 commit comments

Comments
 (0)