about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Chevalier <catamorphism@gmail.com>2012-08-29 13:53:23 -0700
committerTim Chevalier <catamorphism@gmail.com>2012-08-29 13:53:23 -0700
commitec9c68c1df2ab657e630993d34c859d8bcb3f18e (patch)
tree7eac1102be9caf179238b7dc4066b9396a7bd4d5
parent5eef15df126e8dfedc9e72ee3d9456ead0c9d06d (diff)
parent3e4b55807d9778c396ae449fe9a5680508d7d62d (diff)
Merge pull request #3301 from jld/vec-truncate
Add vec::truncate, for efficiently shortening a vector.
-rw-r--r--src/libcore/vec.rs24
1 files changed, 24 insertions, 0 deletions
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index db564fc4a6f..33199576c11 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -42,6 +42,7 @@ export push, push_all, push_all_move;
 export grow;
 export grow_fn;
 export grow_set;
+export truncate;
 export map;
 export mapi;
 export map2;
@@ -611,6 +612,20 @@ fn push_all_move<T>(&v: ~[const T], -rhs: ~[const T]) {
     }
 }
 
+/// Shorten a vector, dropping excess elements.
+fn truncate<T>(&v: ~[const T], newlen: uint) {
+    do as_buf(v) |p, oldlen| {
+        assert(newlen <= oldlen);
+        unsafe {
+            // This loop is optimized out for non-drop types.
+            for uint::range(newlen, oldlen) |i| {
+                let _dropped <- *ptr::offset(p, i);
+            }
+            unsafe::set_len(v, newlen);
+        }
+    }
+}
+
 // Appending
 #[inline(always)]
 pure fn append<T: copy>(+lhs: ~[T], rhs: &[const T]) -> ~[T] {
@@ -2167,6 +2182,15 @@ mod tests {
     }
 
     #[test]
+    fn test_truncate() {
+        let mut v = ~[@6,@5,@4];
+        truncate(v, 1);
+        assert(v.len() == 1);
+        assert(*(v[0]) == 6);
+        // If the unsafe block didn't drop things properly, we blow up here.
+    }
+
+    #[test]
     fn test_map() {
         // Test on-stack map.
         let mut v = ~[1u, 2u, 3u];