Skip to content

Commit a1bf25e

Browse files
committed
Update VecDeque implementation
1 parent 9cdfe03 commit a1bf25e

File tree

12 files changed

+774
-1251
lines changed

12 files changed

+774
-1251
lines changed

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

+115-65
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use core::fmt;
21
use core::iter::FusedIterator;
32
use core::marker::PhantomData;
4-
use core::mem::{self, MaybeUninit};
5-
use core::ptr::{self, NonNull};
3+
use core::mem::{self, SizedTypeProperties};
4+
use core::ptr::NonNull;
5+
use core::{fmt, ptr};
66

77
use crate::alloc::{Allocator, Global};
88

9-
use super::{count, wrap_index, VecDeque};
9+
use super::VecDeque;
1010

1111
/// A draining iterator over the elements of a `VecDeque`.
1212
///
@@ -20,38 +20,72 @@ pub struct Drain<
2020
T: 'a,
2121
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
2222
> {
23-
after_tail: usize,
24-
after_head: usize,
25-
ring: NonNull<[T]>,
26-
tail: usize,
27-
head: usize,
23+
// We can't just use a &mut VecDeque<T, A>, as that would make Drain invariant over T
24+
// and we want it to be covariant instead
2825
deque: NonNull<VecDeque<T, A>>,
29-
_phantom: PhantomData<&'a T>,
26+
// drain_start is stored in deque.len
27+
drain_len: usize,
28+
// index into the logical array, not the physical one (always lies in [0..deque.len))
29+
idx: usize,
30+
// number of elements after the drain range
31+
tail_len: usize,
32+
remaining: usize,
33+
// Needed to make Drain covariant over T
34+
_marker: PhantomData<&'a T>,
3035
}
3136

3237
impl<'a, T, A: Allocator> Drain<'a, T, A> {
3338
pub(super) unsafe fn new(
34-
after_tail: usize,
35-
after_head: usize,
36-
ring: &'a [MaybeUninit<T>],
37-
tail: usize,
38-
head: usize,
39-
deque: NonNull<VecDeque<T, A>>,
39+
deque: &'a mut VecDeque<T, A>,
40+
drain_start: usize,
41+
drain_len: usize,
4042
) -> Self {
41-
let ring = unsafe { NonNull::new_unchecked(ring as *const [MaybeUninit<T>] as *mut _) };
42-
Drain { after_tail, after_head, ring, tail, head, deque, _phantom: PhantomData }
43+
let orig_len = mem::replace(&mut deque.len, drain_start);
44+
let tail_len = orig_len - drain_start - drain_len;
45+
Drain {
46+
deque: NonNull::from(deque),
47+
drain_len,
48+
idx: drain_start,
49+
tail_len,
50+
remaining: drain_len,
51+
_marker: PhantomData,
52+
}
53+
}
54+
55+
// Only returns pointers to the slices, as that's
56+
// all we need to drop them
57+
fn as_slices(&self) -> (*mut [T], *mut [T]) {
58+
unsafe {
59+
let deque = self.deque.as_ref();
60+
let wrapped_start = deque.wrap_idx(self.idx);
61+
62+
if self.remaining <= deque.capacity() - wrapped_start {
63+
// there's only one contigous slice
64+
(
65+
ptr::slice_from_raw_parts_mut(deque.ptr().add(wrapped_start), self.remaining),
66+
&mut [] as *mut [T],
67+
)
68+
} else {
69+
let head_len = deque.capacity() - wrapped_start;
70+
// this will never overflow due to the if condition
71+
let tail_len = self.remaining - head_len;
72+
(
73+
ptr::slice_from_raw_parts_mut(deque.ptr().add(wrapped_start), head_len),
74+
ptr::slice_from_raw_parts_mut(deque.ptr(), tail_len),
75+
)
76+
}
77+
}
4378
}
4479
}
4580

4681
#[stable(feature = "collection_debug", since = "1.17.0")]
4782
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
4883
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4984
f.debug_tuple("Drain")
50-
.field(&self.after_tail)
51-
.field(&self.after_head)
52-
.field(&self.ring)
53-
.field(&self.tail)
54-
.field(&self.head)
85+
.field(&self.drain_len)
86+
.field(&self.idx)
87+
.field(&self.tail_len)
88+
.field(&self.remaining)
5589
.finish()
5690
}
5791
}
@@ -68,57 +102,77 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
68102

69103
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
70104
fn drop(&mut self) {
71-
self.0.for_each(drop);
105+
if self.0.remaining != 0 {
106+
let (front, back) = self.0.as_slices();
107+
unsafe {
108+
ptr::drop_in_place(front);
109+
ptr::drop_in_place(back);
110+
}
111+
}
72112

73113
let source_deque = unsafe { self.0.deque.as_mut() };
74114

75-
// T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head
76-
//
77-
// T t h H
78-
// [. . . o o x x o o . . .]
79-
//
80-
let orig_tail = source_deque.tail;
81-
let drain_tail = source_deque.head;
82-
let drain_head = self.0.after_tail;
83-
let orig_head = self.0.after_head;
115+
let drain_start = source_deque.len();
116+
let drain_len = self.0.drain_len;
117+
let drain_end = drain_start + drain_len;
84118

85-
let tail_len = count(orig_tail, drain_tail, source_deque.cap());
86-
let head_len = count(drain_head, orig_head, source_deque.cap());
119+
let orig_len = self.0.tail_len + drain_end;
120+
121+
if T::IS_ZST {
122+
// no need to copy around any memory if T is a ZST
123+
source_deque.len = orig_len - drain_len;
124+
return;
125+
}
87126

88-
// Restore the original head value
89-
source_deque.head = orig_head;
127+
let head_len = drain_start;
128+
let tail_len = self.0.tail_len;
90129

91-
match (tail_len, head_len) {
130+
match (head_len, tail_len) {
92131
(0, 0) => {
93132
source_deque.head = 0;
94-
source_deque.tail = 0;
133+
source_deque.len = 0;
95134
}
96135
(0, _) => {
97-
source_deque.tail = drain_head;
136+
source_deque.head = source_deque.wrap_idx(drain_len);
137+
source_deque.len = orig_len - drain_len;
98138
}
99139
(_, 0) => {
100-
source_deque.head = drain_tail;
140+
source_deque.len = orig_len - drain_len;
101141
}
102142
_ => unsafe {
103-
if tail_len <= head_len {
104-
source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
105-
source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
143+
if head_len <= tail_len {
144+
source_deque.wrap_copy(
145+
source_deque.head,
146+
source_deque.wrap_idx(drain_len),
147+
head_len,
148+
);
149+
source_deque.head = source_deque.wrap_idx(drain_len);
150+
source_deque.len = orig_len - drain_len;
106151
} else {
107-
source_deque.head = source_deque.wrap_add(drain_tail, head_len);
108-
source_deque.wrap_copy(drain_tail, drain_head, head_len);
152+
source_deque.wrap_copy(
153+
source_deque.wrap_idx(head_len + drain_len),
154+
source_deque.wrap_idx(head_len),
155+
tail_len,
156+
);
157+
source_deque.len = orig_len - drain_len;
109158
}
110159
},
111160
}
112161
}
113162
}
114163

115-
while let Some(item) = self.next() {
116-
let guard = DropGuard(self);
117-
drop(item);
118-
mem::forget(guard);
164+
let guard = DropGuard(self);
165+
let (front, back) = guard.0.as_slices();
166+
unsafe {
167+
// since idx is a logical index, we don't need to worry about wrapping.
168+
guard.0.idx += front.len();
169+
guard.0.remaining -= front.len();
170+
ptr::drop_in_place(front);
171+
guard.0.remaining = 0;
172+
ptr::drop_in_place(back);
119173
}
120174

121-
DropGuard(self);
175+
// Dropping `guard` handles moving the remaining elements into place.
122176
}
123177
}
124178

@@ -128,20 +182,18 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
128182

129183
#[inline]
130184
fn next(&mut self) -> Option<T> {
131-
if self.tail == self.head {
185+
if self.remaining == 0 {
132186
return None;
133187
}
134-
let tail = self.tail;
135-
self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len());
136-
// Safety:
137-
// - `self.tail` in a ring buffer is always a valid index.
138-
// - `self.head` and `self.tail` equality is checked above.
139-
unsafe { Some(ptr::read(self.ring.as_ptr().get_unchecked_mut(tail))) }
188+
let wrapped_idx = unsafe { self.deque.as_ref().wrap_idx(self.idx) };
189+
self.idx += 1;
190+
self.remaining -= 1;
191+
Some(unsafe { self.deque.as_mut().buffer_read(wrapped_idx) })
140192
}
141193

142194
#[inline]
143195
fn size_hint(&self) -> (usize, Option<usize>) {
144-
let len = count(self.tail, self.head, self.ring.len());
196+
let len = self.remaining;
145197
(len, Some(len))
146198
}
147199
}
@@ -150,14 +202,12 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
150202
impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
151203
#[inline]
152204
fn next_back(&mut self) -> Option<T> {
153-
if self.tail == self.head {
205+
if self.remaining == 0 {
154206
return None;
155207
}
156-
self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len());
157-
// Safety:
158-
// - `self.head` in a ring buffer is always a valid index.
159-
// - `self.head` and `self.tail` equality is checked above.
160-
unsafe { Some(ptr::read(self.ring.as_ptr().get_unchecked_mut(self.head))) }
208+
self.remaining -= 1;
209+
let wrapped_idx = unsafe { self.deque.as_ref().wrap_idx(self.idx + self.remaining) };
210+
Some(unsafe { self.deque.as_mut().buffer_read(wrapped_idx) })
161211
}
162212
}
163213

0 commit comments

Comments
 (0)