about summary refs log tree commit diff
path: root/src/libstd/vec.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-05-10 23:21:44 -0700
committerbors <bors@rust-lang.org>2014-05-10 23:21:44 -0700
commitadb8b0b230d5e5c79b4f873825b3d3cff8d1bc8f (patch)
tree770b50ee78ec3b79feeaf70f73f50f1166bed980 /src/libstd/vec.rs
parent11571cd9c1cde63c3b46ca65e608b84647785ac8 (diff)
parent81fadbbc4182c5a34e0d2ff698471abfc1ec0e33 (diff)
downloadrust-adb8b0b230d5e5c79b4f873825b3d3cff8d1bc8f.tar.gz
rust-adb8b0b230d5e5c79b4f873825b3d3cff8d1bc8f.zip
auto merge of #14006 : thestinger/rust/jemalloc, r=alexcrichton
Closes #11807
Diffstat (limited to 'src/libstd/vec.rs')
-rw-r--r--src/libstd/vec.rs89
1 files changed, 61 insertions, 28 deletions
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index da01da26709..aa10be1d1be 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -12,13 +12,12 @@
 
 use cast::{forget, transmute};
 use clone::Clone;
-use cmp::{Ord, Eq, Ordering, TotalEq, TotalOrd};
+use cmp::{Ord, Eq, Ordering, TotalEq, TotalOrd, max};
 use container::{Container, Mutable};
 use default::Default;
 use fmt;
 use iter::{DoubleEndedIterator, FromIterator, Extendable, Iterator, range};
-use libc::{free, c_void};
-use mem::{size_of, move_val_init};
+use mem::{min_align_of, move_val_init, size_of};
 use mem;
 use num;
 use num::{CheckedMul, CheckedAdd};
@@ -26,9 +25,9 @@ use ops::{Add, Drop};
 use option::{None, Option, Some, Expect};
 use ptr::RawPtr;
 use ptr;
-use rt::global_heap::{malloc_raw, realloc_raw};
 use raw::Slice;
 use RawVec = raw::Vec;
+use rt::heap::{allocate, reallocate, deallocate};
 use slice::{ImmutableEqVector, ImmutableVector, Items, MutItems, MutableVector};
 use slice::{MutableTotalOrdVector, OwnedVector, Vector};
 use slice::{MutableVectorAllocating};
@@ -92,11 +91,12 @@ impl<T> Vec<T> {
     /// let vec: Vec<int> = Vec::with_capacity(10);
     /// ```
     pub fn with_capacity(capacity: uint) -> Vec<T> {
+        if size_of::<T>() == 0 { return Vec { len: 0, cap: ::uint::MAX, ptr: 0 as *mut T } }
         if capacity == 0 {
             Vec::new()
         } else {
             let size = capacity.checked_mul(&size_of::<T>()).expect("capacity overflow");
-            let ptr = unsafe { malloc_raw(size) };
+            let ptr = unsafe { allocate(size, min_align_of::<T>()) };
             Vec { len: 0, cap: capacity, ptr: ptr as *mut T }
         }
     }
@@ -401,6 +401,23 @@ impl<T> Container for Vec<T> {
     }
 }
 
+// FIXME: #13996: need a way to mark the return value as `noalias`
+#[inline(never)]
+unsafe fn alloc_or_realloc<T>(ptr: *mut T, size: uint, old_size: uint) -> *mut T {
+    if old_size == 0 {
+        allocate(size, min_align_of::<T>()) as *mut T
+    } else {
+        reallocate(ptr as *mut u8, size, min_align_of::<T>(), old_size) as *mut T
+    }
+}
+
+#[inline]
+unsafe fn dealloc<T>(ptr: *mut T, len: uint) {
+    if size_of::<T>() != 0 {
+        deallocate(ptr as *mut u8, len * size_of::<T>(), min_align_of::<T>())
+    }
+}
+
 impl<T> Vec<T> {
     /// Returns the number of elements the vector can hold without
     /// reallocating.
@@ -477,33 +494,38 @@ impl<T> Vec<T> {
     /// assert_eq!(vec.capacity(), 11);
     /// ```
     pub fn reserve_exact(&mut self, capacity: uint) {
+        if size_of::<T>() == 0 { return }
         if capacity > self.cap {
             let size = capacity.checked_mul(&size_of::<T>()).expect("capacity overflow");
-            self.cap = capacity;
             unsafe {
-                self.ptr = realloc_raw(self.ptr as *mut u8, size) as *mut T;
+                self.ptr = alloc_or_realloc(self.ptr, size, self.cap * size_of::<T>());
             }
+            self.cap = capacity;
         }
     }
 
-    /// Shrink the capacity of the vector to match the length
+    /// Shrink the capacity of the vector as much as possible
     ///
     /// # Example
     ///
     /// ```rust
     /// let mut vec = vec!(1, 2, 3);
     /// vec.shrink_to_fit();
-    /// assert_eq!(vec.capacity(), vec.len());
     /// ```
     pub fn shrink_to_fit(&mut self) {
+        if size_of::<T>() == 0 { return }
         if self.len == 0 {
-            unsafe { free(self.ptr as *mut c_void) };
-            self.cap = 0;
-            self.ptr = 0 as *mut T;
+            if self.cap != 0 {
+                unsafe {
+                    dealloc(self.ptr, self.cap)
+                }
+                self.cap = 0;
+            }
         } else {
             unsafe {
                 // Overflow check is unnecessary as the vector is already at least this large.
-                self.ptr = realloc_raw(self.ptr as *mut u8, self.len * size_of::<T>()) as *mut T;
+                self.ptr = reallocate(self.ptr as *mut u8, self.len * size_of::<T>(),
+                                      min_align_of::<T>(), self.cap * size_of::<T>()) as *mut T;
             }
             self.cap = self.len;
         }
@@ -546,15 +568,20 @@ impl<T> Vec<T> {
     /// ```
     #[inline]
     pub fn push(&mut self, value: T) {
+        if size_of::<T>() == 0 {
+            // zero-size types consume no memory, so we can't rely on the address space running out
+            self.len = self.len.checked_add(&1).expect("length overflow");
+            unsafe { forget(value); }
+            return
+        }
         if self.len == self.cap {
-            if self.cap == 0 { self.cap += 2 }
             let old_size = self.cap * size_of::<T>();
-            self.cap = self.cap * 2;
-            let size = old_size * 2;
+            let size = max(old_size, 2 * size_of::<T>()) * 2;
             if old_size > size { fail!("capacity overflow") }
             unsafe {
-                self.ptr = realloc_raw(self.ptr as *mut u8, size) as *mut T;
+                self.ptr = alloc_or_realloc(self.ptr, size, self.cap * size_of::<T>());
             }
+            self.cap = max(self.cap, 2) * 2;
         }
 
         unsafe {
@@ -638,9 +665,10 @@ impl<T> Vec<T> {
     pub fn move_iter(self) -> MoveItems<T> {
         unsafe {
             let iter = transmute(self.as_slice().iter());
-            let ptr = self.ptr as *mut c_void;
+            let ptr = self.ptr;
+            let cap = self.cap;
             forget(self);
-            MoveItems { allocation: ptr, iter: iter }
+            MoveItems { allocation: ptr, cap: cap, iter: iter }
         }
     }
 
@@ -1386,11 +1414,13 @@ impl<T> Drop for Vec<T> {
     fn drop(&mut self) {
         // This is (and should always remain) a no-op if the fields are
         // zeroed (when moving out, because of #[unsafe_no_drop_flag]).
-        unsafe {
-            for x in self.as_mut_slice().iter() {
-                ptr::read(x);
+        if self.cap != 0 {
+            unsafe {
+                for x in self.as_mut_slice().iter() {
+                    ptr::read(x);
+                }
+                dealloc(self.ptr, self.cap)
             }
-            free(self.ptr as *mut c_void)
         }
     }
 }
@@ -1409,7 +1439,8 @@ impl<T:fmt::Show> fmt::Show for Vec<T> {
 
 /// An iterator that moves out of a vector.
 pub struct MoveItems<T> {
-    allocation: *mut c_void, // the block of memory allocated for the vector
+    allocation: *mut T, // the block of memory allocated for the vector
+    cap: uint, // the capacity of the vector
     iter: Items<'static, T>
 }
 
@@ -1440,9 +1471,11 @@ impl<T> DoubleEndedIterator<T> for MoveItems<T> {
 impl<T> Drop for MoveItems<T> {
     fn drop(&mut self) {
         // destroy the remaining elements
-        for _x in *self {}
-        unsafe {
-            free(self.allocation)
+        if self.cap != 0 {
+            for _x in *self {}
+            unsafe {
+                dealloc(self.allocation, self.cap);
+            }
         }
     }
 }
@@ -1493,7 +1526,7 @@ impl<T> FromVec<T> for ~[T] {
         let vp = v.as_mut_ptr();
 
         unsafe {
-            let ret = malloc_raw(size) as *mut RawVec<()>;
+            let ret = allocate(size, 8) as *mut RawVec<()>;
 
             (*ret).fill = len * mem::nonzero_size_of::<T>();
             (*ret).alloc = len * mem::nonzero_size_of::<T>();