diff options
| author | bors <bors@rust-lang.org> | 2015-08-29 00:06:04 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-08-29 00:06:04 +0000 |
| commit | d50352419eedf95f40dc317c7d5a7fc586189e05 (patch) | |
| tree | b2f3951bcd15f386b03db47a3760d970a6ae80ba /src/libstd | |
| parent | 3c100de75ac94ef33ecafe64810ef4c8113c1579 (diff) | |
| parent | f9b63d39730740e002cc31a38a7a8a3a18d3f46d (diff) | |
| download | rust-d50352419eedf95f40dc317c7d5a7fc586189e05.tar.gz rust-d50352419eedf95f40dc317c7d5a7fc586189e05.zip | |
Auto merge of #28043 - apasel422:rfc-1194, r=alexcrichton
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/collections/hash/map.rs | 37 | ||||
| -rw-r--r-- | src/libstd/collections/hash/mod.rs | 8 | ||||
| -rw-r--r-- | src/libstd/collections/hash/set.rs | 64 |
3 files changed, 105 insertions, 4 deletions
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index d5638bdac69..1e5c012e7d8 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -769,7 +769,7 @@ impl<K, V, S> HashMap<K, V, S> /// If the key already exists, the hashtable will be returned untouched /// and a reference to the existing element will be returned. fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> &mut V { - self.insert_or_replace_with(hash, k, v, |_, _, _| ()) + self.insert_or_replace_with(hash, k, v, |_, _, _, _| ()) } fn insert_or_replace_with<'a, F>(&'a mut self, @@ -778,7 +778,7 @@ impl<K, V, S> HashMap<K, V, S> v: V, mut found_existing: F) -> &'a mut V where - F: FnMut(&mut K, &mut V, V), + F: FnMut(&mut K, &mut V, K, V), { // Worst case, we'll find one empty bucket among `size + 1` buckets. let size = self.table.size(); @@ -801,7 +801,7 @@ impl<K, V, S> HashMap<K, V, S> let (bucket_k, bucket_v) = bucket.into_mut_refs(); debug_assert!(k == *bucket_k); // Key already exists. Get its reference. - found_existing(bucket_k, bucket_v, v); + found_existing(bucket_k, bucket_v, k, v); return bucket_v; } } @@ -1123,7 +1123,7 @@ impl<K, V, S> HashMap<K, V, S> self.reserve(1); let mut retval = None; - self.insert_or_replace_with(hash, k, v, |_, val_ref, val| { + self.insert_or_replace_with(hash, k, v, |_, val_ref, _, val| { retval = Some(replace(val_ref, val)); }); retval @@ -1630,6 +1630,35 @@ impl Default for RandomState { } } +impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S> + where K: Eq + Hash + Borrow<Q>, S: HashState, Q: Eq + Hash +{ + type Key = K; + + fn get(&self, key: &Q) -> Option<&K> { + self.search(key).map(|bucket| bucket.into_refs().0) + } + + fn take(&mut self, key: &Q) -> Option<K> { + if self.table.size() == 0 { + return None + } + + self.search_mut(key).map(|bucket| pop_internal(bucket).0) + } + + fn replace(&mut self, key: K) -> Option<K> { + let hash = self.make_hash(&key); + self.reserve(1); + + let mut retkey = None; + self.insert_or_replace_with(hash, key, (), |key_ref, _, key, _| { + retkey = Some(replace(key_ref, key)); + }); + retkey + } +} + #[cfg(test)] mod test_map { use prelude::v1::*; diff --git a/src/libstd/collections/hash/mod.rs b/src/libstd/collections/hash/mod.rs index 47e300af269..4a6fcf44926 100644 --- a/src/libstd/collections/hash/mod.rs +++ b/src/libstd/collections/hash/mod.rs @@ -15,3 +15,11 @@ mod table; pub mod map; pub mod set; pub mod state; + +trait Recover<Q: ?Sized> { + type Key; + + fn get(&self, key: &Q) -> Option<&Self::Key>; + fn take(&mut self, key: &Q) -> Option<Self::Key>; + fn replace(&mut self, key: Self::Key) -> Option<Self::Key>; +} diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ccad088a298..1f19a72371c 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -20,6 +20,7 @@ use iter::{Iterator, IntoIterator, ExactSizeIterator, FromIterator, Map, Chain, use ops::{BitOr, BitAnd, BitXor, Sub}; use option::Option::{Some, None, self}; +use super::Recover; use super::map::{self, HashMap, Keys, RandomState}; use super::state::HashState; @@ -459,6 +460,18 @@ impl<T, S> HashSet<T, S> self.map.contains_key(value) } + /// Returns a reference to the value in the set, if any, that is equal to the given value. + /// + /// The value may be any borrowed form of the set's value type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the value type. + #[unstable(feature = "set_recovery", issue = "28050")] + pub fn get<Q: ?Sized>(&self, value: &Q) -> Option<&T> + where T: Borrow<Q>, Q: Hash + Eq + { + Recover::get(&self.map, value) + } + /// Returns `true` if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. /// @@ -544,6 +557,13 @@ impl<T, S> HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none() } + /// Adds a value to the set, replacing the existing value, if any, that is equal to the given + /// one. Returns the replaced value. + #[unstable(feature = "set_recovery", issue = "28050")] + pub fn replace(&mut self, value: T) -> Option<T> { + Recover::replace(&mut self.map, value) + } + /// Removes a value from the set. Returns `true` if the value was /// present in the set. /// @@ -568,6 +588,18 @@ impl<T, S> HashSet<T, S> { self.map.remove(value).is_some() } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + /// + /// The value may be any borrowed form of the set's value type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the value type. + #[unstable(feature = "set_recovery", issue = "28050")] + pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T> + where T: Borrow<Q>, Q: Hash + Eq + { + Recover::take(&mut self.map, value) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1261,4 +1293,36 @@ mod test_set { s.extend(1..100); } } + + #[test] + fn test_replace() { + use hash; + + #[derive(Debug)] + struct Foo(&'static str, i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl Eq for Foo {} + + impl hash::Hash for Foo { + fn hash<H: hash::Hasher>(&self, h: &mut H) { + self.0.hash(h); + } + } + + let mut s = HashSet::new(); + assert_eq!(s.replace(Foo("a", 1)), None); + assert_eq!(s.len(), 1); + assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); + assert_eq!(s.len(), 1); + + let mut it = s.iter(); + assert_eq!(it.next(), Some(&Foo("a", 2))); + assert_eq!(it.next(), None); + } } |
