]> git.lizzy.rs Git - rust.git/blobdiff - src/liballoc/raw_vec.rs
Make Vec::new const
[rust.git] / src / liballoc / raw_vec.rs
index 405814c021afef423e4599e514c9e6d19683ba78..dc8ad9ee06169279fafa461a96769a32593f04c7 100644 (file)
@@ -14,7 +14,7 @@
 use core::ptr::{self, NonNull, Unique};
 use core::slice;
 
-use alloc::{Alloc, Layout, Global};
+use alloc::{Alloc, Layout, Global, oom};
 use alloc::CollectionAllocErr;
 use alloc::CollectionAllocErr::*;
 use boxed::Box;
@@ -68,6 +68,16 @@ pub fn new_in(a: A) -> Self {
         }
     }
 
+    /// Like `empty` but parametrized over the choice of allocator for the returned `RawVec`.
+    pub const fn empty_in(a: A) -> Self {
+        // Unique::empty() doubles as "unallocated" and "zero-sized allocation"
+        RawVec {
+            ptr: Unique::empty(),
+            cap: 0,
+            a,
+        }
+    }
+
     /// Like `with_capacity` but parameterized over the choice of
     /// allocator for the returned RawVec.
     #[inline]
@@ -86,8 +96,8 @@ fn allocate_in(cap: usize, zeroed: bool, mut a: A) -> Self {
         unsafe {
             let elem_size = mem::size_of::<T>();
 
-            let alloc_size = cap.checked_mul(elem_size).expect("capacity overflow");
-            alloc_guard(alloc_size).expect("capacity overflow");
+            let alloc_size = cap.checked_mul(elem_size).unwrap_or_else(|| capacity_overflow());
+            alloc_guard(alloc_size).unwrap_or_else(|_| capacity_overflow());
 
             // handles ZSTs and `cap = 0` alike
             let ptr = if alloc_size == 0 {
@@ -101,7 +111,7 @@ fn allocate_in(cap: usize, zeroed: bool, mut a: A) -> Self {
                 };
                 match result {
                     Ok(ptr) => ptr,
-                    Err(_) => a.oom(),
+                    Err(_) => oom(),
                 }
             };
 
@@ -124,6 +134,12 @@ pub fn new() -> Self {
         Self::new_in(Global)
     }
 
+    /// Create a `RawVec` with capcity 0 (on the system heap), regardless of `T`, without
+    /// allocating.
+    pub fn empty() -> Self {
+        Self::empty_in(Global)
+    }
+
     /// Creates a RawVec (on the system heap) with exactly the
     /// capacity and alignment requirements for a `[T; cap]`. This is
     /// equivalent to calling RawVec::new when `cap` is 0 or T is
@@ -310,13 +326,13 @@ pub fn double(&mut self) {
                     // `from_size_align_unchecked`.
                     let new_cap = 2 * self.cap;
                     let new_size = new_cap * elem_size;
-                    alloc_guard(new_size).expect("capacity overflow");
+                    alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
                     let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(),
                                                  cur,
                                                  new_size);
                     match ptr_res {
                         Ok(ptr) => (new_cap, ptr.cast().into()),
-                        Err(_) => self.a.oom(),
+                        Err(_) => oom(),
                     }
                 }
                 None => {
@@ -325,7 +341,7 @@ pub fn double(&mut self) {
                     let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
                     match self.a.alloc_array::<T>(new_cap) {
                         Ok(ptr) => (new_cap, ptr.into()),
-                        Err(_) => self.a.oom(),
+                        Err(_) => oom(),
                     }
                 }
             };
@@ -369,7 +385,7 @@ pub fn double_in_place(&mut self) -> bool {
             // overflow and the alignment is sufficiently small.
             let new_cap = 2 * self.cap;
             let new_size = new_cap * elem_size;
-            alloc_guard(new_size).expect("capacity overflow");
+            alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
             match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) {
                 Ok(_) => {
                     // We can't directly divide `size`.
@@ -441,8 +457,8 @@ pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize)
 
     pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
         match self.try_reserve_exact(used_cap, needed_extra_cap) {
-            Err(CapacityOverflow) => panic!("capacity overflow"),
-            Err(AllocErr) => self.a.oom(),
+            Err(CapacityOverflow) => capacity_overflow(),
+            Err(AllocErr) => oom(),
             Ok(()) => { /* yay */ }
          }
      }
@@ -551,8 +567,8 @@ pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize)
     /// The same as try_reserve, but errors are lowered to a call to oom().
     pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
         match self.try_reserve(used_cap, needed_extra_cap) {
-            Err(CapacityOverflow) => panic!("capacity overflow"),
-            Err(AllocErr) => self.a.oom(),
+            Err(CapacityOverflow) => capacity_overflow(),
+            Err(AllocErr) => oom(),
             Ok(()) => { /* yay */ }
          }
      }
@@ -592,7 +608,7 @@ pub fn reserve_in_place(&mut self, used_cap: usize, needed_extra_cap: usize) ->
             }
 
             let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)
-                              .expect("capacity overflow");
+                .unwrap_or_else(|_| capacity_overflow());
 
             // Here, `cap < used_cap + needed_extra_cap <= new_cap`
             // (regardless of whether `self.cap - used_cap` wrapped).
@@ -600,7 +616,7 @@ pub fn reserve_in_place(&mut self, used_cap: usize, needed_extra_cap: usize) ->
 
             let new_layout = Layout::new::<T>().repeat(new_cap).unwrap().0;
             // FIXME: may crash and burn on over-reserve
-            alloc_guard(new_layout.size()).expect("capacity overflow");
+            alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow());
             match self.a.grow_in_place(
                 NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(),
             ) {
@@ -667,7 +683,7 @@ pub fn shrink_to_fit(&mut self, amount: usize) {
                                      old_layout,
                                      new_size) {
                     Ok(p) => self.ptr = p.cast().into(),
-                    Err(_) => self.a.oom(),
+                    Err(_) => oom(),
                 }
             }
             self.cap = amount;
@@ -732,6 +748,13 @@ fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> {
     }
 }
 
+// One central function responsible for reporting capacity overflows. This'll
+// ensure that the code generation related to these panics is minimal as there's
+// only one location which panics rather than a bunch throughout the module.
+fn capacity_overflow() -> ! {
+    panic!("capacity overflow")
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;