Permalink
Checking mergeability…
Don’t worry, you can still create the pull request.
Comparing changes
Open a pull request
- 2 commits
- 2 files changed
- 0 commit comments
- 1 contributor
Commits on Aug 09, 2015
Unified
Split
Showing
with
133 additions
and 8 deletions.
- +28 −8 src/lib.rs
- +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)) } | |||
| } | |||
| } | |||