return Err(CapacityOverflow);
}
+ if needed_extra_capacity == 0 {
+ return Ok(());
+ }
+
// Nothing we can really do about these checks, sadly.
let required_cap =
used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
- // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
- let double_cap = self.cap * 2;
- // `double_cap` guarantees exponential growth.
- let cap = cmp::max(double_cap, required_cap);
+
+ // This guarantees exponential growth. The doubling cannot overflow
+ // because `cap <= isize::MAX` and the type of `cap` is `usize`.
+ let cap = cmp::max(self.cap * 2, required_cap);
+
+ // Tiny Vecs are dumb. Skip to:
+ // - 8 if the element size is 1, because any heap allocators is likely
+ // to round up a request of less than 8 bytes to at least 8 bytes.
+ // - 4 if elements are moderate-sized (<= 1 KiB).
+ // - 1 otherwise, to avoid wasting too much space for very short Vecs.
+ // Note that `min_non_zero_cap` is computed statically.
+ let elem_size = mem::size_of::<T>();
+ let min_non_zero_cap = if elem_size == 1 {
+ 8
+ } else if elem_size <= 1024 {
+ 4
+ } else {
+ 1
+ };
+ let cap = cmp::max(min_non_zero_cap, cap);
+
let new_layout = Layout::array::<T>(cap);
// `finish_grow` is non-generic over `T`.
vtable: *mut (),
}
}
+
+// This test will likely fail if you change the capacities used in
+// `RawVec::grow_amortized`.
+#[test]
+fn test_push_growth_strategy() {
+ // If the element size is 1, we jump from 0 to 8, then double.
+ {
+ let mut v1: Vec<u8> = vec![];
+ assert_eq!(v1.capacity(), 0);
+
+ for _ in 0..8 {
+ v1.push(0);
+ assert_eq!(v1.capacity(), 8);
+ }
+
+ for _ in 8..16 {
+ v1.push(0);
+ assert_eq!(v1.capacity(), 16);
+ }
+
+ for _ in 16..32 {
+ v1.push(0);
+ assert_eq!(v1.capacity(), 32);
+ }
+
+ for _ in 32..64 {
+ v1.push(0);
+ assert_eq!(v1.capacity(), 64);
+ }
+ }
+
+ // If the element size is 2..=1024, we jump from 0 to 4, then double.
+ {
+ let mut v2: Vec<u16> = vec![];
+ let mut v1024: Vec<[u8; 1024]> = vec![];
+ assert_eq!(v2.capacity(), 0);
+ assert_eq!(v1024.capacity(), 0);
+
+ for _ in 0..4 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 4);
+ assert_eq!(v1024.capacity(), 4);
+ }
+
+ for _ in 4..8 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 8);
+ assert_eq!(v1024.capacity(), 8);
+ }
+
+ for _ in 8..16 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 16);
+ assert_eq!(v1024.capacity(), 16);
+ }
+
+ for _ in 16..32 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 32);
+ assert_eq!(v1024.capacity(), 32);
+ }
+
+ for _ in 32..64 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 64);
+ assert_eq!(v1024.capacity(), 64);
+ }
+ }
+
+ // If the element size is > 1024, we jump from 0 to 1, then double.
+ {
+ let mut v1025: Vec<[u8; 1025]> = vec![];
+ assert_eq!(v1025.capacity(), 0);
+
+ for _ in 0..1 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 1);
+ }
+
+ for _ in 1..2 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 2);
+ }
+
+ for _ in 2..4 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 4);
+ }
+
+ for _ in 4..8 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 8);
+ }
+
+ for _ in 8..16 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 16);
+ }
+
+ for _ in 16..32 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 32);
+ }
+
+ for _ in 32..64 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 64);
+ }
+ }
+}