diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index c0910ab8612..d54d9cf453b 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -398,28 +398,51 @@ pub fn rsplitn(v: &[T], n: uint, f: fn(t: &T) -> bool) -> ~[~[T]] { // Mutators /// Removes the first element from a vector and return it -pub fn shift(v: &mut ~[T]) -> T { - let ln = v.len(); - assert (ln > 0); +pub fn shift(v: &mut ~[T]) -> T unsafe { - let mut vv = ~[]; - *v <-> vv; + assert v.is_not_empty(); - unsafe { - let mut rr; - { - let vv = raw::to_ptr(vv); - rr = move *vv; + if v.len() == 1 { return v.pop() } - for uint::range(1, ln) |i| { - let r = move *ptr::offset(vv, i); - v.push(r); - } - } - raw::set_len(&mut vv, 0); - - rr + if v.len() == 2 { + let last = v.pop(); + let first = v.pop(); + v.push(last); + return first; } + + let ln = v.len(); + let next_ln = v.len() - 1; + + // Save the last element. We're going to overwrite its position + let mut work_elt = v.pop(); + // We still should have room to work where what last element was + assert capacity(v) >= ln; + // Pretend like we have the original length so we can use + // the vector memcpy to overwrite the hole we just made + raw::set_len(v, ln); + + // Memcopy the head element (the one we want) to the location we just + // popped. For the moment it unsafely exists at both the head and last + // positions + let first_slice = view(*v, 0, 1); + let last_slice = mut_view(*v, next_ln, ln); + raw::memcpy(last_slice, first_slice, 1); + + // Memcopy everything to the left one element + let init_slice = mut_view(*v, 0, next_ln); + let tail_slice = view(*v, 1, ln); + raw::memcpy(init_slice, tail_slice, next_ln); + + // Set the new length. Now the vector is back to normal + raw::set_len(v, next_ln); + + // Swap out the element we want from the end + let vp = raw::to_mut_ptr(*v); + let vp = ptr::mut_offset(vp, next_ln - 1); + *vp <-> work_elt; + + return work_elt; } /// Prepend an element to the vector @@ -1760,7 +1783,7 @@ pub struct UnboxedVecRepr { } /// Unsafe operations -mod raw { +pub mod raw { /// The internal representation of a (boxed) vector pub struct VecRepr {