Add [mut_]shift_ref/[mut_]pop_ref functions, which return a pointer to the first/last item in the slice and modify the slice to exclude the returned item. Useful when writing iterators over mutable references.

This commit is contained in:
Niko Matsakis 2013-11-16 17:29:19 -05:00
parent 40439516ec
commit ce44094bbb
1 changed files with 194 additions and 0 deletions

View File

@ -975,6 +975,40 @@ pub trait ImmutableVector<'self, T> {
* foreign interop.
*/
fn as_imm_buf<U>(&self, f: |*T, uint| -> U) -> U;
/**
* Returns a mutable reference to the first element in this slice
* and adjusts the slice in place so that it no longer contains
* that element. O(1).
*
* Equivalent to:
*
* ```
* let head = &self[0];
* *self = self.slice_from(1);
* head
* ```
*
* Fails if slice is empty.
*/
fn shift_ref(&mut self) -> &'self T;
/**
* Returns a mutable reference to the last element in this slice
* and adjusts the slice in place so that it no longer contains
* that element. O(1).
*
* Equivalent to:
*
* ```
* let tail = &self[self.len() - 1];
* *self = self.slice_to(self.len() - 1);
* tail
* ```
*
* Fails if slice is empty.
*/
fn pop_ref(&mut self) -> &'self T;
}
impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
@ -1141,6 +1175,20 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
let s = self.repr();
f(s.data, s.len)
}
fn shift_ref(&mut self) -> &'self T {
unsafe {
let s: &mut Slice<T> = cast::transmute(self);
&*raw::shift_ptr(s)
}
}
fn pop_ref(&mut self) -> &'self T {
unsafe {
let s: &mut Slice<T> = cast::transmute(self);
&*raw::pop_ptr(s)
}
}
}
/// Extension methods for vectors contain `Eq` elements.
@ -1859,23 +1907,61 @@ impl<T:Eq> OwnedEqVector<T> for ~[T] {
pub trait MutableVector<'self, T> {
/// Return a slice that points into another slice.
fn mut_slice(self, start: uint, end: uint) -> &'self mut [T];
/**
* Returns a slice of self from `start` to the end of the vec.
*
* Fails when `start` points outside the bounds of self.
*/
fn mut_slice_from(self, start: uint) -> &'self mut [T];
/**
* Returns a slice of self from the start of the vec to `end`.
*
* Fails when `end` points outside the bounds of self.
*/
fn mut_slice_to(self, end: uint) -> &'self mut [T];
/// Returns an iterator that allows modifying each value
fn mut_iter(self) -> VecMutIterator<'self, T>;
/// Returns a reversed iterator that allows modifying each value
fn mut_rev_iter(self) -> MutRevIterator<'self, T>;
/**
* Returns a mutable reference to the first element in this slice
* and adjusts the slice in place so that it no longer contains
* that element. O(1).
*
* Equivalent to:
*
* ```
* let head = &mut self[0];
* *self = self.mut_slice_from(1);
* head
* ```
*
* Fails if slice is empty.
*/
fn mut_shift_ref(&mut self) -> &'self mut T;
/**
* Returns a mutable reference to the last element in this slice
* and adjusts the slice in place so that it no longer contains
* that element. O(1).
*
* Equivalent to:
*
* ```
* let tail = &mut self[self.len() - 1];
* *self = self.mut_slice_to(self.len() - 1);
* tail
* ```
*
* Fails if slice is empty.
*/
fn mut_pop_ref(&mut self) -> &'self mut T;
/**
* Swaps two elements in a vector
*
@ -1978,6 +2064,20 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] {
self.mut_iter().invert()
}
fn mut_shift_ref(&mut self) -> &'self mut T {
unsafe {
let s: &mut Slice<T> = cast::transmute(self);
cast::transmute_mut(&*raw::shift_ptr(s))
}
}
fn mut_pop_ref(&mut self) -> &'self mut T {
unsafe {
let s: &mut Slice<T> = cast::transmute(self);
cast::transmute_mut(&*raw::pop_ptr(s))
}
}
fn swap(self, a: uint, b: uint) {
unsafe {
// Can't take two mutable loans from one vector, so instead just cast
@ -2189,6 +2289,31 @@ pub mod raw {
}
}
}
/**
* Returns a pointer to first element in slice and adjusts
* slice so it no longer contains that element. Fails if
* slice is empty. O(1).
*/
pub unsafe fn shift_ptr<T>(slice: &mut Slice<T>) -> *T {
if slice.len == 0 { fail!("shift on empty slice"); }
let head: *T = slice.data;
slice.data = ptr::offset(slice.data, 1);
slice.len -= 1;
head
}
/**
* Returns a pointer to last element in slice and adjusts
* slice so it no longer contains that element. Fails if
* slice is empty. O(1).
*/
pub unsafe fn pop_ptr<T>(slice: &mut Slice<T>) -> *T {
if slice.len == 0 { fail!("pop on empty slice"); }
let tail: *T = ptr::offset(slice.data, (slice.len - 1) as int);
slice.len -= 1;
tail
}
}
/// Operations on `[u8]`
@ -3822,6 +3947,75 @@ mod tests {
assert!(!empty.ends_with(bytes!("foo")));
assert!(bytes!("foobar").ends_with(empty));
}
#[test]
fn test_shift_ref() {
let mut x: &[int] = [1, 2, 3, 4, 5];
let h = x.shift_ref();
assert_eq!(*h, 1);
assert_eq!(x.len(), 4);
assert_eq!(x[0], 2);
assert_eq!(x[3], 5);
}
#[test]
#[should_fail]
fn test_shift_ref_empty() {
let mut x: &[int] = [];
x.shift_ref();
}
#[test]
fn test_pop_ref() {
let mut x: &[int] = [1, 2, 3, 4, 5];
let h = x.pop_ref();
assert_eq!(*h, 5);
assert_eq!(x.len(), 4);
assert_eq!(x[0], 1);
assert_eq!(x[3], 4);
}
#[test]
#[should_fail]
fn test_pop_ref_empty() {
let mut x: &[int] = [];
x.pop_ref();
}
#[test]
fn test_mut_shift_ref() {
let mut x: &mut [int] = [1, 2, 3, 4, 5];
let h = x.mut_shift_ref();
assert_eq!(*h, 1);
assert_eq!(x.len(), 4);
assert_eq!(x[0], 2);
assert_eq!(x[3], 5);
}
#[test]
#[should_fail]
fn test_mut_shift_ref_empty() {
let mut x: &mut [int] = [];
x.mut_shift_ref();
}
#[test]
fn test_mut_pop_ref() {
let mut x: &mut [int] = [1, 2, 3, 4, 5];
let h = x.mut_pop_ref();
assert_eq!(*h, 5);
assert_eq!(x.len(), 4);
assert_eq!(x[0], 1);
assert_eq!(x[3], 4);
}
#[test]
#[should_fail]
fn test_mut_pop_ref_empty() {
let mut x: &mut [int] = [];
x.mut_pop_ref();
}
}
#[cfg(test)]