Skip to content

Implement push_mut #135975

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions library/alloc/src/collections/linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -844,11 +844,34 @@ impl<T, A: Allocator> LinkedList<T, A> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn push_front(&mut self, elt: T) {
let _ = self.push_front_mut(elt);
}

/// Adds an element first in the list, returning a reference to it.
///
/// This operation should compute in *O*(1) time.
///
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::LinkedList;
///
/// let mut dl = LinkedList::from([1, 2, 3]);
///
/// let ptr = dl.push_front_mut(2);
/// *ptr += 4;
/// assert_eq!(dl.front().unwrap(), &6);
/// ```
#[unstable(feature = "push_mut", issue = "135974")]
#[must_use = "if you don't need a reference to the value, use LinkedList::push_front instead"]
pub fn push_front_mut(&mut self, elt: T) -> &mut T {
let node = Box::new_in(Node::new(elt), &self.alloc);
let node_ptr = NonNull::from(Box::leak(node));
let mut node_ptr = NonNull::from(Box::leak(node));
// SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked
unsafe {
self.push_front_node(node_ptr);
&mut node_ptr.as_mut().element
}
}

Expand Down Expand Up @@ -893,11 +916,34 @@ impl<T, A: Allocator> LinkedList<T, A> {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_confusables("push", "append")]
pub fn push_back(&mut self, elt: T) {
let _ = self.push_back_mut(elt);
}

/// Adds an element to the back of a list, returning a reference to it.
///
/// This operation should compute in *O*(1) time.
///
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::LinkedList;
///
/// let mut dl = LinkedList::from([1, 2, 3]);
///
/// let ptr = dl.push_back_mut(2);
/// *ptr += 4;
/// assert_eq!(dl.back().unwrap(), &6);
/// ```
#[unstable(feature = "push_mut", issue = "135974")]
#[must_use = "if you don't need a reference to the value, use LinkedList::push_back instead"]
pub fn push_back_mut(&mut self, elt: T) -> &mut T {
let node = Box::new_in(Node::new(elt), &self.alloc);
let node_ptr = NonNull::from(Box::leak(node));
let mut node_ptr = NonNull::from(Box::leak(node));
// SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked
unsafe {
self.push_back_node(node_ptr);
&mut node_ptr.as_mut().element
}
}

Expand Down
100 changes: 89 additions & 11 deletions library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,16 @@ impl<T, A: Allocator> VecDeque<T, A> {
unsafe { ptr::read(self.ptr().add(off)) }
}

/// Writes an element into the buffer, moving it.
/// Writes an element into the buffer, moving it and returning a pointer to it.
/// # Safety
///
/// May only be called if `off < self.capacity()`.
#[inline]
unsafe fn buffer_write(&mut self, off: usize, value: T) {
unsafe fn buffer_write(&mut self, off: usize, value: T) -> &mut T {
unsafe {
ptr::write(self.ptr().add(off), value);
let ptr = self.ptr().add(off);
ptr::write(ptr, value);
&mut *ptr
}
}

Expand Down Expand Up @@ -1888,16 +1893,34 @@ impl<T, A: Allocator> VecDeque<T, A> {
#[stable(feature = "rust1", since = "1.0.0")]
#[track_caller]
pub fn push_front(&mut self, value: T) {
let _ = self.push_front_mut(value);
}

/// Prepends an element to the deque, returning a reference to it.
///
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::VecDeque;
///
/// let mut d = VecDeque::from([1, 2, 3]);
/// let x = d.push_front_mut(8);
/// *x -= 1;
/// assert_eq!(d.front(), Some(&7));
/// ```
#[unstable(feature = "push_mut", issue = "135974")]
#[track_caller]
#[must_use = "if you don't need a reference to the value, use VecDeque::push_front instead"]
pub fn push_front_mut(&mut self, value: T) -> &mut T {
if self.is_full() {
self.grow();
}

self.head = self.wrap_sub(self.head, 1);
self.len += 1;

unsafe {
self.buffer_write(self.head, value);
}
// SAFETY: We know that self.head is within range of the deque.
unsafe { self.buffer_write(self.head, value) }
}

/// Appends an element to the back of the deque.
Expand All @@ -1916,12 +1939,33 @@ impl<T, A: Allocator> VecDeque<T, A> {
#[rustc_confusables("push", "put", "append")]
#[track_caller]
pub fn push_back(&mut self, value: T) {
let _ = self.push_back_mut(value);
}

/// Appends an element to the back of the deque, returning a reference to it.
///
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::VecDeque;
///
/// let mut d = VecDeque::from([1, 2, 3]);
/// let x = d.push_back_mut(9);
/// *x += 1;
/// assert_eq!(d.back(), Some(&10));
/// ```
#[unstable(feature = "push_mut", issue = "135974")]
#[track_caller]
#[must_use = "if you don't need a reference to the value, use VecDeque::push_back instead"]
pub fn push_back_mut(&mut self, value: T) -> &mut T {
if self.is_full() {
self.grow();
}

unsafe { self.buffer_write(self.to_physical_idx(self.len), value) }
let len = self.len;
self.len += 1;
unsafe { self.buffer_write(self.to_physical_idx(len), value) }
}

#[inline]
Expand Down Expand Up @@ -2029,7 +2073,39 @@ impl<T, A: Allocator> VecDeque<T, A> {
#[stable(feature = "deque_extras_15", since = "1.5.0")]
#[track_caller]
pub fn insert(&mut self, index: usize, value: T) {
assert!(index <= self.len(), "index out of bounds");
assert!(self.insert_mut(index, value).is_some(), "index out of bounds");
}

/// Inserts an element at `index` within the deque, shifting all elements
/// with indices greater than or equal to `index` towards the back,
/// and returning a reference to it.
///
/// Element at index 0 is the front of the queue.
///
/// Returns [`None`] if `index` is strictly greater than deque's length.
///
/// # Examples
///
/// ```
/// #![feature(push_mut)]
/// use std::collections::VecDeque;
///
/// let mut vec_deque = VecDeque::from([1, 2, 3]);
///
/// let x = vec_deque.insert_mut(1, 5).unwrap();
/// *x += 7;
/// assert_eq!(vec_deque, &[1, 12, 2, 3]);
///
/// let y = vec_deque.insert_mut(7, 5);
/// assert!(y.is_none());
/// ```
#[unstable(feature = "push_mut", issue = "135974")]
#[track_caller]
#[must_use = "if you don't need a reference to the value or type-safe bound checking, use VecDeque::insert instead"]
pub fn insert_mut(&mut self, index: usize, value: T) -> Option<&mut T> {
if index > self.len() {
return None;
}
if self.is_full() {
self.grow();
}
Expand All @@ -2042,16 +2118,18 @@ impl<T, A: Allocator> VecDeque<T, A> {
unsafe {
// see `remove()` for explanation why this wrap_copy() call is safe.
self.wrap_copy(self.to_physical_idx(index), self.to_physical_idx(index + 1), k);
self.buffer_write(self.to_physical_idx(index), value);
self.len += 1;
let ptr = self.buffer_write(self.to_physical_idx(index), value);
Some(ptr)
}
} else {
let old_head = self.head;
self.head = self.wrap_sub(self.head, 1);
unsafe {
self.wrap_copy(old_head, self.head, index);
self.buffer_write(self.to_physical_idx(index), value);
self.len += 1;
let ptr = self.buffer_write(self.to_physical_idx(index), value);
Some(ptr)
}
}
}
Expand Down
Loading
Loading