Skip to content

Commit 321c4c7

Browse files
reitermarkusDirbaio
authored andcommitted
Add Vec::drain.
1 parent 310c09d commit 321c4c7

File tree

5 files changed

+373
-1
lines changed

5 files changed

+373
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2121
- Added `IntoIterator` implementation for `LinearMap`
2222
- Added `Deque::{get, get_mut, get_unchecked, get_unchecked_mut}`.
2323
- Added `serde::Serialize` and `serde::Deserialize` implementations to `HistoryBuffer`.
24+
- Added `Vec::drain`.
2425

2526
### Changed
2627

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ pub use indexmap::{
9696
pub use indexset::{FnvIndexSet, IndexSet, Iter as IndexSetIter};
9797
pub use linear_map::LinearMap;
9898
pub use string::String;
99+
99100
pub use vec::{Vec, VecView};
100101

101102
#[macro_use]
@@ -107,6 +108,7 @@ mod histbuf;
107108
mod indexmap;
108109
mod indexset;
109110
mod linear_map;
111+
mod slice;
110112
pub mod storage;
111113
pub mod string;
112114
pub mod vec;

src/slice.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use core::ops;
2+
3+
// FIXME: Remove when `slice_range` feature is stable.
4+
#[track_caller]
5+
#[must_use]
6+
pub fn range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
7+
where
8+
R: ops::RangeBounds<usize>,
9+
{
10+
let len = bounds.end;
11+
12+
let start: ops::Bound<&usize> = range.start_bound();
13+
let start = match start {
14+
ops::Bound::Included(&start) => start,
15+
ops::Bound::Excluded(start) => start
16+
.checked_add(1)
17+
.unwrap_or_else(|| panic!("attempted to index slice from after maximum usize")),
18+
ops::Bound::Unbounded => 0,
19+
};
20+
21+
let end: ops::Bound<&usize> = range.end_bound();
22+
let end = match end {
23+
ops::Bound::Included(end) => end
24+
.checked_add(1)
25+
.unwrap_or_else(|| panic!("attempted to index slice up to maximum usize")),
26+
ops::Bound::Excluded(&end) => end,
27+
ops::Bound::Unbounded => len,
28+
};
29+
30+
if start > end {
31+
panic!("slice index starts at {start} but ends at {end}");
32+
}
33+
if end > len {
34+
panic!("range end index {end} out of range for slice of length {len}");
35+
}
36+
37+
ops::Range { start, end }
38+
}

src/vec/drain.rs

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
use core::{
2+
fmt,
3+
iter::FusedIterator,
4+
mem::{self, size_of},
5+
ptr::{self, NonNull},
6+
slice,
7+
};
8+
9+
use super::VecView;
10+
11+
/// A draining iterator for [`Vec`](super::Vec).
12+
///
13+
/// This `struct` is created by [`Vec::drain`](super::Vec::drain).
14+
/// See its documentation for more.
15+
///
16+
/// # Example
17+
///
18+
/// ```
19+
/// use heapless::{vec, Vec};
20+
///
21+
/// let mut v = Vec::<_, 4>::from_array([0, 1, 2]);
22+
/// let iter: vec::Drain<'_, _> = v.drain(..);
23+
/// ```
24+
pub struct Drain<'a, T: 'a> {
25+
/// Index of tail to preserve
26+
pub(super) tail_start: usize,
27+
/// Length of tail
28+
pub(super) tail_len: usize,
29+
/// Current remaining range to remove
30+
pub(super) iter: slice::Iter<'a, T>,
31+
pub(super) vec: NonNull<VecView<T>>,
32+
}
33+
34+
impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
35+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36+
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
37+
}
38+
}
39+
40+
impl<'a, T> Drain<'a, T> {
41+
/// Returns the remaining items of this iterator as a slice.
42+
///
43+
/// # Examples
44+
///
45+
/// ```
46+
/// use heapless::{vec, Vec};
47+
///
48+
/// let mut vec = Vec::<_, 3>::from_array(['a', 'b', 'c']);
49+
/// let mut drain = vec.drain(..);
50+
/// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
51+
/// let _ = drain.next().unwrap();
52+
/// assert_eq!(drain.as_slice(), &['b', 'c']);
53+
/// ```
54+
#[must_use]
55+
pub fn as_slice(&self) -> &[T] {
56+
self.iter.as_slice()
57+
}
58+
}
59+
60+
impl<'a, T> AsRef<[T]> for Drain<'a, T> {
61+
fn as_ref(&self) -> &[T] {
62+
self.as_slice()
63+
}
64+
}
65+
66+
unsafe impl<T: Sync> Sync for Drain<'_, T> {}
67+
unsafe impl<T: Send> Send for Drain<'_, T> {}
68+
69+
impl<T> Iterator for Drain<'_, T> {
70+
type Item = T;
71+
72+
#[inline]
73+
fn next(&mut self) -> Option<T> {
74+
self.iter
75+
.next()
76+
.map(|elt| unsafe { ptr::read(elt as *const _) })
77+
}
78+
79+
fn size_hint(&self) -> (usize, Option<usize>) {
80+
self.iter.size_hint()
81+
}
82+
}
83+
84+
impl<T> DoubleEndedIterator for Drain<'_, T> {
85+
#[inline]
86+
fn next_back(&mut self) -> Option<T> {
87+
self.iter
88+
.next_back()
89+
.map(|elt| unsafe { ptr::read(elt as *const _) })
90+
}
91+
}
92+
93+
impl<T> Drop for Drain<'_, T> {
94+
fn drop(&mut self) {
95+
/// Moves back the un-`Drain`ed elements to restore the original `Vec`.
96+
struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>);
97+
98+
impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> {
99+
fn drop(&mut self) {
100+
if self.0.tail_len > 0 {
101+
unsafe {
102+
let source_vec = self.0.vec.as_mut();
103+
// memmove back untouched tail, update to new length
104+
let start = source_vec.len();
105+
let tail = self.0.tail_start;
106+
if tail != start {
107+
let dst = source_vec.as_mut_ptr().add(start);
108+
let src = source_vec.as_ptr().add(tail);
109+
ptr::copy(src, dst, self.0.tail_len);
110+
}
111+
source_vec.set_len(start + self.0.tail_len);
112+
}
113+
}
114+
}
115+
}
116+
117+
let iter = mem::take(&mut self.iter);
118+
let drop_len = iter.len();
119+
120+
let mut vec = self.vec;
121+
122+
if size_of::<T>() == 0 {
123+
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
124+
// this can be achieved by manipulating the `Vec` length instead of moving values out from `iter`.
125+
unsafe {
126+
let vec = vec.as_mut();
127+
let old_len = vec.len();
128+
vec.set_len(old_len + drop_len + self.tail_len);
129+
vec.truncate(old_len + self.tail_len);
130+
}
131+
132+
return;
133+
}
134+
135+
// ensure elements are moved back into their appropriate places, even when drop_in_place panics
136+
let _guard = DropGuard(self);
137+
138+
if drop_len == 0 {
139+
return;
140+
}
141+
142+
// as_slice() must only be called when iter.len() is > 0 because
143+
// it also gets touched by vec::Splice which may turn it into a dangling pointer
144+
// which would make it and the vec pointer point to different allocations which would
145+
// lead to invalid pointer arithmetic below.
146+
let drop_ptr = iter.as_slice().as_ptr();
147+
148+
unsafe {
149+
// drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place
150+
// a pointer with mutable provenance is necessary. Therefore we must reconstruct
151+
// it from the original vec but also avoid creating a &mut to the front since that could
152+
// invalidate raw pointers to it which some unsafe code might rely on.
153+
let vec_ptr = vec.as_mut().as_mut_ptr();
154+
// FIXME: Replace with `sub_ptr` once stable.
155+
let drop_offset = (drop_ptr as usize - vec_ptr as usize) / size_of::<T>();
156+
let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
157+
ptr::drop_in_place(to_drop);
158+
}
159+
}
160+
}
161+
162+
impl<T> ExactSizeIterator for Drain<'_, T> {}
163+
164+
impl<T> FusedIterator for Drain<'_, T> {}
165+
166+
#[cfg(test)]
167+
mod tests {
168+
use super::super::Vec;
169+
170+
#[test]
171+
fn drain_front() {
172+
let mut vec = Vec::<_, 8>::from_array([1, 2, 3, 4]);
173+
let mut it = vec.drain(..1);
174+
assert_eq!(it.next(), Some(1));
175+
drop(it);
176+
assert_eq!(vec, &[2, 3, 4]);
177+
}
178+
179+
#[test]
180+
fn drain_middle() {
181+
let mut vec = Vec::<_, 8>::from_array([1, 2, 3, 4]);
182+
let mut it = vec.drain(1..3);
183+
assert_eq!(it.next(), Some(2));
184+
assert_eq!(it.next(), Some(3));
185+
drop(it);
186+
assert_eq!(vec, &[1, 4]);
187+
}
188+
189+
#[test]
190+
fn drain_end() {
191+
let mut vec = Vec::<_, 8>::from_array([1, 2, 3, 4]);
192+
let mut it = vec.drain(3..);
193+
assert_eq!(it.next(), Some(4));
194+
drop(it);
195+
assert_eq!(vec, &[1, 2, 3]);
196+
}
197+
198+
#[test]
199+
fn drain_drop_rest() {
200+
droppable!();
201+
202+
let mut vec = Vec::<_, 8>::from_array([
203+
Droppable::new(),
204+
Droppable::new(),
205+
Droppable::new(),
206+
Droppable::new(),
207+
]);
208+
assert_eq!(Droppable::count(), 4);
209+
210+
let mut iter = vec.drain(2..);
211+
assert_eq!(iter.next().unwrap().0, 3);
212+
drop(iter);
213+
assert_eq!(Droppable::count(), 2);
214+
215+
assert_eq!(vec.len(), 2);
216+
assert_eq!(vec.remove(0).0, 1);
217+
assert_eq!(Droppable::count(), 1);
218+
219+
drop(vec);
220+
assert_eq!(Droppable::count(), 0);
221+
}
222+
}

0 commit comments

Comments
 (0)