/rust/registry/src/index.crates.io-1949cf8c6b5b557f/dashmap-6.1.0/src/lib.rs
Line | Count | Source |
1 | | #![allow(clippy::type_complexity)] |
2 | | |
3 | | #[cfg(feature = "arbitrary")] |
4 | | mod arbitrary; |
5 | | pub mod iter; |
6 | | pub mod iter_set; |
7 | | mod lock; |
8 | | pub mod mapref; |
9 | | mod read_only; |
10 | | #[cfg(feature = "serde")] |
11 | | mod serde; |
12 | | mod set; |
13 | | pub mod setref; |
14 | | mod t; |
15 | | pub mod try_result; |
16 | | mod util; |
17 | | |
18 | | #[cfg(feature = "rayon")] |
19 | | pub mod rayon { |
20 | | pub mod map; |
21 | | pub mod read_only; |
22 | | pub mod set; |
23 | | } |
24 | | |
25 | | #[cfg(not(feature = "raw-api"))] |
26 | | use crate::lock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; |
27 | | |
28 | | #[cfg(feature = "raw-api")] |
29 | | pub use crate::lock::{RawRwLock, RwLock, RwLockReadGuard, RwLockWriteGuard}; |
30 | | |
31 | | use cfg_if::cfg_if; |
32 | | use core::borrow::Borrow; |
33 | | use core::fmt; |
34 | | use core::hash::{BuildHasher, Hash, Hasher}; |
35 | | use core::iter::FromIterator; |
36 | | use core::ops::{BitAnd, BitOr, Shl, Shr, Sub}; |
37 | | use crossbeam_utils::CachePadded; |
38 | | use iter::{Iter, IterMut, OwningIter}; |
39 | | pub use mapref::entry::{Entry, OccupiedEntry, VacantEntry}; |
40 | | use mapref::multiple::RefMulti; |
41 | | use mapref::one::{Ref, RefMut}; |
42 | | use once_cell::sync::OnceCell; |
43 | | pub use read_only::ReadOnlyView; |
44 | | pub use set::DashSet; |
45 | | use std::collections::hash_map::RandomState; |
46 | | pub use t::Map; |
47 | | use try_result::TryResult; |
48 | | |
49 | | cfg_if! { |
50 | | if #[cfg(feature = "raw-api")] { |
51 | | pub use util::SharedValue; |
52 | | } else { |
53 | | use util::SharedValue; |
54 | | } |
55 | | } |
56 | | |
57 | | pub(crate) type HashMap<K, V> = hashbrown::raw::RawTable<(K, SharedValue<V>)>; |
58 | | |
59 | | // Temporary reimplementation of [`std::collections::TryReserveError`] |
60 | | // util [`std::collections::TryReserveError`] stabilises. |
61 | | // We cannot easily create `std::collections` error type from `hashbrown` error type |
62 | | // without access to `TryReserveError::kind` method. |
63 | | #[non_exhaustive] |
64 | | #[derive(Clone, PartialEq, Eq, Debug)] |
65 | | pub struct TryReserveError {} |
66 | | |
67 | 0 | fn default_shard_amount() -> usize { |
68 | | static DEFAULT_SHARD_AMOUNT: OnceCell<usize> = OnceCell::new(); |
69 | 0 | *DEFAULT_SHARD_AMOUNT.get_or_init(|| { |
70 | 0 | (std::thread::available_parallelism().map_or(1, usize::from) * 4).next_power_of_two() |
71 | 0 | }) |
72 | 0 | } |
73 | | |
74 | 0 | fn ncb(shard_amount: usize) -> usize { |
75 | 0 | shard_amount.trailing_zeros() as usize |
76 | 0 | } |
77 | | |
78 | | /// DashMap is an implementation of a concurrent associative array/hashmap in Rust. |
79 | | /// |
80 | | /// DashMap tries to implement an easy to use API similar to `std::collections::HashMap` |
81 | | /// with some slight changes to handle concurrency. |
82 | | /// |
83 | | /// DashMap tries to be very simple to use and to be a direct replacement for `RwLock<HashMap<K, V>>`. |
84 | | /// To accomplish this, all methods take `&self` instead of modifying methods taking `&mut self`. |
85 | | /// This allows you to put a DashMap in an `Arc<T>` and share it between threads while being able to modify it. |
86 | | /// |
87 | | /// Documentation mentioning locking behaviour acts in the reference frame of the calling thread. |
88 | | /// This means that it is safe to ignore it across multiple threads. |
89 | | pub struct DashMap<K, V, S = RandomState> { |
90 | | shift: usize, |
91 | | shards: Box<[CachePadded<RwLock<HashMap<K, V>>>]>, |
92 | | hasher: S, |
93 | | } |
94 | | |
95 | | impl<K: Eq + Hash + Clone, V: Clone, S: Clone> Clone for DashMap<K, V, S> { |
96 | 0 | fn clone(&self) -> Self { |
97 | 0 | let mut inner_shards = Vec::new(); |
98 | | |
99 | 0 | for shard in self.shards.iter() { |
100 | 0 | let shard = shard.read(); |
101 | 0 |
|
102 | 0 | inner_shards.push(CachePadded::new(RwLock::new((*shard).clone()))); |
103 | 0 | } |
104 | | |
105 | 0 | Self { |
106 | 0 | shift: self.shift, |
107 | 0 | shards: inner_shards.into_boxed_slice(), |
108 | 0 | hasher: self.hasher.clone(), |
109 | 0 | } |
110 | 0 | } |
111 | | } |
112 | | |
113 | | impl<K, V, S> Default for DashMap<K, V, S> |
114 | | where |
115 | | K: Eq + Hash, |
116 | | S: Default + BuildHasher + Clone, |
117 | | { |
118 | 0 | fn default() -> Self { |
119 | 0 | Self::with_hasher(Default::default()) |
120 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as core::default::Default>::default Unexecuted instantiation: <dashmap::DashMap<_, _, _> as core::default::Default>::default |
121 | | } |
122 | | |
123 | | impl<'a, K: 'a + Eq + Hash, V: 'a> DashMap<K, V, RandomState> { |
124 | | /// Creates a new DashMap with a capacity of 0. |
125 | | /// |
126 | | /// # Examples |
127 | | /// |
128 | | /// ``` |
129 | | /// use dashmap::DashMap; |
130 | | /// |
131 | | /// let reviews = DashMap::new(); |
132 | | /// reviews.insert("Veloren", "What a fantastic game!"); |
133 | | /// ``` |
134 | 0 | pub fn new() -> Self { |
135 | 0 | DashMap::with_hasher(RandomState::default()) |
136 | 0 | } |
137 | | |
138 | | /// Creates a new DashMap with a specified starting capacity. |
139 | | /// |
140 | | /// # Examples |
141 | | /// |
142 | | /// ``` |
143 | | /// use dashmap::DashMap; |
144 | | /// |
145 | | /// let mappings = DashMap::with_capacity(2); |
146 | | /// mappings.insert(2, 4); |
147 | | /// mappings.insert(8, 16); |
148 | | /// ``` |
149 | 0 | pub fn with_capacity(capacity: usize) -> Self { |
150 | 0 | DashMap::with_capacity_and_hasher(capacity, RandomState::default()) |
151 | 0 | } |
152 | | |
153 | | /// Creates a new DashMap with a specified shard amount |
154 | | /// |
155 | | /// shard_amount should greater than 0 and be a power of two. |
156 | | /// If a shard_amount which is not a power of two is provided, the function will panic. |
157 | | /// |
158 | | /// # Examples |
159 | | /// |
160 | | /// ``` |
161 | | /// use dashmap::DashMap; |
162 | | /// |
163 | | /// let mappings = DashMap::with_shard_amount(32); |
164 | | /// mappings.insert(2, 4); |
165 | | /// mappings.insert(8, 16); |
166 | | /// ``` |
167 | 0 | pub fn with_shard_amount(shard_amount: usize) -> Self { |
168 | 0 | Self::with_capacity_and_hasher_and_shard_amount(0, RandomState::default(), shard_amount) |
169 | 0 | } |
170 | | |
171 | | /// Creates a new DashMap with a specified capacity and shard amount. |
172 | | /// |
173 | | /// shard_amount should greater than 0 and be a power of two. |
174 | | /// If a shard_amount which is not a power of two is provided, the function will panic. |
175 | | /// |
176 | | /// # Examples |
177 | | /// |
178 | | /// ``` |
179 | | /// use dashmap::DashMap; |
180 | | /// |
181 | | /// let mappings = DashMap::with_capacity_and_shard_amount(32, 32); |
182 | | /// mappings.insert(2, 4); |
183 | | /// mappings.insert(8, 16); |
184 | | /// ``` |
185 | 0 | pub fn with_capacity_and_shard_amount(capacity: usize, shard_amount: usize) -> Self { |
186 | 0 | Self::with_capacity_and_hasher_and_shard_amount( |
187 | 0 | capacity, |
188 | 0 | RandomState::default(), |
189 | 0 | shard_amount, |
190 | | ) |
191 | 0 | } |
192 | | } |
193 | | |
194 | | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> { |
195 | | /// Wraps this `DashMap` into a read-only view. This view allows to obtain raw references to the stored values. |
196 | 0 | pub fn into_read_only(self) -> ReadOnlyView<K, V, S> { |
197 | 0 | ReadOnlyView::new(self) |
198 | 0 | } |
199 | | |
200 | | /// Creates a new DashMap with a capacity of 0 and the provided hasher. |
201 | | /// |
202 | | /// # Examples |
203 | | /// |
204 | | /// ``` |
205 | | /// use dashmap::DashMap; |
206 | | /// use std::collections::hash_map::RandomState; |
207 | | /// |
208 | | /// let s = RandomState::new(); |
209 | | /// let reviews = DashMap::with_hasher(s); |
210 | | /// reviews.insert("Veloren", "What a fantastic game!"); |
211 | | /// ``` |
212 | 0 | pub fn with_hasher(hasher: S) -> Self { |
213 | 0 | Self::with_capacity_and_hasher(0, hasher) |
214 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::with_hasher Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::with_hasher |
215 | | |
216 | | /// Creates a new DashMap with a specified starting capacity and hasher. |
217 | | /// |
218 | | /// # Examples |
219 | | /// |
220 | | /// ``` |
221 | | /// use dashmap::DashMap; |
222 | | /// use std::collections::hash_map::RandomState; |
223 | | /// |
224 | | /// let s = RandomState::new(); |
225 | | /// let mappings = DashMap::with_capacity_and_hasher(2, s); |
226 | | /// mappings.insert(2, 4); |
227 | | /// mappings.insert(8, 16); |
228 | | /// ``` |
229 | 0 | pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { |
230 | 0 | Self::with_capacity_and_hasher_and_shard_amount(capacity, hasher, default_shard_amount()) |
231 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::with_capacity_and_hasher Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::with_capacity_and_hasher |
232 | | |
233 | | /// Creates a new DashMap with a specified hasher and shard amount |
234 | | /// |
235 | | /// shard_amount should be greater than 0 and a power of two. |
236 | | /// If a shard_amount which is not a power of two is provided, the function will panic. |
237 | | /// |
238 | | /// # Examples |
239 | | /// |
240 | | /// ``` |
241 | | /// use dashmap::DashMap; |
242 | | /// use std::collections::hash_map::RandomState; |
243 | | /// |
244 | | /// let s = RandomState::new(); |
245 | | /// let mappings = DashMap::with_hasher_and_shard_amount(s, 32); |
246 | | /// mappings.insert(2, 4); |
247 | | /// mappings.insert(8, 16); |
248 | | /// ``` |
249 | 0 | pub fn with_hasher_and_shard_amount(hasher: S, shard_amount: usize) -> Self { |
250 | 0 | Self::with_capacity_and_hasher_and_shard_amount(0, hasher, shard_amount) |
251 | 0 | } |
252 | | |
253 | | /// Creates a new DashMap with a specified starting capacity, hasher and shard_amount. |
254 | | /// |
255 | | /// shard_amount should greater than 0 and be a power of two. |
256 | | /// If a shard_amount which is not a power of two is provided, the function will panic. |
257 | | /// |
258 | | /// # Examples |
259 | | /// |
260 | | /// ``` |
261 | | /// use dashmap::DashMap; |
262 | | /// use std::collections::hash_map::RandomState; |
263 | | /// |
264 | | /// let s = RandomState::new(); |
265 | | /// let mappings = DashMap::with_capacity_and_hasher_and_shard_amount(2, s, 32); |
266 | | /// mappings.insert(2, 4); |
267 | | /// mappings.insert(8, 16); |
268 | | /// ``` |
269 | 0 | pub fn with_capacity_and_hasher_and_shard_amount( |
270 | 0 | mut capacity: usize, |
271 | 0 | hasher: S, |
272 | 0 | shard_amount: usize, |
273 | 0 | ) -> Self { |
274 | 0 | assert!(shard_amount > 1); |
275 | 0 | assert!(shard_amount.is_power_of_two()); |
276 | | |
277 | 0 | let shift = util::ptr_size_bits() - ncb(shard_amount); |
278 | | |
279 | 0 | if capacity != 0 { |
280 | 0 | capacity = (capacity + (shard_amount - 1)) & !(shard_amount - 1); |
281 | 0 | } |
282 | | |
283 | 0 | let cps = capacity / shard_amount; |
284 | | |
285 | 0 | let shards = (0..shard_amount) |
286 | 0 | .map(|_| CachePadded::new(RwLock::new(HashMap::with_capacity(cps)))) Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::with_capacity_and_hasher_and_shard_amount::{closure#0} Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::with_capacity_and_hasher_and_shard_amount::{closure#0} |
287 | 0 | .collect(); |
288 | | |
289 | 0 | Self { |
290 | 0 | shift, |
291 | 0 | shards, |
292 | 0 | hasher, |
293 | 0 | } |
294 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::with_capacity_and_hasher_and_shard_amount Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::with_capacity_and_hasher_and_shard_amount |
295 | | |
296 | | /// Hash a given item to produce a usize. |
297 | | /// Uses the provided or default HashBuilder. |
298 | 0 | pub fn hash_usize<T: Hash>(&self, item: &T) -> usize { |
299 | 0 | self.hash_u64(item) as usize |
300 | 0 | } |
301 | | |
302 | 0 | fn hash_u64<T: Hash>(&self, item: &T) -> u64 { |
303 | 0 | let mut hasher = self.hasher.build_hasher(); |
304 | | |
305 | 0 | item.hash(&mut hasher); |
306 | | |
307 | 0 | hasher.finish() |
308 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::hash_u64::<&usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::hash_u64::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::hash_u64::<&usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::hash_u64::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::hash_u64::<&usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::hash_u64::<&usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::hash_u64::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::hash_u64::<&usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::hash_u64::<usize> Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::hash_u64::<_> |
309 | | |
310 | | cfg_if! { |
311 | | if #[cfg(feature = "raw-api")] { |
312 | | /// Allows you to peek at the inner shards that store your data. |
313 | | /// You should probably not use this unless you know what you are doing. |
314 | | /// |
315 | | /// Requires the `raw-api` feature to be enabled. |
316 | | /// |
317 | | /// # Examples |
318 | | /// |
319 | | /// ``` |
320 | | /// use dashmap::DashMap; |
321 | | /// |
322 | | /// let map = DashMap::<(), ()>::new(); |
323 | | /// println!("Amount of shards: {}", map.shards().len()); |
324 | | /// ``` |
325 | | pub fn shards(&self) -> &[CachePadded<RwLock<HashMap<K, V>>>] { |
326 | | &self.shards |
327 | | } |
328 | | |
329 | | /// Provides mutable access to the inner shards that store your data. |
330 | | /// You should probably not use this unless you know what you are doing. |
331 | | /// |
332 | | /// Requires the `raw-api` feature to be enabled. |
333 | | /// |
334 | | /// # Examples |
335 | | /// |
336 | | /// ``` |
337 | | /// use dashmap::DashMap; |
338 | | /// use dashmap::SharedValue; |
339 | | /// use std::hash::{Hash, Hasher, BuildHasher}; |
340 | | /// |
341 | | /// let mut map = DashMap::<i32, &'static str>::new(); |
342 | | /// let shard_ind = map.determine_map(&42); |
343 | | /// let mut factory = map.hasher().clone(); |
344 | | /// let hasher = |tuple: &(i32, SharedValue<&'static str>)| { |
345 | | /// let mut hasher = factory.build_hasher(); |
346 | | /// tuple.0.hash(&mut hasher); |
347 | | /// hasher.finish() |
348 | | /// }; |
349 | | /// let data = (42, SharedValue::new("forty two")); |
350 | | /// let hash = hasher(&data); |
351 | | /// map.shards_mut()[shard_ind].get_mut().insert(hash, data, hasher); |
352 | | /// assert_eq!(*map.get(&42).unwrap(), "forty two"); |
353 | | /// ``` |
354 | | pub fn shards_mut(&mut self) -> &mut [CachePadded<RwLock<HashMap<K, V>>>] { |
355 | | &mut self.shards |
356 | | } |
357 | | |
358 | | /// Consumes this `DashMap` and returns the inner shards. |
359 | | /// You should probably not use this unless you know what you are doing. |
360 | | /// |
361 | | /// Requires the `raw-api` feature to be enabled. |
362 | | /// |
363 | | /// See [`DashMap::shards()`] and [`DashMap::shards_mut()`] for more information. |
364 | | pub fn into_shards(self) -> Box<[CachePadded<RwLock<HashMap<K, V>>>]> { |
365 | | self.shards |
366 | | } |
367 | | } else { |
368 | | #[allow(dead_code)] |
369 | 0 | pub(crate) fn shards(&self) -> &[CachePadded<RwLock<HashMap<K, V>>>] { |
370 | 0 | &self.shards |
371 | 0 | } |
372 | | |
373 | | #[allow(dead_code)] |
374 | 0 | pub(crate) fn shards_mut(&mut self) -> &mut [CachePadded<RwLock<HashMap<K, V>>>] { |
375 | 0 | &mut self.shards |
376 | 0 | } |
377 | | |
378 | | #[allow(dead_code)] |
379 | 0 | pub(crate) fn into_shards(self) -> Box<[CachePadded<RwLock<HashMap<K, V>>>]> { |
380 | 0 | self.shards |
381 | 0 | } |
382 | | } |
383 | | } |
384 | | |
385 | | cfg_if! { |
386 | | if #[cfg(feature = "raw-api")] { |
387 | | /// Finds which shard a certain key is stored in. |
388 | | /// You should probably not use this unless you know what you are doing. |
389 | | /// Note that shard selection is dependent on the default or provided HashBuilder. |
390 | | /// |
391 | | /// Requires the `raw-api` feature to be enabled. |
392 | | /// |
393 | | /// # Examples |
394 | | /// |
395 | | /// ``` |
396 | | /// use dashmap::DashMap; |
397 | | /// |
398 | | /// let map = DashMap::new(); |
399 | | /// map.insert("coca-cola", 1.4); |
400 | | /// println!("coca-cola is stored in shard: {}", map.determine_map("coca-cola")); |
401 | | /// ``` |
402 | | pub fn determine_map<Q>(&self, key: &Q) -> usize |
403 | | where |
404 | | K: Borrow<Q>, |
405 | | Q: Hash + Eq + ?Sized, |
406 | | { |
407 | | let hash = self.hash_usize(&key); |
408 | | self.determine_shard(hash) |
409 | | } |
410 | | } |
411 | | } |
412 | | |
413 | | cfg_if! { |
414 | | if #[cfg(feature = "raw-api")] { |
415 | | /// Finds which shard a certain hash is stored in. |
416 | | /// |
417 | | /// Requires the `raw-api` feature to be enabled. |
418 | | /// |
419 | | /// # Examples |
420 | | /// |
421 | | /// ``` |
422 | | /// use dashmap::DashMap; |
423 | | /// |
424 | | /// let map: DashMap<i32, i32> = DashMap::new(); |
425 | | /// let key = "key"; |
426 | | /// let hash = map.hash_usize(&key); |
427 | | /// println!("hash is stored in shard: {}", map.determine_shard(hash)); |
428 | | /// ``` |
429 | | pub fn determine_shard(&self, hash: usize) -> usize { |
430 | | // Leave the high 7 bits for the HashBrown SIMD tag. |
431 | | (hash << 7) >> self.shift |
432 | | } |
433 | | } else { |
434 | | |
435 | 0 | pub(crate) fn determine_shard(&self, hash: usize) -> usize { |
436 | | // Leave the high 7 bits for the HashBrown SIMD tag. |
437 | 0 | (hash << 7) >> self.shift |
438 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::determine_shard Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::determine_shard Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::determine_shard Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::determine_shard Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::determine_shard Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::determine_shard |
439 | | } |
440 | | } |
441 | | |
442 | | /// Returns a reference to the map's [`BuildHasher`]. |
443 | | /// |
444 | | /// # Examples |
445 | | /// |
446 | | /// ```rust |
447 | | /// use dashmap::DashMap; |
448 | | /// use std::collections::hash_map::RandomState; |
449 | | /// |
450 | | /// let hasher = RandomState::new(); |
451 | | /// let map: DashMap<i32, i32> = DashMap::new(); |
452 | | /// let hasher: &RandomState = map.hasher(); |
453 | | /// ``` |
454 | | /// |
455 | | /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html |
456 | 0 | pub fn hasher(&self) -> &S { |
457 | 0 | &self.hasher |
458 | 0 | } |
459 | | |
460 | | /// Inserts a key and a value into the map. Returns the old value associated with the key if there was one. |
461 | | /// |
462 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
463 | | /// |
464 | | /// # Examples |
465 | | /// |
466 | | /// ``` |
467 | | /// use dashmap::DashMap; |
468 | | /// |
469 | | /// let map = DashMap::new(); |
470 | | /// map.insert("I am the key!", "And I am the value!"); |
471 | | /// ``` |
472 | 0 | pub fn insert(&self, key: K, value: V) -> Option<V> { |
473 | 0 | self._insert(key, value) |
474 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::insert Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::insert Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::insert Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::insert Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::insert |
475 | | |
476 | | /// Removes an entry from the map, returning the key and value if they existed in the map. |
477 | | /// |
478 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
479 | | /// |
480 | | /// # Examples |
481 | | /// |
482 | | /// ``` |
483 | | /// use dashmap::DashMap; |
484 | | /// |
485 | | /// let soccer_team = DashMap::new(); |
486 | | /// soccer_team.insert("Jack", "Goalie"); |
487 | | /// assert_eq!(soccer_team.remove("Jack").unwrap().1, "Goalie"); |
488 | | /// ``` |
489 | 0 | pub fn remove<Q>(&self, key: &Q) -> Option<(K, V)> |
490 | 0 | where |
491 | 0 | K: Borrow<Q>, |
492 | 0 | Q: Hash + Eq + ?Sized, |
493 | | { |
494 | 0 | self._remove(key) |
495 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::remove::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::remove::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::remove::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::remove::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::remove::<usize> Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::remove::<_> |
496 | | |
497 | | /// Removes an entry from the map, returning the key and value |
498 | | /// if the entry existed and the provided conditional function returned true. |
499 | | /// |
500 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
501 | | /// |
502 | | /// ``` |
503 | | /// use dashmap::DashMap; |
504 | | /// |
505 | | /// let soccer_team = DashMap::new(); |
506 | | /// soccer_team.insert("Sam", "Forward"); |
507 | | /// soccer_team.remove_if("Sam", |_, position| position == &"Goalie"); |
508 | | /// assert!(soccer_team.contains_key("Sam")); |
509 | | /// ``` |
510 | | /// ``` |
511 | | /// use dashmap::DashMap; |
512 | | /// |
513 | | /// let soccer_team = DashMap::new(); |
514 | | /// soccer_team.insert("Sam", "Forward"); |
515 | | /// soccer_team.remove_if("Sam", |_, position| position == &"Forward"); |
516 | | /// assert!(!soccer_team.contains_key("Sam")); |
517 | | /// ``` |
518 | 0 | pub fn remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K, &V) -> bool) -> Option<(K, V)> |
519 | 0 | where |
520 | 0 | K: Borrow<Q>, |
521 | 0 | Q: Hash + Eq + ?Sized, |
522 | | { |
523 | 0 | self._remove_if(key, f) |
524 | 0 | } |
525 | | |
526 | 0 | pub fn remove_if_mut<Q>(&self, key: &Q, f: impl FnOnce(&K, &mut V) -> bool) -> Option<(K, V)> |
527 | 0 | where |
528 | 0 | K: Borrow<Q>, |
529 | 0 | Q: Hash + Eq + ?Sized, |
530 | | { |
531 | 0 | self._remove_if_mut(key, f) |
532 | 0 | } |
533 | | |
534 | | /// Creates an iterator over a DashMap yielding immutable references. |
535 | | /// |
536 | | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. |
537 | | /// |
538 | | /// # Examples |
539 | | /// |
540 | | /// ``` |
541 | | /// use dashmap::DashMap; |
542 | | /// |
543 | | /// let words = DashMap::new(); |
544 | | /// words.insert("hello", "world"); |
545 | | /// assert_eq!(words.iter().count(), 1); |
546 | | /// ``` |
547 | 0 | pub fn iter(&'a self) -> Iter<'a, K, V, S, DashMap<K, V, S>> { |
548 | 0 | self._iter() |
549 | 0 | } |
550 | | |
551 | | /// Iterator over a DashMap yielding mutable references. |
552 | | /// |
553 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
554 | | /// |
555 | | /// # Examples |
556 | | /// |
557 | | /// ``` |
558 | | /// use dashmap::DashMap; |
559 | | /// |
560 | | /// let map = DashMap::new(); |
561 | | /// map.insert("Johnny", 21); |
562 | | /// map.iter_mut().for_each(|mut r| *r += 1); |
563 | | /// assert_eq!(*map.get("Johnny").unwrap(), 22); |
564 | | /// ``` |
565 | 0 | pub fn iter_mut(&'a self) -> IterMut<'a, K, V, S, DashMap<K, V, S>> { |
566 | 0 | self._iter_mut() |
567 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::iter_mut Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::iter_mut |
568 | | |
569 | | /// Get an immutable reference to an entry in the map |
570 | | /// |
571 | | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. |
572 | | /// |
573 | | /// # Examples |
574 | | /// |
575 | | /// ``` |
576 | | /// use dashmap::DashMap; |
577 | | /// |
578 | | /// let youtubers = DashMap::new(); |
579 | | /// youtubers.insert("Bosnian Bill", 457000); |
580 | | /// assert_eq!(*youtubers.get("Bosnian Bill").unwrap(), 457000); |
581 | | /// ``` |
582 | 0 | pub fn get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K, V>> |
583 | 0 | where |
584 | 0 | K: Borrow<Q>, |
585 | 0 | Q: Hash + Eq + ?Sized, |
586 | | { |
587 | 0 | self._get(key) |
588 | 0 | } |
589 | | |
590 | | /// Get a mutable reference to an entry in the map |
591 | | /// |
592 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
593 | | /// |
594 | | /// # Examples |
595 | | /// |
596 | | /// ``` |
597 | | /// use dashmap::DashMap; |
598 | | /// |
599 | | /// let class = DashMap::new(); |
600 | | /// class.insert("Albin", 15); |
601 | | /// *class.get_mut("Albin").unwrap() -= 1; |
602 | | /// assert_eq!(*class.get("Albin").unwrap(), 14); |
603 | | /// ``` |
604 | 0 | pub fn get_mut<Q>(&'a self, key: &Q) -> Option<RefMut<'a, K, V>> |
605 | 0 | where |
606 | 0 | K: Borrow<Q>, |
607 | 0 | Q: Hash + Eq + ?Sized, |
608 | | { |
609 | 0 | self._get_mut(key) |
610 | 0 | } |
611 | | |
612 | | /// Get an immutable reference to an entry in the map, if the shard is not locked. |
613 | | /// If the shard is locked, the function will return [TryResult::Locked]. |
614 | | /// |
615 | | /// # Examples |
616 | | /// |
617 | | /// ``` |
618 | | /// use dashmap::DashMap; |
619 | | /// use dashmap::try_result::TryResult; |
620 | | /// |
621 | | /// let map = DashMap::new(); |
622 | | /// map.insert("Johnny", 21); |
623 | | /// |
624 | | /// assert_eq!(*map.try_get("Johnny").unwrap(), 21); |
625 | | /// |
626 | | /// let _result1_locking = map.get_mut("Johnny"); |
627 | | /// |
628 | | /// let result2 = map.try_get("Johnny"); |
629 | | /// assert!(result2.is_locked()); |
630 | | /// ``` |
631 | 0 | pub fn try_get<Q>(&'a self, key: &Q) -> TryResult<Ref<'a, K, V>> |
632 | 0 | where |
633 | 0 | K: Borrow<Q>, |
634 | 0 | Q: Hash + Eq + ?Sized, |
635 | | { |
636 | 0 | self._try_get(key) |
637 | 0 | } |
638 | | |
639 | | /// Get a mutable reference to an entry in the map, if the shard is not locked. |
640 | | /// If the shard is locked, the function will return [TryResult::Locked]. |
641 | | /// |
642 | | /// # Examples |
643 | | /// |
644 | | /// ``` |
645 | | /// use dashmap::DashMap; |
646 | | /// use dashmap::try_result::TryResult; |
647 | | /// |
648 | | /// let map = DashMap::new(); |
649 | | /// map.insert("Johnny", 21); |
650 | | /// |
651 | | /// *map.try_get_mut("Johnny").unwrap() += 1; |
652 | | /// assert_eq!(*map.get("Johnny").unwrap(), 22); |
653 | | /// |
654 | | /// let _result1_locking = map.get("Johnny"); |
655 | | /// |
656 | | /// let result2 = map.try_get_mut("Johnny"); |
657 | | /// assert!(result2.is_locked()); |
658 | | /// ``` |
659 | 0 | pub fn try_get_mut<Q>(&'a self, key: &Q) -> TryResult<RefMut<'a, K, V>> |
660 | 0 | where |
661 | 0 | K: Borrow<Q>, |
662 | 0 | Q: Hash + Eq + ?Sized, |
663 | | { |
664 | 0 | self._try_get_mut(key) |
665 | 0 | } |
666 | | |
667 | | /// Remove excess capacity to reduce memory usage. |
668 | | /// |
669 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
670 | | /// # Examples |
671 | | /// |
672 | | /// ``` |
673 | | /// use dashmap::DashMap; |
674 | | /// use dashmap::try_result::TryResult; |
675 | | /// |
676 | | /// let map = DashMap::new(); |
677 | | /// map.insert("Johnny", 21); |
678 | | /// assert!(map.capacity() > 0); |
679 | | /// map.remove("Johnny"); |
680 | | /// map.shrink_to_fit(); |
681 | | /// assert_eq!(map.capacity(), 0); |
682 | | /// ``` |
683 | 0 | pub fn shrink_to_fit(&self) { |
684 | 0 | self._shrink_to_fit(); |
685 | 0 | } |
686 | | |
687 | | /// Retain elements that whose predicates return true |
688 | | /// and discard elements whose predicates return false. |
689 | | /// |
690 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
691 | | /// |
692 | | /// # Examples |
693 | | /// |
694 | | /// ``` |
695 | | /// use dashmap::DashMap; |
696 | | /// |
697 | | /// let people = DashMap::new(); |
698 | | /// people.insert("Albin", 15); |
699 | | /// people.insert("Jones", 22); |
700 | | /// people.insert("Charlie", 27); |
701 | | /// people.retain(|_, v| *v > 20); |
702 | | /// assert_eq!(people.len(), 2); |
703 | | /// ``` |
704 | 0 | pub fn retain(&self, f: impl FnMut(&K, &mut V) -> bool) { |
705 | 0 | self._retain(f); |
706 | 0 | } |
707 | | |
708 | | /// Fetches the total number of key-value pairs stored in the map. |
709 | | /// |
710 | | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. |
711 | | /// |
712 | | /// # Examples |
713 | | /// |
714 | | /// ``` |
715 | | /// use dashmap::DashMap; |
716 | | /// |
717 | | /// let people = DashMap::new(); |
718 | | /// people.insert("Albin", 15); |
719 | | /// people.insert("Jones", 22); |
720 | | /// people.insert("Charlie", 27); |
721 | | /// assert_eq!(people.len(), 3); |
722 | | /// ``` |
723 | 0 | pub fn len(&self) -> usize { |
724 | 0 | self._len() |
725 | 0 | } |
726 | | |
727 | | /// Checks if the map is empty or not. |
728 | | /// |
729 | | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. |
730 | | /// |
731 | | /// # Examples |
732 | | /// |
733 | | /// ``` |
734 | | /// use dashmap::DashMap; |
735 | | /// |
736 | | /// let map = DashMap::<(), ()>::new(); |
737 | | /// assert!(map.is_empty()); |
738 | | /// ``` |
739 | 0 | pub fn is_empty(&self) -> bool { |
740 | 0 | self._is_empty() |
741 | 0 | } |
742 | | |
743 | | /// Removes all key-value pairs in the map. |
744 | | /// |
745 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
746 | | /// |
747 | | /// # Examples |
748 | | /// |
749 | | /// ``` |
750 | | /// use dashmap::DashMap; |
751 | | /// |
752 | | /// let stats = DashMap::new(); |
753 | | /// stats.insert("Goals", 4); |
754 | | /// assert!(!stats.is_empty()); |
755 | | /// stats.clear(); |
756 | | /// assert!(stats.is_empty()); |
757 | | /// ``` |
758 | 0 | pub fn clear(&self) { |
759 | 0 | self._clear(); |
760 | 0 | } |
761 | | |
762 | | /// Returns how many key-value pairs the map can store without reallocating. |
763 | | /// |
764 | | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. |
765 | 0 | pub fn capacity(&self) -> usize { |
766 | 0 | self._capacity() |
767 | 0 | } |
768 | | |
769 | | /// Modify a specific value according to a function. |
770 | | /// |
771 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
772 | | /// |
773 | | /// # Examples |
774 | | /// |
775 | | /// ``` |
776 | | /// use dashmap::DashMap; |
777 | | /// |
778 | | /// let stats = DashMap::new(); |
779 | | /// stats.insert("Goals", 4); |
780 | | /// stats.alter("Goals", |_, v| v * 2); |
781 | | /// assert_eq!(*stats.get("Goals").unwrap(), 8); |
782 | | /// ``` |
783 | | /// |
784 | | /// # Panics |
785 | | /// |
786 | | /// If the given closure panics, then `alter` will abort the process |
787 | 0 | pub fn alter<Q>(&self, key: &Q, f: impl FnOnce(&K, V) -> V) |
788 | 0 | where |
789 | 0 | K: Borrow<Q>, |
790 | 0 | Q: Hash + Eq + ?Sized, |
791 | | { |
792 | 0 | self._alter(key, f); |
793 | 0 | } |
794 | | |
795 | | /// Modify every value in the map according to a function. |
796 | | /// |
797 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
798 | | /// |
799 | | /// # Examples |
800 | | /// |
801 | | /// ``` |
802 | | /// use dashmap::DashMap; |
803 | | /// |
804 | | /// let stats = DashMap::new(); |
805 | | /// stats.insert("Wins", 4); |
806 | | /// stats.insert("Losses", 2); |
807 | | /// stats.alter_all(|_, v| v + 1); |
808 | | /// assert_eq!(*stats.get("Wins").unwrap(), 5); |
809 | | /// assert_eq!(*stats.get("Losses").unwrap(), 3); |
810 | | /// ``` |
811 | | /// |
812 | | /// # Panics |
813 | | /// |
814 | | /// If the given closure panics, then `alter_all` will abort the process |
815 | 0 | pub fn alter_all(&self, f: impl FnMut(&K, V) -> V) { |
816 | 0 | self._alter_all(f); |
817 | 0 | } |
818 | | |
819 | | /// Scoped access into an item of the map according to a function. |
820 | | /// |
821 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
822 | | /// |
823 | | /// # Examples |
824 | | /// |
825 | | /// ``` |
826 | | /// use dashmap::DashMap; |
827 | | /// |
828 | | /// let warehouse = DashMap::new(); |
829 | | /// warehouse.insert(4267, ("Banana", 100)); |
830 | | /// warehouse.insert(2359, ("Pear", 120)); |
831 | | /// let fruit = warehouse.view(&4267, |_k, v| *v); |
832 | | /// assert_eq!(fruit, Some(("Banana", 100))); |
833 | | /// ``` |
834 | | /// |
835 | | /// # Panics |
836 | | /// |
837 | | /// If the given closure panics, then `view` will abort the process |
838 | 0 | pub fn view<Q, R>(&self, key: &Q, f: impl FnOnce(&K, &V) -> R) -> Option<R> |
839 | 0 | where |
840 | 0 | K: Borrow<Q>, |
841 | 0 | Q: Hash + Eq + ?Sized, |
842 | | { |
843 | 0 | self._view(key, f) |
844 | 0 | } |
845 | | |
846 | | /// Checks if the map contains a specific key. |
847 | | /// |
848 | | /// **Locking behaviour:** May deadlock if called when holding a mutable reference into the map. |
849 | | /// |
850 | | /// # Examples |
851 | | /// |
852 | | /// ``` |
853 | | /// use dashmap::DashMap; |
854 | | /// |
855 | | /// let team_sizes = DashMap::new(); |
856 | | /// team_sizes.insert("Dakota Cherries", 23); |
857 | | /// assert!(team_sizes.contains_key("Dakota Cherries")); |
858 | | /// ``` |
859 | 0 | pub fn contains_key<Q>(&self, key: &Q) -> bool |
860 | 0 | where |
861 | 0 | K: Borrow<Q>, |
862 | 0 | Q: Hash + Eq + ?Sized, |
863 | | { |
864 | 0 | self._contains_key(key) |
865 | 0 | } |
866 | | |
867 | | /// Advanced entry API that tries to mimic `std::collections::HashMap`. |
868 | | /// See the documentation on `dashmap::mapref::entry` for more details. |
869 | | /// |
870 | | /// **Locking behaviour:** May deadlock if called when holding any sort of reference into the map. |
871 | 0 | pub fn entry(&'a self, key: K) -> Entry<'a, K, V> { |
872 | 0 | self._entry(key) |
873 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::entry Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::entry Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::entry Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::entry Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::entry |
874 | | |
875 | | /// Advanced entry API that tries to mimic `std::collections::HashMap`. |
876 | | /// See the documentation on `dashmap::mapref::entry` for more details. |
877 | | /// |
878 | | /// Returns None if the shard is currently locked. |
879 | 0 | pub fn try_entry(&'a self, key: K) -> Option<Entry<'a, K, V>> { |
880 | 0 | self._try_entry(key) |
881 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>>>::try_entry Unexecuted instantiation: <dashmap::DashMap<_, _, _>>::try_entry |
882 | | |
883 | | /// Advanced entry API that tries to mimic `std::collections::HashMap::try_reserve`. |
884 | | /// Tries to reserve capacity for at least `shard * additional` |
885 | | /// and may reserve more space to avoid frequent reallocations. |
886 | | /// |
887 | | /// # Errors |
888 | | /// |
889 | | /// If the capacity overflows, or the allocator reports a failure, then an error is returned. |
890 | | // TODO: return std::collections::TryReserveError once std::collections::TryReserveErrorKind stabilises. |
891 | 0 | pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { |
892 | 0 | for shard in self.shards.iter() { |
893 | 0 | shard |
894 | 0 | .write() |
895 | 0 | .try_reserve(additional, |(k, _v)| { |
896 | 0 | let mut hasher = self.hasher.build_hasher(); |
897 | 0 | k.hash(&mut hasher); |
898 | 0 | hasher.finish() |
899 | 0 | }) |
900 | 0 | .map_err(|_| TryReserveError {})?; |
901 | | } |
902 | 0 | Ok(()) |
903 | 0 | } |
904 | | } |
905 | | |
906 | | impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S> |
907 | | for DashMap<K, V, S> |
908 | | { |
909 | 0 | fn _shard_count(&self) -> usize { |
910 | 0 | self.shards.len() |
911 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_shard_count Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_shard_count |
912 | | |
913 | 0 | unsafe fn _get_read_shard(&'a self, i: usize) -> &'a HashMap<K, V> { |
914 | 0 | debug_assert!(i < self.shards.len()); |
915 | | |
916 | 0 | &*self.shards.get_unchecked(i).data_ptr() |
917 | 0 | } |
918 | | |
919 | 0 | unsafe fn _yield_read_shard(&'a self, i: usize) -> RwLockReadGuard<'a, HashMap<K, V>> { |
920 | 0 | debug_assert!(i < self.shards.len()); |
921 | | |
922 | 0 | self.shards.get_unchecked(i).read() |
923 | 0 | } |
924 | | |
925 | 0 | unsafe fn _yield_write_shard(&'a self, i: usize) -> RwLockWriteGuard<'a, HashMap<K, V>> { |
926 | 0 | debug_assert!(i < self.shards.len()); |
927 | | |
928 | 0 | self.shards.get_unchecked(i).write() |
929 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_yield_write_shard Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_yield_write_shard Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_yield_write_shard Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_yield_write_shard Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_yield_write_shard Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_yield_write_shard |
930 | | |
931 | 0 | unsafe fn _try_yield_read_shard( |
932 | 0 | &'a self, |
933 | 0 | i: usize, |
934 | 0 | ) -> Option<RwLockReadGuard<'a, HashMap<K, V>>> { |
935 | 0 | debug_assert!(i < self.shards.len()); |
936 | | |
937 | 0 | self.shards.get_unchecked(i).try_read() |
938 | 0 | } |
939 | | |
940 | 0 | unsafe fn _try_yield_write_shard( |
941 | 0 | &'a self, |
942 | 0 | i: usize, |
943 | 0 | ) -> Option<RwLockWriteGuard<'a, HashMap<K, V>>> { |
944 | 0 | debug_assert!(i < self.shards.len()); |
945 | | |
946 | 0 | self.shards.get_unchecked(i).try_write() |
947 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_try_yield_write_shard Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_try_yield_write_shard |
948 | | |
949 | 0 | fn _insert(&self, key: K, value: V) -> Option<V> { |
950 | 0 | match self.entry(key) { |
951 | 0 | Entry::Occupied(mut o) => Some(o.insert(value)), |
952 | 0 | Entry::Vacant(v) => { |
953 | 0 | v.insert(value); |
954 | 0 | None |
955 | | } |
956 | | } |
957 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_insert Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_insert Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_insert Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_insert Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_insert |
958 | | |
959 | 0 | fn _remove<Q>(&self, key: &Q) -> Option<(K, V)> |
960 | 0 | where |
961 | 0 | K: Borrow<Q>, |
962 | 0 | Q: Hash + Eq + ?Sized, |
963 | | { |
964 | 0 | let hash = self.hash_u64(&key); |
965 | | |
966 | 0 | let idx = self.determine_shard(hash as usize); |
967 | | |
968 | 0 | let mut shard = unsafe { self._yield_write_shard(idx) }; |
969 | | |
970 | 0 | if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) { Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize>::{closure#0} Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize>::{closure#0} Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize>::{closure#0} Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize>::{closure#0} Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize>::{closure#0} Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_remove::<_>::{closure#0} |
971 | 0 | let ((k, v), _) = unsafe { shard.remove(bucket) }; |
972 | 0 | Some((k, v.into_inner())) |
973 | | } else { |
974 | 0 | None |
975 | | } |
976 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize> Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_remove::<usize> Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_remove::<_> |
977 | | |
978 | 0 | fn _remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K, &V) -> bool) -> Option<(K, V)> |
979 | 0 | where |
980 | 0 | K: Borrow<Q>, |
981 | 0 | Q: Hash + Eq + ?Sized, |
982 | | { |
983 | 0 | let hash = self.hash_u64(&key); |
984 | | |
985 | 0 | let idx = self.determine_shard(hash as usize); |
986 | | |
987 | 0 | let mut shard = unsafe { self._yield_write_shard(idx) }; |
988 | | |
989 | 0 | if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) { |
990 | 0 | let (k, v) = unsafe { bucket.as_ref() }; |
991 | 0 | if f(k, v.get()) { |
992 | 0 | let ((k, v), _) = unsafe { shard.remove(bucket) }; |
993 | 0 | Some((k, v.into_inner())) |
994 | | } else { |
995 | 0 | None |
996 | | } |
997 | | } else { |
998 | 0 | None |
999 | | } |
1000 | 0 | } |
1001 | | |
1002 | 0 | fn _remove_if_mut<Q>(&self, key: &Q, f: impl FnOnce(&K, &mut V) -> bool) -> Option<(K, V)> |
1003 | 0 | where |
1004 | 0 | K: Borrow<Q>, |
1005 | 0 | Q: Hash + Eq + ?Sized, |
1006 | | { |
1007 | 0 | let hash = self.hash_u64(&key); |
1008 | | |
1009 | 0 | let idx = self.determine_shard(hash as usize); |
1010 | | |
1011 | 0 | let mut shard = unsafe { self._yield_write_shard(idx) }; |
1012 | | |
1013 | 0 | if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) { |
1014 | 0 | let (k, v) = unsafe { bucket.as_mut() }; |
1015 | 0 | if f(k, v.get_mut()) { |
1016 | 0 | let ((k, v), _) = unsafe { shard.remove(bucket) }; |
1017 | 0 | Some((k, v.into_inner())) |
1018 | | } else { |
1019 | 0 | None |
1020 | | } |
1021 | | } else { |
1022 | 0 | None |
1023 | | } |
1024 | 0 | } |
1025 | | |
1026 | 0 | fn _iter(&'a self) -> Iter<'a, K, V, S, DashMap<K, V, S>> { |
1027 | 0 | Iter::new(self) |
1028 | 0 | } |
1029 | | |
1030 | 0 | fn _iter_mut(&'a self) -> IterMut<'a, K, V, S, DashMap<K, V, S>> { |
1031 | 0 | IterMut::new(self) |
1032 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_iter_mut Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_iter_mut |
1033 | | |
1034 | 0 | fn _get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K, V>> |
1035 | 0 | where |
1036 | 0 | K: Borrow<Q>, |
1037 | 0 | Q: Hash + Eq + ?Sized, |
1038 | | { |
1039 | 0 | let hash = self.hash_u64(&key); |
1040 | | |
1041 | 0 | let idx = self.determine_shard(hash as usize); |
1042 | | |
1043 | 0 | let shard = unsafe { self._yield_read_shard(idx) }; |
1044 | | |
1045 | 0 | if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) { |
1046 | | unsafe { |
1047 | 0 | let (k, v) = bucket.as_ref(); |
1048 | 0 | Some(Ref::new(shard, k, v.as_ptr())) |
1049 | | } |
1050 | | } else { |
1051 | 0 | None |
1052 | | } |
1053 | 0 | } |
1054 | | |
1055 | 0 | fn _get_mut<Q>(&'a self, key: &Q) -> Option<RefMut<'a, K, V>> |
1056 | 0 | where |
1057 | 0 | K: Borrow<Q>, |
1058 | 0 | Q: Hash + Eq + ?Sized, |
1059 | | { |
1060 | 0 | let hash = self.hash_u64(&key); |
1061 | | |
1062 | 0 | let idx = self.determine_shard(hash as usize); |
1063 | | |
1064 | 0 | let shard = unsafe { self._yield_write_shard(idx) }; |
1065 | | |
1066 | 0 | if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) { |
1067 | | unsafe { |
1068 | 0 | let (k, v) = bucket.as_ref(); |
1069 | 0 | Some(RefMut::new(shard, k, v.as_ptr())) |
1070 | | } |
1071 | | } else { |
1072 | 0 | None |
1073 | | } |
1074 | 0 | } |
1075 | | |
1076 | 0 | fn _try_get<Q>(&'a self, key: &Q) -> TryResult<Ref<'a, K, V>> |
1077 | 0 | where |
1078 | 0 | K: Borrow<Q>, |
1079 | 0 | Q: Hash + Eq + ?Sized, |
1080 | | { |
1081 | 0 | let hash = self.hash_u64(&key); |
1082 | | |
1083 | 0 | let idx = self.determine_shard(hash as usize); |
1084 | | |
1085 | 0 | let shard = match unsafe { self._try_yield_read_shard(idx) } { |
1086 | 0 | Some(shard) => shard, |
1087 | 0 | None => return TryResult::Locked, |
1088 | | }; |
1089 | | |
1090 | 0 | if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) { |
1091 | | unsafe { |
1092 | 0 | let (k, v) = bucket.as_ref(); |
1093 | 0 | TryResult::Present(Ref::new(shard, k, v.as_ptr())) |
1094 | | } |
1095 | | } else { |
1096 | 0 | TryResult::Absent |
1097 | | } |
1098 | 0 | } |
1099 | | |
1100 | 0 | fn _try_get_mut<Q>(&'a self, key: &Q) -> TryResult<RefMut<'a, K, V>> |
1101 | 0 | where |
1102 | 0 | K: Borrow<Q>, |
1103 | 0 | Q: Hash + Eq + ?Sized, |
1104 | | { |
1105 | 0 | let hash = self.hash_u64(&key); |
1106 | | |
1107 | 0 | let idx = self.determine_shard(hash as usize); |
1108 | | |
1109 | 0 | let shard = match unsafe { self._try_yield_write_shard(idx) } { |
1110 | 0 | Some(shard) => shard, |
1111 | 0 | None => return TryResult::Locked, |
1112 | | }; |
1113 | | |
1114 | 0 | if let Some(bucket) = shard.find(hash, |(k, _v)| key == k.borrow()) { |
1115 | | unsafe { |
1116 | 0 | let (k, v) = bucket.as_ref(); |
1117 | 0 | TryResult::Present(RefMut::new(shard, k, v.as_ptr())) |
1118 | | } |
1119 | | } else { |
1120 | 0 | TryResult::Absent |
1121 | | } |
1122 | 0 | } |
1123 | | |
1124 | 0 | fn _shrink_to_fit(&self) { |
1125 | 0 | self.shards.iter().for_each(|s| { |
1126 | 0 | let mut shard = s.write(); |
1127 | 0 | let size = shard.len(); |
1128 | 0 | shard.shrink_to(size, |(k, _v)| { |
1129 | 0 | let mut hasher = self.hasher.build_hasher(); |
1130 | 0 | k.hash(&mut hasher); |
1131 | 0 | hasher.finish() |
1132 | 0 | }) |
1133 | 0 | }); |
1134 | 0 | } |
1135 | | |
1136 | 0 | fn _retain(&self, mut f: impl FnMut(&K, &mut V) -> bool) { |
1137 | 0 | self.shards.iter().for_each(|s| { |
1138 | | unsafe { |
1139 | 0 | let mut shard = s.write(); |
1140 | | // Here we only use `iter` as a temporary, preventing use-after-free |
1141 | 0 | for bucket in shard.iter() { |
1142 | 0 | let (k, v) = bucket.as_mut(); |
1143 | 0 | if !f(&*k, v.get_mut()) { |
1144 | 0 | shard.erase(bucket); |
1145 | 0 | } |
1146 | | } |
1147 | | } |
1148 | 0 | }); |
1149 | 0 | } |
1150 | | |
1151 | 0 | fn _len(&self) -> usize { |
1152 | 0 | self.shards.iter().map(|s| s.read().len()).sum() |
1153 | 0 | } |
1154 | | |
1155 | 0 | fn _capacity(&self) -> usize { |
1156 | 0 | self.shards.iter().map(|s| s.read().capacity()).sum() |
1157 | 0 | } |
1158 | | |
1159 | 0 | fn _alter<Q>(&self, key: &Q, f: impl FnOnce(&K, V) -> V) |
1160 | 0 | where |
1161 | 0 | K: Borrow<Q>, |
1162 | 0 | Q: Hash + Eq + ?Sized, |
1163 | | { |
1164 | 0 | if let Some(mut r) = self.get_mut(key) { |
1165 | 0 | util::map_in_place_2(r.pair_mut(), f); |
1166 | 0 | } |
1167 | 0 | } |
1168 | | |
1169 | 0 | fn _alter_all(&self, mut f: impl FnMut(&K, V) -> V) { |
1170 | 0 | self.iter_mut() |
1171 | 0 | .for_each(|mut m| util::map_in_place_2(m.pair_mut(), &mut f)); |
1172 | 0 | } |
1173 | | |
1174 | 0 | fn _view<Q, R>(&self, key: &Q, f: impl FnOnce(&K, &V) -> R) -> Option<R> |
1175 | 0 | where |
1176 | 0 | K: Borrow<Q>, |
1177 | 0 | Q: Hash + Eq + ?Sized, |
1178 | | { |
1179 | 0 | self.get(key).map(|r| { |
1180 | 0 | let (k, v) = r.pair(); |
1181 | 0 | f(k, v) |
1182 | 0 | }) |
1183 | 0 | } |
1184 | | |
1185 | 0 | fn _entry(&'a self, key: K) -> Entry<'a, K, V> { |
1186 | 0 | let hash = self.hash_u64(&key); |
1187 | | |
1188 | 0 | let idx = self.determine_shard(hash as usize); |
1189 | | |
1190 | 0 | let mut shard = unsafe { self._yield_write_shard(idx) }; |
1191 | | |
1192 | 0 | match shard.find_or_find_insert_slot( |
1193 | 0 | hash, |
1194 | 0 | |(k, _v)| k == &key, Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_entry::{closure#0} Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_entry::{closure#0} Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_entry::{closure#0} Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_entry::{closure#0} Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_entry::{closure#0} |
1195 | 0 | |(k, _v)| { |
1196 | 0 | let mut hasher = self.hasher.build_hasher(); |
1197 | 0 | k.hash(&mut hasher); |
1198 | 0 | hasher.finish() |
1199 | 0 | }, Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_entry::{closure#1} Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_entry::{closure#1} |
1200 | | ) { |
1201 | 0 | Ok(elem) => Entry::Occupied(unsafe { OccupiedEntry::new(shard, key, elem) }), |
1202 | 0 | Err(slot) => Entry::Vacant(unsafe { VacantEntry::new(shard, key, hash, slot) }), |
1203 | | } |
1204 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_entry Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_entry Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_entry Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_entry Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_entry |
1205 | | |
1206 | 0 | fn _try_entry(&'a self, key: K) -> Option<Entry<'a, K, V>> { |
1207 | 0 | let hash = self.hash_u64(&key); |
1208 | | |
1209 | 0 | let idx = self.determine_shard(hash as usize); |
1210 | | |
1211 | 0 | let mut shard = match unsafe { self._try_yield_write_shard(idx) } { |
1212 | 0 | Some(shard) => shard, |
1213 | 0 | None => return None, |
1214 | | }; |
1215 | | |
1216 | 0 | match shard.find_or_find_insert_slot( |
1217 | 0 | hash, |
1218 | 0 | |(k, _v)| k == &key, Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_try_entry::{closure#0} Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_try_entry::{closure#0} |
1219 | 0 | |(k, _v)| { |
1220 | 0 | let mut hasher = self.hasher.build_hasher(); |
1221 | 0 | k.hash(&mut hasher); |
1222 | 0 | hasher.finish() |
1223 | 0 | }, Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_try_entry::{closure#1} Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_try_entry::{closure#1} |
1224 | | ) { |
1225 | 0 | Ok(elem) => Some(Entry::Occupied(unsafe { |
1226 | 0 | OccupiedEntry::new(shard, key, elem) |
1227 | 0 | })), |
1228 | 0 | Err(slot) => Some(Entry::Vacant(unsafe { |
1229 | 0 | VacantEntry::new(shard, key, hash, slot) |
1230 | 0 | })), |
1231 | | } |
1232 | 0 | } Unexecuted instantiation: <dashmap::DashMap<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>> as dashmap::t::Map<usize, core::option::Option<gix_tempfile::forksafe::ForksafeTempfile>, std::hash::random::RandomState>>::_try_entry Unexecuted instantiation: <dashmap::DashMap<_, _, _> as dashmap::t::Map<_, _, _>>::_try_entry |
1233 | | |
1234 | 0 | fn _hasher(&self) -> S { |
1235 | 0 | self.hasher.clone() |
1236 | 0 | } |
1237 | | } |
1238 | | |
1239 | | impl<K: Eq + Hash + fmt::Debug, V: fmt::Debug, S: BuildHasher + Clone> fmt::Debug |
1240 | | for DashMap<K, V, S> |
1241 | | { |
1242 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1243 | 0 | let mut pmap = f.debug_map(); |
1244 | | |
1245 | 0 | for r in self { |
1246 | 0 | let (k, v) = r.pair(); |
1247 | 0 |
|
1248 | 0 | pmap.entry(k, v); |
1249 | 0 | } |
1250 | | |
1251 | 0 | pmap.finish() |
1252 | 0 | } |
1253 | | } |
1254 | | |
1255 | | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> Shl<(K, V)> for &'a DashMap<K, V, S> { |
1256 | | type Output = Option<V>; |
1257 | | |
1258 | 0 | fn shl(self, pair: (K, V)) -> Self::Output { |
1259 | 0 | self.insert(pair.0, pair.1) |
1260 | 0 | } |
1261 | | } |
1262 | | |
1263 | | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> Shr<&Q> for &'a DashMap<K, V, S> |
1264 | | where |
1265 | | K: Borrow<Q>, |
1266 | | Q: Hash + Eq + ?Sized, |
1267 | | { |
1268 | | type Output = Ref<'a, K, V>; |
1269 | | |
1270 | 0 | fn shr(self, key: &Q) -> Self::Output { |
1271 | 0 | self.get(key).unwrap() |
1272 | 0 | } |
1273 | | } |
1274 | | |
1275 | | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> BitOr<&Q> for &'a DashMap<K, V, S> |
1276 | | where |
1277 | | K: Borrow<Q>, |
1278 | | Q: Hash + Eq + ?Sized, |
1279 | | { |
1280 | | type Output = RefMut<'a, K, V>; |
1281 | | |
1282 | 0 | fn bitor(self, key: &Q) -> Self::Output { |
1283 | 0 | self.get_mut(key).unwrap() |
1284 | 0 | } |
1285 | | } |
1286 | | |
1287 | | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> Sub<&Q> for &'a DashMap<K, V, S> |
1288 | | where |
1289 | | K: Borrow<Q>, |
1290 | | Q: Hash + Eq + ?Sized, |
1291 | | { |
1292 | | type Output = Option<(K, V)>; |
1293 | | |
1294 | 0 | fn sub(self, key: &Q) -> Self::Output { |
1295 | 0 | self.remove(key) |
1296 | 0 | } |
1297 | | } |
1298 | | |
1299 | | impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone, Q> BitAnd<&Q> for &'a DashMap<K, V, S> |
1300 | | where |
1301 | | K: Borrow<Q>, |
1302 | | Q: Hash + Eq + ?Sized, |
1303 | | { |
1304 | | type Output = bool; |
1305 | | |
1306 | 0 | fn bitand(self, key: &Q) -> Self::Output { |
1307 | 0 | self.contains_key(key) |
1308 | 0 | } |
1309 | | } |
1310 | | |
1311 | | impl<K: Eq + Hash, V, S: BuildHasher + Clone> IntoIterator for DashMap<K, V, S> { |
1312 | | type Item = (K, V); |
1313 | | |
1314 | | type IntoIter = OwningIter<K, V, S>; |
1315 | | |
1316 | 0 | fn into_iter(self) -> Self::IntoIter { |
1317 | 0 | OwningIter::new(self) |
1318 | 0 | } |
1319 | | } |
1320 | | |
1321 | | impl<'a, K: Eq + Hash, V, S: BuildHasher + Clone> IntoIterator for &'a DashMap<K, V, S> { |
1322 | | type Item = RefMulti<'a, K, V>; |
1323 | | |
1324 | | type IntoIter = Iter<'a, K, V, S, DashMap<K, V, S>>; |
1325 | | |
1326 | 0 | fn into_iter(self) -> Self::IntoIter { |
1327 | 0 | self.iter() |
1328 | 0 | } |
1329 | | } |
1330 | | |
1331 | | impl<K: Eq + Hash, V, S: BuildHasher + Clone> Extend<(K, V)> for DashMap<K, V, S> { |
1332 | 0 | fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, intoiter: I) { |
1333 | 0 | for pair in intoiter.into_iter() { |
1334 | 0 | self.insert(pair.0, pair.1); |
1335 | 0 | } |
1336 | 0 | } |
1337 | | } |
1338 | | |
1339 | | impl<K: Eq + Hash, V, S: BuildHasher + Clone + Default> FromIterator<(K, V)> for DashMap<K, V, S> { |
1340 | 0 | fn from_iter<I: IntoIterator<Item = (K, V)>>(intoiter: I) -> Self { |
1341 | 0 | let mut map = DashMap::default(); |
1342 | | |
1343 | 0 | map.extend(intoiter); |
1344 | | |
1345 | 0 | map |
1346 | 0 | } |
1347 | | } |
1348 | | |
1349 | | #[cfg(feature = "typesize")] |
1350 | | impl<K, V, S> typesize::TypeSize for DashMap<K, V, S> |
1351 | | where |
1352 | | K: typesize::TypeSize + Eq + Hash, |
1353 | | V: typesize::TypeSize, |
1354 | | S: typesize::TypeSize + Clone + BuildHasher, |
1355 | | { |
1356 | | fn extra_size(&self) -> usize { |
1357 | | let shards_extra_size: usize = self |
1358 | | .shards |
1359 | | .iter() |
1360 | | .map(|shard_lock| { |
1361 | | let shard = shard_lock.read(); |
1362 | | let hashtable_size = shard.allocation_info().1.size(); |
1363 | | |
1364 | | // Safety: The iterator is dropped before the HashTable |
1365 | | let iter = unsafe { shard.iter() }; |
1366 | | let entry_size_iter = iter.map(|bucket| { |
1367 | | // Safety: The iterator returns buckets with valid pointers to entries |
1368 | | let (key, value) = unsafe { bucket.as_ref() }; |
1369 | | key.extra_size() + value.get().extra_size() |
1370 | | }); |
1371 | | |
1372 | | core::mem::size_of::<CachePadded<RwLock<HashMap<K, V>>>>() |
1373 | | + hashtable_size |
1374 | | + entry_size_iter.sum::<usize>() |
1375 | | }) |
1376 | | .sum(); |
1377 | | |
1378 | | self.hasher.extra_size() + shards_extra_size |
1379 | | } |
1380 | | |
1381 | | typesize::if_typesize_details! { |
1382 | | fn get_collection_item_count(&self) -> Option<usize> { |
1383 | | Some(self.len()) |
1384 | | } |
1385 | | } |
1386 | | } |
1387 | | |
1388 | | #[cfg(test)] |
1389 | | mod tests { |
1390 | | use crate::DashMap; |
1391 | | use std::collections::hash_map::RandomState; |
1392 | | |
1393 | | #[test] |
1394 | | fn test_basic() { |
1395 | | let dm = DashMap::new(); |
1396 | | |
1397 | | dm.insert(0, 0); |
1398 | | |
1399 | | assert_eq!(dm.get(&0).unwrap().value(), &0); |
1400 | | } |
1401 | | |
1402 | | #[test] |
1403 | | fn test_default() { |
1404 | | let dm: DashMap<u32, u32> = DashMap::default(); |
1405 | | |
1406 | | dm.insert(0, 0); |
1407 | | |
1408 | | assert_eq!(dm.get(&0).unwrap().value(), &0); |
1409 | | } |
1410 | | |
1411 | | #[test] |
1412 | | fn test_multiple_hashes() { |
1413 | | let dm: DashMap<u32, u32> = DashMap::default(); |
1414 | | |
1415 | | for i in 0..100 { |
1416 | | dm.insert(0, i); |
1417 | | |
1418 | | dm.insert(i, i); |
1419 | | } |
1420 | | |
1421 | | for i in 1..100 { |
1422 | | let r = dm.get(&i).unwrap(); |
1423 | | |
1424 | | assert_eq!(i, *r.value()); |
1425 | | |
1426 | | assert_eq!(i, *r.key()); |
1427 | | } |
1428 | | |
1429 | | let r = dm.get(&0).unwrap(); |
1430 | | |
1431 | | assert_eq!(99, *r.value()); |
1432 | | } |
1433 | | |
1434 | | #[test] |
1435 | | fn test_more_complex_values() { |
1436 | | #[derive(Hash, PartialEq, Debug, Clone)] |
1437 | | |
1438 | | struct T0 { |
1439 | | s: String, |
1440 | | u: u8, |
1441 | | } |
1442 | | |
1443 | | let dm = DashMap::new(); |
1444 | | |
1445 | | let range = 0..10; |
1446 | | |
1447 | | for i in range { |
1448 | | let t = T0 { |
1449 | | s: i.to_string(), |
1450 | | u: i as u8, |
1451 | | }; |
1452 | | |
1453 | | dm.insert(i, t.clone()); |
1454 | | |
1455 | | assert_eq!(&t, dm.get(&i).unwrap().value()); |
1456 | | } |
1457 | | } |
1458 | | |
1459 | | #[test] |
1460 | | fn test_different_hashers_randomstate() { |
1461 | | let dm_hm_default: DashMap<u32, u32, RandomState> = |
1462 | | DashMap::with_hasher(RandomState::new()); |
1463 | | |
1464 | | for i in 0..10 { |
1465 | | dm_hm_default.insert(i, i); |
1466 | | |
1467 | | assert_eq!(i, *dm_hm_default.get(&i).unwrap().value()); |
1468 | | } |
1469 | | } |
1470 | | |
1471 | | #[test] |
1472 | | fn test_map_view() { |
1473 | | let dm = DashMap::new(); |
1474 | | |
1475 | | let vegetables: [String; 4] = [ |
1476 | | "Salad".to_string(), |
1477 | | "Beans".to_string(), |
1478 | | "Potato".to_string(), |
1479 | | "Tomato".to_string(), |
1480 | | ]; |
1481 | | |
1482 | | // Give it some values |
1483 | | dm.insert(0, "Banana".to_string()); |
1484 | | dm.insert(4, "Pear".to_string()); |
1485 | | dm.insert(9, "Potato".to_string()); |
1486 | | dm.insert(12, "Chicken".to_string()); |
1487 | | |
1488 | | let potato_vegetableness = dm.view(&9, |_, v| vegetables.contains(v)); |
1489 | | assert_eq!(potato_vegetableness, Some(true)); |
1490 | | |
1491 | | let chicken_vegetableness = dm.view(&12, |_, v| vegetables.contains(v)); |
1492 | | assert_eq!(chicken_vegetableness, Some(false)); |
1493 | | |
1494 | | let not_in_map = dm.view(&30, |_k, _v| false); |
1495 | | assert_eq!(not_in_map, None); |
1496 | | } |
1497 | | |
1498 | | #[test] |
1499 | | fn test_try_get() { |
1500 | | { |
1501 | | let map = DashMap::new(); |
1502 | | map.insert("Johnny", 21); |
1503 | | |
1504 | | assert_eq!(*map.try_get("Johnny").unwrap(), 21); |
1505 | | |
1506 | | let _result1_locking = map.get_mut("Johnny"); |
1507 | | |
1508 | | let result2 = map.try_get("Johnny"); |
1509 | | assert!(result2.is_locked()); |
1510 | | } |
1511 | | |
1512 | | { |
1513 | | let map = DashMap::new(); |
1514 | | map.insert("Johnny", 21); |
1515 | | |
1516 | | *map.try_get_mut("Johnny").unwrap() += 1; |
1517 | | assert_eq!(*map.get("Johnny").unwrap(), 22); |
1518 | | |
1519 | | let _result1_locking = map.get("Johnny"); |
1520 | | |
1521 | | let result2 = map.try_get_mut("Johnny"); |
1522 | | assert!(result2.is_locked()); |
1523 | | } |
1524 | | } |
1525 | | |
1526 | | #[test] |
1527 | | fn test_try_reserve() { |
1528 | | let mut map: DashMap<i32, i32> = DashMap::new(); |
1529 | | // DashMap is empty and doesn't allocate memory |
1530 | | assert_eq!(map.capacity(), 0); |
1531 | | |
1532 | | map.try_reserve(10).unwrap(); |
1533 | | |
1534 | | // And now map can hold at least 10 elements |
1535 | | assert!(map.capacity() >= 10); |
1536 | | } |
1537 | | |
1538 | | #[test] |
1539 | | fn test_try_reserve_errors() { |
1540 | | let mut map: DashMap<i32, i32> = DashMap::new(); |
1541 | | |
1542 | | match map.try_reserve(usize::MAX) { |
1543 | | Err(_) => {} |
1544 | | _ => panic!("should have raised CapacityOverflow error"), |
1545 | | } |
1546 | | } |
1547 | | } |