Skip to content

Commit 3191886

Browse files
committed
Auto merge of #38551 - aidanhs:aphs-vec-in-place, r=brson
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.
2 parents e1dfe3d + 75fe66e commit 3191886

File tree

4 files changed

+95
-1
lines changed

4 files changed

+95
-1
lines changed

src/libcollections/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#![feature(nonzero)]
4646
#![feature(pattern)]
4747
#![feature(placement_in)]
48+
#![feature(placement_in_syntax)]
4849
#![feature(placement_new_protocol)]
4950
#![feature(shared)]
5051
#![feature(slice_get_slice)]

src/libcollections/vec.rs

+73-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ use core::hash::{self, Hash};
7777
use core::intrinsics::{arith_offset, assume};
7878
use core::iter::{FromIterator, FusedIterator, TrustedLen};
7979
use core::mem;
80-
use core::ops::{Index, IndexMut};
80+
use core::ops::{InPlace, Index, IndexMut, Place, Placer};
8181
use core::ops;
8282
use core::ptr;
8383
use core::ptr::Shared;
@@ -1246,6 +1246,29 @@ impl<T: Clone> Vec<T> {
12461246
pub fn extend_from_slice(&mut self, other: &[T]) {
12471247
self.spec_extend(other.iter())
12481248
}
1249+
1250+
/// Returns a place for insertion at the back of the `Vec`.
1251+
///
1252+
/// Using this method with placement syntax is equivalent to [`push`](#method.push),
1253+
/// but may be more efficient.
1254+
///
1255+
/// # Examples
1256+
///
1257+
/// ```
1258+
/// #![feature(collection_placement)]
1259+
/// #![feature(placement_in_syntax)]
1260+
///
1261+
/// let mut vec = vec![1, 2];
1262+
/// vec.place_back() <- 3;
1263+
/// vec.place_back() <- 4;
1264+
/// assert_eq!(&vec, &[1, 2, 3, 4]);
1265+
/// ```
1266+
#[unstable(feature = "collection_placement",
1267+
reason = "placement protocol is subject to change",
1268+
issue = "30172")]
1269+
pub fn place_back(&mut self) -> PlaceBack<T> {
1270+
PlaceBack { vec: self }
1271+
}
12491272
}
12501273

12511274
// 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> {
21192142

21202143
#[unstable(feature = "fused", issue = "35602")]
21212144
impl<'a, T> FusedIterator for Drain<'a, T> {}
2145+
2146+
/// A place for insertion at the back of a `Vec`.
2147+
///
2148+
/// See [`Vec::place_back`](struct.Vec.html#method.place_back) for details.
2149+
#[must_use = "places do nothing unless written to with `<-` syntax"]
2150+
#[unstable(feature = "collection_placement",
2151+
reason = "struct name and placement protocol are subject to change",
2152+
issue = "30172")]
2153+
pub struct PlaceBack<'a, T: 'a> {
2154+
vec: &'a mut Vec<T>,
2155+
}
2156+
2157+
#[unstable(feature = "collection_placement",
2158+
reason = "placement protocol is subject to change",
2159+
issue = "30172")]
2160+
impl<'a, T> Placer<T> for PlaceBack<'a, T> {
2161+
type Place = PlaceBack<'a, T>;
2162+
2163+
fn make_place(self) -> Self {
2164+
// This will panic or abort if we would allocate > isize::MAX bytes
2165+
// or if the length increment would overflow for zero-sized types.
2166+
if self.vec.len == self.vec.buf.cap() {
2167+
self.vec.buf.double();
2168+
}
2169+
self
2170+
}
2171+
}
2172+
2173+
#[unstable(feature = "collection_placement",
2174+
reason = "placement protocol is subject to change",
2175+
issue = "30172")]
2176+
impl<'a, T> Place<T> for PlaceBack<'a, T> {
2177+
fn pointer(&mut self) -> *mut T {
2178+
unsafe { self.vec.as_mut_ptr().offset(self.vec.len as isize) }
2179+
}
2180+
}
2181+
2182+
#[unstable(feature = "collection_placement",
2183+
reason = "placement protocol is subject to change",
2184+
issue = "30172")]
2185+
impl<'a, T> InPlace<T> for PlaceBack<'a, T> {
2186+
type Owner = &'a mut T;
2187+
2188+
unsafe fn finalize(mut self) -> &'a mut T {
2189+
let ptr = self.pointer();
2190+
self.vec.len += 1;
2191+
&mut *ptr
2192+
}
2193+
}

src/libcollectionstest/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
#![feature(binary_heap_extras)]
1414
#![feature(box_syntax)]
1515
#![feature(btree_range)]
16+
#![feature(collection_placement)]
1617
#![feature(collections)]
1718
#![feature(collections_bound)]
1819
#![feature(const_fn)]
1920
#![feature(dedup_by)]
2021
#![feature(enumset)]
2122
#![feature(exact_size_is_empty)]
2223
#![feature(pattern)]
24+
#![feature(placement_in_syntax)]
2325
#![feature(rand)]
2426
#![feature(repeat_str)]
2527
#![feature(step_by)]

src/libcollectionstest/vec.rs

+19
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::ascii::AsciiExt;
1212
use std::borrow::Cow;
1313
use std::iter::{FromIterator, repeat};
1414
use std::mem::size_of;
15+
use std::panic;
1516
use std::vec::{Drain, IntoIter};
1617

1718
use test::Bencher;
@@ -615,6 +616,24 @@ fn assert_covariance() {
615616
}
616617
}
617618

619+
#[test]
620+
fn test_placement() {
621+
let mut vec = vec![1];
622+
assert_eq!(vec.place_back() <- 2, &2);
623+
assert_eq!(vec.len(), 2);
624+
assert_eq!(vec.place_back() <- 3, &3);
625+
assert_eq!(vec.len(), 3);
626+
assert_eq!(&vec, &[1, 2, 3]);
627+
}
628+
629+
#[test]
630+
fn test_placement_panic() {
631+
let mut vec = vec![1, 2, 3];
632+
fn mkpanic() -> usize { panic!() }
633+
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); }));
634+
assert_eq!(vec.len(), 3);
635+
}
636+
618637
#[bench]
619638
fn bench_new(b: &mut Bencher) {
620639
b.iter(|| {

0 commit comments

Comments
 (0)