Skip to content

Commit 8c94587

Browse files
balt-devtraviscross
balt-dev
authored andcommitted
Implement push_mut
1 parent 852f15c commit 8c94587

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2503,6 +2503,104 @@ impl<T, A: Allocator> Vec<T, A> {
25032503
Ok(())
25042504
}
25052505

2506+
/// Appends an element to the back of a collection, returning a reference to it.
2507+
///
2508+
/// # Panics
2509+
///
2510+
/// Panics if the new capacity exceeds `isize::MAX` _bytes_.
2511+
///
2512+
/// # Examples
2513+
///
2514+
/// ```
2515+
/// #![feature(push_mut)]
2516+
///
2517+
/// # #[allow(unused)]
2518+
/// #[derive(PartialEq, Eq, Debug)]
2519+
/// struct Item { identifier: &'static str, count: usize }
2520+
///
2521+
/// impl Default for Item {
2522+
/// fn default() -> Self {
2523+
/// return Self { identifier: "stone", count: 64 }
2524+
/// }
2525+
/// }
2526+
///
2527+
/// let mut items = vec![];
2528+
///
2529+
/// // We can mutate the just-pushed value without having to fetch it again
2530+
/// for count in [15, 35, 61] {
2531+
/// let item = items.push_mut(Item::default());
2532+
/// item.count = count;
2533+
/// }
2534+
///
2535+
/// assert_eq!(
2536+
/// items,
2537+
/// [Item { identifier: "stone", count: 15 }, Item { identifier: "stone", count: 35 }, Item { identifier: "stone", count: 61 }]
2538+
/// );
2539+
/// ```
2540+
///
2541+
/// # Time complexity
2542+
///
2543+
/// Takes amortized *O*(1) time. If the vector's length would exceed its
2544+
/// capacity after the push, *O*(*capacity*) time is taken to copy the
2545+
/// vector's elements to a larger allocation. This expensive operation is
2546+
/// offset by the *capacity* *O*(1) insertions it allows.
2547+
#[cfg(not(no_global_oom_handling))]
2548+
#[inline]
2549+
#[unstable(feature = "push_mut", issue = "135974")]
2550+
#[track_caller]
2551+
#[must_use = "if you don't need a reference to the value, use Vec::push instead"]
2552+
pub fn push_mut(&mut self, value: T) -> &mut T {
2553+
// Inform codegen that the length does not change across grow_one().
2554+
let len = self.len;
2555+
// This will panic or abort if we would allocate > isize::MAX bytes
2556+
// or if the length increment would overflow for zero-sized types.
2557+
if len == self.buf.capacity() {
2558+
self.buf.grow_one();
2559+
}
2560+
unsafe {
2561+
let end = self.as_mut_ptr().add(len);
2562+
ptr::write(end, value);
2563+
self.len = len + 1;
2564+
// SAFETY: We just wrote a value to the pointer that will live the lifetime of the reference.
2565+
&mut *end
2566+
}
2567+
}
2568+
2569+
/// Appends an element and returns a reference to it if there is sufficient spare capacity, otherwise an error is returned
2570+
/// with the element.
2571+
///
2572+
/// Unlike [`push_mut`] this method will not reallocate when there's insufficient capacity.
2573+
/// The caller should use [`reserve`] or [`try_reserve`] to ensure that there is enough capacity.
2574+
///
2575+
/// [`push_mut`]: Vec::push_mut
2576+
/// [`reserve`]: Vec::reserve
2577+
/// [`try_reserve`]: Vec::try_reserve
2578+
///
2579+
/// # Time complexity
2580+
///
2581+
/// Takes *O*(1) time.
2582+
//
2583+
// Since there's currently no way to have multiple unstable attributes on the same item, I compromised.
2584+
// Uncomment/delete the respective attribute when its respective issue stabilizes, since this falls under both.
2585+
//
2586+
#[unstable(feature = "push_mut", issue = "135974")]
2587+
// #[unstable(feature = "vec_push_within_capacity", issue = "100486")]
2588+
//
2589+
#[inline]
2590+
#[must_use = "if you don't need a reference to the value, use Vec::push_within_capacity instead"]
2591+
pub fn push_mut_within_capacity(&mut self, value: T) -> Result<&mut T, T> {
2592+
if self.len == self.buf.capacity() {
2593+
return Err(value);
2594+
}
2595+
unsafe {
2596+
let end = self.as_mut_ptr().add(self.len);
2597+
ptr::write(end, value);
2598+
self.len += 1;
2599+
// SAFETY: We just wrote a value to the pointer that will live the lifetime of the reference.
2600+
Ok(&mut *end)
2601+
}
2602+
}
2603+
25062604
/// Removes the last element from a vector and returns it, or [`None`] if it
25072605
/// is empty.
25082606
///

0 commit comments

Comments
 (0)