Skip to content

Commit f01287c

Browse files
committed
add VecDeque::splice
1 parent e5efc33 commit f01287c

File tree

6 files changed

+299
-13
lines changed

6 files changed

+299
-13
lines changed

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ pub struct Drain<
2121
> {
2222
// We can't just use a &mut VecDeque<T, A>, as that would make Drain invariant over T
2323
// and we want it to be covariant instead
24-
deque: NonNull<VecDeque<T, A>>,
24+
pub(super) deque: NonNull<VecDeque<T, A>>,
2525
// drain_start is stored in deque.len
26-
drain_len: usize,
26+
pub(super) drain_len: usize,
2727
// index into the logical array, not the physical one (always lies in [0..deque.len))
2828
idx: usize,
29-
// number of elements remaining after dropping the drain
30-
new_len: usize,
29+
// number of elements after the drained range
30+
pub(super) tail_len: usize,
3131
remaining: usize,
3232
// Needed to make Drain covariant over T
3333
_marker: PhantomData<&'a T>,
@@ -40,12 +40,12 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
4040
drain_len: usize,
4141
) -> Self {
4242
let orig_len = mem::replace(&mut deque.len, drain_start);
43-
let new_len = orig_len - drain_len;
43+
let tail_len = orig_len - drain_start - drain_len;
4444
Drain {
4545
deque: NonNull::from(deque),
4646
drain_len,
4747
idx: drain_start,
48-
new_len,
48+
tail_len,
4949
remaining: drain_len,
5050
_marker: PhantomData,
5151
}
@@ -78,7 +78,7 @@ impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
7878
f.debug_tuple("Drain")
7979
.field(&self.drain_len)
8080
.field(&self.idx)
81-
.field(&self.new_len)
81+
.field(&self.tail_len)
8282
.field(&self.remaining)
8383
.finish()
8484
}
@@ -125,17 +125,16 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
125125
let source_deque = unsafe { self.0.deque.as_mut() };
126126

127127
let drain_len = self.0.drain_len;
128-
let new_len = self.0.new_len;
128+
let head_len = source_deque.len; // #elements in front of the drain
129+
let tail_len = self.0.tail_len; // #elements behind the drain
130+
let new_len = head_len + tail_len;
129131

130132
if T::IS_ZST {
131133
// no need to copy around any memory if T is a ZST
132134
source_deque.len = new_len;
133135
return;
134136
}
135137

136-
let head_len = source_deque.len; // #elements in front of the drain
137-
let tail_len = new_len - head_len; // #elements behind the drain
138-
139138
// Next, we will fill the hole left by the drain with as few writes as possible.
140139
// The code below handles the following control flow and reduces the amount of
141140
// branches under the assumption that `head_len == 0 || tail_len == 0`, i.e.
@@ -219,7 +218,7 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
219218
}
220219

221220
if new_len == 0 {
222-
// Special case: If the entire dequeue was drained, reset the head back to 0,
221+
// Special case: If the entire deque was drained, reset the head back to 0,
223222
// like `.clear()` does.
224223
source_deque.head = 0;
225224
} else if head_len < tail_len {

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ use self::spec_from_iter::SpecFromIter;
6060

6161
mod spec_from_iter;
6262

63+
#[cfg(not(no_global_oom_handling))]
64+
#[unstable(feature = "deque_extend_front", issue = "146975")]
65+
pub use self::splice::Splice;
66+
67+
#[cfg(not(no_global_oom_handling))]
68+
mod splice;
69+
6370
#[cfg(test)]
6471
mod tests;
6572

@@ -1791,6 +1798,64 @@ impl<T, A: Allocator> VecDeque<T, A> {
17911798
unsafe { Drain::new(self, drain_start, drain_len) }
17921799
}
17931800

1801+
/// Creates a splicing iterator that replaces the specified range in the deque with the given
1802+
/// `replace_with` iterator and yields the removed items. `replace_with` does not need to be the
1803+
/// same length as `range`.
1804+
///
1805+
/// `range` is removed even if the `Splice` iterator is not consumed before it is dropped.
1806+
///
1807+
/// It is unspecified how many elements are removed from the deque if the `Splice` value is
1808+
/// leaked.
1809+
///
1810+
/// The input iterator `replace_with` is only consumed when the `Splice` value is dropped.
1811+
///
1812+
/// This is optimal if:
1813+
///
1814+
/// * The tail (elements in the deque after `range`) is empty,
1815+
/// * or `replace_with` yields fewer or equal elements than `range`'s length
1816+
/// * or the lower bound of its `size_hint()` is exact.
1817+
///
1818+
/// Otherwise, a temporary vector is allocated and the tail is moved twice.
1819+
///
1820+
/// # Panics
1821+
///
1822+
/// Panics if the range has `start_bound > end_bound`, or, if the range is
1823+
/// bounded on either end and past the length of the deque.
1824+
///
1825+
/// # Examples
1826+
///
1827+
/// ```
1828+
/// # #![feature(deque_extend_front)]
1829+
/// # use std::collections::VecDeque;
1830+
///
1831+
/// let mut v = VecDeque::from(vec![1, 2, 3, 4]);
1832+
/// let new = [7, 8, 9];
1833+
/// let u: Vec<_> = v.splice(1..3, new).collect();
1834+
/// assert_eq!(v, [1, 7, 8, 9, 4]);
1835+
/// assert_eq!(u, [2, 3]);
1836+
/// ```
1837+
///
1838+
/// Using `splice` to insert new items into a vector efficiently at a specific position
1839+
/// indicated by an empty range:
1840+
///
1841+
/// ```
1842+
/// # #![feature(deque_extend_front)]
1843+
/// # use std::collections::VecDeque;
1844+
///
1845+
/// let mut v = VecDeque::from(vec![1, 5]);
1846+
/// let new = [2, 3, 4];
1847+
/// v.splice(1..1, new);
1848+
/// assert_eq!(v, [1, 2, 3, 4, 5]);
1849+
/// ```
1850+
#[unstable(feature = "deque_extend_front", issue = "146975")]
1851+
pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A>
1852+
where
1853+
R: RangeBounds<usize>,
1854+
I: IntoIterator<Item = T>,
1855+
{
1856+
Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
1857+
}
1858+
17941859
/// Clears the deque, removing all values.
17951860
///
17961861
/// # Examples
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use core::alloc::Allocator;
2+
3+
use crate::alloc::Global;
4+
use crate::collections::vec_deque::Drain;
5+
use crate::vec::Vec;
6+
7+
/// A splicing iterator for `VecDeque`.
8+
///
9+
/// This struct is created by [`VecDeque::splice()`][super::VecDeque::splice].
10+
/// See its documentation for more.
11+
///
12+
/// # Example
13+
///
14+
/// ```
15+
/// # #![feature(deque_extend_front)]
16+
/// # use std::collections::VecDeque;
17+
///
18+
/// let mut v = VecDeque::from(vec![0, 1, 2]);
19+
/// let new = [7, 8];
20+
/// let iter: std::collections::vec_deque::Splice<'_, _> = v.splice(1.., new);
21+
/// ```
22+
#[unstable(feature = "deque_extend_front", issue = "146975")]
23+
#[derive(Debug)]
24+
pub struct Splice<
25+
'a,
26+
I: Iterator + 'a,
27+
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
28+
> {
29+
pub(super) drain: Drain<'a, I::Item, A>,
30+
pub(super) replace_with: I,
31+
}
32+
33+
#[unstable(feature = "deque_extend_front", issue = "146975")]
34+
impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> {
35+
type Item = I::Item;
36+
37+
fn next(&mut self) -> Option<Self::Item> {
38+
self.drain.next()
39+
}
40+
41+
fn size_hint(&self) -> (usize, Option<usize>) {
42+
self.drain.size_hint()
43+
}
44+
}
45+
46+
#[unstable(feature = "deque_extend_front", issue = "146975")]
47+
impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
48+
fn next_back(&mut self) -> Option<Self::Item> {
49+
self.drain.next_back()
50+
}
51+
}
52+
53+
#[unstable(feature = "deque_extend_front", issue = "146975")]
54+
impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
55+
56+
// See also: [`crate::vec::Splice`].
57+
#[unstable(feature = "deque_extend_front", issue = "146975")]
58+
impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
59+
fn drop(&mut self) {
60+
// This will set drain.remaining to 0, so its drop won't try to read deallocated memory on
61+
// drop.
62+
self.drain.by_ref().for_each(drop);
63+
64+
// At this point draining is done and the only remaining tasks are splicing
65+
// and moving things into the final place.
66+
67+
unsafe {
68+
let tail_len = self.drain.tail_len; // #elements behind the drain
69+
70+
if tail_len == 0 {
71+
self.drain.deque.as_mut().extend(self.replace_with.by_ref());
72+
return;
73+
}
74+
75+
// First fill the range left by drain().
76+
if !self.drain.fill(&mut self.replace_with) {
77+
return;
78+
}
79+
80+
// There may be more elements. Use the lower bound as an estimate.
81+
// FIXME: Is the upper bound a better guess? Or something else?
82+
let (lower_bound, _upper_bound) = self.replace_with.size_hint();
83+
if lower_bound > 0 {
84+
self.drain.move_tail(lower_bound);
85+
if !self.drain.fill(&mut self.replace_with) {
86+
return;
87+
}
88+
}
89+
90+
// Collect any remaining elements.
91+
// This is a zero-length vector which does not allocate if `lower_bound` was exact.
92+
let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
93+
// Now we have an exact count.
94+
if collected.len() > 0 {
95+
self.drain.move_tail(collected.len());
96+
let filled = self.drain.fill(&mut collected);
97+
debug_assert!(filled);
98+
debug_assert_eq!(collected.len(), 0);
99+
}
100+
}
101+
// Let `Drain::drop` move the tail back if necessary and restore `deque.len`.
102+
}
103+
}
104+
105+
/// Private helper methods for `Splice::drop`
106+
impl<T, A: Allocator> Drain<'_, T, A> {
107+
/// The range from `self.deque.len` to `self.deque.len + self.drain_len` contains elements that
108+
/// have been moved out.
109+
/// Fill that range as much as possible with new elements from the `replace_with` iterator.
110+
/// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.)
111+
///
112+
/// # Safety
113+
///
114+
/// self.deque must be valid. self.deque.len and self.deque.len + self.drain_len must be less
115+
/// than twice the deque's capacity.
116+
unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
117+
let deque = unsafe { self.deque.as_mut() };
118+
let range_start = deque.len;
119+
let range_end = range_start + self.drain_len;
120+
121+
for idx in range_start..range_end {
122+
if let Some(new_item) = replace_with.next() {
123+
let index = deque.to_physical_idx(idx);
124+
unsafe { deque.buffer_write(index, new_item) };
125+
deque.len += 1;
126+
self.drain_len -= 1;
127+
} else {
128+
return false;
129+
}
130+
}
131+
true
132+
}
133+
134+
/// Makes room for inserting more elements before the tail.
135+
///
136+
/// # Safety
137+
///
138+
/// self.deque must be valid.
139+
unsafe fn move_tail(&mut self, additional: usize) {
140+
let deque = unsafe { self.deque.as_mut() };
141+
let tail_start = deque.len + self.drain_len;
142+
deque.buf.reserve(tail_start + self.tail_len, additional);
143+
144+
let new_tail_start = tail_start + additional;
145+
unsafe {
146+
deque.wrap_copy(tail_start, new_tail_start, self.tail_len);
147+
}
148+
self.drain_len += additional;
149+
}
150+
}

library/alloc/src/vec/splice.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
5050
#[stable(feature = "vec_splice", since = "1.21.0")]
5151
impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
5252

53+
// See also: [`crate::collections::vec_deque::Splice`].
5354
#[stable(feature = "vec_splice", since = "1.21.0")]
5455
impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
5556
fn drop(&mut self) {

library/alloctests/tests/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#![feature(allocator_api)]
22
#![feature(alloc_layout_extra)]
3+
#![feature(deque_extend_front)]
34
#![feature(iter_array_chunks)]
45
#![feature(assert_matches)]
56
#![feature(wtf8_internals)]
67
#![feature(char_max_len)]
78
#![feature(cow_is_borrowed)]
89
#![feature(core_intrinsics)]
9-
#![feature(deque_extend_front)]
1010
#![feature(downcast_unchecked)]
1111
#![feature(exact_size_is_empty)]
1212
#![feature(hashmap_internals)]

library/alloctests/tests/vec_deque.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,3 +2081,74 @@ fn test_extend_and_prepend_from_within() {
20812081
v.extend_from_within(..);
20822082
assert_eq!(v.iter().map(|s| &**s).collect::<String>(), "123123123123");
20832083
}
2084+
2085+
#[test]
2086+
fn test_splice() {
2087+
let mut v = VecDeque::from(vec![1, 2, 3, 4, 5]);
2088+
let a = [10, 11, 12];
2089+
v.splice(2..4, a);
2090+
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
2091+
v.splice(1..3, Some(20));
2092+
assert_eq!(v, &[1, 20, 11, 12, 5]);
2093+
}
2094+
2095+
#[test]
2096+
fn test_splice_inclusive_range() {
2097+
let mut v = VecDeque::from(vec![1, 2, 3, 4, 5]);
2098+
let a = [10, 11, 12];
2099+
let t1: Vec<_> = v.splice(2..=3, a).collect();
2100+
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
2101+
assert_eq!(t1, &[3, 4]);
2102+
let t2: Vec<_> = v.splice(1..=2, Some(20)).collect();
2103+
assert_eq!(v, &[1, 20, 11, 12, 5]);
2104+
assert_eq!(t2, &[2, 10]);
2105+
}
2106+
2107+
#[test]
2108+
fn test_splice_inclusive_range2() {
2109+
let mut v = VecDeque::from(vec![1, 2, 10, 11, 12, 5]);
2110+
let t2: Vec<_> = v.splice(1..=2, Some(20)).collect();
2111+
assert_eq!(v, &[1, 20, 11, 12, 5]);
2112+
assert_eq!(t2, &[2, 10]);
2113+
}
2114+
2115+
#[test]
2116+
#[should_panic]
2117+
fn test_splice_out_of_bounds() {
2118+
let mut v = VecDeque::from(vec![1, 2, 3, 4, 5]);
2119+
let a = [10, 11, 12];
2120+
v.splice(5..6, a);
2121+
}
2122+
2123+
#[test]
2124+
#[should_panic]
2125+
fn test_splice_inclusive_out_of_bounds() {
2126+
let mut v = VecDeque::from(vec![1, 2, 3, 4, 5]);
2127+
let a = [10, 11, 12];
2128+
v.splice(5..=5, a);
2129+
}
2130+
2131+
#[test]
2132+
fn test_splice_items_zero_sized() {
2133+
let mut vec = VecDeque::from(vec![(), (), ()]);
2134+
let vec2 = VecDeque::from(vec![]);
2135+
let t: Vec<_> = vec.splice(1..2, vec2.iter().cloned()).collect();
2136+
assert_eq!(vec, &[(), ()]);
2137+
assert_eq!(t, &[()]);
2138+
}
2139+
2140+
#[test]
2141+
fn test_splice_unbounded() {
2142+
let mut vec = VecDeque::from(vec![1, 2, 3, 4, 5]);
2143+
let t: Vec<_> = vec.splice(.., None).collect();
2144+
assert_eq!(vec, &[]);
2145+
assert_eq!(t, &[1, 2, 3, 4, 5]);
2146+
}
2147+
2148+
#[test]
2149+
fn test_splice_forget() {
2150+
let mut v = VecDeque::from(vec![1, 2, 3, 4, 5]);
2151+
let a = [10, 11, 12];
2152+
std::mem::forget(v.splice(2..4, a));
2153+
assert_eq!(v, &[1, 2]);
2154+
}

0 commit comments

Comments
 (0)