Skip to content

Implement placement-in protocol for LinkedList #31696

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

Merged
merged 1 commit into from
Feb 17, 2016
Merged
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
2 changes: 2 additions & 0 deletions src/libcollections/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
#![feature(nonzero)]
#![feature(num_bits_bytes)]
#![feature(pattern)]
#![feature(placement_in)]
#![feature(placement_new_protocol)]
#![feature(shared)]
#![feature(slice_bytes)]
#![feature(slice_patterns)]
Expand Down
150 changes: 148 additions & 2 deletions src/libcollections/linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@

#![stable(feature = "rust1", since = "1.0.0")]

use alloc::boxed::Box;
use alloc::boxed::{Box, IntermediateBox};
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hasher, Hash};
use core::iter::FromIterator;
use core::mem;
use core::ptr::Shared;
use core::ops::{BoxPlace, InPlace, Place, Placer};
use core::ptr::{self, Shared};

/// A doubly-linked list.
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -660,6 +661,56 @@ impl<T> LinkedList<T> {

second_part
}

/// Returns a place for insertion at the front of the list.
///
/// Using this method with placement syntax is equivalent to [`push_front`]
/// (#method.push_front), but may be more efficient.
///
/// # Examples
///
/// ```
/// #![feature(collection_placement)]
/// #![feature(placement_in_syntax)]
///
/// use std::collections::LinkedList;
///
/// let mut list = LinkedList::new();
/// list.front_place() <- 2;
/// list.front_place() <- 4;
/// assert!(list.iter().eq(&[4, 2]));
/// ```
#[unstable(feature = "collection_placement",
reason = "method name and placement protocol are subject to change",
issue = "30172")]
pub fn front_place(&mut self) -> FrontPlace<T> {
FrontPlace { list: self, node: IntermediateBox::make_place() }
}

/// Returns a place for insertion at the back of the list.
///
/// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back),
/// but may be more efficient.
///
/// # Examples
///
/// ```
/// #![feature(collection_placement)]
/// #![feature(placement_in_syntax)]
///
/// use std::collections::LinkedList;
///
/// let mut list = LinkedList::new();
/// list.back_place() <- 2;
/// list.back_place() <- 4;
/// assert!(list.iter().eq(&[2, 4]));
/// ```
#[unstable(feature = "collection_placement",
reason = "method name and placement protocol are subject to change",
issue = "30172")]
pub fn back_place(&mut self) -> BackPlace<T> {
BackPlace { list: self, node: IntermediateBox::make_place() }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -984,6 +1035,101 @@ impl<A: Hash> Hash for LinkedList<A> {
}
}

unsafe fn finalize<T>(node: IntermediateBox<Node<T>>) -> Box<Node<T>> {
let mut node = node.finalize();
ptr::write(&mut node.next, None);
ptr::write(&mut node.prev, Rawlink::none());
node
}

/// A place for insertion at the front of a `LinkedList`.
///
/// See [`LinkedList::front_place`](struct.LinkedList.html#method.front_place) for details.
#[must_use = "places do nothing unless written to with `<-` syntax"]
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol are subject to change",
issue = "30172")]
pub struct FrontPlace<'a, T: 'a> {
list: &'a mut LinkedList<T>,
node: IntermediateBox<Node<T>>,
}

#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Placer<T> for FrontPlace<'a, T> {
type Place = Self;

fn make_place(self) -> Self {
self
}
}

#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Place<T> for FrontPlace<'a, T> {
fn pointer(&mut self) -> *mut T {
unsafe { &mut (*self.node.pointer()).value }
}
}

#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> InPlace<T> for FrontPlace<'a, T> {
type Owner = ();

unsafe fn finalize(self) {
let FrontPlace { list, node } = self;
list.push_front_node(finalize(node));
}
}

/// A place for insertion at the back of a `LinkedList`.
///
/// See [`LinkedList::back_place`](struct.LinkedList.html#method.back_place) for details.
#[must_use = "places do nothing unless written to with `<-` syntax"]
#[unstable(feature = "collection_placement",
reason = "struct name and placement protocol are subject to change",
issue = "30172")]
pub struct BackPlace<'a, T: 'a> {
list: &'a mut LinkedList<T>,
node: IntermediateBox<Node<T>>,
}

#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Placer<T> for BackPlace<'a, T> {
type Place = Self;

fn make_place(self) -> Self {
self
}
}

#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Place<T> for BackPlace<'a, T> {
fn pointer(&mut self) -> *mut T {
unsafe { &mut (*self.node.pointer()).value }
}
}

#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> InPlace<T> for BackPlace<'a, T> {
type Owner = ();

unsafe fn finalize(self) {
let BackPlace { list, node } = self;
list.push_back_node(finalize(node));
}
}

// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters.
#[allow(dead_code)]
fn assert_covariance() {
Expand Down