Skip to content

Commit acd2be4

Browse files
committed
std::vec: use some unsafe code to optimise remove.
Also, add `.remove_opt` and replace `.unshift` with `.remove(0)`. The code size reduction seem to compensate for not having the optimised special cases. This makes the included benchmark more than 3 times faster.
1 parent 8163251 commit acd2be4

File tree

1 file changed

+74
-39
lines changed

1 file changed

+74
-39
lines changed

src/libstd/vec.rs

+74-39
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,22 @@ pub trait OwnedVector<T> {
14161416
/// elements after position i one position to the right.
14171417
fn insert(&mut self, i: uint, x:T);
14181418

1419+
/// Remove and return the element at position `i` within `v`,
1420+
/// shifting all elements after position `i` one position to the
1421+
/// left. Returns `None` if `i` is out of bounds.
1422+
///
1423+
/// # Example
1424+
/// ```rust
1425+
/// let mut v = ~[1, 2, 3];
1426+
/// assert_eq!(v.remove_opt(1), Some(2));
1427+
/// assert_eq!(v, ~[1, 3]);
1428+
///
1429+
/// assert_eq!(v.remove_opt(4), None);
1430+
/// // v is unchanged:
1431+
/// assert_eq!(v, ~[1, 3]);
1432+
/// ```
1433+
fn remove_opt(&mut self, i: uint) -> Option<T>;
1434+
14191435
/// Remove and return the element at position i within v, shifting
14201436
/// all elements after position i one position to the left.
14211437
fn remove(&mut self, i: uint) -> T;
@@ -1625,39 +1641,7 @@ impl<T> OwnedVector<T> for ~[T] {
16251641
}
16261642

16271643
fn shift_opt(&mut self) -> Option<T> {
1628-
match self.len() {
1629-
0 => None,
1630-
1 => self.pop_opt(),
1631-
2 => {
1632-
let last = self.pop();
1633-
let first = self.pop_opt();
1634-
self.push(last);
1635-
first
1636-
}
1637-
len => {
1638-
unsafe {
1639-
let next_len = len - 1;
1640-
1641-
let ptr = self.as_ptr();
1642-
1643-
// copy out the head element, for the moment it exists
1644-
// unsafely on the stack and as the first element of the
1645-
// vector.
1646-
let head = ptr::read_ptr(ptr);
1647-
1648-
// Memcpy everything to the left one element (leaving the
1649-
// last element unsafely in two consecutive memory
1650-
// locations)
1651-
ptr::copy_memory(self.as_mut_ptr(), ptr.offset(1), next_len);
1652-
1653-
// set the new length, which means the second instance of
1654-
// the last element is forgotten.
1655-
self.set_len(next_len);
1656-
1657-
Some(head)
1658-
}
1659-
}
1660-
}
1644+
self.remove_opt(0)
16611645
}
16621646

16631647
fn unshift(&mut self, x: T) {
@@ -1683,16 +1667,33 @@ impl<T> OwnedVector<T> for ~[T] {
16831667
}
16841668
}
16851669

1670+
#[inline]
16861671
fn remove(&mut self, i: uint) -> T {
1672+
match self.remove_opt(i) {
1673+
Some(t) => t,
1674+
None => fail!("remove: the len is {} but the index is {}", self.len(), i)
1675+
}
1676+
}
1677+
1678+
fn remove_opt(&mut self, i: uint) -> Option<T> {
16871679
let len = self.len();
1688-
assert!(i < len);
1680+
if i < len {
1681+
unsafe { // infallible
1682+
// the place we are taking from.
1683+
let ptr = self.as_mut_ptr().offset(i as int);
1684+
// copy it out, unsafely having a copy of the value on
1685+
// the stack and in the vector at the same time.
1686+
let ret = Some(ptr::read_ptr(ptr as *T));
1687+
1688+
// Shift everything down to fill in that spot.
1689+
ptr::copy_memory(ptr, ptr.offset(1), len - i - 1);
1690+
self.set_len(len - 1);
16891691

1690-
let mut j = i;
1691-
while j < len - 1 {
1692-
self.swap(j, j + 1);
1693-
j += 1;
1692+
ret
1693+
}
1694+
} else {
1695+
None
16941696
}
1695-
self.pop()
16961697
}
16971698
fn swap_remove(&mut self, index: uint) -> T {
16981699
let ln = self.len();
@@ -3422,6 +3423,29 @@ mod tests {
34223423
a.insert(4, 5);
34233424
}
34243425

3426+
#[test]
3427+
fn test_remove_opt() {
3428+
let mut a = ~[1,2,3,4];
3429+
3430+
assert_eq!(a.remove_opt(2), Some(3));
3431+
assert_eq!(a, ~[1,2,4]);
3432+
3433+
assert_eq!(a.remove_opt(2), Some(4));
3434+
assert_eq!(a, ~[1,2]);
3435+
3436+
assert_eq!(a.remove_opt(2), None);
3437+
assert_eq!(a, ~[1,2]);
3438+
3439+
assert_eq!(a.remove_opt(0), Some(1));
3440+
assert_eq!(a, ~[2]);
3441+
3442+
assert_eq!(a.remove_opt(0), Some(2));
3443+
assert_eq!(a, ~[]);
3444+
3445+
assert_eq!(a.remove_opt(0), None);
3446+
assert_eq!(a.remove_opt(10), None);
3447+
}
3448+
34253449
#[test]
34263450
fn test_remove() {
34273451
let mut a = ~[1, 2, 3, 4];
@@ -4342,4 +4366,15 @@ mod bench {
43424366
}
43434367
})
43444368
}
4369+
#[bench]
4370+
fn random_removes(bh: &mut BenchHarness) {
4371+
let mut rng = weak_rng();
4372+
bh.iter(|| {
4373+
let mut v = vec::from_elem(130, (0u, 0u));
4374+
for _ in range(0, 100) {
4375+
let l = v.len();
4376+
v.remove(rng.gen::<uint>() % l);
4377+
}
4378+
})
4379+
}
43454380
}

0 commit comments

Comments
 (0)