Skip to content

Commit d503524

Browse files
committed
Auto merge of #28043 - apasel422:rfc-1194, r=alexcrichton
2 parents 3c100de + f9b63d3 commit d503524

File tree

8 files changed

+283
-13
lines changed

8 files changed

+283
-13
lines changed

src/libcollections/btree/map.rs

+92-9
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
459459
}
460460
});
461461
match result {
462-
Finished(ret) => return ret,
462+
Finished(ret) => return ret.map(|(_, v)| v),
463463
Continue(new_stack) => stack = new_stack
464464
}
465465
}
@@ -693,16 +693,16 @@ mod stack {
693693
impl<'a, K, V> SearchStack<'a, K, V, handle::KV, handle::Leaf> {
694694
/// Removes the key and value in the top element of the stack, then handles underflows as
695695
/// described in BTree's pop function.
696-
fn remove_leaf(mut self) -> V {
696+
fn remove_leaf(mut self) -> (K, V) {
697697
self.map.length -= 1;
698698

699699
// Remove the key-value pair from the leaf that this search stack points to.
700700
// Then, note if the leaf is underfull, and promptly forget the leaf and its ptr
701701
// to avoid ownership issues.
702-
let (value, mut underflow) = unsafe {
703-
let (_, value) = self.top.from_raw_mut().remove_as_leaf();
702+
let (key_val, mut underflow) = unsafe {
703+
let key_val = self.top.from_raw_mut().remove_as_leaf();
704704
let underflow = self.top.from_raw().node().is_underfull();
705-
(value, underflow)
705+
(key_val, underflow)
706706
};
707707

708708
loop {
@@ -717,7 +717,7 @@ mod stack {
717717
self.map.depth -= 1;
718718
self.map.root.hoist_lone_child();
719719
}
720-
return value;
720+
return key_val;
721721
}
722722
Some(mut handle) => {
723723
if underflow {
@@ -728,7 +728,7 @@ mod stack {
728728
}
729729
} else {
730730
// All done!
731-
return value;
731+
return key_val;
732732
}
733733
}
734734
}
@@ -739,7 +739,7 @@ mod stack {
739739
impl<'a, K, V> SearchStack<'a, K, V, handle::KV, handle::LeafOrInternal> {
740740
/// Removes the key and value in the top element of the stack, then handles underflows as
741741
/// described in BTree's pop function.
742-
pub fn remove(self) -> V {
742+
pub fn remove(self) -> (K, V) {
743743
// Ensure that the search stack goes to a leaf. This is necessary to perform deletion
744744
// in a BTree. Note that this may put the tree in an inconsistent state (further
745745
// described in into_leaf's comments), but this is immediately fixed by the
@@ -1208,7 +1208,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
12081208
/// Takes the value of the entry out of the map, and returns it.
12091209
#[stable(feature = "rust1", since = "1.0.0")]
12101210
pub fn remove(self) -> V {
1211-
self.stack.remove()
1211+
self.stack.remove().1
12121212
}
12131213
}
12141214

@@ -1609,3 +1609,86 @@ impl<K: Ord, V> BTreeMap<K, V> {
16091609
}
16101610
}
16111611
}
1612+
1613+
impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()> where K: Borrow<Q> + Ord, Q: Ord {
1614+
type Key = K;
1615+
1616+
fn get(&self, key: &Q) -> Option<&K> {
1617+
let mut cur_node = &self.root;
1618+
loop {
1619+
match Node::search(cur_node, key) {
1620+
Found(handle) => return Some(handle.into_kv().0),
1621+
GoDown(handle) => match handle.force() {
1622+
Leaf(_) => return None,
1623+
Internal(internal_handle) => {
1624+
cur_node = internal_handle.into_edge();
1625+
continue;
1626+
}
1627+
}
1628+
}
1629+
}
1630+
}
1631+
1632+
fn take(&mut self, key: &Q) -> Option<K> {
1633+
// See `remove` for an explanation of this.
1634+
1635+
let mut stack = stack::PartialSearchStack::new(self);
1636+
loop {
1637+
let result = stack.with(move |pusher, node| {
1638+
match Node::search(node, key) {
1639+
Found(handle) => {
1640+
// Perfect match. Terminate the stack here, and remove the entry
1641+
Finished(Some(pusher.seal(handle).remove()))
1642+
},
1643+
GoDown(handle) => {
1644+
// We need to keep searching, try to go down the next edge
1645+
match handle.force() {
1646+
// We're at a leaf; the key isn't in here
1647+
Leaf(_) => Finished(None),
1648+
Internal(internal_handle) => Continue(pusher.push(internal_handle))
1649+
}
1650+
}
1651+
}
1652+
});
1653+
match result {
1654+
Finished(ret) => return ret.map(|(k, _)| k),
1655+
Continue(new_stack) => stack = new_stack
1656+
}
1657+
}
1658+
}
1659+
1660+
fn replace(&mut self, mut key: K) -> Option<K> {
1661+
// See `insert` for an explanation of this.
1662+
1663+
let mut stack = stack::PartialSearchStack::new(self);
1664+
1665+
loop {
1666+
let result = stack.with(move |pusher, node| {
1667+
match Node::search::<K, _>(node, &key) {
1668+
Found(mut handle) => {
1669+
mem::swap(handle.key_mut(), &mut key);
1670+
Finished(Some(key))
1671+
},
1672+
GoDown(handle) => {
1673+
match handle.force() {
1674+
Leaf(leaf_handle) => {
1675+
pusher.seal(leaf_handle).insert(key, ());
1676+
Finished(None)
1677+
}
1678+
Internal(internal_handle) => {
1679+
Continue((pusher.push(internal_handle), key, ()))
1680+
}
1681+
}
1682+
}
1683+
}
1684+
});
1685+
match result {
1686+
Finished(ret) => return ret,
1687+
Continue((new_stack, renewed_key, _)) => {
1688+
stack = new_stack;
1689+
key = renewed_key;
1690+
}
1691+
}
1692+
}
1693+
}
1694+
}

src/libcollections/btree/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@
1111
mod node;
1212
pub mod map;
1313
pub mod set;
14+
15+
trait Recover<Q: ?Sized> {
16+
type Key;
17+
18+
fn get(&self, key: &Q) -> Option<&Self::Key>;
19+
fn take(&mut self, key: &Q) -> Option<Self::Key>;
20+
fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
21+
}

src/libcollections/btree/set.rs

+28
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use core::ops::{BitOr, BitAnd, BitXor, Sub};
1919

2020
use borrow::Borrow;
2121
use btree_map::{BTreeMap, Keys};
22+
use super::Recover;
2223
use Bound;
2324

2425
// FIXME(conventions): implement bounded iterators
@@ -329,6 +330,16 @@ impl<T: Ord> BTreeSet<T> {
329330
self.map.contains_key(value)
330331
}
331332

333+
/// Returns a reference to the value in the set, if any, that is equal to the given value.
334+
///
335+
/// The value may be any borrowed form of the set's value type,
336+
/// but the ordering on the borrowed form *must* match the
337+
/// ordering on the value type.
338+
#[unstable(feature = "set_recovery", issue = "28050")]
339+
pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T> where T: Borrow<Q>, Q: Ord {
340+
Recover::get(&self.map, value)
341+
}
342+
332343
/// Returns `true` if the set has no elements in common with `other`.
333344
/// This is equivalent to checking for an empty intersection.
334345
///
@@ -436,6 +447,13 @@ impl<T: Ord> BTreeSet<T> {
436447
self.map.insert(value, ()).is_none()
437448
}
438449

450+
/// Adds a value to the set, replacing the existing value, if any, that is equal to the given
451+
/// one. Returns the replaced value.
452+
#[unstable(feature = "set_recovery", issue = "28050")]
453+
pub fn replace(&mut self, value: T) -> Option<T> {
454+
Recover::replace(&mut self.map, value)
455+
}
456+
439457
/// Removes a value from the set. Returns `true` if the value was
440458
/// present in the set.
441459
///
@@ -458,6 +476,16 @@ impl<T: Ord> BTreeSet<T> {
458476
pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool where T: Borrow<Q>, Q: Ord {
459477
self.map.remove(value).is_some()
460478
}
479+
480+
/// Removes and returns the value in the set, if any, that is equal to the given one.
481+
///
482+
/// The value may be any borrowed form of the set's value type,
483+
/// but the ordering on the borrowed form *must* match the
484+
/// ordering on the value type.
485+
#[unstable(feature = "set_recovery", issue = "28050")]
486+
pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T> where T: Borrow<Q>, Q: Ord {
487+
Recover::take(&mut self.map, value)
488+
}
461489
}
462490

463491
#[stable(feature = "rust1", since = "1.0.0")]

src/libcollectionstest/btree/set.rs

+49
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,52 @@ fn test_extend_ref() {
211211
assert!(a.contains(&5));
212212
assert!(a.contains(&6));
213213
}
214+
215+
#[test]
216+
fn test_recovery() {
217+
use std::cmp::Ordering;
218+
219+
#[derive(Debug)]
220+
struct Foo(&'static str, i32);
221+
222+
impl PartialEq for Foo {
223+
fn eq(&self, other: &Self) -> bool {
224+
self.0 == other.0
225+
}
226+
}
227+
228+
impl Eq for Foo {}
229+
230+
impl PartialOrd for Foo {
231+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
232+
self.0.partial_cmp(&other.0)
233+
}
234+
}
235+
236+
impl Ord for Foo {
237+
fn cmp(&self, other: &Self) -> Ordering {
238+
self.0.cmp(&other.0)
239+
}
240+
}
241+
242+
let mut s = BTreeSet::new();
243+
assert_eq!(s.replace(Foo("a", 1)), None);
244+
assert_eq!(s.len(), 1);
245+
assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1)));
246+
assert_eq!(s.len(), 1);
247+
248+
{
249+
let mut it = s.iter();
250+
assert_eq!(it.next(), Some(&Foo("a", 2)));
251+
assert_eq!(it.next(), None);
252+
}
253+
254+
assert_eq!(s.get(&Foo("a", 1)), Some(&Foo("a", 2)));
255+
assert_eq!(s.take(&Foo("a", 1)), Some(Foo("a", 2)));
256+
assert_eq!(s.len(), 0);
257+
258+
assert_eq!(s.get(&Foo("a", 1)), None);
259+
assert_eq!(s.take(&Foo("a", 1)), None);
260+
261+
assert_eq!(s.iter().next(), None);
262+
}

src/libcollectionstest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#![feature(rand)]
2626
#![feature(range_inclusive)]
2727
#![feature(rustc_private)]
28+
#![feature(set_recovery)]
2829
#![feature(slice_bytes)]
2930
#![feature(slice_splits)]
3031
#![feature(split_off)]

src/libstd/collections/hash/map.rs

+33-4
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ impl<K, V, S> HashMap<K, V, S>
769769
/// If the key already exists, the hashtable will be returned untouched
770770
/// and a reference to the existing element will be returned.
771771
fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> &mut V {
772-
self.insert_or_replace_with(hash, k, v, |_, _, _| ())
772+
self.insert_or_replace_with(hash, k, v, |_, _, _, _| ())
773773
}
774774

775775
fn insert_or_replace_with<'a, F>(&'a mut self,
@@ -778,7 +778,7 @@ impl<K, V, S> HashMap<K, V, S>
778778
v: V,
779779
mut found_existing: F)
780780
-> &'a mut V where
781-
F: FnMut(&mut K, &mut V, V),
781+
F: FnMut(&mut K, &mut V, K, V),
782782
{
783783
// Worst case, we'll find one empty bucket among `size + 1` buckets.
784784
let size = self.table.size();
@@ -801,7 +801,7 @@ impl<K, V, S> HashMap<K, V, S>
801801
let (bucket_k, bucket_v) = bucket.into_mut_refs();
802802
debug_assert!(k == *bucket_k);
803803
// Key already exists. Get its reference.
804-
found_existing(bucket_k, bucket_v, v);
804+
found_existing(bucket_k, bucket_v, k, v);
805805
return bucket_v;
806806
}
807807
}
@@ -1123,7 +1123,7 @@ impl<K, V, S> HashMap<K, V, S>
11231123
self.reserve(1);
11241124

11251125
let mut retval = None;
1126-
self.insert_or_replace_with(hash, k, v, |_, val_ref, val| {
1126+
self.insert_or_replace_with(hash, k, v, |_, val_ref, _, val| {
11271127
retval = Some(replace(val_ref, val));
11281128
});
11291129
retval
@@ -1630,6 +1630,35 @@ impl Default for RandomState {
16301630
}
16311631
}
16321632

1633+
impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S>
1634+
where K: Eq + Hash + Borrow<Q>, S: HashState, Q: Eq + Hash
1635+
{
1636+
type Key = K;
1637+
1638+
fn get(&self, key: &Q) -> Option<&K> {
1639+
self.search(key).map(|bucket| bucket.into_refs().0)
1640+
}
1641+
1642+
fn take(&mut self, key: &Q) -> Option<K> {
1643+
if self.table.size() == 0 {
1644+
return None
1645+
}
1646+
1647+
self.search_mut(key).map(|bucket| pop_internal(bucket).0)
1648+
}
1649+
1650+
fn replace(&mut self, key: K) -> Option<K> {
1651+
let hash = self.make_hash(&key);
1652+
self.reserve(1);
1653+
1654+
let mut retkey = None;
1655+
self.insert_or_replace_with(hash, key, (), |key_ref, _, key, _| {
1656+
retkey = Some(replace(key_ref, key));
1657+
});
1658+
retkey
1659+
}
1660+
}
1661+
16331662
#[cfg(test)]
16341663
mod test_map {
16351664
use prelude::v1::*;

src/libstd/collections/hash/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,11 @@ mod table;
1515
pub mod map;
1616
pub mod set;
1717
pub mod state;
18+
19+
trait Recover<Q: ?Sized> {
20+
type Key;
21+
22+
fn get(&self, key: &Q) -> Option<&Self::Key>;
23+
fn take(&mut self, key: &Q) -> Option<Self::Key>;
24+
fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
25+
}

0 commit comments

Comments
 (0)