diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 68b067012d3..f9746f5694a 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -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)] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index f2ef54f6e56..c399283babf 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -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; @@ -1246,6 +1246,29 @@ impl Vec { 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 { + PlaceBack { vec: self } + } } // Set the length of the vec when the `SetLenOnDrop` value goes out of scope. @@ -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, +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Placer 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 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 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 + } +} diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index d4fb5ea03ad..05671e41ed3 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -13,6 +13,7 @@ #![feature(binary_heap_extras)] #![feature(box_syntax)] #![feature(btree_range)] +#![feature(collection_placement)] #![feature(collections)] #![feature(collections_bound)] #![feature(const_fn)] @@ -20,6 +21,7 @@ #![feature(enumset)] #![feature(exact_size_is_empty)] #![feature(pattern)] +#![feature(placement_in_syntax)] #![feature(rand)] #![feature(repeat_str)] #![feature(step_by)] diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 3bc1321d756..6d0f1eaffaa 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -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; @@ -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(|| {