Skip to content

Commit

Permalink
Auto merge of #38551 - aidanhs:aphs-vec-in-place, r=brson
Browse files Browse the repository at this point in the history
Implement placement-in protocol for `Vec`

Follow-up of #32366 per comment at #30172 (comment), updating to latest rust, leaving @apasel422 as author and putting myself as committer.

I've removed the implementation of `push` in terms of place to make this PR more conservative.
  • Loading branch information
bors committed Jan 7, 2017
2 parents e1dfe3d + 75fe66e commit 3191886
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/libcollections/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#![feature(nonzero)]
#![feature(pattern)]
#![feature(placement_in)]
#![feature(placement_in_syntax)]
#![feature(placement_new_protocol)]
#![feature(shared)]
#![feature(slice_get_slice)]
Expand Down
74 changes: 73 additions & 1 deletion src/libcollections/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ use core::hash::{self, Hash};
use core::intrinsics::{arith_offset, assume};
use core::iter::{FromIterator, FusedIterator, TrustedLen};
use core::mem;
use core::ops::{Index, IndexMut};
use core::ops::{InPlace, Index, IndexMut, Place, Placer};
use core::ops;
use core::ptr;
use core::ptr::Shared;
Expand Down Expand Up @@ -1246,6 +1246,29 @@ impl<T: Clone> Vec<T> {
pub fn extend_from_slice(&mut self, other: &[T]) {
self.spec_extend(other.iter())
}

/// Returns a place for insertion at the back of the `Vec`.
///
/// Using this method with placement syntax is equivalent to [`push`](#method.push),
/// but may be more efficient.
///
/// # Examples
///
/// ```
/// #![feature(collection_placement)]
/// #![feature(placement_in_syntax)]
///
/// let mut vec = vec![1, 2];
/// vec.place_back() <- 3;
/// vec.place_back() <- 4;
/// assert_eq!(&vec, &[1, 2, 3, 4]);
/// ```
#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
pub fn place_back(&mut self) -> PlaceBack<T> {
PlaceBack { vec: self }
}
}

// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
Expand Down Expand Up @@ -2119,3 +2142,52 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> {

#[unstable(feature = "fused", issue = "35602")]
impl<'a, T> FusedIterator for Drain<'a, T> {}

/// A place for insertion at the back of a `Vec`.
///
/// See [`Vec::place_back`](struct.Vec.html#method.place_back) 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 PlaceBack<'a, T: 'a> {
vec: &'a mut Vec<T>,
}

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

fn make_place(self) -> Self {
// This will panic or abort if we would allocate > isize::MAX bytes
// or if the length increment would overflow for zero-sized types.
if self.vec.len == self.vec.buf.cap() {
self.vec.buf.double();
}
self
}
}

#[unstable(feature = "collection_placement",
reason = "placement protocol is subject to change",
issue = "30172")]
impl<'a, T> Place<T> for PlaceBack<'a, T> {
fn pointer(&mut self) -> *mut T {
unsafe { self.vec.as_mut_ptr().offset(self.vec.len as isize) }
}
}

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

unsafe fn finalize(mut self) -> &'a mut T {
let ptr = self.pointer();
self.vec.len += 1;
&mut *ptr
}
}
2 changes: 2 additions & 0 deletions src/libcollectionstest/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
#![feature(binary_heap_extras)]
#![feature(box_syntax)]
#![feature(btree_range)]
#![feature(collection_placement)]
#![feature(collections)]
#![feature(collections_bound)]
#![feature(const_fn)]
#![feature(dedup_by)]
#![feature(enumset)]
#![feature(exact_size_is_empty)]
#![feature(pattern)]
#![feature(placement_in_syntax)]
#![feature(rand)]
#![feature(repeat_str)]
#![feature(step_by)]
Expand Down
19 changes: 19 additions & 0 deletions src/libcollectionstest/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::iter::{FromIterator, repeat};
use std::mem::size_of;
use std::panic;
use std::vec::{Drain, IntoIter};

use test::Bencher;
Expand Down Expand Up @@ -615,6 +616,24 @@ fn assert_covariance() {
}
}

#[test]
fn test_placement() {
let mut vec = vec![1];
assert_eq!(vec.place_back() <- 2, &2);
assert_eq!(vec.len(), 2);
assert_eq!(vec.place_back() <- 3, &3);
assert_eq!(vec.len(), 3);
assert_eq!(&vec, &[1, 2, 3]);
}

#[test]
fn test_placement_panic() {
let mut vec = vec![1, 2, 3];
fn mkpanic() -> usize { panic!() }
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); }));
assert_eq!(vec.len(), 3);
}

#[bench]
fn bench_new(b: &mut Bencher) {
b.iter(|| {
Expand Down

0 comments on commit 3191886

Please sign in to comment.