Skip to content

Commit f94c51f

Browse files
committedFeb 13, 2025··
Use equivalent instead of Borrow for key equality checks.
1 parent c0b6983 commit f94c51f

File tree

5 files changed

+52
-77
lines changed

5 files changed

+52
-77
lines changed
 

‎Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ inline = ["hashbrown/inline-more"]
2222
[dependencies]
2323
lock_api = "0.4.12"
2424
parking_lot_core = "0.9.10"
25+
equivalent = "1.0.1"
2526
hashbrown = { version = "0.15.2", default-features = false }
2627
serde = { version = "1.0.217", optional = true, features = ["derive"] }
2728
cfg-if = "1.0.0"

‎src/lib.rs

+33-58
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ use crate::lock::RwLock;
2929
pub use crate::lock::{RawRwLock, RwLock};
3030

3131
use cfg_if::cfg_if;
32-
use core::borrow::Borrow;
3332
use core::fmt;
3433
use core::hash::{BuildHasher, Hash, Hasher};
3534
use core::iter::FromIterator;
3635
use core::ops::{BitAnd, BitOr, Shl, Shr, Sub};
3736
use crossbeam_utils::CachePadded;
37+
pub use equivalent::Equivalent;
3838
use hashbrown::hash_table;
3939
use iter::{Iter, IterMut, OwningIter};
4040
use lock::{RwLockReadGuardDetached, RwLockWriteGuardDetached};
@@ -389,8 +389,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
389389
/// ```
390390
pub fn determine_map<Q>(&self, key: &Q) -> usize
391391
where
392-
K: Borrow<Q>,
393-
Q: Hash + Eq + ?Sized,
392+
Q: Hash + Equivalent<K> + ?Sized,
394393
{
395394
let hash = self.hash_usize(&key);
396395
self.determine_shard(hash)
@@ -508,8 +507,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
508507
/// ```
509508
pub fn remove<Q>(&self, key: &Q) -> Option<(K, V)>
510509
where
511-
K: Borrow<Q>,
512-
Q: Hash + Eq + ?Sized,
510+
Q: Hash + Equivalent<K> + ?Sized,
513511
{
514512
self._remove(key)
515513
}
@@ -537,16 +535,14 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
537535
/// ```
538536
pub fn remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K, &V) -> bool) -> Option<(K, V)>
539537
where
540-
K: Borrow<Q>,
541-
Q: Hash + Eq + ?Sized,
538+
Q: Hash + Equivalent<K> + ?Sized,
542539
{
543540
self._remove_if(key, f)
544541
}
545542

546543
pub fn remove_if_mut<Q>(&self, key: &Q, f: impl FnOnce(&K, &mut V) -> bool) -> Option<(K, V)>
547544
where
548-
K: Borrow<Q>,
549-
Q: Hash + Eq + ?Sized,
545+
Q: Hash + Equivalent<K> + ?Sized,
550546
{
551547
self._remove_if_mut(key, f)
552548
}
@@ -601,8 +597,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
601597
/// ```
602598
pub fn get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K, V>>
603599
where
604-
K: Borrow<Q>,
605-
Q: Hash + Eq + ?Sized,
600+
Q: Hash + Equivalent<K> + ?Sized,
606601
{
607602
self._get(key)
608603
}
@@ -623,8 +618,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
623618
/// ```
624619
pub fn get_mut<Q>(&'a self, key: &Q) -> Option<RefMut<'a, K, V>>
625620
where
626-
K: Borrow<Q>,
627-
Q: Hash + Eq + ?Sized,
621+
Q: Hash + Equivalent<K> + ?Sized,
628622
{
629623
self._get_mut(key)
630624
}
@@ -650,8 +644,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
650644
/// ```
651645
pub fn try_get<Q>(&'a self, key: &Q) -> TryResult<Ref<'a, K, V>>
652646
where
653-
K: Borrow<Q>,
654-
Q: Hash + Eq + ?Sized,
647+
Q: Hash + Equivalent<K> + ?Sized,
655648
{
656649
self._try_get(key)
657650
}
@@ -678,8 +671,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
678671
/// ```
679672
pub fn try_get_mut<Q>(&'a self, key: &Q) -> TryResult<RefMut<'a, K, V>>
680673
where
681-
K: Borrow<Q>,
682-
Q: Hash + Eq + ?Sized,
674+
Q: Hash + Equivalent<K> + ?Sized,
683675
{
684676
self._try_get_mut(key)
685677
}
@@ -806,8 +798,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
806798
/// If the given closure panics, then `alter` will abort the process
807799
pub fn alter<Q>(&self, key: &Q, f: impl FnOnce(&K, V) -> V)
808800
where
809-
K: Borrow<Q>,
810-
Q: Hash + Eq + ?Sized,
801+
Q: Hash + Equivalent<K> + ?Sized,
811802
{
812803
self._alter(key, f);
813804
}
@@ -857,8 +848,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
857848
/// If the given closure panics, then `view` will abort the process
858849
pub fn view<Q, R>(&self, key: &Q, f: impl FnOnce(&K, &V) -> R) -> Option<R>
859850
where
860-
K: Borrow<Q>,
861-
Q: Hash + Eq + ?Sized,
851+
Q: Hash + Equivalent<K> + ?Sized,
862852
{
863853
self._view(key, f)
864854
}
@@ -878,8 +868,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
878868
/// ```
879869
pub fn contains_key<Q>(&self, key: &Q) -> bool
880870
where
881-
K: Borrow<Q>,
882-
Q: Hash + Eq + ?Sized,
871+
Q: Hash + Equivalent<K> + ?Sized,
883872
{
884873
self._contains_key(key)
885874
}
@@ -936,16 +925,15 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
936925

937926
fn _remove<Q>(&self, key: &Q) -> Option<(K, V)>
938927
where
939-
K: Borrow<Q>,
940-
Q: Hash + Eq + ?Sized,
928+
Q: Hash + Equivalent<K> + ?Sized,
941929
{
942930
let hash = self.hash_u64(&key);
943931

944932
let idx = self.determine_shard(hash as usize);
945933

946934
let mut shard = self.shards[idx].write();
947935

948-
if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key == k.borrow()) {
936+
if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key.equivalent(k)) {
949937
let ((k, v), _) = entry.remove();
950938
Some((k, v))
951939
} else {
@@ -955,16 +943,15 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
955943

956944
fn _remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K, &V) -> bool) -> Option<(K, V)>
957945
where
958-
K: Borrow<Q>,
959-
Q: Hash + Eq + ?Sized,
946+
Q: Hash + Equivalent<K> + ?Sized,
960947
{
961948
let hash = self.hash_u64(&key);
962949

963950
let idx = self.determine_shard(hash as usize);
964951

965952
let mut shard = self.shards[idx].write();
966953

967-
if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key == k.borrow()) {
954+
if let Ok(entry) = shard.find_entry(hash, |(k, _v)| key.equivalent(k)) {
968955
let (k, v) = entry.get();
969956
if f(k, v) {
970957
let ((k, v), _) = entry.remove();
@@ -979,16 +966,15 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
979966

980967
fn _remove_if_mut<Q>(&self, key: &Q, f: impl FnOnce(&K, &mut V) -> bool) -> Option<(K, V)>
981968
where
982-
K: Borrow<Q>,
983-
Q: Hash + Eq + ?Sized,
969+
Q: Hash + Equivalent<K> + ?Sized,
984970
{
985971
let hash = self.hash_u64(&key);
986972

987973
let idx = self.determine_shard(hash as usize);
988974

989975
let mut shard = self.shards[idx].write();
990976

991-
if let Ok(mut entry) = shard.find_entry(hash, |(k, _v)| key == k.borrow()) {
977+
if let Ok(mut entry) = shard.find_entry(hash, |(k, _v)| key.equivalent(k)) {
992978
let (k, v) = entry.get_mut();
993979
if f(k, v) {
994980
let ((k, v), _) = entry.remove();
@@ -1011,8 +997,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
1011997

1012998
fn _get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K, V>>
1013999
where
1014-
K: Borrow<Q>,
1015-
Q: Hash + Eq + ?Sized,
1000+
Q: Hash + Equivalent<K> + ?Sized,
10161001
{
10171002
let hash = self.hash_u64(&key);
10181003

@@ -1022,7 +1007,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
10221007
// SAFETY: The data will not outlive the guard, since we pass the guard to `Ref`.
10231008
let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(shard) };
10241009

1025-
if let Some((k, v)) = shard.find(hash, |(k, _v)| key == k.borrow()) {
1010+
if let Some((k, v)) = shard.find(hash, |(k, _v)| key.equivalent(k)) {
10261011
Some(Ref::new(guard, k, v))
10271012
} else {
10281013
None
@@ -1031,8 +1016,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
10311016

10321017
fn _get_mut<Q>(&'a self, key: &Q) -> Option<RefMut<'a, K, V>>
10331018
where
1034-
K: Borrow<Q>,
1035-
Q: Hash + Eq + ?Sized,
1019+
Q: Hash + Equivalent<K> + ?Sized,
10361020
{
10371021
let hash = self.hash_u64(&key);
10381022

@@ -1042,7 +1026,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
10421026
// SAFETY: The data will not outlive the guard, since we pass the guard to `RefMut`.
10431027
let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) };
10441028

1045-
if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key == k.borrow()) {
1029+
if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key.equivalent(k)) {
10461030
Some(RefMut::new(guard, k, v))
10471031
} else {
10481032
None
@@ -1051,8 +1035,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
10511035

10521036
fn _try_get<Q>(&'a self, key: &Q) -> TryResult<Ref<'a, K, V>>
10531037
where
1054-
K: Borrow<Q>,
1055-
Q: Hash + Eq + ?Sized,
1038+
Q: Hash + Equivalent<K> + ?Sized,
10561039
{
10571040
let hash = self.hash_u64(&key);
10581041

@@ -1065,7 +1048,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
10651048
// SAFETY: The data will not outlive the guard, since we pass the guard to `Ref`.
10661049
let (guard, shard) = unsafe { RwLockReadGuardDetached::detach_from(shard) };
10671050

1068-
if let Some((k, v)) = shard.find(hash, |(k, _v)| key == k.borrow()) {
1051+
if let Some((k, v)) = shard.find(hash, |(k, _v)| key.equivalent(k)) {
10691052
TryResult::Present(Ref::new(guard, k, v))
10701053
} else {
10711054
TryResult::Absent
@@ -1074,8 +1057,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
10741057

10751058
fn _try_get_mut<Q>(&'a self, key: &Q) -> TryResult<RefMut<'a, K, V>>
10761059
where
1077-
K: Borrow<Q>,
1078-
Q: Hash + Eq + ?Sized,
1060+
Q: Hash + Equivalent<K> + ?Sized,
10791061
{
10801062
let hash = self.hash_u64(&key);
10811063

@@ -1088,7 +1070,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
10881070
// SAFETY: The data will not outlive the guard, since we pass the guard to `RefMut`.
10891071
let (guard, shard) = unsafe { RwLockWriteGuardDetached::detach_from(shard) };
10901072

1091-
if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key == k.borrow()) {
1073+
if let Some((k, v)) = shard.find_mut(hash, |(k, _v)| key.equivalent(k)) {
10921074
TryResult::Present(RefMut::new(guard, k, v))
10931075
} else {
10941076
TryResult::Absent
@@ -1123,8 +1105,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
11231105

11241106
fn _alter<Q>(&self, key: &Q, f: impl FnOnce(&K, V) -> V)
11251107
where
1126-
K: Borrow<Q>,
1127-
Q: Hash + Eq + ?Sized,
1108+
Q: Hash + Equivalent<K> + ?Sized,
11281109
{
11291110
if let Some(mut r) = self.get_mut(key) {
11301111
util::map_in_place_2(r.pair_mut(), f);
@@ -1138,8 +1119,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
11381119

11391120
fn _view<Q, R>(&self, key: &Q, f: impl FnOnce(&K, &V) -> R) -> Option<R>
11401121
where
1141-
K: Borrow<Q>,
1142-
Q: Hash + Eq + ?Sized,
1122+
Q: Hash + Equivalent<K> + ?Sized,
11431123
{
11441124
self.get(key).map(|r| {
11451125
let (k, v) = r.pair();
@@ -1208,8 +1188,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> DashMap<K, V, S>
12081188

12091189
fn _contains_key<Q>(&'a self, key: &Q) -> bool
12101190
where
1211-
K: Borrow<Q>,
1212-
Q: Hash + Eq + ?Sized,
1191+
Q: Hash + Equivalent<K> + ?Sized,
12131192
{
12141193
self._get(key).is_some()
12151194
}
@@ -1245,8 +1224,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> Shl<(K, V)> for &'a D
12451224

12461225
impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> Shr<&Q> for &'a DashMap<K, V, S>
12471226
where
1248-
K: Borrow<Q>,
1249-
Q: Hash + Eq + ?Sized,
1227+
Q: Hash + Equivalent<K> + ?Sized,
12501228
{
12511229
type Output = Ref<'a, K, V>;
12521230

@@ -1257,8 +1235,7 @@ where
12571235

12581236
impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> BitOr<&Q> for &'a DashMap<K, V, S>
12591237
where
1260-
K: Borrow<Q>,
1261-
Q: Hash + Eq + ?Sized,
1238+
Q: Hash + Equivalent<K> + ?Sized,
12621239
{
12631240
type Output = RefMut<'a, K, V>;
12641241

@@ -1269,8 +1246,7 @@ where
12691246

12701247
impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> Sub<&Q> for &'a DashMap<K, V, S>
12711248
where
1272-
K: Borrow<Q>,
1273-
Q: Hash + Eq + ?Sized,
1249+
Q: Hash + Equivalent<K> + ?Sized,
12741250
{
12751251
type Output = Option<(K, V)>;
12761252

@@ -1281,8 +1257,7 @@ where
12811257

12821258
impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> BitAnd<&Q> for &'a DashMap<K, V, S>
12831259
where
1284-
K: Borrow<Q>,
1285-
Q: Hash + Eq + ?Sized,
1260+
Q: Hash + Equivalent<K> + ?Sized,
12861261
{
12871262
type Output = bool;
12881263

‎src/read_only.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use crate::lock::RwLock;
22
use crate::{DashMap, HashMap};
33
use cfg_if::cfg_if;
4-
use core::borrow::Borrow;
54
use core::fmt;
65
use core::hash::{BuildHasher, Hash};
76
use crossbeam_utils::CachePadded;
7+
use equivalent::Equivalent;
88
use std::collections::hash_map::RandomState;
99

1010
/// A read-only view into a `DashMap`. Allows to obtain raw references to the stored values.
@@ -58,26 +58,23 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
5858
/// Returns `true` if the map contains a value for the specified key.
5959
pub fn contains_key<Q>(&'a self, key: &Q) -> bool
6060
where
61-
K: Borrow<Q>,
62-
Q: Hash + Eq + ?Sized,
61+
Q: Hash + Equivalent<K> + ?Sized,
6362
{
6463
self.get(key).is_some()
6564
}
6665

6766
/// Returns a reference to the value corresponding to the key.
6867
pub fn get<Q>(&'a self, key: &Q) -> Option<&'a V>
6968
where
70-
K: Borrow<Q>,
71-
Q: Hash + Eq + ?Sized,
69+
Q: Hash + Equivalent<K> + ?Sized,
7270
{
7371
self.get_key_value(key).map(|(_k, v)| v)
7472
}
7573

7674
/// Returns the key-value pair corresponding to the supplied key.
7775
pub fn get_key_value<Q>(&'a self, key: &Q) -> Option<(&'a K, &'a V)>
7876
where
79-
K: Borrow<Q>,
80-
Q: Hash + Eq + ?Sized,
77+
Q: Hash + Equivalent<K> + ?Sized,
8178
{
8279
let hash = self.map.hash_u64(&key);
8380

@@ -87,7 +84,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
8784
let shard = unsafe { &*shard.data_ptr() };
8885

8986
shard
90-
.find(hash, |(k, _v)| key == k.borrow())
87+
.find(hash, |(k, _v)| key.equivalent(k))
9188
.map(|(k, v)| (k, v))
9289
}
9390

‎src/set.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ use crate::DashMap;
66
#[cfg(feature = "raw-api")]
77
use crate::HashMap;
88
use cfg_if::cfg_if;
9-
use core::borrow::Borrow;
109
use core::fmt;
1110
use core::hash::{BuildHasher, Hash};
1211
use core::iter::FromIterator;
1312
#[cfg(feature = "raw-api")]
1413
use crossbeam_utils::CachePadded;
14+
use equivalent::Equivalent;
1515
use std::collections::hash_map::RandomState;
1616

1717
/// DashSet is a thin wrapper around [`DashMap`] using `()` as the value type. It uses
@@ -163,8 +163,7 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
163163
/// ```
164164
pub fn determine_map<Q>(&self, key: &Q) -> usize
165165
where
166-
K: Borrow<Q>,
167-
Q: Hash + Eq + ?Sized,
166+
Q: Hash + Equivalent<K> + ?Sized,
168167
{
169168
self.inner.determine_map(key)
170169
}
@@ -220,8 +219,7 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
220219
/// ```
221220
pub fn remove<Q>(&self, key: &Q) -> Option<K>
222221
where
223-
K: Borrow<Q>,
224-
Q: Hash + Eq + ?Sized,
222+
Q: Hash + Equivalent<K> + ?Sized,
225223
{
226224
self.inner.remove(key).map(|(k, _)| k)
227225
}
@@ -247,8 +245,7 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
247245
/// ```
248246
pub fn remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K) -> bool) -> Option<K>
249247
where
250-
K: Borrow<Q>,
251-
Q: Hash + Eq + ?Sized,
248+
Q: Hash + Equivalent<K> + ?Sized,
252249
{
253250
// TODO: Don't create another closure around f
254251
self.inner.remove_if(key, |k, _| f(k)).map(|(k, _)| k)
@@ -284,8 +281,7 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
284281
/// ```
285282
pub fn get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K>>
286283
where
287-
K: Borrow<Q>,
288-
Q: Hash + Eq + ?Sized,
284+
Q: Hash + Equivalent<K> + ?Sized,
289285
{
290286
self.inner.get(key).map(Ref::new)
291287
}
@@ -380,8 +376,7 @@ impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> {
380376
/// ```
381377
pub fn contains<Q>(&self, key: &Q) -> bool
382378
where
383-
K: Borrow<Q>,
384-
Q: Hash + Eq + ?Sized,
379+
Q: Hash + Equivalent<K> + ?Sized,
385380
{
386381
self.inner.contains_key(key)
387382
}

0 commit comments

Comments
 (0)
Please sign in to comment.