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