Skip to content

Commit d62b903

Browse files
committed
VecDeque::resize should re-use the buffer in the passed-in element
Today it always copies it for *every* appended element, but one of those clones is avoidable.
1 parent 101e182 commit d62b903

File tree

9 files changed

+329
-2
lines changed

9 files changed

+329
-2
lines changed

library/alloc/src/collections/vec_deque/mod.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use core::cmp::{self, Ordering};
1111
use core::fmt;
1212
use core::hash::{Hash, Hasher};
13-
use core::iter::{repeat_with, FromIterator};
13+
use core::iter::{repeat_n, repeat_with, FromIterator};
1414
use core::marker::PhantomData;
1515
use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties};
1616
use core::ops::{Index, IndexMut, Range, RangeBounds};
@@ -2833,7 +2833,12 @@ impl<T: Clone, A: Allocator> VecDeque<T, A> {
28332833
/// ```
28342834
#[stable(feature = "deque_extras", since = "1.16.0")]
28352835
pub fn resize(&mut self, new_len: usize, value: T) {
2836-
self.resize_with(new_len, || value.clone());
2836+
if new_len > self.len() {
2837+
let extra = new_len - self.len();
2838+
self.extend(repeat_n(value, extra))
2839+
} else {
2840+
self.truncate(new_len);
2841+
}
28372842
}
28382843
}
28392844

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
#![feature(inplace_iteration)]
125125
#![feature(iter_advance_by)]
126126
#![feature(iter_next_chunk)]
127+
#![feature(iter_repeat_n)]
127128
#![feature(layout_for_ptr)]
128129
#![feature(maybe_uninit_slice)]
129130
#![feature(maybe_uninit_uninit_array)]

library/alloc/tests/vec_deque.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1727,3 +1727,11 @@ fn test_from_zero_sized_vec() {
17271727
let queue = VecDeque::from(v);
17281728
assert_eq!(queue.len(), 100);
17291729
}
1730+
1731+
#[test]
1732+
fn test_resize_keeps_reserved_space_from_item() {
1733+
let v = Vec::<i32>::with_capacity(1234);
1734+
let mut d = VecDeque::new();
1735+
d.resize(1, v);
1736+
assert_eq!(d[0].capacity(), 1234);
1737+
}

library/core/src/iter/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ pub use self::sources::{once, Once};
401401
pub use self::sources::{once_with, OnceWith};
402402
#[stable(feature = "rust1", since = "1.0.0")]
403403
pub use self::sources::{repeat, Repeat};
404+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
405+
pub use self::sources::{repeat_n, RepeatN};
404406
#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
405407
pub use self::sources::{repeat_with, RepeatWith};
406408
#[stable(feature = "iter_successors", since = "1.34.0")]

library/core/src/iter/sources.rs

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod from_generator;
44
mod once;
55
mod once_with;
66
mod repeat;
7+
mod repeat_n;
78
mod repeat_with;
89
mod successors;
910

@@ -16,6 +17,9 @@ pub use self::empty::{empty, Empty};
1617
#[stable(feature = "iter_once", since = "1.2.0")]
1718
pub use self::once::{once, Once};
1819

20+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
21+
pub use self::repeat_n::{repeat_n, RepeatN};
22+
1923
#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
2024
pub use self::repeat_with::{repeat_with, RepeatWith};
2125

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
use crate::iter::{FusedIterator, TrustedLen};
2+
use crate::mem::ManuallyDrop;
3+
4+
/// Creates a new iterator that repeats a single element a given number of times.
5+
///
6+
/// The `repeat_n()` function repeats a single value exactly `n` times.
7+
///
8+
/// This is very similar to using [`repeat()`] with [`Iterator::take()`],
9+
/// but there are two differences:
10+
/// - `repeat_n()` can return the original value, rather than always cloning.
11+
/// - `repeat_n()` produces an [`ExactSizeIterator`].
12+
///
13+
/// [`repeat()`]: crate::iter::repeat
14+
///
15+
/// # Examples
16+
///
17+
/// Basic usage:
18+
///
19+
/// ```
20+
/// #![feature(iter_repeat_n)]
21+
/// use std::iter;
22+
///
23+
/// // four of the the number four:
24+
/// let mut four_fours = iter::repeat_n(4, 4);
25+
///
26+
/// assert_eq!(Some(4), four_fours.next());
27+
/// assert_eq!(Some(4), four_fours.next());
28+
/// assert_eq!(Some(4), four_fours.next());
29+
/// assert_eq!(Some(4), four_fours.next());
30+
///
31+
/// // no more fours
32+
/// assert_eq!(None, four_fours.next());
33+
/// ```
34+
///
35+
/// For non-`Copy` types,
36+
///
37+
/// ```
38+
/// #![feature(iter_repeat_n)]
39+
/// use std::iter;
40+
///
41+
/// let v: Vec<i32> = Vec::with_capacity(123);
42+
/// let mut it = iter::repeat_n(v, 5);
43+
///
44+
/// for i in 0..4 {
45+
/// // It starts by cloning things
46+
/// let cloned = it.next().unwrap();
47+
/// assert_eq!(cloned.len(), 0);
48+
/// assert_eq!(cloned.capacity(), 0);
49+
/// }
50+
///
51+
/// // ... but the last item is the original one
52+
/// let last = it.next().unwrap();
53+
/// assert_eq!(last.len(), 0);
54+
/// assert_eq!(last.capacity(), 123);
55+
///
56+
/// // ... and now we're done
57+
/// assert_eq!(None, it.next());
58+
/// ```
59+
#[inline]
60+
#[unstable(
61+
feature = "iter_repeat_n",
62+
reason = "waiting on FCP to decide whether to expose publicly",
63+
issue = "104434"
64+
)]
65+
pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
66+
let mut element = ManuallyDrop::new(element);
67+
68+
if count == 0 {
69+
// SAFETY: we definitely haven't dropped it yet, since we only just got
70+
// passed it in, and because the count is zero the instance we're about
71+
// to create won't drop it, so to avoid leaking we need to now.
72+
unsafe { ManuallyDrop::drop(&mut element) };
73+
}
74+
75+
RepeatN { element, count }
76+
}
77+
78+
/// An iterator that repeats an element an exact number of times.
79+
///
80+
/// This `struct` is created by the [`repeat_n()`] function.
81+
/// See its documentation for more.
82+
#[derive(Clone, Debug)]
83+
#[unstable(
84+
feature = "iter_repeat_n",
85+
reason = "waiting on FCP to decide whether to expose publicly",
86+
issue = "104434"
87+
)]
88+
pub struct RepeatN<A> {
89+
count: usize,
90+
// Invariant: has been dropped iff count == 0.
91+
element: ManuallyDrop<A>,
92+
}
93+
94+
impl<A> RepeatN<A> {
95+
/// If we haven't already dropped the element, return it in an option.
96+
///
97+
/// Clears the count so it won't be dropped again later.
98+
#[inline]
99+
fn take_element(&mut self) -> Option<A> {
100+
if self.count > 0 {
101+
self.count = 0;
102+
// SAFETY: We just set count to zero so it won't be dropped again,
103+
// and it used to be non-zero so it hasn't already been dropped.
104+
unsafe { Some(ManuallyDrop::take(&mut self.element)) }
105+
} else {
106+
None
107+
}
108+
}
109+
}
110+
111+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
112+
impl<A> Drop for RepeatN<A> {
113+
fn drop(&mut self) {
114+
self.take_element();
115+
}
116+
}
117+
118+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
119+
impl<A: Clone> Iterator for RepeatN<A> {
120+
type Item = A;
121+
122+
#[inline]
123+
fn next(&mut self) -> Option<A> {
124+
if self.count == 0 {
125+
return None;
126+
}
127+
128+
self.count -= 1;
129+
Some(if self.count == 0 {
130+
// SAFETY: the check above ensured that the count used to be non-zero,
131+
// so element hasn't been dropped yet, and we just lowered the count to
132+
// zero so it won't be dropped later, and thus it's okay to take it here.
133+
unsafe { ManuallyDrop::take(&mut self.element) }
134+
} else {
135+
A::clone(&mut self.element)
136+
})
137+
}
138+
139+
#[inline]
140+
fn size_hint(&self) -> (usize, Option<usize>) {
141+
let len = self.len();
142+
(len, Some(len))
143+
}
144+
145+
#[inline]
146+
fn advance_by(&mut self, skip: usize) -> Result<(), usize> {
147+
let len = self.count;
148+
149+
if skip >= len {
150+
self.take_element();
151+
}
152+
153+
if skip > len {
154+
Err(len)
155+
} else {
156+
self.count = len - skip;
157+
Ok(())
158+
}
159+
}
160+
161+
#[inline]
162+
fn last(mut self) -> Option<A> {
163+
self.take_element()
164+
}
165+
166+
#[inline]
167+
fn count(self) -> usize {
168+
self.len()
169+
}
170+
}
171+
172+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
173+
impl<A: Clone> ExactSizeIterator for RepeatN<A> {
174+
fn len(&self) -> usize {
175+
self.count
176+
}
177+
}
178+
179+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
180+
impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
181+
#[inline]
182+
fn next_back(&mut self) -> Option<A> {
183+
self.next()
184+
}
185+
186+
#[inline]
187+
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
188+
self.advance_by(n)
189+
}
190+
191+
#[inline]
192+
fn nth_back(&mut self, n: usize) -> Option<A> {
193+
self.nth(n)
194+
}
195+
}
196+
197+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
198+
impl<A: Clone> FusedIterator for RepeatN<A> {}
199+
200+
#[unstable(feature = "trusted_len", issue = "37572")]
201+
unsafe impl<A: Clone> TrustedLen for RepeatN<A> {}

library/core/tests/iter/sources.rs

+49
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,52 @@ fn test_empty() {
106106
let mut it = empty::<i32>();
107107
assert_eq!(it.next(), None);
108108
}
109+
110+
#[test]
111+
fn test_repeat_n_drop() {
112+
#[derive(Clone, Debug)]
113+
struct DropCounter<'a>(&'a Cell<usize>);
114+
impl Drop for DropCounter<'_> {
115+
fn drop(&mut self) {
116+
self.0.set(self.0.get() + 1);
117+
}
118+
}
119+
120+
// `repeat_n(x, 0)` drops `x` immediately
121+
let count = Cell::new(0);
122+
let item = DropCounter(&count);
123+
let mut it = repeat_n(item, 0);
124+
assert_eq!(count.get(), 1);
125+
assert!(it.next().is_none());
126+
assert_eq!(count.get(), 1);
127+
drop(it);
128+
assert_eq!(count.get(), 1);
129+
130+
// Dropping the iterator needs to drop the item if it's non-empty
131+
let count = Cell::new(0);
132+
let item = DropCounter(&count);
133+
let it = repeat_n(item, 3);
134+
assert_eq!(count.get(), 0);
135+
drop(it);
136+
assert_eq!(count.get(), 1);
137+
138+
// Dropping the iterator doesn't drop the item if it was exhausted
139+
let count = Cell::new(0);
140+
let item = DropCounter(&count);
141+
let mut it = repeat_n(item, 3);
142+
assert_eq!(count.get(), 0);
143+
let x0 = it.next().unwrap();
144+
assert_eq!(count.get(), 0);
145+
let x1 = it.next().unwrap();
146+
assert_eq!(count.get(), 0);
147+
let x2 = it.next().unwrap();
148+
assert_eq!(count.get(), 0);
149+
assert!(it.next().is_none());
150+
assert_eq!(count.get(), 0);
151+
assert!(it.next().is_none());
152+
assert_eq!(count.get(), 0);
153+
drop(it);
154+
assert_eq!(count.get(), 0);
155+
drop((x0, x1, x2));
156+
assert_eq!(count.get(), 3);
157+
}

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#![feature(iter_is_partitioned)]
7474
#![feature(iter_next_chunk)]
7575
#![feature(iter_order_by)]
76+
#![feature(iter_repeat_n)]
7677
#![feature(iterator_try_collect)]
7778
#![feature(iterator_try_reduce)]
7879
#![feature(const_mut_refs)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// compile-flags: -O
2+
// only-x86_64
3+
// ignore-debug: the debug assertions get in the way
4+
5+
#![crate_type = "lib"]
6+
#![feature(iter_repeat_n)]
7+
8+
#[derive(Clone)]
9+
pub struct NotCopy(u16);
10+
11+
impl Drop for NotCopy {
12+
fn drop(&mut self) {}
13+
}
14+
15+
// For a type where `Drop::drop` doesn't do anything observable and a clone is the
16+
// same as a move, make sure that the extra case for the last item disappears.
17+
18+
#[no_mangle]
19+
// CHECK-LABEL: @iter_repeat_n_next
20+
pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCopy> {
21+
// CHECK-NEXT: start:
22+
// CHECK-NOT: br
23+
// CHECK: %[[COUNT:.+]] = load i64
24+
// CHECK-NEXT: %[[COUNT_ZERO:.+]] = icmp eq i64 %[[COUNT]], 0
25+
// CHECK-NEXT: br i1 %[[COUNT_ZERO]], label %[[EMPTY:.+]], label %[[NOT_EMPTY:.+]]
26+
27+
// CHECK: [[NOT_EMPTY]]:
28+
// CHECK-NEXT: %[[DEC:.+]] = add i64 %[[COUNT]], -1
29+
// CHECK-NEXT: store i64 %[[DEC]]
30+
// CHECK-NOT: br
31+
// CHECK: %[[VAL:.+]] = load i16
32+
// CHECK-NEXT: br label %[[EMPTY]]
33+
34+
// CHECK: [[EMPTY]]:
35+
// CHECK-NOT: br
36+
// CHECK: phi i16 [ undef, %start ], [ %[[VAL]], %[[NOT_EMPTY]] ]
37+
// CHECK-NOT: br
38+
// CHECK: ret
39+
40+
it.next()
41+
}
42+
43+
// And as a result, using the iterator can optimize without special cases for
44+
// the last iteration, like `memset`ing all the items in one call.
45+
46+
#[no_mangle]
47+
// CHECK-LABEL: @vec_extend_via_iter_repeat_n
48+
pub fn vec_extend_via_iter_repeat_n() -> Vec<u8> {
49+
// CHECK: %[[ADDR:.+]] = tail call dereferenceable_or_null(1234) ptr @__rust_alloc(i64 1234, i64 1)
50+
// CHECK: tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(1234) %[[ADDR]], i8 42, i64 1234,
51+
52+
let n = 1234_usize;
53+
let mut v = Vec::with_capacity(n);
54+
v.extend(std::iter::repeat_n(42_u8, n));
55+
v
56+
}

0 commit comments

Comments
 (0)