Skip to content

Commit 785237d

Browse files
author
Yuki Okushi
authored
Rollup merge of #104435 - scottmcm:iter-repeat-n, r=thomcc
`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. This adds `iter::repeat_n` (#104434) as the primitive needed to do this. If this PR is acceptable, I'll also use this in `Vec` rather than its custom `ExtendElement` type & infrastructure that is harder to share between multiple different containers: https://github.com/rust-lang/rust/blob/101e1822c3e54e63996c8aaa014d55716f3937eb/library/alloc/src/vec/mod.rs#L2479-L2492
2 parents e69b842 + 71bb200 commit 785237d

File tree

9 files changed

+323
-2
lines changed

9 files changed

+323
-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

+195
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
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(feature = "iter_repeat_n", issue = "104434")]
61+
#[doc(hidden)] // waiting on ACP#120 to decide whether to expose publicly
62+
pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
63+
let mut element = ManuallyDrop::new(element);
64+
65+
if count == 0 {
66+
// SAFETY: we definitely haven't dropped it yet, since we only just got
67+
// passed it in, and because the count is zero the instance we're about
68+
// to create won't drop it, so to avoid leaking we need to now.
69+
unsafe { ManuallyDrop::drop(&mut element) };
70+
}
71+
72+
RepeatN { element, count }
73+
}
74+
75+
/// An iterator that repeats an element an exact number of times.
76+
///
77+
/// This `struct` is created by the [`repeat_n()`] function.
78+
/// See its documentation for more.
79+
#[derive(Clone, Debug)]
80+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
81+
#[doc(hidden)] // waiting on ACP#120 to decide whether to expose publicly
82+
pub struct RepeatN<A> {
83+
count: usize,
84+
// Invariant: has been dropped iff count == 0.
85+
element: ManuallyDrop<A>,
86+
}
87+
88+
impl<A> RepeatN<A> {
89+
/// If we haven't already dropped the element, return it in an option.
90+
///
91+
/// Clears the count so it won't be dropped again later.
92+
#[inline]
93+
fn take_element(&mut self) -> Option<A> {
94+
if self.count > 0 {
95+
self.count = 0;
96+
// SAFETY: We just set count to zero so it won't be dropped again,
97+
// and it used to be non-zero so it hasn't already been dropped.
98+
unsafe { Some(ManuallyDrop::take(&mut self.element)) }
99+
} else {
100+
None
101+
}
102+
}
103+
}
104+
105+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
106+
impl<A> Drop for RepeatN<A> {
107+
fn drop(&mut self) {
108+
self.take_element();
109+
}
110+
}
111+
112+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
113+
impl<A: Clone> Iterator for RepeatN<A> {
114+
type Item = A;
115+
116+
#[inline]
117+
fn next(&mut self) -> Option<A> {
118+
if self.count == 0 {
119+
return None;
120+
}
121+
122+
self.count -= 1;
123+
Some(if self.count == 0 {
124+
// SAFETY: the check above ensured that the count used to be non-zero,
125+
// so element hasn't been dropped yet, and we just lowered the count to
126+
// zero so it won't be dropped later, and thus it's okay to take it here.
127+
unsafe { ManuallyDrop::take(&mut self.element) }
128+
} else {
129+
A::clone(&mut self.element)
130+
})
131+
}
132+
133+
#[inline]
134+
fn size_hint(&self) -> (usize, Option<usize>) {
135+
let len = self.len();
136+
(len, Some(len))
137+
}
138+
139+
#[inline]
140+
fn advance_by(&mut self, skip: usize) -> Result<(), usize> {
141+
let len = self.count;
142+
143+
if skip >= len {
144+
self.take_element();
145+
}
146+
147+
if skip > len {
148+
Err(len)
149+
} else {
150+
self.count = len - skip;
151+
Ok(())
152+
}
153+
}
154+
155+
#[inline]
156+
fn last(mut self) -> Option<A> {
157+
self.take_element()
158+
}
159+
160+
#[inline]
161+
fn count(self) -> usize {
162+
self.len()
163+
}
164+
}
165+
166+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
167+
impl<A: Clone> ExactSizeIterator for RepeatN<A> {
168+
fn len(&self) -> usize {
169+
self.count
170+
}
171+
}
172+
173+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
174+
impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
175+
#[inline]
176+
fn next_back(&mut self) -> Option<A> {
177+
self.next()
178+
}
179+
180+
#[inline]
181+
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
182+
self.advance_by(n)
183+
}
184+
185+
#[inline]
186+
fn nth_back(&mut self, n: usize) -> Option<A> {
187+
self.nth(n)
188+
}
189+
}
190+
191+
#[unstable(feature = "iter_repeat_n", issue = "104434")]
192+
impl<A: Clone> FusedIterator for RepeatN<A> {}
193+
194+
#[unstable(feature = "trusted_len", issue = "37572")]
195+
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
@@ -75,6 +75,7 @@
7575
#![feature(iter_is_partitioned)]
7676
#![feature(iter_next_chunk)]
7777
#![feature(iter_order_by)]
78+
#![feature(iter_repeat_n)]
7879
#![feature(iterator_try_collect)]
7980
#![feature(iterator_try_reduce)]
8081
#![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)