Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abstract key lookup trait, so that it can be extended #10

Merged
merged 1 commit into from Sep 11, 2017
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.
+88 −31
Diff settings

Always

Just for now

Copy path View file
@@ -557,7 +557,7 @@ fn remove_ordermap_100_000(b: &mut Bencher) {
b.iter(|| {
let mut map = map.clone();
for key in &keys {
map.remove(&key).is_some();
map.remove(key).is_some();
}
assert_eq!(map.len(), 0);
map
Copy path View file
@@ -0,0 +1,27 @@

use std::borrow::Borrow;

/// Key equivalence trait.
///
/// This trait allows hash table lookup to be customized.
/// It has one blanket implementation that uses the regular `Borrow` solution,
/// just like `HashMap` and `BTreeMap` do, so that you can pass `&str` to lookup
/// into a map with `String` keys and so on.
///
/// # Contract
///
/// The implementor must hash like `K`, if applicable.
pub trait Equivalent<K> {
/// Compare self to `key` and return `true` if they are equal.
fn equivalent(&self, key: &K) -> bool;
}

impl<Q: ?Sized, K> Equivalent<K> for Q
where Q: Eq,
K: Borrow<Q>,
{
#[inline]
fn equivalent(&self, key: &K) -> bool {
*self == *key.borrow()
}
}
Copy path View file
@@ -5,12 +5,12 @@ mod macros;
#[cfg(feature = "serde-1")]
mod serde;
mod util;
mod equivalent;

use std::hash::Hash;
use std::hash::BuildHasher;
use std::hash::Hasher;
use std::collections::hash_map::RandomState;
use std::borrow::Borrow;
use std::ops::RangeFull;

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

use util::{second, ptrdistance, enumerate};
pub use equivalent::Equivalent;

fn hash_elem_using<B: BuildHasher, K: ?Sized + Hash>(build: &B, k: &K) -> HashValue {
let mut h = build.build_hasher();
@@ -824,8 +825,7 @@ impl<K, V, S> OrderMap<K, V, S>
///
/// Computes in **O(1)** time (average).
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
where K: Borrow<Q>,
Q: Eq + Hash,
where Q: Hash + Equivalent<K>,
{
self.find(key).is_some()
}
@@ -835,15 +835,13 @@ impl<K, V, S> OrderMap<K, V, S>
///
/// Computes in **O(1)** time (average).
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
where K: Borrow<Q>,
Q: Eq + Hash,
where Q: Hash + Equivalent<K>,
{
self.get_pair(key).map(second)
}

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

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

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

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

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

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

/// Remove the key-value pair equivalent to `key` and return
@@ -920,8 +913,7 @@ impl<K, V, S> OrderMap<K, V, S>
///
/// Computes in **O(1)** time (average).
pub fn swap_remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
where K: Borrow<Q>,
Q: Eq + Hash,
where Q: Hash + Equivalent<K>,
{
self.swap_remove_pair(key).map(second)
}
@@ -930,8 +922,7 @@ impl<K, V, S> OrderMap<K, V, S>
///
/// Computes in **O(1)** time (average).
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
where K: Borrow<Q>,
Q: Eq + Hash,
where Q: Hash + Equivalent<K>,
{
self.swap_remove(key)
}
@@ -944,8 +935,7 @@ impl<K, V, S> OrderMap<K, V, S>
///
/// Return `None` if `key` is not in map.
pub fn swap_remove_pair<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
where K: Borrow<Q>,
Q: Eq + Hash,
where Q: Hash + Equivalent<K>,
{
let (probe, found) = match self.find(key) {
None => return None,
@@ -1470,9 +1460,8 @@ impl<K, V, S> IntoIterator for OrderMap<K, V, S>
use std::ops::{Index, IndexMut};

impl<'a, K, V, Q: ?Sized, S> Index<&'a Q> for OrderMap<K, V, S>
where K: Eq + Hash,
K: Borrow<Q>,
Q: Eq + Hash,
where Q: Hash + Equivalent<K>,
K: Hash + Eq,
S: BuildHasher,
{
type Output = V;
@@ -1492,9 +1481,8 @@ impl<'a, K, V, Q: ?Sized, S> Index<&'a Q> for OrderMap<K, V, S>
///
/// You can **not** insert new pairs with index syntax, use `.insert()`.
impl<'a, K, V, Q: ?Sized, S> IndexMut<&'a Q> for OrderMap<K, V, S>
where K: Eq + Hash,
K: Borrow<Q>,
Q: Eq + Hash,
where Q: Hash + Equivalent<K>,
K: Hash + Eq,
S: BuildHasher,
{
/// ***Panics*** if `key` is not present in the map.
Copy path View file
@@ -0,0 +1,42 @@

#[macro_use] extern crate ordermap;

use ordermap::Equivalent;

use std::hash::Hash;

#[derive(Debug, Hash)]
pub struct Pair<A, B>(pub A, pub B);

impl<A, B, C, D> PartialEq<(A, B)> for Pair<C, D>
where C: PartialEq<A>,
D: PartialEq<B>,
{
fn eq(&self, rhs: &(A, B)) -> bool {
self.0 == rhs.0 &&
self.1 == rhs.1 &&
true
}
}

impl<A, B, X> Equivalent<X> for Pair<A, B>
where Pair<A, B>: PartialEq<X>,
A: Hash + Eq,
B: Hash + Eq,
{
fn equivalent(&self, other: &X) -> bool {
*self == *other
}
}

#[test]
fn test_lookup() {
let s = String::from;
let map = ordermap! {
(s("a"), s("b")) => 1,
(s("a"), s("x")) => 2,
};

assert!(map.contains_key(&Pair("a", "b")));
assert!(!map.contains_key(&Pair("b", "a")));
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.