Skip to content

Commit

Permalink
Auto merge of #89123 - the8472:push_in_capacity, r=amanieu
Browse files Browse the repository at this point in the history
add Vec::push_within_capacity - fallible, does not allocate

This method can serve several purposes. It

* is fallible
* guarantees that items in Vec aren't moved
* allows loops that do `reserve` and `push` separately to avoid pulling in the allocation machinery a second time in the `push` part which should make things easier on the optimizer
* eases the path towards `ArrayVec` a bit since - compared to `push()` - there are fewer questions around how it should be implemented

I haven't named it `try_push` because that should probably occupy a middle ground that will still try to reserve and only return an error in the unlikely OOM case.

resolves #84649
  • Loading branch information
bors committed Oct 9, 2022
2 parents e07250d + c110dab commit e6280cd
Showing 1 changed file with 45 additions and 0 deletions.
45 changes: 45 additions & 0 deletions alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,51 @@ impl<T, A: Allocator> Vec<T, A> {
}
}

/// Appends an element if there is sufficient spare capacity, otherwise an error is returned
/// with the element.
///
/// Unlike [`push`] this method will not reallocate when there's insufficient capacity.
/// The caller should use [`reserve`] or [`try_reserve`] to ensure that there is enough capacity.
///
/// [`push`]: Vec::push
/// [`reserve`]: Vec::reserve
/// [`try_reserve`]: Vec::try_reserve
///
/// # Examples
///
/// A manual, panic-free alternative to [`FromIterator`]:
///
/// ```
/// #![feature(vec_push_within_capacity)]
///
/// use std::collections::TryReserveError;
/// fn from_iter_fallible<T>(iter: impl Iterator<Item=T>) -> Result<Vec<T>, TryReserveError> {
/// let mut vec = Vec::new();
/// for value in iter {
/// if let Err(value) = vec.push_within_capacity(value) {
/// vec.try_reserve(1)?;
/// // this cannot fail, the previous line either returned or added at least 1 free slot
/// let _ = vec.push_within_capacity(value);
/// }
/// }
/// Ok(vec)
/// }
/// assert_eq!(from_iter_fallible(0..100), Ok(Vec::from_iter(0..100)));
/// ```
#[inline]
#[unstable(feature = "vec_push_within_capacity", issue = "100486")]
pub fn push_within_capacity(&mut self, value: T) -> Result<(), T> {
if self.len == self.buf.capacity() {
return Err(value);
}
unsafe {
let end = self.as_mut_ptr().add(self.len);
ptr::write(end, value);
self.len += 1;
}
Ok(())
}

/// Removes the last element from a vector and returns it, or [`None`] if it
/// is empty.
///
Expand Down

0 comments on commit e6280cd

Please sign in to comment.