1#![doc = include_str!("../README.md")]
2
3mod encapsulate;
4
5#[cfg(feature = "parking-lot")]
6use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
7#[cfg(not(feature = "parking-lot"))]
8use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
9
10use std::{
11 collections::{hash_map::RandomState, HashMap as Map},
12 hash::{BuildHasher, Hash, Hasher},
13};
14
15pub use encapsulate::*;
16
17pub struct HashMap<K, V, S = RandomState> {
18 hasher: S,
19 shift: usize,
20 shards: Box<[RwLock<Map<K, V, S>>]>,
21}
22
23impl<K, V> HashMap<K, V> {
24 #[inline]
29 pub fn new() -> Self {
30 Self::with_hasher(RandomState::default())
31 }
32
33 #[inline]
38 pub fn with_capacity(capacity: usize) -> Self {
39 Self::with_capacity_and_hasher(capacity, RandomState::default())
40 }
41}
42
43impl<K: Hash, V, S: BuildHasher> HashMap<K, V, S> {
44 #[inline]
45 pub fn read<'a>(&'a self, key: &'a K) -> Readable<'a, K, V, S> {
46 Readable {
47 #[cfg(not(feature = "parking-lot"))]
48 map: self.shard(key).read().unwrap(),
49 #[cfg(feature = "parking-lot")]
50 map: self.shard(key).read(),
51 key,
52 }
53 }
54
55 #[inline]
56 pub fn write(&self, key: K) -> Writeable<K, V, S> {
57 Writeable {
58 #[cfg(not(feature = "parking-lot"))]
59 map: self.shard(&key).write().unwrap(),
60 #[cfg(feature = "parking-lot")]
61 map: self.shard(&key).write(),
62 key,
63 }
64 }
65
66 #[inline]
67 pub fn shard(&self, key: &K) -> &RwLock<Map<K, V, S>> {
68 let idx = self.shard_idx(key);
69 unsafe { self.shards.get_unchecked(idx) }
70 }
71
72 pub fn shard_idx(&self, key: &K) -> usize {
73 let mut hasher = self.hasher.build_hasher();
74 key.hash(&mut hasher);
75 let hash = hasher.finish() as usize;
76 (hash << 7) >> self.shift
78 }
79}
80
81impl<K, V, S: Clone> HashMap<K, V, S> {
82 #[inline]
83 pub fn shards(&self) -> &[RwLock<Map<K, V, S>>] {
85 self.shards.as_ref()
86 }
87
88 #[inline]
101 pub fn with_hasher(hasher: S) -> Self {
102 Self::with_capacity_and_hasher(0, hasher)
103 }
104
105 pub fn with_capacity_and_hasher(mut capacity: usize, hasher: S) -> Self {
119 let shard_amount = (num_cpus::get() * 4).next_power_of_two();
120 if capacity != 0 {
121 capacity = (capacity + (shard_amount - 1)) & !(shard_amount - 1);
122 }
123 Self {
124 shift: std::mem::size_of::<usize>() * 8 - shard_amount.trailing_zeros() as usize,
125 shards: (0..shard_amount)
126 .map(|_| {
127 RwLock::new(Map::with_capacity_and_hasher(
128 capacity / shard_amount,
129 hasher.clone(),
130 ))
131 })
132 .collect(),
133 hasher,
134 }
135 }
136}
137
138impl<K, V> Default for HashMap<K, V> {
139 fn default() -> Self {
140 Self::new()
141 }
142}