Skip to content

Commit

Permalink
auto merge of #10757 : TeXitoi/rust/mut-split-iter, r=alexcrichton
Browse files Browse the repository at this point in the history
I've renamed `MutableVector::mut_split(at)` to `MutableVector::mut_split_at(at)` to be coherent with ImmutableVector.  As specified in the commit log, The `size_hint` method is not optimal because of #9629.
  • Loading branch information
bors committed Dec 3, 2013
2 parents e2d192c + 44fc3c6 commit 899217c
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 15 deletions.
6 changes: 3 additions & 3 deletions src/libextra/ringbuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,14 @@ impl<T> RingBuf<T> {
// start_index to self.elts.len()
// and then
// 0 to end_index
let (temp, remaining1) = self.elts.mut_split(start_index);
let (remaining2, _) = temp.mut_split(end_index);
let (temp, remaining1) = self.elts.mut_split_at(start_index);
let (remaining2, _) = temp.mut_split_at(end_index);
RingBufMutIterator { remaining1: remaining1,
remaining2: remaining2,
nelts: self.nelts }
} else {
// Items to iterate goes from start_index to end_index:
let (empty, elts) = self.elts.mut_split(0);
let (empty, elts) = self.elts.mut_split_at(0);
let remaining1 = elts.mut_slice(start_index, end_index);
RingBufMutIterator { remaining1: remaining1,
remaining2: empty,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/borrowck/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,8 +666,8 @@ The current rules could use some correction:
function will fail to compile:
fn mut_shift_ref<'a,T>(x: &mut &'a mut [T]) -> &'a mut T {
// `mut_split` will restrict mutation against *x:
let (head, tail) = (*x).mut_split(1);
// `mut_split_at` will restrict mutation against *x:
let (head, tail) = (*x).mut_split_at(1);
// Hence mutating `*x` yields an error here:
*x = tail;
Expand Down
126 changes: 116 additions & 10 deletions src/libstd/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -858,20 +858,24 @@ pub trait ImmutableVector<'self, T> {
/// Returns a reversed iterator over a vector
fn rev_iter(self) -> RevIterator<'self, T>;
/// Returns an iterator over the subslices of the vector which are
/// separated by elements that match `pred`.
/// separated by elements that match `pred`. The matched element
/// is not contained in the subslices.
fn split(self, pred: 'self |&T| -> bool) -> SplitIterator<'self, T>;
/// Returns an iterator over the subslices of the vector which are
/// separated by elements that match `pred`, limited to splitting
/// at most `n` times.
/// at most `n` times. The matched element is not contained in
/// the subslices.
fn splitn(self, n: uint, pred: 'self |&T| -> bool) -> SplitIterator<'self, T>;
/// Returns an iterator over the subslices of the vector which are
/// separated by elements that match `pred`. This starts at the
/// end of the vector and works backwards.
/// end of the vector and works backwards. The matched element is
/// not contained in the subslices.
fn rsplit(self, pred: 'self |&T| -> bool) -> RSplitIterator<'self, T>;
/// Returns an iterator over the subslices of the vector which are
/// separated by elements that match `pred` limited to splitting
/// at most `n` times. This starts at the end of the vector and
/// works backwards.
/// works backwards. The matched element is not contained in the
/// subslices.
fn rsplitn(self, n: uint, pred: 'self |&T| -> bool) -> RSplitIterator<'self, T>;

/**
Expand Down Expand Up @@ -1933,6 +1937,11 @@ pub trait MutableVector<'self, T> {
/// Returns a reversed iterator that allows modifying each value
fn mut_rev_iter(self) -> MutRevIterator<'self, T>;

/// Returns an iterator over the mutable subslices of the vector
/// which are separated by elements that match `pred`. The
/// matched element is not contained in the subslices.
fn mut_split(self, pred: 'self |&T| -> bool) -> MutSplitIterator<'self, T>;

/**
* Returns an iterator over `size` elements of the vector at a time.
* The chunks are mutable and do not overlap. If `size` does not divide the
Expand Down Expand Up @@ -1995,7 +2004,7 @@ pub trait MutableVector<'self, T> {
* itself) and the second will contain all indices from
* `mid..len` (excluding the index `len` itself).
*/
fn mut_split(self, mid: uint) -> (&'self mut [T],
fn mut_split_at(self, mid: uint) -> (&'self mut [T],
&'self mut [T]);

/// Reverse the order of elements in a vector, in place
Expand Down Expand Up @@ -2052,7 +2061,7 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] {
}

#[inline]
fn mut_split(self, mid: uint) -> (&'self mut [T], &'self mut [T]) {
fn mut_split_at(self, mid: uint) -> (&'self mut [T], &'self mut [T]) {
unsafe {
let len = self.len();
let self2: &'self mut [T] = cast::transmute_copy(&self);
Expand Down Expand Up @@ -2081,6 +2090,11 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] {
self.mut_iter().invert()
}

#[inline]
fn mut_split(self, pred: 'self |&T| -> bool) -> MutSplitIterator<'self, T> {
MutSplitIterator { v: self, pred: pred, finished: false }
}

#[inline]
fn mut_chunks(self, chunk_size: uint) -> MutChunkIter<'self, T> {
assert!(chunk_size > 0);
Expand Down Expand Up @@ -2575,6 +2589,73 @@ impl<'self, T> Clone for VecIterator<'self, T> {
iterator!{struct VecMutIterator -> *mut T, &'self mut T}
pub type MutRevIterator<'self, T> = Invert<VecMutIterator<'self, T>>;

/// An iterator over the subslices of the vector which are separated
/// by elements that match `pred`.
pub struct MutSplitIterator<'self, T> {
priv v: &'self mut [T],
priv pred: 'self |t: &T| -> bool,
priv finished: bool
}

impl<'self, T> Iterator<&'self mut [T]> for MutSplitIterator<'self, T> {
#[inline]
fn next(&mut self) -> Option<&'self mut [T]> {
if self.finished { return None; }

match self.v.iter().position(|x| (self.pred)(x)) {
None => {
self.finished = true;
let tmp = util::replace(&mut self.v, &mut []);
let len = tmp.len();
let (head, tail) = tmp.mut_split_at(len);
self.v = tail;
Some(head)
}
Some(idx) => {
let tmp = util::replace(&mut self.v, &mut []);
let (head, tail) = tmp.mut_split_at(idx);
self.v = tail.mut_slice_from(1);
Some(head)
}
}
}

#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
if self.finished { return (0, Some(0)) }

// if the predicate doesn't match anything, we yield one slice
// if it matches every element, we yield len+1 empty slices.
// FIXME #9629
//(1, Some(self.v.len() + 1))
(1, None)
}
}

impl<'self, T> DoubleEndedIterator<&'self mut [T]> for MutSplitIterator<'self, T> {
#[inline]
fn next_back(&mut self) -> Option<&'self mut [T]> {
if self.finished { return None; }

match self.v.iter().rposition(|x| (self.pred)(x)) {
None => {
self.finished = true;
let tmp = util::replace(&mut self.v, &mut []);
let len = tmp.len();
let (head, tail) = tmp.mut_split_at(len);
self.v = tail;
Some(head)
}
Some(idx) => {
let tmp = util::replace(&mut self.v, &mut []);
let (head, tail) = tmp.mut_split_at(idx);
self.v = head;
Some(tail.mut_slice_from(1))
}
}
}
}

/// An iterator over a vector in (non-overlapping) mutable chunks (`size` elements at a time). When
/// the vector len is not evenly divided by the chunk size, the last slice of the iteration will be
/// the remainder.
Expand All @@ -2592,7 +2673,7 @@ impl<'self, T> Iterator<&'self mut [T]> for MutChunkIter<'self, T> {
} else {
let sz = cmp::min(self.remaining, self.chunk_size);
let tmp = util::replace(&mut self.v, &mut []);
let (head, tail) = tmp.mut_split(sz);
let (head, tail) = tmp.mut_split_at(sz);
self.v = tail;
self.remaining -= sz;
Some(head)
Expand Down Expand Up @@ -2620,7 +2701,7 @@ impl<'self, T> DoubleEndedIterator<&'self mut [T]> for MutChunkIter<'self, T> {
let remainder = self.remaining % self.chunk_size;
let sz = if remainder != 0 { remainder } else { self.chunk_size };
let tmp = util::replace(&mut self.v, &mut []);
let (head, tail) = tmp.mut_split(self.remaining - sz);
let (head, tail) = tmp.mut_split_at(self.remaining - sz);
self.v = head;
self.remaining -= sz;
Some(tail)
Expand Down Expand Up @@ -3898,10 +3979,10 @@ mod tests {
}

#[test]
fn test_mut_split() {
fn test_mut_split_at() {
let mut values = [1u8,2,3,4,5];
{
let (left, right) = values.mut_split(2);
let (left, right) = values.mut_split_at(2);
assert_eq!(left.slice(0, left.len()), [1, 2]);
for p in left.mut_iter() {
*p += 1;
Expand Down Expand Up @@ -4038,6 +4119,31 @@ mod tests {
x.pop_ref();
}

#[test]
fn test_mut_splitator() {
let mut xs = [0,1,0,2,3,0,0,4,5,0];
assert_eq!(xs.mut_split(|x| *x == 0).len(), 6);
for slice in xs.mut_split(|x| *x == 0) {
slice.reverse();
}
assert_eq!(xs, [0,1,0,3,2,0,0,5,4,0]);

let mut xs = [0,1,0,2,3,0,0,4,5,0,6,7];
for slice in xs.mut_split(|x| *x == 0).take(5) {
slice.reverse();
}
assert_eq!(xs, [0,1,0,3,2,0,0,5,4,0,6,7]);
}

#[test]
fn test_mut_splitator_invert() {
let mut xs = [1,2,0,3,4,0,0,5,6,0];
for slice in xs.mut_split(|x| *x == 0).invert().take(4) {
slice.reverse();
}
assert_eq!(xs, [1,2,0,4,3,0,0,6,5,0]);
}

#[test]
fn test_mut_chunks() {
let mut v = [0u8, 1, 2, 3, 4, 5, 6];
Expand Down

0 comments on commit 899217c

Please sign in to comment.