Skip to content

Commit 5a987e9

Browse files
committed
feat(allocator): add Vec::push_fast method
1 parent c92422b commit 5a987e9

File tree

1 file changed

+60
-0
lines changed
  • crates/oxc_allocator/src/vec2

1 file changed

+60
-0
lines changed

crates/oxc_allocator/src/vec2/mod.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,6 +1459,8 @@ impl<'a, T: 'a, A: Alloc> Vec<'a, T, A> {
14591459

14601460
/// Appends an element to the back of a vector.
14611461
///
1462+
/// See also [`push_fast`].
1463+
///
14621464
/// # Panics
14631465
///
14641466
/// Panics if the number of elements in the vector overflows a `u32`.
@@ -1474,6 +1476,8 @@ impl<'a, T: 'a, A: Alloc> Vec<'a, T, A> {
14741476
/// vec.push(3);
14751477
/// assert_eq!(vec, [1, 2, 3]);
14761478
/// ```text
1479+
///
1480+
/// [`push_fast`]: Self::push_fast
14771481
#[inline]
14781482
pub fn push(&mut self, value: T) {
14791483
// This will panic or abort if we would allocate > isize::MAX bytes
@@ -1488,6 +1492,62 @@ impl<'a, T: 'a, A: Alloc> Vec<'a, T, A> {
14881492
}
14891493
}
14901494

1495+
/// Appends an element to the back of a vector, when it's likely that there's sufficient capacity.
1496+
///
1497+
/// This method is equivalent to [`push`] except that it is optimized for the case where there's
1498+
/// capacity for at least one more element, without needing to grow.
1499+
///
1500+
/// When you're dealing with a large `Vec` which grows infrequently, this method can be faster.
1501+
///
1502+
/// # Panics
1503+
///
1504+
/// Panics if the number of elements in the vector overflows a `u32`.
1505+
///
1506+
/// # Examples
1507+
///
1508+
/// ```text
1509+
/// use bumpalo::{Bump, collections::Vec};
1510+
///
1511+
/// let b = Bump::new();
1512+
///
1513+
/// let mut vec = Vec::from_iter_in([1, 2, 3], &b);
1514+
/// vec.pop();
1515+
/// vec.push_fast(4);
1516+
/// assert_eq!(vec, [1, 2, 4]);
1517+
/// ```text
1518+
///
1519+
/// [`push`]: Self::push
1520+
#[inline]
1521+
pub fn push_fast(&mut self, value: T) {
1522+
#[expect(clippy::if_not_else)]
1523+
if self.len_u32() != self.capacity_u32() {
1524+
// Capacity for at least 1 more element. Write it.
1525+
unsafe {
1526+
let end = self.buf.ptr().add(self.len_usize());
1527+
ptr::write(end, value);
1528+
self.buf.increase_len(1);
1529+
}
1530+
} else {
1531+
// At capacity. Grow.
1532+
// This branch is rarely taken, so marked as `#[cold]` and `#[inline(never)]`.
1533+
#[cold]
1534+
#[inline(never)]
1535+
fn push_slow<T, A: Alloc>(v: &mut Vec<'_, T, A>, value: T) {
1536+
// This will panic or abort if we would allocate > `isize::MAX` bytes
1537+
// or if the length increment would overflow for zero-sized types.
1538+
v.buf.grow_one();
1539+
1540+
unsafe {
1541+
let end = v.buf.ptr().add(v.len_usize());
1542+
ptr::write(end, value);
1543+
v.buf.increase_len(1);
1544+
}
1545+
}
1546+
1547+
push_slow(self, value);
1548+
}
1549+
}
1550+
14911551
/// Removes the last element from a vector and returns it, or [`None`] if it
14921552
/// is empty.
14931553
///

0 commit comments

Comments
 (0)