Skip to content

Commit 2c21f34

Browse files
committed
Rewrite core::vec::shift to not allocate
1 parent dbc52ce commit 2c21f34

File tree

1 file changed

+42
-19
lines changed

1 file changed

+42
-19
lines changed

src/libcore/vec.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -398,28 +398,51 @@ pub fn rsplitn<T: Copy>(v: &[T], n: uint, f: fn(t: &T) -> bool) -> ~[~[T]] {
398398
// Mutators
399399

400400
/// Removes the first element from a vector and return it
401-
pub fn shift<T>(v: &mut ~[T]) -> T {
402-
let ln = v.len();
403-
assert (ln > 0);
401+
pub fn shift<T>(v: &mut ~[T]) -> T unsafe {
404402

405-
let mut vv = ~[];
406-
*v <-> vv;
403+
assert v.is_not_empty();
407404

408-
unsafe {
409-
let mut rr;
410-
{
411-
let vv = raw::to_ptr(vv);
412-
rr = move *vv;
413-
414-
for uint::range(1, ln) |i| {
415-
let r = move *ptr::offset(vv, i);
416-
v.push(r);
417-
}
418-
}
419-
raw::set_len(&mut vv, 0);
405+
if v.len() == 1 { return v.pop() }
420406

421-
rr
407+
if v.len() == 2 {
408+
let last = v.pop();
409+
let first = v.pop();
410+
v.push(last);
411+
return first;
422412
}
413+
414+
let ln = v.len();
415+
let next_ln = v.len() - 1;
416+
417+
// Save the last element. We're going to overwrite its position
418+
let mut work_elt = v.pop();
419+
// We still should have room to work where what last element was
420+
assert capacity(v) >= ln;
421+
// Pretend like we have the original length so we can use
422+
// the vector memcpy to overwrite the hole we just made
423+
raw::set_len(v, ln);
424+
425+
// Memcopy the head element (the one we want) to the location we just
426+
// popped. For the moment it unsafely exists at both the head and last
427+
// positions
428+
let first_slice = view(*v, 0, 1);
429+
let last_slice = mut_view(*v, next_ln, ln);
430+
raw::memcpy(last_slice, first_slice, 1);
431+
432+
// Memcopy everything to the left one element
433+
let init_slice = mut_view(*v, 0, next_ln);
434+
let tail_slice = view(*v, 1, ln);
435+
raw::memcpy(init_slice, tail_slice, next_ln);
436+
437+
// Set the new length. Now the vector is back to normal
438+
raw::set_len(v, next_ln);
439+
440+
// Swap out the element we want from the end
441+
let vp = raw::to_mut_ptr(*v);
442+
let vp = ptr::mut_offset(vp, next_ln - 1);
443+
*vp <-> work_elt;
444+
445+
return work_elt;
423446
}
424447

425448
/// Prepend an element to the vector
@@ -1760,7 +1783,7 @@ pub struct UnboxedVecRepr {
17601783
}
17611784

17621785
/// Unsafe operations
1763-
mod raw {
1786+
pub mod raw {
17641787

17651788
/// The internal representation of a (boxed) vector
17661789
pub struct VecRepr {

0 commit comments

Comments
 (0)