diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 7218d15ded5f8..81eb94f14cac2 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -13,7 +13,7 @@ use core::fmt::Debug; use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, Peekable, FusedIterator}; use core::marker::PhantomData; -use core::ops::Index; +use core::ops::{Index, InPlace, Place, Placer}; use core::{fmt, intrinsics, mem, ptr}; use borrow::Borrow; @@ -447,6 +447,62 @@ impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { } } +/// A place for insertion to a `Entry`. +/// +/// See [`BTreeMap::entry`](struct.BTreeMap.html#method.entry) for details. +#[must_use = "places do nothing unless written to with <- syntax"] +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol is subject to change", + issue = "30172")] +#[derive(Debug)] +pub struct EntryPlace<'a, K: 'a + Debug + Ord, V: 'a> { + entry: Entry<'a, K, V>, + value: V, +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, K, V> Placer for Entry<'a, K, V> + where K: 'a + Debug + Ord { + type Place = EntryPlace<'a, K, V>; + + fn make_place(self) -> EntryPlace<'a, K, V> { + let uninit = unsafe { mem::uninitialized() }; + EntryPlace { entry: self, value: uninit } + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, K, V> Place for EntryPlace<'a, K, V> + where K: 'a + Debug + Ord { + fn pointer(&mut self) -> *mut V { + &mut self.value + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, K, V> InPlace for EntryPlace<'a, K, V> + where K: 'a + Debug + Ord { + type Owner = (); + + unsafe fn finalize(self) { + match self.entry { + Occupied(mut o) => { + o.insert(self.value); + } + Vacant(v) => { + v.insert(self.value); + } + } + } +} + + // An iterator for merging two sorted sequences into one struct MergeIter> { left: Peekable, diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollectionstest/btree/map.rs index 2c899d96940ec..eacc59b7d40d5 100644 --- a/src/libcollectionstest/btree/map.rs +++ b/src/libcollectionstest/btree/map.rs @@ -12,6 +12,7 @@ use std::collections::BTreeMap; use std::collections::Bound::{self, Excluded, Included, Unbounded}; use std::collections::btree_map::Entry::{Occupied, Vacant}; use std::rc::Rc; +use panic; use std::iter::FromIterator; use super::DeterministicRng; @@ -685,3 +686,29 @@ fn test_split_off_large_random_sorted() { assert!(map.into_iter().eq(data.clone().into_iter().filter(|x| x.0 < key))); assert!(right.into_iter().eq(data.into_iter().filter(|x| x.0 >= key))); } + +#[test] +fn test_placement_in() { + let mut map = HashMap::new(); + map.extend((0..10).map(|i| (i, i))); + + map.entry(100) <- 100; + assert_eq!(map[&100], 100); + + map.entry(0) <- 10; + assert_eq!(map[&0], 10); + + assert_eq!(map.len(), 11); +} + +#[test] +fn test_placement_panic() { + let mut map = HashMap::new(); + map.extend((0..10).map(|i| (i, i))); + + fn mkpanic() -> usize { panic!() } + + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(0) <- mkpanic(); })); + assert_eq!(map.len(), 10); + assert_eq!(map[&0], 0); +}