Skip to content

Commit 9482492

Browse files
committed
Add drain method to AccumulateVec/ArrayVec
You can now call .drain(..) on SmallVec, AccumulateVec and ArrayVec
1 parent f8c4d10 commit 9482492

File tree

3 files changed

+126
-1
lines changed

3 files changed

+126
-1
lines changed

src/librustc_data_structures/accumulate_vec.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use std::ops::{Deref, DerefMut};
1919
use std::iter::{self, IntoIterator, FromIterator};
2020
use std::slice;
2121
use std::vec;
22+
use std::collections::range::RangeArgument;
2223

2324
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
2425

@@ -71,6 +72,19 @@ impl<A: Array> AccumulateVec<A> {
7172
AccumulateVec::Heap(ref mut vec) => vec.pop(),
7273
}
7374
}
75+
76+
pub fn drain<R>(&mut self, range: R) -> Drain<A>
77+
where R: RangeArgument<usize>
78+
{
79+
match *self {
80+
AccumulateVec::Array(ref mut v) => {
81+
Drain::Array(v.drain(range))
82+
},
83+
AccumulateVec::Heap(ref mut v) => {
84+
Drain::Heap(v.drain(range))
85+
},
86+
}
87+
}
7488
}
7589

7690
impl<A: Array> Deref for AccumulateVec<A> {
@@ -132,6 +146,31 @@ impl<A: Array> Iterator for IntoIter<A> {
132146
}
133147
}
134148

149+
pub enum Drain<'a, A: Array>
150+
where A::Element: 'a
151+
{
152+
Array(array_vec::Drain<'a, A>),
153+
Heap(vec::Drain<'a, A::Element>),
154+
}
155+
156+
impl<'a, A: Array> Iterator for Drain<'a, A> {
157+
type Item = A::Element;
158+
159+
fn next(&mut self) -> Option<A::Element> {
160+
match *self {
161+
Drain::Array(ref mut drain) => drain.next(),
162+
Drain::Heap(ref mut drain) => drain.next(),
163+
}
164+
}
165+
166+
fn size_hint(&self) -> (usize, Option<usize>) {
167+
match *self {
168+
Drain::Array(ref drain) => drain.size_hint(),
169+
Drain::Heap(ref drain) => drain.size_hint(),
170+
}
171+
}
172+
}
173+
135174
impl<A: Array> IntoIterator for AccumulateVec<A> {
136175
type Item = A::Element;
137176
type IntoIter = IntoIter<A>;

src/librustc_data_structures/array_vec.rs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
1313
use std::marker::Unsize;
1414
use std::iter::Extend;
15-
use std::ptr::{self, drop_in_place};
15+
use std::ptr::{self, drop_in_place, Shared};
1616
use std::ops::{Deref, DerefMut, Range};
1717
use std::hash::{Hash, Hasher};
1818
use std::slice;
1919
use std::fmt;
2020
use std::mem;
21+
use std::collections::range::RangeArgument;
2122

2223
pub unsafe trait Array {
2324
type Element;
@@ -103,6 +104,44 @@ impl<A: Array> ArrayVec<A> {
103104
None
104105
}
105106
}
107+
108+
pub fn drain<R>(&mut self, range: R) -> Drain<A>
109+
where R: RangeArgument<usize>
110+
{
111+
// Memory safety
112+
//
113+
// When the Drain is first created, it shortens the length of
114+
// the source vector to make sure no uninitalized or moved-from elements
115+
// are accessible at all if the Drain's destructor never gets to run.
116+
//
117+
// Drain will ptr::read out the values to remove.
118+
// When finished, remaining tail of the vec is copied back to cover
119+
// the hole, and the vector length is restored to the new length.
120+
//
121+
let len = self.len();
122+
let start = *range.start().unwrap_or(&0);
123+
let end = *range.end().unwrap_or(&len);
124+
assert!(start <= end);
125+
assert!(end <= len);
126+
127+
unsafe {
128+
// set self.vec length's to start, to be safe in case Drain is leaked
129+
self.set_len(start);
130+
// Use the borrow in the IterMut to indicate borrowing behavior of the
131+
// whole Drain iterator (like &mut T).
132+
let range_slice = {
133+
let arr = &mut self.values as &mut [ManuallyDrop<_>];
134+
slice::from_raw_parts_mut(arr.as_mut_ptr().offset(start as isize),
135+
end - start)
136+
};
137+
Drain {
138+
tail_start: end,
139+
tail_len: len - end,
140+
iter: range_slice.iter(),
141+
array_vec: Shared::new(self as *mut _),
142+
}
143+
}
144+
}
106145
}
107146

108147
impl<A> Default for ArrayVec<A>
@@ -179,6 +218,51 @@ impl<A: Array> Iterator for Iter<A> {
179218
}
180219
}
181220

221+
pub struct Drain<'a, A: Array>
222+
where A::Element: 'a
223+
{
224+
tail_start: usize,
225+
tail_len: usize,
226+
iter: slice::Iter<'a, ManuallyDrop<A::Element>>,
227+
array_vec: Shared<ArrayVec<A>>,
228+
}
229+
230+
impl<'a, A: Array> Iterator for Drain<'a, A> {
231+
type Item = A::Element;
232+
233+
#[inline]
234+
fn next(&mut self) -> Option<A::Element> {
235+
self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value })
236+
}
237+
238+
fn size_hint(&self) -> (usize, Option<usize>) {
239+
self.iter.size_hint()
240+
}
241+
}
242+
243+
impl<'a, A: Array> Drop for Drain<'a, A> {
244+
fn drop(&mut self) {
245+
// exhaust self first
246+
while let Some(_) = self.next() {}
247+
248+
if self.tail_len > 0 {
249+
unsafe {
250+
let source_array_vec = &mut **self.array_vec;
251+
// memmove back untouched tail, update to new length
252+
let start = source_array_vec.len();
253+
let tail = self.tail_start;
254+
{
255+
let mut arr = &mut source_array_vec.values as &mut [ManuallyDrop<_>];
256+
let src = arr.as_ptr().offset(tail as isize);
257+
let dst = arr.as_mut_ptr().offset(start as isize);
258+
ptr::copy(src, dst, self.tail_len);
259+
};
260+
source_array_vec.set_len(start + self.tail_len);
261+
}
262+
}
263+
}
264+
}
265+
182266
impl<A: Array> IntoIterator for ArrayVec<A> {
183267
type Item = A::Element;
184268
type IntoIter = Iter<A>;

src/librustc_data_structures/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
html_root_url = "https://doc.rust-lang.org/nightly/")]
2626
#![cfg_attr(not(stage0), deny(warnings))]
2727

28+
#![feature(shared)]
29+
#![feature(collections_range)]
2830
#![feature(nonzero)]
2931
#![feature(rustc_private)]
3032
#![feature(staged_api)]

0 commit comments

Comments
 (0)