Skip to content

Commit fb35dbb

Browse files
authored
Merge pull request rust-lang#10 from bluss/lookup-trait
Abstract key lookup trait, so that it can be extended
2 parents 97f22a3 + fc0dd18 commit fb35dbb

File tree

4 files changed

+88
-31
lines changed

4 files changed

+88
-31
lines changed

benches/bench.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ fn remove_ordermap_100_000(b: &mut Bencher) {
557557
b.iter(|| {
558558
let mut map = map.clone();
559559
for key in &keys {
560-
map.remove(&key).is_some();
560+
map.remove(key).is_some();
561561
}
562562
assert_eq!(map.len(), 0);
563563
map

src/equivalent.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
use std::borrow::Borrow;
3+
4+
/// Key equivalence trait.
5+
///
6+
/// This trait allows hash table lookup to be customized.
7+
/// It has one blanket implementation that uses the regular `Borrow` solution,
8+
/// just like `HashMap` and `BTreeMap` do, so that you can pass `&str` to lookup
9+
/// into a map with `String` keys and so on.
10+
///
11+
/// # Contract
12+
///
13+
/// The implementor must hash like `K`, if applicable.
14+
pub trait Equivalent<K> {
15+
/// Compare self to `key` and return `true` if they are equal.
16+
fn equivalent(&self, key: &K) -> bool;
17+
}
18+
19+
impl<Q: ?Sized, K> Equivalent<K> for Q
20+
where Q: Eq,
21+
K: Borrow<Q>,
22+
{
23+
#[inline]
24+
fn equivalent(&self, key: &K) -> bool {
25+
*self == *key.borrow()
26+
}
27+
}

src/lib.rs

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ mod macros;
55
#[cfg(feature = "serde-1")]
66
mod serde;
77
mod util;
8+
mod equivalent;
89

910
use std::hash::Hash;
1011
use std::hash::BuildHasher;
1112
use std::hash::Hasher;
1213
use std::collections::hash_map::RandomState;
13-
use std::borrow::Borrow;
1414
use std::ops::RangeFull;
1515

1616
use std::cmp::{max, Ordering};
@@ -19,6 +19,7 @@ use std::mem::{replace};
1919
use std::marker::PhantomData;
2020

2121
use util::{second, ptrdistance, enumerate};
22+
pub use equivalent::Equivalent;
2223

2324
fn hash_elem_using<B: BuildHasher, K: ?Sized + Hash>(build: &B, k: &K) -> HashValue {
2425
let mut h = build.build_hasher();
@@ -824,8 +825,7 @@ impl<K, V, S> OrderMap<K, V, S>
824825
///
825826
/// Computes in **O(1)** time (average).
826827
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
827-
where K: Borrow<Q>,
828-
Q: Eq + Hash,
828+
where Q: Hash + Equivalent<K>,
829829
{
830830
self.find(key).is_some()
831831
}
@@ -835,15 +835,13 @@ impl<K, V, S> OrderMap<K, V, S>
835835
///
836836
/// Computes in **O(1)** time (average).
837837
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
838-
where K: Borrow<Q>,
839-
Q: Eq + Hash,
838+
where Q: Hash + Equivalent<K>,
840839
{
841840
self.get_pair(key).map(second)
842841
}
843842

844843
pub fn get_pair<Q: ?Sized>(&self, key: &Q) -> Option<(&K, &V)>
845-
where K: Borrow<Q>,
846-
Q: Eq + Hash,
844+
where Q: Hash + Equivalent<K>,
847845
{
848846
if let Some((_, found)) = self.find(key) {
849847
let entry = &self.entries[found];
@@ -855,8 +853,7 @@ impl<K, V, S> OrderMap<K, V, S>
855853

856854
/// Return item index, key and value
857855
pub fn get_pair_index<Q: ?Sized>(&self, key: &Q) -> Option<(usize, &K, &V)>
858-
where K: Borrow<Q>,
859-
Q: Eq + Hash,
856+
where Q: Hash + Equivalent<K>,
860857
{
861858
if let Some((_, found)) = self.find(key) {
862859
let entry = &self.entries[found];
@@ -867,16 +864,14 @@ impl<K, V, S> OrderMap<K, V, S>
867864
}
868865

869866
pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
870-
where K: Borrow<Q>,
871-
Q: Eq + Hash,
867+
where Q: Hash + Equivalent<K>,
872868
{
873869
self.get_pair_mut(key).map(second)
874870
}
875871

876872
pub fn get_pair_mut<Q: ?Sized>(&mut self, key: &Q)
877873
-> Option<(&mut K, &mut V)>
878-
where K: Borrow<Q>,
879-
Q: Eq + Hash,
874+
where Q: Hash + Equivalent<K>,
880875
{
881876
if let Some((_, found)) = self.find(key) {
882877
let entry = &mut self.entries[found];
@@ -888,8 +883,7 @@ impl<K, V, S> OrderMap<K, V, S>
888883

889884
pub fn get_pair_index_mut<Q: ?Sized>(&mut self, key: &Q)
890885
-> Option<(usize, &mut K, &mut V)>
891-
where K: Borrow<Q>,
892-
Q: Eq + Hash,
886+
where Q: Hash + Equivalent<K>,
893887
{
894888
if let Some((_, found)) = self.find(key) {
895889
let entry = &mut self.entries[found];
@@ -901,12 +895,11 @@ impl<K, V, S> OrderMap<K, V, S>
901895

902896
/// Return probe (indices) and position (entries)
903897
fn find<Q: ?Sized>(&self, key: &Q) -> Option<(usize, usize)>
904-
where K: Borrow<Q>,
905-
Q: Eq + Hash,
898+
where Q: Hash + Equivalent<K>,
906899
{
907900
if self.len() == 0 { return None; }
908901
let h = hash_elem_using(&self.hash_builder, key);
909-
self.find_using(h, move |entry| { *entry.key.borrow() == *key })
902+
self.find_using(h, move |entry| { Q::equivalent(key, &entry.key) })
910903
}
911904

912905
/// Remove the key-value pair equivalent to `key` and return
@@ -920,8 +913,7 @@ impl<K, V, S> OrderMap<K, V, S>
920913
///
921914
/// Computes in **O(1)** time (average).
922915
pub fn swap_remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
923-
where K: Borrow<Q>,
924-
Q: Eq + Hash,
916+
where Q: Hash + Equivalent<K>,
925917
{
926918
self.swap_remove_pair(key).map(second)
927919
}
@@ -930,8 +922,7 @@ impl<K, V, S> OrderMap<K, V, S>
930922
///
931923
/// Computes in **O(1)** time (average).
932924
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
933-
where K: Borrow<Q>,
934-
Q: Eq + Hash,
925+
where Q: Hash + Equivalent<K>,
935926
{
936927
self.swap_remove(key)
937928
}
@@ -944,8 +935,7 @@ impl<K, V, S> OrderMap<K, V, S>
944935
///
945936
/// Return `None` if `key` is not in map.
946937
pub fn swap_remove_pair<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
947-
where K: Borrow<Q>,
948-
Q: Eq + Hash,
938+
where Q: Hash + Equivalent<K>,
949939
{
950940
let (probe, found) = match self.find(key) {
951941
None => return None,
@@ -1470,9 +1460,8 @@ impl<K, V, S> IntoIterator for OrderMap<K, V, S>
14701460
use std::ops::{Index, IndexMut};
14711461

14721462
impl<'a, K, V, Q: ?Sized, S> Index<&'a Q> for OrderMap<K, V, S>
1473-
where K: Eq + Hash,
1474-
K: Borrow<Q>,
1475-
Q: Eq + Hash,
1463+
where Q: Hash + Equivalent<K>,
1464+
K: Hash + Eq,
14761465
S: BuildHasher,
14771466
{
14781467
type Output = V;
@@ -1492,9 +1481,8 @@ impl<'a, K, V, Q: ?Sized, S> Index<&'a Q> for OrderMap<K, V, S>
14921481
///
14931482
/// You can **not** insert new pairs with index syntax, use `.insert()`.
14941483
impl<'a, K, V, Q: ?Sized, S> IndexMut<&'a Q> for OrderMap<K, V, S>
1495-
where K: Eq + Hash,
1496-
K: Borrow<Q>,
1497-
Q: Eq + Hash,
1484+
where Q: Hash + Equivalent<K>,
1485+
K: Hash + Eq,
14981486
S: BuildHasher,
14991487
{
15001488
/// ***Panics*** if `key` is not present in the map.

tests/equivalent_trait.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
#[macro_use] extern crate ordermap;
3+
4+
use ordermap::Equivalent;
5+
6+
use std::hash::Hash;
7+
8+
#[derive(Debug, Hash)]
9+
pub struct Pair<A, B>(pub A, pub B);
10+
11+
impl<A, B, C, D> PartialEq<(A, B)> for Pair<C, D>
12+
where C: PartialEq<A>,
13+
D: PartialEq<B>,
14+
{
15+
fn eq(&self, rhs: &(A, B)) -> bool {
16+
self.0 == rhs.0 &&
17+
self.1 == rhs.1 &&
18+
true
19+
}
20+
}
21+
22+
impl<A, B, X> Equivalent<X> for Pair<A, B>
23+
where Pair<A, B>: PartialEq<X>,
24+
A: Hash + Eq,
25+
B: Hash + Eq,
26+
{
27+
fn equivalent(&self, other: &X) -> bool {
28+
*self == *other
29+
}
30+
}
31+
32+
#[test]
33+
fn test_lookup() {
34+
let s = String::from;
35+
let map = ordermap! {
36+
(s("a"), s("b")) => 1,
37+
(s("a"), s("x")) => 2,
38+
};
39+
40+
assert!(map.contains_key(&Pair("a", "b")));
41+
assert!(!map.contains_key(&Pair("b", "a")));
42+
}

0 commit comments

Comments
 (0)