Implement ArrayVec::remove() and ::drain()
This commit is contained in:
+180
-4
@@ -17,7 +17,9 @@ use std::hash::{Hash, Hasher};
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
mod array;
|
mod array;
|
||||||
|
mod misc;
|
||||||
pub use array::Array;
|
pub use array::Array;
|
||||||
|
pub use misc::RangeArgument;
|
||||||
|
|
||||||
|
|
||||||
unsafe fn new_array<A: Array>() -> A {
|
unsafe fn new_array<A: Array>() -> A {
|
||||||
@@ -169,9 +171,7 @@ impl<A: Array> ArrayVec<A> {
|
|||||||
///
|
///
|
||||||
/// let mut array = ArrayVec::from([1, 2, 3]);
|
/// let mut array = ArrayVec::from([1, 2, 3]);
|
||||||
///
|
///
|
||||||
/// let elt = array.swap_remove(0);
|
/// assert_eq!(array.swap_remove(0), Some(1));
|
||||||
///
|
|
||||||
/// assert_eq!(elt, Some(1));
|
|
||||||
/// assert_eq!(&array[..], &[3, 2]);
|
/// assert_eq!(&array[..], &[3, 2]);
|
||||||
///
|
///
|
||||||
/// assert_eq!(array.swap_remove(10), None);
|
/// assert_eq!(array.swap_remove(10), None);
|
||||||
@@ -184,6 +184,80 @@ impl<A: Array> ArrayVec<A> {
|
|||||||
self.swap(index, len - 1);
|
self.swap(index, len - 1);
|
||||||
self.pop()
|
self.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove the element at **index** and shift the following elements down.
|
||||||
|
///
|
||||||
|
/// Return **Some(** *element* **)** if the index is in bounds, else **None**.
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
/// ```
|
||||||
|
/// use arrayvec::ArrayVec;
|
||||||
|
///
|
||||||
|
/// let mut array = ArrayVec::from([1, 2, 3]);
|
||||||
|
///
|
||||||
|
/// assert_eq!(array.remove(0), Some(1));
|
||||||
|
/// assert_eq!(&array[..], &[2, 3]);
|
||||||
|
///
|
||||||
|
/// assert_eq!(array.remove(10), None);
|
||||||
|
/// ```
|
||||||
|
pub fn remove(&mut self, index: usize) -> Option<A::Item> {
|
||||||
|
if index >= self.len() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.drain(index..index + 1).next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a draining iterator that removes the specified range in the vector
|
||||||
|
/// and yields the removed items from start to end. The element range is
|
||||||
|
/// removed even if the iterator is not consumed until the end.
|
||||||
|
///
|
||||||
|
/// Note: It is unspecified how many elements are removed from the vector,
|
||||||
|
/// if the `Drain` value is leaked.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the starting point is greater than the end point or if
|
||||||
|
/// the end point is greater than the length of the vector.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use arrayvec::ArrayVec;
|
||||||
|
///
|
||||||
|
/// let mut v = ArrayVec::from([1, 2, 3]);
|
||||||
|
/// let u: Vec<_> = v.drain(0..2).collect();
|
||||||
|
/// assert_eq!(&v[..], &[3]);
|
||||||
|
/// assert_eq!(&u[..], &[1, 2]);
|
||||||
|
/// ```
|
||||||
|
pub fn drain<R: RangeArgument>(&mut self, range: R) -> Drain<A> {
|
||||||
|
// Memory safety
|
||||||
|
//
|
||||||
|
// When the Drain is first created, it shortens the length of
|
||||||
|
// the source vector to make sure no uninitalized or moved-from elements
|
||||||
|
// are accessible at all if the Drain's destructor never gets to run.
|
||||||
|
//
|
||||||
|
// Drain will ptr::read out the values to remove.
|
||||||
|
// When finished, remaining tail of the vec is copied back to cover
|
||||||
|
// the hole, and the vector length is restored to the new length.
|
||||||
|
//
|
||||||
|
let len = self.len();
|
||||||
|
let start = range.start().unwrap_or(0);
|
||||||
|
let end = range.end().unwrap_or(len);
|
||||||
|
// bounds check happens here
|
||||||
|
let range_slice: *const _ = &self[start..end];
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// set self.vec length's to start, to be safe in case Drain is leaked
|
||||||
|
self.len = start as u8;
|
||||||
|
Drain {
|
||||||
|
tail_start: end,
|
||||||
|
tail_len: len - end,
|
||||||
|
iter: (*range_slice).iter(),
|
||||||
|
vec: self as *mut _,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Array> Deref for ArrayVec<A> {
|
impl<A: Array> Deref for ArrayVec<A> {
|
||||||
@@ -283,7 +357,7 @@ impl<A: Array> IntoIterator for ArrayVec<A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// By-value iterator for ArrayVec.
|
/// By-value iterator for **ArrayVec**.
|
||||||
pub struct IntoIter<A: Array> {
|
pub struct IntoIter<A: Array> {
|
||||||
index: u8,
|
index: u8,
|
||||||
v: ArrayVec<A>,
|
v: ArrayVec<A>,
|
||||||
@@ -338,6 +412,83 @@ impl<A: Array> Drop for IntoIter<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A draining iterator for **ArrayVec**.
|
||||||
|
pub struct Drain<'a, A>
|
||||||
|
where A: Array,
|
||||||
|
A::Item: 'a,
|
||||||
|
{
|
||||||
|
/// Index of tail to preserve
|
||||||
|
tail_start: usize,
|
||||||
|
/// Length of tail
|
||||||
|
tail_len: usize,
|
||||||
|
/// Current remaining range to remove
|
||||||
|
iter: slice::Iter<'a, A::Item>,
|
||||||
|
vec: *mut ArrayVec<A>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a, A: Array + Sync> Sync for Drain<'a, A> {}
|
||||||
|
unsafe impl<'a, A: Array + Send> Send for Drain<'a, A> {}
|
||||||
|
|
||||||
|
impl<'a, A: Array> Iterator for Drain<'a, A>
|
||||||
|
where A::Item: 'a,
|
||||||
|
{
|
||||||
|
type Item = A::Item;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.iter.next().map(|elt|
|
||||||
|
unsafe {
|
||||||
|
ptr::read(elt as *const _)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.iter.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A: Array> DoubleEndedIterator for Drain<'a, A>
|
||||||
|
where A::Item: 'a,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.iter.next_back().map(|elt|
|
||||||
|
unsafe {
|
||||||
|
ptr::read(elt as *const _)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A: Array> ExactSizeIterator for Drain<'a, A> where A::Item: 'a {}
|
||||||
|
|
||||||
|
impl<'a, A: Array> Drop for Drain<'a, A>
|
||||||
|
where A::Item: 'a
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// exhaust self first
|
||||||
|
while let Some(_) = self.next() { }
|
||||||
|
|
||||||
|
if self.tail_len > 0 {
|
||||||
|
unsafe {
|
||||||
|
let source_vec = &mut *self.vec;
|
||||||
|
// memmove back untouched tail, update to new length
|
||||||
|
let start = source_vec.len();
|
||||||
|
let tail = self.tail_start;
|
||||||
|
let src = source_vec.as_ptr().offset(tail as isize);
|
||||||
|
let dst = source_vec.as_mut_ptr().offset(start as isize);
|
||||||
|
ptr::copy(src, dst, self.tail_len);
|
||||||
|
source_vec.len = (start + self.tail_len) as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Extend the **ArrayVec** with an iterator.
|
/// Extend the **ArrayVec** with an iterator.
|
||||||
///
|
///
|
||||||
/// Does not extract more items than there is space for. No error
|
/// Does not extract more items than there is space for. No error
|
||||||
@@ -520,3 +671,28 @@ fn test_compact_size() {
|
|||||||
println!("{}", mem::size_of::<QuadArray>());
|
println!("{}", mem::size_of::<QuadArray>());
|
||||||
assert!(mem::size_of::<QuadArray>() <= 24);
|
assert!(mem::size_of::<QuadArray>() <= 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_drain() {
|
||||||
|
let mut v = ArrayVec::from([0; 8]);
|
||||||
|
v.pop();
|
||||||
|
v.drain(0..7);
|
||||||
|
assert_eq!(&v[..], &[]);
|
||||||
|
|
||||||
|
v.extend(0..);
|
||||||
|
v.drain(1..4);
|
||||||
|
assert_eq!(&v[..], &[0, 4, 5, 6, 7]);
|
||||||
|
let u: ArrayVec<[_; 3]> = v.drain(1..4).rev().collect();
|
||||||
|
assert_eq!(&u[..], &[6, 5, 4]);
|
||||||
|
assert_eq!(&v[..], &[0, 7]);
|
||||||
|
v.drain(..);
|
||||||
|
assert_eq!(&v[..], &[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_drain_oob() {
|
||||||
|
let mut v = ArrayVec::from([0; 8]);
|
||||||
|
v.pop();
|
||||||
|
v.drain(0..8);
|
||||||
|
}
|
||||||
|
|||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
use std::ops::{
|
||||||
|
RangeFull,
|
||||||
|
RangeFrom,
|
||||||
|
RangeTo,
|
||||||
|
Range,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// **RangeArgument** is implemented by Rust's built-in range types, produced
|
||||||
|
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
|
||||||
|
pub trait RangeArgument {
|
||||||
|
#[doc(hidden)]
|
||||||
|
/// Start index (inclusive)
|
||||||
|
fn start(&self) -> Option<usize> { None }
|
||||||
|
#[doc(hidden)]
|
||||||
|
/// End index (exclusive)
|
||||||
|
fn end(&self) -> Option<usize> { None }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl RangeArgument for RangeFull {}
|
||||||
|
|
||||||
|
impl RangeArgument for RangeFrom<usize> {
|
||||||
|
fn start(&self) -> Option<usize> { Some(self.start) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RangeArgument for RangeTo<usize> {
|
||||||
|
fn end(&self) -> Option<usize> { Some(self.end) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RangeArgument for Range<usize> {
|
||||||
|
fn start(&self) -> Option<usize> { Some(self.start) }
|
||||||
|
fn end(&self) -> Option<usize> { Some(self.end) }
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user