Skip to content

Commit d2b1900

Browse files
committed
Use reserve instead of unchecked math in push
`push` currently uses this line to reserve space in the vector: ``` self.grow(cmp::max(cap * 2, 1)) ``` This risks overflowing `usize`. In practice this won't lead to any bugs, because the capacity can't be larger than `isize::MAX` because of invariants upheld in liballoc, but this is not easy to see. Replacing this with `self.reserve(1)` is clearer, easier to reason about safety (because `reserve` uses checked arithmetic), and will make it easier to change the growth strategy in the future. (Currently `reserve(1)` will grow to the next power of 2.) This does not regress any of the `push` benchmarks. Marking `reserve` as inline is necessary to prevent `insert` benchmarks from regressing because of a change in the optimizer's inlining decisions there.
1 parent 62c525a commit d2b1900

File tree

1 file changed

+2
-1
lines changed

1 file changed

+2
-1
lines changed

lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ impl<A: Array> SmallVec<A> {
574574
unsafe {
575575
let (_, &mut len, cap) = self.triple_mut();
576576
if len == cap {
577-
self.grow(cmp::max(cap * 2, 1))
577+
self.reserve(1);
578578
}
579579
let (ptr, len_ptr, _) = self.triple_mut();
580580
*len_ptr = len + 1;
@@ -632,6 +632,7 @@ impl<A: Array> SmallVec<A> {
632632
/// If the new capacity would overflow `usize` then it will be set to `usize::max_value()`
633633
/// instead. (This means that inserting `additional` new elements is not guaranteed to be
634634
/// possible after calling this function.)
635+
#[inline]
635636
pub fn reserve(&mut self, additional: usize) {
636637
// prefer triple_mut() even if triple() would work
637638
// so that the optimizer removes duplicated calls to it

0 commit comments

Comments
 (0)