Skip to content

Commit 80a2867

Browse files
committed
libstd: Deprecate _equiv methods
This commit deprecates the `_equiv` family of methods on `HashMap` and `HashSet` by instead generalizing the "normal" methods like `get` and `remove` to use the new `std::borrow` infrastructure. [breaking-change]
1 parent 5eec666 commit 80a2867

File tree

2 files changed

+84
-123
lines changed

2 files changed

+84
-123
lines changed

src/libstd/collections/hash/map.rs

Lines changed: 62 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub use self::Entry::*;
1414
use self::SearchResult::*;
1515
use self::VacantEntryState::*;
1616

17+
use borrow::BorrowFrom;
1718
use clone::Clone;
1819
use cmp::{max, Eq, Equiv, PartialEq};
1920
use default::Default;
@@ -142,7 +143,7 @@ impl DefaultResizePolicy {
142143
// about the size of rust executables.
143144
//
144145
// Annotate exceedingly likely branches in `table::make_hash`
145-
// and `search_hashed_generic` to reduce instruction cache pressure
146+
// and `search_hashed` to reduce instruction cache pressure
146147
// and mispredictions once it becomes possible (blocked on issue #11092).
147148
//
148149
// Shrinking the table could simply reallocate in place after moving buckets
@@ -286,10 +287,10 @@ pub struct HashMap<K, V, H = RandomSipHasher> {
286287
}
287288

288289
/// Search for a pre-hashed key.
289-
fn search_hashed_generic<K, V, M: Deref<RawTable<K, V>>>(table: M,
290-
hash: &SafeHash,
291-
is_match: |&K| -> bool)
292-
-> SearchResult<K, V, M> {
290+
fn search_hashed<K, V, M: Deref<RawTable<K, V>>>(table: M,
291+
hash: &SafeHash,
292+
is_match: |&K| -> bool)
293+
-> SearchResult<K, V, M> {
293294
let size = table.size();
294295
let mut probe = Bucket::new(table, hash);
295296
let ib = probe.index();
@@ -325,11 +326,6 @@ fn search_hashed_generic<K, V, M: Deref<RawTable<K, V>>>(table: M,
325326
TableRef(probe.into_table())
326327
}
327328

328-
fn search_hashed<K: Eq, V, M: Deref<RawTable<K, V>>>(table: M, hash: &SafeHash, k: &K)
329-
-> SearchResult<K, V, M> {
330-
search_hashed_generic(table, hash, |k_| *k == *k_)
331-
}
332-
333329
fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> (K, V) {
334330
let (empty, retkey, retval) = starting_bucket.take();
335331
let mut gap = match empty.gap_peek() {
@@ -432,26 +428,32 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
432428
fn search_equiv<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a self, q: &Q)
433429
-> Option<FullBucketImm<'a, K, V>> {
434430
let hash = self.make_hash(q);
435-
search_hashed_generic(&self.table, &hash, |k| q.equiv(k)).into_option()
431+
search_hashed(&self.table, &hash, |k| q.equiv(k)).into_option()
436432
}
437433

438434
fn search_equiv_mut<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a mut self, q: &Q)
439435
-> Option<FullBucketMut<'a, K, V>> {
440436
let hash = self.make_hash(q);
441-
search_hashed_generic(&mut self.table, &hash, |k| q.equiv(k)).into_option()
437+
search_hashed(&mut self.table, &hash, |k| q.equiv(k)).into_option()
442438
}
443439

444440
/// Search for a key, yielding the index if it's found in the hashtable.
445441
/// If you already have the hash for the key lying around, use
446442
/// search_hashed.
447-
fn search<'a>(&'a self, k: &K) -> Option<FullBucketImm<'a, K, V>> {
448-
let hash = self.make_hash(k);
449-
search_hashed(&self.table, &hash, k).into_option()
443+
fn search<'a, Sized? Q>(&'a self, q: &Q) -> Option<FullBucketImm<'a, K, V>>
444+
where Q: BorrowFrom<K> + Eq + Hash<S>
445+
{
446+
let hash = self.make_hash(q);
447+
search_hashed(&self.table, &hash, |k| q.eq(BorrowFrom::borrow_from(k)))
448+
.into_option()
450449
}
451450

452-
fn search_mut<'a>(&'a mut self, k: &K) -> Option<FullBucketMut<'a, K, V>> {
453-
let hash = self.make_hash(k);
454-
search_hashed(&mut self.table, &hash, k).into_option()
451+
fn search_mut<'a, Sized? Q>(&'a mut self, q: &Q) -> Option<FullBucketMut<'a, K, V>>
452+
where Q: BorrowFrom<K> + Eq + Hash<S>
453+
{
454+
let hash = self.make_hash(q);
455+
search_hashed(&mut self.table, &hash, |k| q.eq(BorrowFrom::borrow_from(k)))
456+
.into_option()
455457
}
456458

457459
// The caller should ensure that invariants by Robin Hood Hashing hold.
@@ -748,18 +750,14 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
748750
}
749751
}
750752

751-
/// Return true if the map contains a value for the specified key,
752-
/// using equivalence.
753-
///
754-
/// See [pop_equiv](#method.pop_equiv) for an extended example.
753+
/// Deprecated: use `contains_key` and `BorrowFrom` instead.
754+
#[deprecated = "use contains_key and BorrowFrom instead"]
755755
pub fn contains_key_equiv<Sized? Q: Hash<S> + Equiv<K>>(&self, key: &Q) -> bool {
756756
self.search_equiv(key).is_some()
757757
}
758758

759-
/// Return the value corresponding to the key in the map, using
760-
/// equivalence.
761-
///
762-
/// See [pop_equiv](#method.pop_equiv) for an extended example.
759+
/// Deprecated: use `get` and `BorrowFrom` instead.
760+
#[deprecated = "use get and BorrowFrom instead"]
763761
pub fn find_equiv<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a self, k: &Q) -> Option<&'a V> {
764762
match self.search_equiv(k) {
765763
None => None,
@@ -770,52 +768,8 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
770768
}
771769
}
772770

773-
/// Remove an equivalent key from the map, returning the value at the
774-
/// key if the key was previously in the map.
775-
///
776-
/// # Example
777-
///
778-
/// This is a slightly silly example where we define the number's
779-
/// parity as the equivalence class. It is important that the
780-
/// values hash the same, which is why we implement `Hash`.
781-
///
782-
/// ```
783-
/// use std::collections::HashMap;
784-
/// use std::hash::Hash;
785-
/// use std::hash::sip::SipState;
786-
///
787-
/// #[deriving(Eq, PartialEq)]
788-
/// struct EvenOrOdd {
789-
/// num: uint
790-
/// };
791-
///
792-
/// impl Hash for EvenOrOdd {
793-
/// fn hash(&self, state: &mut SipState) {
794-
/// let parity = self.num % 2;
795-
/// parity.hash(state);
796-
/// }
797-
/// }
798-
///
799-
/// impl Equiv<EvenOrOdd> for EvenOrOdd {
800-
/// fn equiv(&self, other: &EvenOrOdd) -> bool {
801-
/// self.num % 2 == other.num % 2
802-
/// }
803-
/// }
804-
///
805-
/// let mut map = HashMap::new();
806-
/// map.insert(EvenOrOdd { num: 3 }, "foo");
807-
///
808-
/// assert!(map.contains_key_equiv(&EvenOrOdd { num: 1 }));
809-
/// assert!(!map.contains_key_equiv(&EvenOrOdd { num: 4 }));
810-
///
811-
/// assert_eq!(map.find_equiv(&EvenOrOdd { num: 5 }), Some(&"foo"));
812-
/// assert_eq!(map.find_equiv(&EvenOrOdd { num: 2 }), None);
813-
///
814-
/// assert_eq!(map.pop_equiv(&EvenOrOdd { num: 1 }), Some("foo"));
815-
/// assert_eq!(map.pop_equiv(&EvenOrOdd { num: 2 }), None);
816-
///
817-
/// ```
818-
#[experimental]
771+
/// Deprecated: use `remove` and `BorrowFrom` instead.
772+
#[deprecated = "use remove and BorrowFrom instead"]
819773
pub fn pop_equiv<Sized? Q:Hash<S> + Equiv<K>>(&mut self, k: &Q) -> Option<V> {
820774
if self.table.size() == 0 {
821775
return None
@@ -1036,6 +990,10 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
1036990

1037991
/// Returns a reference to the value corresponding to the key.
1038992
///
993+
/// The key may be any borrowed form of the map's key type, but
994+
/// `Hash` and `Eq` on the borrowed form *must* match those for
995+
/// the key type.
996+
///
1039997
/// # Example
1040998
///
1041999
/// ```
@@ -1047,7 +1005,9 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
10471005
/// assert_eq!(map.get(&2), None);
10481006
/// ```
10491007
#[unstable = "matches collection reform specification, waiting for dust to settle"]
1050-
pub fn get(&self, k: &K) -> Option<&V> {
1008+
pub fn get<Sized? Q>(&self, k: &Q) -> Option<&V>
1009+
where Q: Hash<S> + Eq + BorrowFrom<K>
1010+
{
10511011
self.search(k).map(|bucket| {
10521012
let (_, v) = bucket.into_refs();
10531013
v
@@ -1056,6 +1016,10 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
10561016

10571017
/// Returns true if the map contains a value for the specified key.
10581018
///
1019+
/// The key may be any borrowed form of the map's key type, but
1020+
/// `Hash` and `Eq` on the borrowed form *must* match those for
1021+
/// the key type.
1022+
///
10591023
/// # Example
10601024
///
10611025
/// ```
@@ -1067,7 +1031,9 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
10671031
/// assert_eq!(map.contains_key(&2), false);
10681032
/// ```
10691033
#[unstable = "matches collection reform specification, waiting for dust to settle"]
1070-
pub fn contains_key(&self, k: &K) -> bool {
1034+
pub fn contains_key<Sized? Q>(&self, k: &Q) -> bool
1035+
where Q: Hash<S> + Eq + BorrowFrom<K>
1036+
{
10711037
self.search(k).is_some()
10721038
}
10731039

@@ -1079,6 +1045,10 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
10791045

10801046
/// Returns a mutable reference to the value corresponding to the key.
10811047
///
1048+
/// The key may be any borrowed form of the map's key type, but
1049+
/// `Hash` and `Eq` on the borrowed form *must* match those for
1050+
/// the key type.
1051+
///
10821052
/// # Example
10831053
///
10841054
/// ```
@@ -1093,7 +1063,9 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
10931063
/// assert_eq!(map[1], "b");
10941064
/// ```
10951065
#[unstable = "matches collection reform specification, waiting for dust to settle"]
1096-
pub fn get_mut(&mut self, k: &K) -> Option<&mut V> {
1066+
pub fn get_mut<Sized? Q>(&mut self, k: &Q) -> Option<&mut V>
1067+
where Q: Hash<S> + Eq + BorrowFrom<K>
1068+
{
10971069
match self.search_mut(k) {
10981070
Some(bucket) => {
10991071
let (_, v) = bucket.into_mut_refs();
@@ -1147,6 +1119,10 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
11471119
/// Removes a key from the map, returning the value at the key if the key
11481120
/// was previously in the map.
11491121
///
1122+
/// The key may be any borrowed form of the map's key type, but
1123+
/// `Hash` and `Eq` on the borrowed form *must* match those for
1124+
/// the key type.
1125+
///
11501126
/// # Example
11511127
///
11521128
/// ```
@@ -1158,7 +1134,9 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
11581134
/// assert_eq!(map.remove(&1), None);
11591135
/// ```
11601136
#[unstable = "matches collection reform specification, waiting for dust to settle"]
1161-
pub fn remove(&mut self, k: &K) -> Option<V> {
1137+
pub fn remove<Sized? Q>(&mut self, k: &Q) -> Option<V>
1138+
where Q: Hash<S> + Eq + BorrowFrom<K>
1139+
{
11621140
if self.table.size() == 0 {
11631141
return None
11641142
}
@@ -1271,16 +1249,20 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> Default for HashMap<K, V, H>
12711249
}
12721250
}
12731251

1274-
impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> Index<K, V> for HashMap<K, V, H> {
1252+
impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> Index<Q, V> for HashMap<K, V, H>
1253+
where Q: BorrowFrom<K> + Hash<S> + Eq
1254+
{
12751255
#[inline]
1276-
fn index<'a>(&'a self, index: &K) -> &'a V {
1256+
fn index<'a>(&'a self, index: &Q) -> &'a V {
12771257
self.get(index).expect("no entry found for key")
12781258
}
12791259
}
12801260

1281-
impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> IndexMut<K, V> for HashMap<K, V, H> {
1261+
impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> IndexMut<Q, V> for HashMap<K, V, H>
1262+
where Q: BorrowFrom<K> + Hash<S> + Eq
1263+
{
12821264
#[inline]
1283-
fn index_mut<'a>(&'a mut self, index: &K) -> &'a mut V {
1265+
fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V {
12841266
match self.get_mut(index) {
12851267
Some(v) => v,
12861268
None => panic!("no entry found for key")

src/libstd/collections/hash/set.rs

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
// ignore-lexer-test FIXME #15883
1212

13+
use borrow::BorrowFrom;
1314
use cmp::{Eq, Equiv, PartialEq};
1415
use core::kinds::Sized;
1516
use default::Default;
@@ -184,47 +185,9 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
184185
self.map.reserve(n)
185186
}
186187

187-
/// Returns true if the hash set contains a value equivalent to the
188-
/// given query value.
189-
///
190-
/// # Example
191-
///
192-
/// This is a slightly silly example where we define the number's
193-
/// parity as the equivalance class. It is important that the
194-
/// values hash the same, which is why we implement `Hash`.
195-
///
196-
/// ```
197-
/// use std::collections::HashSet;
198-
/// use std::hash::Hash;
199-
/// use std::hash::sip::SipState;
200-
///
201-
/// #[deriving(Eq, PartialEq)]
202-
/// struct EvenOrOdd {
203-
/// num: uint
204-
/// };
205-
///
206-
/// impl Hash for EvenOrOdd {
207-
/// fn hash(&self, state: &mut SipState) {
208-
/// let parity = self.num % 2;
209-
/// parity.hash(state);
210-
/// }
211-
/// }
212-
///
213-
/// impl Equiv<EvenOrOdd> for EvenOrOdd {
214-
/// fn equiv(&self, other: &EvenOrOdd) -> bool {
215-
/// self.num % 2 == other.num % 2
216-
/// }
217-
/// }
218-
///
219-
/// let mut set = HashSet::new();
220-
/// set.insert(EvenOrOdd { num: 3u });
221-
///
222-
/// assert!(set.contains_equiv(&EvenOrOdd { num: 3u }));
223-
/// assert!(set.contains_equiv(&EvenOrOdd { num: 5u }));
224-
/// assert!(!set.contains_equiv(&EvenOrOdd { num: 4u }));
225-
/// assert!(!set.contains_equiv(&EvenOrOdd { num: 2u }));
226-
///
227-
/// ```
188+
/// Deprecated: use `contains` and `BorrowFrom`.
189+
#[deprecated = "use contains and BorrowFrom"]
190+
#[allow(deprecated)]
228191
pub fn contains_equiv<Sized? Q: Hash<S> + Equiv<T>>(&self, value: &Q) -> bool {
229192
self.map.contains_key_equiv(value)
230193
}
@@ -427,6 +390,10 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
427390

428391
/// Returns `true` if the set contains a value.
429392
///
393+
/// The value may be any borrowed form of the set's value type, but
394+
/// `Hash` and `Eq` on the borrowed form *must* match those for
395+
/// the value type.
396+
///
430397
/// # Example
431398
///
432399
/// ```
@@ -437,7 +404,11 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
437404
/// assert_eq!(set.contains(&4), false);
438405
/// ```
439406
#[unstable = "matches collection reform specification, waiting for dust to settle"]
440-
pub fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
407+
pub fn contains<Sized? Q>(&self, value: &Q) -> bool
408+
where Q: BorrowFrom<T> + Hash<S> + Eq
409+
{
410+
self.map.contains_key(value)
411+
}
441412

442413
/// Returns `true` if the set has no elements in common with `other`.
443414
/// This is equivalent to checking for an empty intersection.
@@ -527,6 +498,10 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
527498
/// Removes a value from the set. Returns `true` if the value was
528499
/// present in the set.
529500
///
501+
/// The value may be any borrowed form of the set's value type, but
502+
/// `Hash` and `Eq` on the borrowed form *must* match those for
503+
/// the value type.
504+
///
530505
/// # Example
531506
///
532507
/// ```
@@ -539,7 +514,11 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
539514
/// assert_eq!(set.remove(&2), false);
540515
/// ```
541516
#[unstable = "matches collection reform specification, waiting for dust to settle"]
542-
pub fn remove(&mut self, value: &T) -> bool { self.map.remove(value).is_some() }
517+
pub fn remove<Sized? Q>(&mut self, value: &Q) -> bool
518+
where Q: BorrowFrom<T> + Hash<S> + Eq
519+
{
520+
self.map.remove(value).is_some()
521+
}
543522
}
544523

545524
impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {

0 commit comments

Comments
 (0)