Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
  • 2 commits
  • 2 files changed
  • 0 commit comments
  • 1 contributor
Commits on Aug 09, 2015
Showing with 133 additions and 8 deletions.
  1. +28 −8 src/lib.rs
  2. +105 −0 src/range.rs
@@ -17,8 +17,9 @@ use std::fmt;
use odds::debug_assert_unreachable;

mod array;
mod range;
pub use array::Array;
pub use odds::IndexRange as RangeArgument;
use range::IntoCheckedRange;
use array::Index;


@@ -306,7 +307,9 @@ impl<A: Array> ArrayVec<A> {
/// assert_eq!(&v[..], &[3]);
/// assert_eq!(&u[..], &[1, 2]);
/// ```
pub fn drain<R: RangeArgument>(&mut self, range: R) -> Drain<A> {
pub fn drain<R>(&mut self, range: R) -> Drain<A>
where R: IntoCheckedRange
{
// Memory safety
//
// When the Drain is first created, it shortens the length of
@@ -318,17 +321,20 @@ impl<A: Array> ArrayVec<A> {
// 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];
let r = match range.into_checked_range(len) {
Err(i) => drain_panic(i),
Ok(r) => r,
};

unsafe {
let range_slice: *const _ = odds::slice_unchecked(&*self, r.start, r.end);

// set self.vec length's to start, to be safe in case Drain is leaked
self.set_len(start);
self.set_len(r.start);
Drain {
tail_start: end,
tail_len: len - end,
tail_start: r.end,
tail_len: len - r.end,
iter: (*range_slice).iter(),
vec: self as *mut _,
}
@@ -679,3 +685,17 @@ impl<A: Array> AsMut<[A::Item]> for ArrayVec<A> {
impl<A: Array> fmt::Debug for ArrayVec<A> where A::Item: fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
}

#[inline(never)]
fn drain_panic(i: usize) -> ! {
panic!("ArrayVec::drain: Index {} out of bounds", i);
}

#[test]
fn drain_range() {
let mut arr = ArrayVec::from([1,2,3]);
arr.drain(range::InclusiveRange { start: 1, end: 2, });
assert_eq!(&arr[..], &[1]);
arr.drain(range::InclusiveRange { start: 0, end: 0, });
assert_eq!(&arr[..], &[]);
}
@@ -0,0 +1,105 @@
use std::cmp;

use std::ops::{
RangeFull,
RangeFrom,
RangeTo,
Range,
};

/// For illustration, add an inclusive range too
#[derive(Copy, Clone)]
pub struct InclusiveRange<T> {
pub start: T,
pub end: T,
}

pub trait IntoIndexRange {
fn into_index_range(self, len: usize) -> Range<usize>;
}

pub unsafe trait IntoCheckedRange {
fn into_checked_range(self, len: usize) -> Result<Range<usize>, usize>;
}


impl IntoIndexRange for RangeFull {
#[inline]
fn into_index_range(self, len: usize) -> Range<usize> {
0..len
}
}

impl IntoIndexRange for RangeFrom<usize> {
#[inline]
fn into_index_range(self, len: usize) -> Range<usize> {
self.start..len
}
}

impl IntoIndexRange for RangeTo<usize> {
#[inline]
fn into_index_range(self, _len: usize) -> Range<usize> {
0..self.end
}
}

impl IntoIndexRange for Range<usize> {
#[inline]
fn into_index_range(self, _len: usize) -> Range<usize> {
self
}
}

impl IntoIndexRange for InclusiveRange<usize> {
#[inline]
fn into_index_range(self, _len: usize) -> Range<usize> {
// this doesn't work so well!
self.start..self.end.saturating_add(1)
}
}


unsafe impl IntoCheckedRange for RangeFull {
#[inline]
fn into_checked_range(self, len: usize) -> Result<Range<usize>, usize> {
Ok(0..len)
}
}

unsafe impl IntoCheckedRange for RangeFrom<usize> {
#[inline]
fn into_checked_range(self, len: usize) -> Result<Range<usize>, usize> {
if self.start <= len {
Ok(self.start..len)
} else { Err(self.start) }
}
}

unsafe impl IntoCheckedRange for RangeTo<usize> {
#[inline]
fn into_checked_range(self, len: usize) -> Result<Range<usize>, usize> {
if self.end <= len {
Ok(0..self.end)
} else { Err(self.end) }
}
}

unsafe impl IntoCheckedRange for Range<usize> {
#[inline]
fn into_checked_range(self, len: usize) -> Result<Range<usize>, usize> {
if self.start <= self.end && self.end <= len {
Ok(self.start..self.end)
} else { Err(cmp::max(self.start, self.end)) }
}
}

unsafe impl IntoCheckedRange for InclusiveRange<usize> {
#[inline]
// this doesn't work so well
fn into_checked_range(self, len: usize) -> Result<Range<usize>, usize> {
if self.start <= self.end && self.end < len {
Ok(self.start..self.end + 1)
} else { Err(cmp::max(self.start, self.end)) }
}
}

No commit comments for this range

You can’t perform that action at this time.