Skip to content

Commit f420726

Browse files
committed
Remove RawVec::double.
It's only used once, for `VecDeque`, and can easily be replaced by something else. The commit changes `grow_if_necessary` to `grow` to avoid some small regressions caused by changed inlining. The commit also removes `Strategy::Double`, and streamlines the remaining variants of `Strategy`. It's a compile time win on some benchmarks because the many instantations of `RawVec::grow` are a little smaller.
1 parent a3cc435 commit f420726

File tree

2 files changed

+23
-88
lines changed

2 files changed

+23
-88
lines changed

src/liballoc/collections/vec_deque.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -1354,7 +1354,9 @@ impl<T> VecDeque<T> {
13541354
/// ```
13551355
#[stable(feature = "rust1", since = "1.0.0")]
13561356
pub fn push_front(&mut self, value: T) {
1357-
self.grow_if_necessary();
1357+
if self.is_full() {
1358+
self.grow();
1359+
}
13581360

13591361
self.tail = self.wrap_sub(self.tail, 1);
13601362
let tail = self.tail;
@@ -1377,7 +1379,9 @@ impl<T> VecDeque<T> {
13771379
/// ```
13781380
#[stable(feature = "rust1", since = "1.0.0")]
13791381
pub fn push_back(&mut self, value: T) {
1380-
self.grow_if_necessary();
1382+
if self.is_full() {
1383+
self.grow();
1384+
}
13811385

13821386
let head = self.head;
13831387
self.head = self.wrap_add(self.head, 1);
@@ -1485,7 +1489,9 @@ impl<T> VecDeque<T> {
14851489
#[stable(feature = "deque_extras_15", since = "1.5.0")]
14861490
pub fn insert(&mut self, index: usize, value: T) {
14871491
assert!(index <= self.len(), "index out of bounds");
1488-
self.grow_if_necessary();
1492+
if self.is_full() {
1493+
self.grow();
1494+
}
14891495

14901496
// Move the least number of elements in the ring buffer and insert
14911497
// the given object
@@ -2003,11 +2009,13 @@ impl<T> VecDeque<T> {
20032009
}
20042010

20052011
// This may panic or abort
2006-
#[inline]
2007-
fn grow_if_necessary(&mut self) {
2012+
#[inline(never)]
2013+
fn grow(&mut self) {
20082014
if self.is_full() {
20092015
let old_cap = self.cap();
2010-
self.buf.double();
2016+
// Double the buffer size.
2017+
self.buf.reserve_exact(old_cap, old_cap);
2018+
assert!(self.cap() == old_cap * 2);
20112019
unsafe {
20122020
self.handle_capacity_increase(old_cap);
20132021
}

src/liballoc/raw_vec.rs

+9-82
Original file line numberDiff line numberDiff line change
@@ -211,64 +211,6 @@ impl<T, A: AllocRef> RawVec<T, A> {
211211
}
212212
}
213213

214-
/// Doubles the size of the type's backing allocation. This is common enough
215-
/// to want to do that it's easiest to just have a dedicated method. Slightly
216-
/// more efficient logic can be provided for this than the general case.
217-
///
218-
/// This function is ideal for when pushing elements one-at-a-time because
219-
/// you don't need to incur the costs of the more general computations
220-
/// reserve needs to do to guard against overflow. You do however need to
221-
/// manually check if your `len == capacity`.
222-
///
223-
/// # Panics
224-
///
225-
/// * Panics if `T` is zero-sized on the assumption that you managed to exhaust
226-
/// all `usize::MAX` slots in your imaginary buffer.
227-
/// * Panics on 32-bit platforms if the requested capacity exceeds
228-
/// `isize::MAX` bytes.
229-
///
230-
/// # Aborts
231-
///
232-
/// Aborts on OOM
233-
///
234-
/// # Examples
235-
///
236-
/// ```
237-
/// # #![feature(raw_vec_internals)]
238-
/// # extern crate alloc;
239-
/// # use std::ptr;
240-
/// # use alloc::raw_vec::RawVec;
241-
/// struct MyVec<T> {
242-
/// buf: RawVec<T>,
243-
/// len: usize,
244-
/// }
245-
///
246-
/// impl<T> MyVec<T> {
247-
/// pub fn push(&mut self, elem: T) {
248-
/// if self.len == self.buf.capacity() { self.buf.double(); }
249-
/// // double would have aborted or panicked if the len exceeded
250-
/// // `isize::MAX` so this is safe to do unchecked now.
251-
/// unsafe {
252-
/// ptr::write(self.buf.ptr().add(self.len), elem);
253-
/// }
254-
/// self.len += 1;
255-
/// }
256-
/// }
257-
/// # fn main() {
258-
/// # let mut vec = MyVec { buf: RawVec::new(), len: 0 };
259-
/// # vec.push(1);
260-
/// # }
261-
/// ```
262-
#[inline(never)]
263-
#[cold]
264-
pub fn double(&mut self) {
265-
match self.grow(Double, MayMove, Uninitialized) {
266-
Err(CapacityOverflow) => capacity_overflow(),
267-
Err(AllocError { layout, .. }) => handle_alloc_error(layout),
268-
Ok(()) => { /* yay */ }
269-
}
270-
}
271-
272214
/// Ensures that the buffer contains at least enough space to hold
273215
/// `used_capacity + needed_extra_capacity` elements. If it doesn't already have
274216
/// enough capacity, will reallocate enough space plus comfortable slack
@@ -336,7 +278,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
336278
needed_extra_capacity: usize,
337279
) -> Result<(), TryReserveError> {
338280
if self.needs_to_grow(used_capacity, needed_extra_capacity) {
339-
self.grow(Amortized { used_capacity, needed_extra_capacity }, MayMove, Uninitialized)
281+
self.grow(Amortized, used_capacity, needed_extra_capacity, MayMove, Uninitialized)
340282
} else {
341283
Ok(())
342284
}
@@ -363,7 +305,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
363305
// This is more readable than putting this in one line:
364306
// `!self.needs_to_grow(...) || self.grow(...).is_ok()`
365307
if self.needs_to_grow(used_capacity, needed_extra_capacity) {
366-
self.grow(Amortized { used_capacity, needed_extra_capacity }, InPlace, Uninitialized)
308+
self.grow(Amortized, used_capacity, needed_extra_capacity, InPlace, Uninitialized)
367309
.is_ok()
368310
} else {
369311
true
@@ -405,7 +347,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
405347
needed_extra_capacity: usize,
406348
) -> Result<(), TryReserveError> {
407349
if self.needs_to_grow(used_capacity, needed_extra_capacity) {
408-
self.grow(Exact { used_capacity, needed_extra_capacity }, MayMove, Uninitialized)
350+
self.grow(Exact, used_capacity, needed_extra_capacity, MayMove, Uninitialized)
409351
} else {
410352
Ok(())
411353
}
@@ -432,9 +374,8 @@ impl<T, A: AllocRef> RawVec<T, A> {
432374

433375
#[derive(Copy, Clone)]
434376
enum Strategy {
435-
Double,
436-
Amortized { used_capacity: usize, needed_extra_capacity: usize },
437-
Exact { used_capacity: usize, needed_extra_capacity: usize },
377+
Amortized,
378+
Exact,
438379
}
439380
use Strategy::*;
440381

@@ -459,6 +400,8 @@ impl<T, A: AllocRef> RawVec<T, A> {
459400
fn grow(
460401
&mut self,
461402
strategy: Strategy,
403+
used_capacity: usize,
404+
needed_extra_capacity: usize,
462405
placement: ReallocPlacement,
463406
init: AllocInit,
464407
) -> Result<(), TryReserveError> {
@@ -469,23 +412,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
469412
return Err(CapacityOverflow);
470413
}
471414
let new_layout = match strategy {
472-
Double => unsafe {
473-
// Since we guarantee that we never allocate more than `isize::MAX` bytes,
474-
// `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow.
475-
// Additionally the alignment will never be too large as to "not be satisfiable",
476-
// so `Layout::from_size_align` will always return `Some`.
477-
//
478-
// TL;DR, we bypass runtime checks due to dynamic assertions in this module,
479-
// allowing us to use `from_size_align_unchecked`.
480-
let cap = if self.cap == 0 {
481-
// Skip to 4 because tiny `Vec`'s are dumb; but not if that would cause overflow.
482-
if elem_size > usize::MAX / 8 { 1 } else { 4 }
483-
} else {
484-
self.cap * 2
485-
};
486-
Layout::from_size_align_unchecked(cap * elem_size, mem::align_of::<T>())
487-
},
488-
Amortized { used_capacity, needed_extra_capacity } => {
415+
Amortized => {
489416
// Nothing we can really do about these checks, sadly.
490417
let required_cap =
491418
used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
@@ -495,7 +422,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
495422
let cap = cmp::max(double_cap, required_cap);
496423
Layout::array::<T>(cap).map_err(|_| CapacityOverflow)?
497424
}
498-
Exact { used_capacity, needed_extra_capacity } => {
425+
Exact => {
499426
let cap =
500427
used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
501428
Layout::array::<T>(cap).map_err(|_| CapacityOverflow)?

0 commit comments

Comments
 (0)