Skip to content

Commit 39f439f

Browse files
authored
Merge pull request #47 from jonhoo/steal-from-44
Steal good commits from #44
2 parents 82111cf + 3bf1f8b commit 39f439f

File tree

6 files changed

+64
-52
lines changed

6 files changed

+64
-52
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ crossbeam-epoch = "0.9"
2727
parking_lot = "0.10"
2828
num_cpus = "1.12.0"
2929

30+
[dependencies.ahash]
31+
version = "0.3.2"
32+
default-features = false
33+
3034
[dev-dependencies]
3135
rand = "0.7"
3236
rayon = "1.3"

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@
196196
#![deny(
197197
missing_docs,
198198
missing_debug_implementations,
199+
unreachable_pub,
199200
intra_doc_link_resolution_failure
200201
)]
201202
#![warn(rust_2018_idioms)]
@@ -209,6 +210,9 @@ pub mod iter;
209210

210211
pub use map::HashMap;
211212

213+
/// Default hasher for [`HashMap`].
214+
pub type DefaultHashBuilder = ahash::RandomState;
215+
212216
/// Types needed to safely access shared data concurrently.
213217
pub mod epoch {
214218
pub use crossbeam_epoch::{pin, Guard};

src/map.rs

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use crate::node::*;
33
use crate::raw::*;
44
use crossbeam_epoch::{self as epoch, Atomic, Guard, Owned, Shared};
55
use std::borrow::Borrow;
6-
use std::collections::hash_map::RandomState;
76
use std::fmt::{self, Debug, Formatter};
87
use std::hash::{BuildHasher, Hash, Hasher};
98
use std::iter::FromIterator;
@@ -12,18 +11,14 @@ use std::sync::{
1211
Once,
1312
};
1413

15-
macro_rules! isize_bits {
16-
() => {
17-
std::mem::size_of::<isize>() * 8
18-
};
19-
}
14+
const ISIZE_BITS: usize = core::mem::size_of::<isize>() * 8;
2015

2116
/// The largest possible table capacity. This value must be
2217
/// exactly 1<<30 to stay within Java array allocation and indexing
2318
/// bounds for power of two table sizes, and is further required
2419
/// because the top two bits of 32bit hash fields are used for
2520
/// control purposes.
26-
const MAXIMUM_CAPACITY: usize = 1 << 30; // TODO: use isize_bits!()
21+
const MAXIMUM_CAPACITY: usize = 1 << 30; // TODO: use ISIZE_BITS
2722

2823
/// The default initial table capacity. Must be a power of 2
2924
/// (i.e., at least 1) and at most `MAXIMUM_CAPACITY`.
@@ -38,15 +33,15 @@ const MIN_TRANSFER_STRIDE: isize = 16;
3833

3934
/// The number of bits used for generation stamp in `size_ctl`.
4035
/// Must be at least 6 for 32bit arrays.
41-
const RESIZE_STAMP_BITS: usize = isize_bits!() / 2;
36+
const RESIZE_STAMP_BITS: usize = ISIZE_BITS / 2;
4237

4338
/// The maximum number of threads that can help resize.
4439
/// Must fit in `32 - RESIZE_STAMP_BITS` bits for 32 bit architectures
4540
/// and `64 - RESIZE_STAMP_BITS` bits for 64 bit architectures
46-
const MAX_RESIZERS: isize = (1 << (isize_bits!() - RESIZE_STAMP_BITS)) - 1;
41+
const MAX_RESIZERS: isize = (1 << (ISIZE_BITS - RESIZE_STAMP_BITS)) - 1;
4742

4843
/// The bit shift for recording size stamp in `size_ctl`.
49-
const RESIZE_STAMP_SHIFT: usize = isize_bits!() - RESIZE_STAMP_BITS;
44+
const RESIZE_STAMP_SHIFT: usize = ISIZE_BITS - RESIZE_STAMP_BITS;
5045

5146
static NCPU_INITIALIZER: Once = Once::new();
5247
static NCPU: AtomicUsize = AtomicUsize::new(0);
@@ -61,7 +56,7 @@ macro_rules! load_factor {
6156
/// A concurrent hash table.
6257
///
6358
/// See the [crate-level documentation](index.html) for details.
64-
pub struct HashMap<K, V, S = RandomState> {
59+
pub struct HashMap<K, V, S = crate::DefaultHashBuilder> {
6560
/// The array of bins. Lazily initialized upon first insertion.
6661
/// Size is always a power of two. Accessed directly by iterators.
6762
table: Atomic<Table<K, V>>,
@@ -85,30 +80,32 @@ pub struct HashMap<K, V, S = RandomState> {
8580
build_hasher: S,
8681
}
8782

88-
impl<K, V> Default for HashMap<K, V, RandomState>
83+
impl<K, V, S> Default for HashMap<K, V, S>
8984
where
9085
K: Sync + Send + Clone + Hash + Eq,
9186
V: Sync + Send,
87+
S: BuildHasher + Default,
9288
{
9389
fn default() -> Self {
9490
Self::new()
9591
}
9692
}
9793

98-
impl<K, V> HashMap<K, V, RandomState>
94+
impl<K, V, S> HashMap<K, V, S>
9995
where
10096
K: Sync + Send + Clone + Hash + Eq,
10197
V: Sync + Send,
98+
S: BuildHasher + Default,
10299
{
103100
/// Creates a new, empty map with the default initial table size (16).
104101
pub fn new() -> Self {
105-
Self::with_hasher(RandomState::new())
102+
Self::with_hasher(S::default())
106103
}
107104

108105
/// Creates a new, empty map with an initial table size accommodating the specified number of
109106
/// elements without the need to dynamically resize.
110107
pub fn with_capacity(n: usize) -> Self {
111-
Self::with_capacity_and_hasher(RandomState::new(), n)
108+
Self::with_capacity_and_hasher(S::default(), n)
112109
}
113110
}
114111

@@ -172,16 +169,16 @@ where
172169
h.finish()
173170
}
174171

172+
#[inline]
175173
/// Tests if `key` is a key in this table.
176174
///
177175
/// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed
178176
/// form must match those for the key type.
179-
pub fn contains_key<Q>(&self, key: &Q) -> bool
177+
pub fn contains_key<Q>(&self, key: &Q, guard: &Guard) -> bool
180178
where
181179
K: Borrow<Q>,
182180
Q: ?Sized + Hash + Eq,
183181
{
184-
let guard = crossbeam_epoch::pin();
185182
self.get(key, &guard).is_some()
186183
}
187184

@@ -261,19 +258,19 @@ where
261258
unsafe { v.as_ref() }
262259
}
263260

261+
#[inline]
264262
/// Obtains the value to which `key` is mapped and passes it through the closure `then`.
265263
///
266264
/// Returns `None` if this map contains no mapping for `key`.
267265
///
268266
/// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed
269267
/// form must match those for the key type.
270-
pub fn get_and<Q, R, F>(&self, key: &Q, then: F) -> Option<R>
268+
pub fn get_and<Q, R, F>(&self, key: &Q, then: F, guard: &Guard) -> Option<R>
271269
where
272270
K: Borrow<Q>,
273271
Q: ?Sized + Hash + Eq,
274272
F: FnOnce(&V) -> R,
275273
{
276-
let guard = &crossbeam_epoch::pin();
277274
self.get(key, guard).map(then)
278275
}
279276

@@ -536,7 +533,7 @@ where
536533
}
537534
}
538535

539-
fn put_all<'g, I: Iterator<Item = (K, V)>>(&self, iter: I, guard: &'g Guard) {
536+
fn put_all<I: Iterator<Item = (K, V)>>(&self, iter: I, guard: &Guard) {
540537
for (key, value) in iter {
541538
self.put(key, value, false, guard);
542539
}
@@ -1164,7 +1161,7 @@ where
11641161
}
11651162

11661163
/// Tries to presize table to accommodate the given number of elements.
1167-
fn try_presize<'g>(&self, size: usize, guard: &'g Guard) {
1164+
fn try_presize(&self, size: usize, guard: &Guard) {
11681165
let requested_capacity = if size >= MAXIMUM_CAPACITY / 2 {
11691166
MAXIMUM_CAPACITY
11701167
} else {
@@ -1275,11 +1272,9 @@ where
12751272
#[inline]
12761273
/// Tries to reserve capacity for at least additional more elements.
12771274
/// The collection may reserve more space to avoid frequent reallocations.
1278-
pub fn reserve(&self, additional: usize) {
1275+
pub fn reserve(&self, additional: usize, guard: &Guard) {
12791276
let absolute = self.len() + additional;
1280-
1281-
let guard = epoch::pin();
1282-
self.try_presize(absolute, &guard);
1277+
self.try_presize(absolute, guard);
12831278
}
12841279

12851280
/// Removes the key (and its corresponding value) from this map.
@@ -1472,16 +1467,15 @@ where
14721467
/// If `f` returns `false` for a given key/value pair, but the value for that pair is concurrently
14731468
/// modified before the removal takes place, the entry will not be removed.
14741469
/// If you want the removal to happen even in the case of concurrent modification, use [`HashMap::retain_force`].
1475-
pub fn retain<F>(&self, mut f: F)
1470+
pub fn retain<F>(&self, mut f: F, guard: &Guard)
14761471
where
14771472
F: FnMut(&K, &V) -> bool,
14781473
{
1479-
let guard = epoch::pin();
14801474
// removed selected keys
14811475
for (k, v) in self.iter(&guard) {
14821476
if !f(k, v) {
14831477
let old_value: Shared<'_, V> = Shared::from(v as *const V);
1484-
self.replace_node(k, None, Some(old_value), &guard);
1478+
self.replace_node(k, None, Some(old_value), guard);
14851479
}
14861480
}
14871481
}
@@ -1492,15 +1486,14 @@ where
14921486
///
14931487
/// This method always deletes any key/value pair that `f` returns `false` for,
14941488
/// even if if the value is updated concurrently. If you do not want that behavior, use [`HashMap::retain`].
1495-
pub fn retain_force<F>(&self, mut f: F)
1489+
pub fn retain_force<F>(&self, mut f: F, guard: &Guard)
14961490
where
14971491
F: FnMut(&K, &V) -> bool,
14981492
{
1499-
let guard = epoch::pin();
15001493
// removed selected keys
15011494
for (k, v) in self.iter(&guard) {
15021495
if !f(k, v) {
1503-
self.replace_node(k, None, None, &guard);
1496+
self.replace_node(k, None, None, guard);
15041497
}
15051498
}
15061499
}
@@ -1544,7 +1537,7 @@ where
15441537
#[inline]
15451538
#[cfg(test)]
15461539
/// Returns the capacity of the map.
1547-
fn capacity<'g>(&self, guard: &'g Guard) -> usize {
1540+
fn capacity(&self, guard: &Guard) -> usize {
15481541
let table = self.table.load(Ordering::Relaxed, &guard);
15491542

15501543
if table.is_null() {
@@ -1644,9 +1637,9 @@ where
16441637
(iter.size_hint().0 + 1) / 2
16451638
};
16461639

1647-
self.reserve(reserve);
1640+
let guard = epoch::pin();
16481641

1649-
let guard = crossbeam_epoch::pin();
1642+
self.reserve(reserve, &guard);
16501643
(*self).put_all(iter.into_iter(), &guard);
16511644
}
16521645
}
@@ -1663,10 +1656,11 @@ where
16631656
}
16641657
}
16651658

1666-
impl<K, V> FromIterator<(K, V)> for HashMap<K, V, RandomState>
1659+
impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S>
16671660
where
16681661
K: Sync + Send + Clone + Hash + Eq,
16691662
V: Sync + Send,
1663+
S: BuildHasher + Default,
16701664
{
16711665
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
16721666
let mut iter = iter.into_iter();
@@ -1688,21 +1682,23 @@ where
16881682
}
16891683
}
16901684

1691-
impl<'a, K, V> FromIterator<(&'a K, &'a V)> for HashMap<K, V, RandomState>
1685+
impl<'a, K, V, S> FromIterator<(&'a K, &'a V)> for HashMap<K, V, S>
16921686
where
16931687
K: Sync + Send + Copy + Hash + Eq,
16941688
V: Sync + Send + Copy,
1689+
S: BuildHasher + Default,
16951690
{
16961691
#[inline]
16971692
fn from_iter<T: IntoIterator<Item = (&'a K, &'a V)>>(iter: T) -> Self {
16981693
Self::from_iter(iter.into_iter().map(|(&k, &v)| (k, v)))
16991694
}
17001695
}
17011696

1702-
impl<'a, K, V> FromIterator<&'a (K, V)> for HashMap<K, V, RandomState>
1697+
impl<'a, K, V, S> FromIterator<&'a (K, V)> for HashMap<K, V, S>
17031698
where
17041699
K: Sync + Send + Copy + Hash + Eq,
17051700
V: Sync + Send + Copy,
1701+
S: BuildHasher + Default,
17061702
{
17071703
#[inline]
17081704
fn from_iter<T: IntoIterator<Item = &'a (K, V)>>(iter: T) -> Self {
@@ -1733,7 +1729,6 @@ where
17331729
/// Returns the number of physical CPUs in the machine (_O(1)_).
17341730
fn num_cpus() -> usize {
17351731
NCPU_INITIALIZER.call_once(|| NCPU.store(num_cpus::get_physical(), Ordering::Relaxed));
1736-
17371732
NCPU.load(Ordering::Relaxed)
17381733
}
17391734

@@ -1764,6 +1759,7 @@ fn capacity() {
17641759
// The table has been resized once (and it's capacity doubled),
17651760
// since we inserted more elements than it can hold
17661761
}
1762+
17671763
#[cfg(test)]
17681764
mod tests {
17691765
use super::*;
@@ -1774,7 +1770,7 @@ mod tests {
17741770

17751771
map.insert(42, 0, &guard);
17761772

1777-
map.reserve(32);
1773+
map.reserve(32, &guard);
17781774

17791775
let capacity = map.capacity(&guard);
17801776
assert!(capacity >= 16 + 32);
@@ -1785,7 +1781,7 @@ mod tests {
17851781
let map = HashMap::<usize, usize>::new();
17861782
let guard = epoch::pin();
17871783

1788-
map.reserve(32);
1784+
map.reserve(32, &guard);
17891785

17901786
let capacity = map.capacity(&guard);
17911787
assert!(capacity >= 32);

tests/basic.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ fn get_and() {
448448
let guard = epoch::pin();
449449
map.insert(42, 32, &guard);
450450

451-
assert_eq!(map.get_and(&42, |value| *value + 10), Some(42));
451+
assert_eq!(map.get_and(&42, |value| *value + 10, &guard), Some(42));
452452
}
453453

454454
#[test]
@@ -528,47 +528,53 @@ fn from_iter_empty() {
528528

529529
#[test]
530530
fn retain_empty() {
531+
let guard = epoch::pin();
531532
let map = HashMap::<&'static str, u32>::new();
532-
map.retain(|_, _| false);
533+
map.retain(|_, _| false, &guard);
533534
assert_eq!(map.len(), 0);
534535
}
535536

536537
#[test]
537538
fn retain_all_false() {
539+
let guard = epoch::pin();
538540
let map: HashMap<u32, u32> = (0..10 as u32).map(|x| (x, x)).collect();
539-
map.retain(|_, _| false);
541+
map.retain(|_, _| false, &guard);
540542
assert_eq!(map.len(), 0);
541543
}
542544

543545
#[test]
544546
fn retain_all_true() {
545547
let size = 10usize;
548+
let guard = epoch::pin();
546549
let map: HashMap<usize, usize> = (0..size).map(|x| (x, x)).collect();
547-
map.retain(|_, _| true);
550+
map.retain(|_, _| true, &guard);
548551
assert_eq!(map.len(), size);
549552
}
550553

551554
#[test]
552555
fn retain_some() {
556+
let guard = epoch::pin();
553557
let map: HashMap<u32, u32> = (0..10).map(|x| (x, x)).collect();
554558
let expected_map: HashMap<u32, u32> = (5..10).map(|x| (x, x)).collect();
555-
map.retain(|_, v| *v >= 5);
559+
map.retain(|_, v| *v >= 5, &guard);
556560
assert_eq!(map.len(), 5);
557561
assert_eq!(map, expected_map);
558562
}
559563

560564
#[test]
561565
fn retain_force_empty() {
566+
let guard = epoch::pin();
562567
let map = HashMap::<&'static str, u32>::new();
563-
map.retain_force(|_, _| false);
568+
map.retain_force(|_, _| false, &guard);
564569
assert_eq!(map.len(), 0);
565570
}
566571

567572
#[test]
568573
fn retain_force_some() {
574+
let guard = epoch::pin();
569575
let map: HashMap<u32, u32> = (0..10).map(|x| (x, x)).collect();
570576
let expected_map: HashMap<u32, u32> = (5..10).map(|x| (x, x)).collect();
571-
map.retain_force(|_, v| *v >= 5);
577+
map.retain_force(|_, v| *v >= 5, &guard);
572578
assert_eq!(map.len(), 5);
573579
assert_eq!(map, expected_map);
574580
}

0 commit comments

Comments
 (0)