Auto merge of #103093 - rytheo:linked-list-alloc-api, r=Mark-Simulacrum

Add support for allocators in `LinkedList`

Allows `LinkedList` to use a custom allocator
This commit is contained in:
bors 2023-04-25 11:34:58 +00:00
commit 20d90b14ff
2 changed files with 260 additions and 171 deletions

View File

@ -18,9 +18,10 @@
use core::iter::FusedIterator; use core::iter::FusedIterator;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem; use core::mem;
use core::ptr::NonNull; use core::ptr::{NonNull, Unique};
use super::SpecExtend; use super::SpecExtend;
use crate::alloc::{Allocator, Global};
use crate::boxed::Box; use crate::boxed::Box;
#[cfg(test)] #[cfg(test)]
@ -47,11 +48,15 @@
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")]
#[rustc_insignificant_dtor] #[rustc_insignificant_dtor]
pub struct LinkedList<T> { pub struct LinkedList<
T,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
head: Option<NonNull<Node<T>>>, head: Option<NonNull<Node<T>>>,
tail: Option<NonNull<Node<T>>>, tail: Option<NonNull<Node<T>>>,
len: usize, len: usize,
marker: PhantomData<Box<Node<T>>>, alloc: A,
marker: PhantomData<Box<Node<T>, A>>,
} }
struct Node<T> { struct Node<T> {
@ -81,6 +86,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
head: self.head, head: self.head,
tail: self.tail, tail: self.tail,
len: self.len, len: self.len,
alloc: Global,
marker: PhantomData, marker: PhantomData,
})) }))
.field(&self.len) .field(&self.len)
@ -117,6 +123,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
head: self.head, head: self.head,
tail: self.tail, tail: self.tail,
len: self.len, len: self.len,
alloc: Global,
marker: PhantomData, marker: PhantomData,
})) }))
.field(&self.len) .field(&self.len)
@ -132,12 +139,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// [`into_iter`]: LinkedList::into_iter /// [`into_iter`]: LinkedList::into_iter
#[derive(Clone)] #[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> { pub struct IntoIter<
list: LinkedList<T>, T,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
list: LinkedList<T, A>,
} }
#[stable(feature = "collection_debug", since = "1.17.0")] #[stable(feature = "collection_debug", since = "1.17.0")]
impl<T: fmt::Debug> fmt::Debug for IntoIter<T> { impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoIter").field(&self.list).finish() f.debug_tuple("IntoIter").field(&self.list).finish()
} }
@ -148,22 +158,25 @@ fn new(element: T) -> Self {
Node { next: None, prev: None, element } Node { next: None, prev: None, element }
} }
fn into_element(self: Box<Self>) -> T { fn into_element<A: Allocator>(self: Box<Self, A>) -> T {
self.element self.element
} }
} }
// private methods // private methods
impl<T> LinkedList<T> { impl<T, A: Allocator> LinkedList<T, A> {
/// Adds the given node to the front of the list. /// Adds the given node to the front of the list.
///
/// # Safety
/// `node` must point to a valid node that was boxed using the list's allocator.
#[inline] #[inline]
fn push_front_node(&mut self, mut node: Box<Node<T>>) { unsafe fn push_front_node(&mut self, node: Unique<Node<T>>) {
// This method takes care not to create mutable references to whole nodes, // This method takes care not to create mutable references to whole nodes,
// to maintain validity of aliasing pointers into `element`. // to maintain validity of aliasing pointers into `element`.
unsafe { unsafe {
node.next = self.head; (*node.as_ptr()).next = self.head;
node.prev = None; (*node.as_ptr()).prev = None;
let node = Some(Box::leak(node).into()); let node = Some(NonNull::from(node));
match self.head { match self.head {
None => self.tail = node, None => self.tail = node,
@ -178,11 +191,11 @@ fn push_front_node(&mut self, mut node: Box<Node<T>>) {
/// Removes and returns the node at the front of the list. /// Removes and returns the node at the front of the list.
#[inline] #[inline]
fn pop_front_node(&mut self) -> Option<Box<Node<T>>> { fn pop_front_node(&mut self) -> Option<Box<Node<T>, &A>> {
// This method takes care not to create mutable references to whole nodes, // This method takes care not to create mutable references to whole nodes,
// to maintain validity of aliasing pointers into `element`. // to maintain validity of aliasing pointers into `element`.
self.head.map(|node| unsafe { self.head.map(|node| unsafe {
let node = Box::from_raw(node.as_ptr()); let node = Box::from_raw_in(node.as_ptr(), &self.alloc);
self.head = node.next; self.head = node.next;
match self.head { match self.head {
@ -197,14 +210,17 @@ fn pop_front_node(&mut self) -> Option<Box<Node<T>>> {
} }
/// Adds the given node to the back of the list. /// Adds the given node to the back of the list.
///
/// # Safety
/// `node` must point to a valid node that was boxed using the list's allocator.
#[inline] #[inline]
fn push_back_node(&mut self, mut node: Box<Node<T>>) { unsafe fn push_back_node(&mut self, node: Unique<Node<T>>) {
// This method takes care not to create mutable references to whole nodes, // This method takes care not to create mutable references to whole nodes,
// to maintain validity of aliasing pointers into `element`. // to maintain validity of aliasing pointers into `element`.
unsafe { unsafe {
node.next = None; (*node.as_ptr()).next = None;
node.prev = self.tail; (*node.as_ptr()).prev = self.tail;
let node = Some(Box::leak(node).into()); let node = Some(NonNull::from(node));
match self.tail { match self.tail {
None => self.head = node, None => self.head = node,
@ -219,11 +235,11 @@ fn push_back_node(&mut self, mut node: Box<Node<T>>) {
/// Removes and returns the node at the back of the list. /// Removes and returns the node at the back of the list.
#[inline] #[inline]
fn pop_back_node(&mut self) -> Option<Box<Node<T>>> { fn pop_back_node(&mut self) -> Option<Box<Node<T>, &A>> {
// This method takes care not to create mutable references to whole nodes, // This method takes care not to create mutable references to whole nodes,
// to maintain validity of aliasing pointers into `element`. // to maintain validity of aliasing pointers into `element`.
self.tail.map(|node| unsafe { self.tail.map(|node| unsafe {
let node = Box::from_raw(node.as_ptr()); let node = Box::from_raw_in(node.as_ptr(), &self.alloc);
self.tail = node.prev; self.tail = node.prev;
match self.tail { match self.tail {
@ -321,7 +337,10 @@ unsafe fn split_off_before_node(
&mut self, &mut self,
split_node: Option<NonNull<Node<T>>>, split_node: Option<NonNull<Node<T>>>,
at: usize, at: usize,
) -> Self { ) -> Self
where
A: Clone,
{
// The split node is the new head node of the second part // The split node is the new head node of the second part
if let Some(mut split_node) = split_node { if let Some(mut split_node) = split_node {
let first_part_head; let first_part_head;
@ -342,6 +361,7 @@ unsafe fn split_off_before_node(
head: first_part_head, head: first_part_head,
tail: first_part_tail, tail: first_part_tail,
len: at, len: at,
alloc: self.alloc.clone(),
marker: PhantomData, marker: PhantomData,
}; };
@ -351,7 +371,7 @@ unsafe fn split_off_before_node(
first_part first_part
} else { } else {
mem::replace(self, LinkedList::new()) mem::replace(self, LinkedList::new_in(self.alloc.clone()))
} }
} }
@ -360,7 +380,10 @@ unsafe fn split_off_after_node(
&mut self, &mut self,
split_node: Option<NonNull<Node<T>>>, split_node: Option<NonNull<Node<T>>>,
at: usize, at: usize,
) -> Self { ) -> Self
where
A: Clone,
{
// The split node is the new tail node of the first part and owns // The split node is the new tail node of the first part and owns
// the head of the second part. // the head of the second part.
if let Some(mut split_node) = split_node { if let Some(mut split_node) = split_node {
@ -382,6 +405,7 @@ unsafe fn split_off_after_node(
head: second_part_head, head: second_part_head,
tail: second_part_tail, tail: second_part_tail,
len: self.len - at, len: self.len - at,
alloc: self.alloc.clone(),
marker: PhantomData, marker: PhantomData,
}; };
@ -391,7 +415,7 @@ unsafe fn split_off_after_node(
second_part second_part
} else { } else {
mem::replace(self, LinkedList::new()) mem::replace(self, LinkedList::new_in(self.alloc.clone()))
} }
} }
} }
@ -420,7 +444,7 @@ impl<T> LinkedList<T> {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[must_use] #[must_use]
pub const fn new() -> Self { pub const fn new() -> Self {
LinkedList { head: None, tail: None, len: 0, marker: PhantomData } LinkedList { head: None, tail: None, len: 0, alloc: Global, marker: PhantomData }
} }
/// Moves all elements from `other` to the end of the list. /// Moves all elements from `other` to the end of the list.
@ -471,7 +495,26 @@ pub fn append(&mut self, other: &mut Self) {
} }
} }
} }
}
impl<T, A: Allocator> LinkedList<T, A> {
/// Constructs an empty `LinkedList<T, A>`.
///
/// # Examples
///
/// ```
/// #![feature(allocator_api)]
///
/// use std::alloc::System;
/// use std::collections::LinkedList;
///
/// let list: LinkedList<u32, _> = LinkedList::new_in(System);
/// ```
#[inline]
#[unstable(feature = "allocator_api", issue = "32838")]
pub const fn new_in(alloc: A) -> Self {
LinkedList { head: None, tail: None, len: 0, alloc, marker: PhantomData }
}
/// Provides a forward iterator. /// Provides a forward iterator.
/// ///
/// # Examples /// # Examples
@ -532,7 +575,7 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
#[inline] #[inline]
#[must_use] #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_front(&self) -> Cursor<'_, T> { pub fn cursor_front(&self) -> Cursor<'_, T, A> {
Cursor { index: 0, current: self.head, list: self } Cursor { index: 0, current: self.head, list: self }
} }
@ -542,7 +585,7 @@ pub fn cursor_front(&self) -> Cursor<'_, T> {
#[inline] #[inline]
#[must_use] #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> { pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T, A> {
CursorMut { index: 0, current: self.head, list: self } CursorMut { index: 0, current: self.head, list: self }
} }
@ -552,7 +595,7 @@ pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> {
#[inline] #[inline]
#[must_use] #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_back(&self) -> Cursor<'_, T> { pub fn cursor_back(&self) -> Cursor<'_, T, A> {
Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
} }
@ -562,7 +605,7 @@ pub fn cursor_back(&self) -> Cursor<'_, T> {
#[inline] #[inline]
#[must_use] #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> { pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T, A> {
CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
} }
@ -638,7 +681,15 @@ pub fn len(&self) -> usize {
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn clear(&mut self) { pub fn clear(&mut self) {
*self = Self::new(); // We need to drop the nodes while keeping self.alloc
// We can do this by moving (head, tail, len) into a new list that borrows self.alloc
drop(LinkedList {
head: self.head.take(),
tail: self.tail.take(),
len: mem::take(&mut self.len),
alloc: &self.alloc,
marker: PhantomData,
});
} }
/// Returns `true` if the `LinkedList` contains an element equal to the /// Returns `true` if the `LinkedList` contains an element equal to the
@ -790,7 +841,12 @@ pub fn back_mut(&mut self) -> Option<&mut T> {
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn push_front(&mut self, elt: T) { pub fn push_front(&mut self, elt: T) {
self.push_front_node(Box::new(Node::new(elt))); let node = Box::new_in(Node::new(elt), &self.alloc);
let node_ptr = Unique::from(Box::leak(node));
// SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc
unsafe {
self.push_front_node(node_ptr);
}
} }
/// Removes the first element and returns it, or `None` if the list is /// Removes the first element and returns it, or `None` if the list is
@ -833,7 +889,12 @@ pub fn pop_front(&mut self) -> Option<T> {
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn push_back(&mut self, elt: T) { pub fn push_back(&mut self, elt: T) {
self.push_back_node(Box::new(Node::new(elt))); let node = Box::new_in(Node::new(elt), &self.alloc);
let node_ptr = Unique::from(Box::leak(node));
// SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc
unsafe {
self.push_back_node(node_ptr);
}
} }
/// Removes the last element from a list and returns it, or `None` if /// Removes the last element from a list and returns it, or `None` if
@ -883,13 +944,16 @@ pub fn pop_back(&mut self) -> Option<T> {
/// assert_eq!(split.pop_front(), None); /// assert_eq!(split.pop_front(), None);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn split_off(&mut self, at: usize) -> LinkedList<T> { pub fn split_off(&mut self, at: usize) -> LinkedList<T, A>
where
A: Clone,
{
let len = self.len(); let len = self.len();
assert!(at <= len, "Cannot split off at a nonexistent index"); assert!(at <= len, "Cannot split off at a nonexistent index");
if at == 0 { if at == 0 {
return mem::take(self); return mem::replace(self, Self::new_in(self.alloc.clone()));
} else if at == len { } else if at == len {
return Self::new(); return Self::new_in(self.alloc.clone());
} }
// Below, we iterate towards the `i-1`th node, either from the start or the end, // Below, we iterate towards the `i-1`th node, either from the start or the end,
@ -987,7 +1051,7 @@ pub fn remove(&mut self, at: usize) -> T {
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]); /// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]);
/// ``` /// ```
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F> pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
where where
F: FnMut(&mut T) -> bool, F: FnMut(&mut T) -> bool,
{ {
@ -1000,11 +1064,11 @@ pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F>
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T> Drop for LinkedList<T> { unsafe impl<#[may_dangle] T, A: Allocator> Drop for LinkedList<T, A> {
fn drop(&mut self) { fn drop(&mut self) {
struct DropGuard<'a, T>(&'a mut LinkedList<T>); struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList<T, A>);
impl<'a, T> Drop for DropGuard<'a, T> { impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
fn drop(&mut self) { fn drop(&mut self) {
// Continue the same loop we do below. This only runs when a destructor has // Continue the same loop we do below. This only runs when a destructor has
// panicked. If another one panics this will abort. // panicked. If another one panics this will abort.
@ -1012,11 +1076,10 @@ fn drop(&mut self) {
} }
} }
while let Some(node) = self.pop_front_node() { // Wrap self so that if a destructor panics, we can try to keep looping
let guard = DropGuard(self); let guard = DropGuard(self);
drop(node); while guard.0.pop_front_node().is_some() {}
mem::forget(guard); mem::forget(guard);
}
} }
} }
@ -1159,14 +1222,18 @@ fn default() -> Self {
/// ///
/// When created, cursors start at the front of the list, or the "ghost" non-element if the list is empty. /// When created, cursors start at the front of the list, or the "ghost" non-element if the list is empty.
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
pub struct Cursor<'a, T: 'a> { pub struct Cursor<
'a,
T: 'a,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
index: usize, index: usize,
current: Option<NonNull<Node<T>>>, current: Option<NonNull<Node<T>>>,
list: &'a LinkedList<T>, list: &'a LinkedList<T, A>,
} }
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
impl<T> Clone for Cursor<'_, T> { impl<T, A: Allocator> Clone for Cursor<'_, T, A> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
let Cursor { index, current, list } = *self; let Cursor { index, current, list } = *self;
Cursor { index, current, list } Cursor { index, current, list }
@ -1174,7 +1241,7 @@ fn clone(&self) -> Self {
} }
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
impl<T: fmt::Debug> fmt::Debug for Cursor<'_, T> { impl<T: fmt::Debug, A: Allocator> fmt::Debug for Cursor<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Cursor").field(&self.list).field(&self.index()).finish() f.debug_tuple("Cursor").field(&self.list).field(&self.index()).finish()
} }
@ -1191,20 +1258,24 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// To accommodate this, there is a "ghost" non-element that yields `None` between the head and /// To accommodate this, there is a "ghost" non-element that yields `None` between the head and
/// tail of the list. /// tail of the list.
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
pub struct CursorMut<'a, T: 'a> { pub struct CursorMut<
'a,
T: 'a,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
index: usize, index: usize,
current: Option<NonNull<Node<T>>>, current: Option<NonNull<Node<T>>>,
list: &'a mut LinkedList<T>, list: &'a mut LinkedList<T, A>,
} }
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
impl<T: fmt::Debug> fmt::Debug for CursorMut<'_, T> { impl<T: fmt::Debug, A: Allocator> fmt::Debug for CursorMut<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("CursorMut").field(&self.list).field(&self.index()).finish() f.debug_tuple("CursorMut").field(&self.list).field(&self.index()).finish()
} }
} }
impl<'a, T> Cursor<'a, T> { impl<'a, T, A: Allocator> Cursor<'a, T, A> {
/// Returns the cursor position index within the `LinkedList`. /// Returns the cursor position index within the `LinkedList`.
/// ///
/// This returns `None` if the cursor is currently pointing to the /// This returns `None` if the cursor is currently pointing to the
@ -1321,7 +1392,7 @@ pub fn back(&self) -> Option<&'a T> {
} }
} }
impl<'a, T> CursorMut<'a, T> { impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
/// Returns the cursor position index within the `LinkedList`. /// Returns the cursor position index within the `LinkedList`.
/// ///
/// This returns `None` if the cursor is currently pointing to the /// This returns `None` if the cursor is currently pointing to the
@ -1426,7 +1497,7 @@ pub fn peek_prev(&mut self) -> Option<&mut T> {
/// `CursorMut` is frozen for the lifetime of the `Cursor`. /// `CursorMut` is frozen for the lifetime of the `Cursor`.
#[must_use] #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn as_cursor(&self) -> Cursor<'_, T> { pub fn as_cursor(&self) -> Cursor<'_, T, A> {
Cursor { list: self.list, current: self.current, index: self.index } Cursor { list: self.list, current: self.current, index: self.index }
} }
} }
@ -1434,86 +1505,6 @@ pub fn as_cursor(&self) -> Cursor<'_, T> {
// Now the list editing operations // Now the list editing operations
impl<'a, T> CursorMut<'a, T> { impl<'a, T> CursorMut<'a, T> {
/// Inserts a new element into the `LinkedList` after the current one.
///
/// If the cursor is pointing at the "ghost" non-element then the new element is
/// inserted at the front of the `LinkedList`.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn insert_after(&mut self, item: T) {
unsafe {
let spliced_node = Box::leak(Box::new(Node::new(item))).into();
let node_next = match self.current {
None => self.list.head,
Some(node) => node.as_ref().next,
};
self.list.splice_nodes(self.current, node_next, spliced_node, spliced_node, 1);
if self.current.is_none() {
// The "ghost" non-element's index has changed.
self.index = self.list.len;
}
}
}
/// Inserts a new element into the `LinkedList` before the current one.
///
/// If the cursor is pointing at the "ghost" non-element then the new element is
/// inserted at the end of the `LinkedList`.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn insert_before(&mut self, item: T) {
unsafe {
let spliced_node = Box::leak(Box::new(Node::new(item))).into();
let node_prev = match self.current {
None => self.list.tail,
Some(node) => node.as_ref().prev,
};
self.list.splice_nodes(node_prev, self.current, spliced_node, spliced_node, 1);
self.index += 1;
}
}
/// Removes the current element from the `LinkedList`.
///
/// The element that was removed is returned, and the cursor is
/// moved to point to the next element in the `LinkedList`.
///
/// If the cursor is currently pointing to the "ghost" non-element then no element
/// is removed and `None` is returned.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn remove_current(&mut self) -> Option<T> {
let unlinked_node = self.current?;
unsafe {
self.current = unlinked_node.as_ref().next;
self.list.unlink_node(unlinked_node);
let unlinked_node = Box::from_raw(unlinked_node.as_ptr());
Some(unlinked_node.element)
}
}
/// Removes the current element from the `LinkedList` without deallocating the list node.
///
/// The node that was removed is returned as a new `LinkedList` containing only this node.
/// The cursor is moved to point to the next element in the current `LinkedList`.
///
/// If the cursor is currently pointing to the "ghost" non-element then no element
/// is removed and `None` is returned.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn remove_current_as_list(&mut self) -> Option<LinkedList<T>> {
let mut unlinked_node = self.current?;
unsafe {
self.current = unlinked_node.as_ref().next;
self.list.unlink_node(unlinked_node);
unlinked_node.as_mut().prev = None;
unlinked_node.as_mut().next = None;
Some(LinkedList {
head: Some(unlinked_node),
tail: Some(unlinked_node),
len: 1,
marker: PhantomData,
})
}
}
/// Inserts the elements from the given `LinkedList` after the current one. /// Inserts the elements from the given `LinkedList` after the current one.
/// ///
/// If the cursor is pointing at the "ghost" non-element then the new elements are /// If the cursor is pointing at the "ghost" non-element then the new elements are
@ -1556,6 +1547,92 @@ pub fn splice_before(&mut self, list: LinkedList<T>) {
self.index += splice_len; self.index += splice_len;
} }
} }
}
impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
/// Inserts a new element into the `LinkedList` after the current one.
///
/// If the cursor is pointing at the "ghost" non-element then the new element is
/// inserted at the front of the `LinkedList`.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn insert_after(&mut self, item: T) {
unsafe {
let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into();
let node_next = match self.current {
None => self.list.head,
Some(node) => node.as_ref().next,
};
self.list.splice_nodes(self.current, node_next, spliced_node, spliced_node, 1);
if self.current.is_none() {
// The "ghost" non-element's index has changed.
self.index = self.list.len;
}
}
}
/// Inserts a new element into the `LinkedList` before the current one.
///
/// If the cursor is pointing at the "ghost" non-element then the new element is
/// inserted at the end of the `LinkedList`.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn insert_before(&mut self, item: T) {
unsafe {
let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into();
let node_prev = match self.current {
None => self.list.tail,
Some(node) => node.as_ref().prev,
};
self.list.splice_nodes(node_prev, self.current, spliced_node, spliced_node, 1);
self.index += 1;
}
}
/// Removes the current element from the `LinkedList`.
///
/// The element that was removed is returned, and the cursor is
/// moved to point to the next element in the `LinkedList`.
///
/// If the cursor is currently pointing to the "ghost" non-element then no element
/// is removed and `None` is returned.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn remove_current(&mut self) -> Option<T> {
let unlinked_node = self.current?;
unsafe {
self.current = unlinked_node.as_ref().next;
self.list.unlink_node(unlinked_node);
let unlinked_node = Box::from_raw(unlinked_node.as_ptr());
Some(unlinked_node.element)
}
}
/// Removes the current element from the `LinkedList` without deallocating the list node.
///
/// The node that was removed is returned as a new `LinkedList` containing only this node.
/// The cursor is moved to point to the next element in the current `LinkedList`.
///
/// If the cursor is currently pointing to the "ghost" non-element then no element
/// is removed and `None` is returned.
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn remove_current_as_list(&mut self) -> Option<LinkedList<T, A>>
where
A: Clone,
{
let mut unlinked_node = self.current?;
unsafe {
self.current = unlinked_node.as_ref().next;
self.list.unlink_node(unlinked_node);
unlinked_node.as_mut().prev = None;
unlinked_node.as_mut().next = None;
Some(LinkedList {
head: Some(unlinked_node),
tail: Some(unlinked_node),
len: 1,
alloc: self.list.alloc.clone(),
marker: PhantomData,
})
}
}
/// Splits the list into two after the current element. This will return a /// Splits the list into two after the current element. This will return a
/// new list consisting of everything after the cursor, with the original /// new list consisting of everything after the cursor, with the original
@ -1564,7 +1641,10 @@ pub fn splice_before(&mut self, list: LinkedList<T>) {
/// If the cursor is pointing at the "ghost" non-element then the entire contents /// If the cursor is pointing at the "ghost" non-element then the entire contents
/// of the `LinkedList` are moved. /// of the `LinkedList` are moved.
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn split_after(&mut self) -> LinkedList<T> { pub fn split_after(&mut self) -> LinkedList<T, A>
where
A: Clone,
{
let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 }; let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 };
if self.index == self.list.len { if self.index == self.list.len {
// The "ghost" non-element's index has changed to 0. // The "ghost" non-element's index has changed to 0.
@ -1580,7 +1660,10 @@ pub fn split_after(&mut self) -> LinkedList<T> {
/// If the cursor is pointing at the "ghost" non-element then the entire contents /// If the cursor is pointing at the "ghost" non-element then the entire contents
/// of the `LinkedList` are moved. /// of the `LinkedList` are moved.
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn split_before(&mut self) -> LinkedList<T> { pub fn split_before(&mut self) -> LinkedList<T, A>
where
A: Clone,
{
let split_off_idx = self.index; let split_off_idx = self.index;
self.index = 0; self.index = 0;
unsafe { self.list.split_off_before_node(self.current, split_off_idx) } unsafe { self.list.split_off_before_node(self.current, split_off_idx) }
@ -1722,11 +1805,15 @@ pub fn back_mut(&mut self) -> Option<&mut T> {
/// An iterator produced by calling `drain_filter` on LinkedList. /// An iterator produced by calling `drain_filter` on LinkedList.
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
pub struct DrainFilter<'a, T: 'a, F: 'a> pub struct DrainFilter<
where 'a,
T: 'a,
F: 'a,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> where
F: FnMut(&mut T) -> bool, F: FnMut(&mut T) -> bool,
{ {
list: &'a mut LinkedList<T>, list: &'a mut LinkedList<T, A>,
it: Option<NonNull<Node<T>>>, it: Option<NonNull<Node<T>>>,
pred: F, pred: F,
idx: usize, idx: usize,
@ -1734,7 +1821,7 @@ pub struct DrainFilter<'a, T: 'a, F: 'a>
} }
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
impl<T, F> Iterator for DrainFilter<'_, T, F> impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
where where
F: FnMut(&mut T) -> bool, F: FnMut(&mut T) -> bool,
{ {
@ -1763,16 +1850,16 @@ fn size_hint(&self) -> (usize, Option<usize>) {
} }
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
impl<T, F> Drop for DrainFilter<'_, T, F> impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
where where
F: FnMut(&mut T) -> bool, F: FnMut(&mut T) -> bool,
{ {
fn drop(&mut self) { fn drop(&mut self) {
struct DropGuard<'r, 'a, T, F>(&'r mut DrainFilter<'a, T, F>) struct DropGuard<'r, 'a, T, F, A: Allocator>(&'r mut DrainFilter<'a, T, F, A>)
where where
F: FnMut(&mut T) -> bool; F: FnMut(&mut T) -> bool;
impl<'r, 'a, T, F> Drop for DropGuard<'r, 'a, T, F> impl<'r, 'a, T, F, A: Allocator> Drop for DropGuard<'r, 'a, T, F, A>
where where
F: FnMut(&mut T) -> bool, F: FnMut(&mut T) -> bool,
{ {
@ -1800,7 +1887,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T> Iterator for IntoIter<T> { impl<T, A: Allocator> Iterator for IntoIter<T, A> {
type Item = T; type Item = T;
#[inline] #[inline]
@ -1815,7 +1902,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T> DoubleEndedIterator for IntoIter<T> { impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
#[inline] #[inline]
fn next_back(&mut self) -> Option<T> { fn next_back(&mut self) -> Option<T> {
self.list.pop_back() self.list.pop_back()
@ -1823,10 +1910,10 @@ fn next_back(&mut self) -> Option<T> {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {} impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {}
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for IntoIter<T> {} impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
#[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")]
impl<T> Default for IntoIter<T> { impl<T> Default for IntoIter<T> {
@ -1852,19 +1939,19 @@ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T> IntoIterator for LinkedList<T> { impl<T, A: Allocator> IntoIterator for LinkedList<T, A> {
type Item = T; type Item = T;
type IntoIter = IntoIter<T>; type IntoIter = IntoIter<T, A>;
/// Consumes the list into an iterator yielding elements by value. /// Consumes the list into an iterator yielding elements by value.
#[inline] #[inline]
fn into_iter(self) -> IntoIter<T> { fn into_iter(self) -> IntoIter<T, A> {
IntoIter { list: self } IntoIter { list: self }
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> IntoIterator for &'a LinkedList<T> { impl<'a, T, A: Allocator> IntoIterator for &'a LinkedList<T, A> {
type Item = &'a T; type Item = &'a T;
type IntoIter = Iter<'a, T>; type IntoIter = Iter<'a, T>;
@ -1874,7 +1961,7 @@ fn into_iter(self) -> Iter<'a, T> {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> IntoIterator for &'a mut LinkedList<T> { impl<'a, T, A: Allocator> IntoIterator for &'a mut LinkedList<T, A> {
type Item = &'a mut T; type Item = &'a mut T;
type IntoIter = IterMut<'a, T>; type IntoIter = IterMut<'a, T>;
@ -1884,7 +1971,7 @@ fn into_iter(self) -> IterMut<'a, T> {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T> Extend<T> for LinkedList<T> { impl<T, A: Allocator> Extend<T> for LinkedList<T, A> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
<Self as SpecExtend<I>>::spec_extend(self, iter); <Self as SpecExtend<I>>::spec_extend(self, iter);
} }
@ -1895,7 +1982,7 @@ fn extend_one(&mut self, elem: T) {
} }
} }
impl<I: IntoIterator> SpecExtend<I> for LinkedList<I::Item> { impl<I: IntoIterator, A: Allocator> SpecExtend<I> for LinkedList<I::Item, A> {
default fn spec_extend(&mut self, iter: I) { default fn spec_extend(&mut self, iter: I) {
iter.into_iter().for_each(move |elt| self.push_back(elt)); iter.into_iter().for_each(move |elt| self.push_back(elt));
} }
@ -1908,7 +1995,7 @@ fn spec_extend(&mut self, ref mut other: LinkedList<T>) {
} }
#[stable(feature = "extend_ref", since = "1.2.0")] #[stable(feature = "extend_ref", since = "1.2.0")]
impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList<T> { impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for LinkedList<T, A> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned()); self.extend(iter.into_iter().cloned());
} }
@ -1920,7 +2007,7 @@ fn extend_one(&mut self, &elem: &'a T) {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialEq> PartialEq for LinkedList<T> { impl<T: PartialEq, A: Allocator> PartialEq for LinkedList<T, A> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().eq(other) self.len() == other.len() && self.iter().eq(other)
} }
@ -1931,17 +2018,17 @@ fn ne(&self, other: &Self) -> bool {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq> Eq for LinkedList<T> {} impl<T: Eq, A: Allocator> Eq for LinkedList<T, A> {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd> PartialOrd for LinkedList<T> { impl<T: PartialOrd, A: Allocator> PartialOrd for LinkedList<T, A> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.iter().partial_cmp(other) self.iter().partial_cmp(other)
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Ord for LinkedList<T> { impl<T: Ord, A: Allocator> Ord for LinkedList<T, A> {
#[inline] #[inline]
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
self.iter().cmp(other) self.iter().cmp(other)
@ -1949,9 +2036,11 @@ fn cmp(&self, other: &Self) -> Ordering {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone> Clone for LinkedList<T> { impl<T: Clone, A: Allocator + Clone> Clone for LinkedList<T, A> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
self.iter().cloned().collect() let mut list = Self::new_in(self.alloc.clone());
list.extend(self.iter().cloned());
list
} }
fn clone_from(&mut self, other: &Self) { fn clone_from(&mut self, other: &Self) {
@ -1969,14 +2058,14 @@ fn clone_from(&mut self, other: &Self) {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug> fmt::Debug for LinkedList<T> { impl<T: fmt::Debug, A: Allocator> fmt::Debug for LinkedList<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self).finish() f.debug_list().entries(self).finish()
} }
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for LinkedList<T> { impl<T: Hash, A: Allocator> Hash for LinkedList<T, A> {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
state.write_length_prefix(self.len()); state.write_length_prefix(self.len());
for elt in self { for elt in self {
@ -2016,10 +2105,10 @@ fn c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> {
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Send> Send for LinkedList<T> {} unsafe impl<T: Send, A: Allocator + Send> Send for LinkedList<T, A> {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Sync> Sync for LinkedList<T> {} unsafe impl<T: Sync, A: Allocator + Sync> Sync for LinkedList<T, A> {}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Sync> Send for Iter<'_, T> {} unsafe impl<T: Sync> Send for Iter<'_, T> {}
@ -2034,13 +2123,13 @@ unsafe impl<T: Send> Send for IterMut<'_, T> {}
unsafe impl<T: Sync> Sync for IterMut<'_, T> {} unsafe impl<T: Sync> Sync for IterMut<'_, T> {}
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
unsafe impl<T: Sync> Send for Cursor<'_, T> {} unsafe impl<T: Sync, A: Allocator + Sync> Send for Cursor<'_, T, A> {}
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
unsafe impl<T: Sync> Sync for Cursor<'_, T> {} unsafe impl<T: Sync, A: Allocator + Sync> Sync for Cursor<'_, T, A> {}
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
unsafe impl<T: Send> Send for CursorMut<'_, T> {} unsafe impl<T: Send, A: Allocator + Send> Send for CursorMut<'_, T, A> {}
#[unstable(feature = "linked_list_cursors", issue = "58533")] #[unstable(feature = "linked_list_cursors", issue = "58533")]
unsafe impl<T: Sync> Sync for CursorMut<'_, T> {} unsafe impl<T: Sync, A: Allocator + Sync> Sync for CursorMut<'_, T, A> {}

View File

@ -130,8 +130,8 @@
// cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String] // cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String]
// cdb-command: dx linkedlist // cdb-command: dx linkedlist
// cdb-check:linkedlist : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList<i32>] // cdb-check:linkedlist : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList<i32,alloc::alloc::Global>]
// cdb-check: [<Raw View>] [Type: alloc::collections::linked_list::LinkedList<i32>] // cdb-check: [<Raw View>] [Type: alloc::collections::linked_list::LinkedList<i32,alloc::alloc::Global>]
// cdb-check: [0x0] : 128 [Type: int] // cdb-check: [0x0] : 128 [Type: int]
// cdb-check: [0x1] : 42 [Type: int] // cdb-check: [0x1] : 42 [Type: int]