about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-01-07 13:02:52 +0000
committerbors <bors@rust-lang.org>2017-01-07 13:02:52 +0000
commit31918864261c9fde79df1f84c5f22ab40b115ca9 (patch)
tree4467f64120e66a03cdf586ec064dbd8c98bed445
parente1dfe3d678de05f0e5b5f1bfa9c06025a7a0fb37 (diff)
parent75fe66e349d8ec4393562a775ce457c61bf9e11b (diff)
downloadrust-31918864261c9fde79df1f84c5f22ab40b115ca9.tar.gz
rust-31918864261c9fde79df1f84c5f22ab40b115ca9.zip
Auto merge of #38551 - aidanhs:aphs-vec-in-place, r=brson
Implement placement-in protocol for `Vec`

Follow-up of #32366 per comment at https://github.com/rust-lang/rust/issues/30172#issuecomment-268099009, 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.
-rw-r--r--src/libcollections/lib.rs1
-rw-r--r--src/libcollections/vec.rs74
-rw-r--r--src/libcollectionstest/lib.rs2
-rw-r--r--src/libcollectionstest/vec.rs19
4 files changed, 95 insertions, 1 deletions
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<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.
@@ -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
+    }
+}
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(|| {