moka_cht/segment/
map.rs

1//! A lock-free hash map implemented with segmented bucket pointer arrays, open
2//! addressing, and linear probing.
3
4use crate::map::{
5    bucket::{self, BucketArray},
6    bucket_array_ref::BucketArrayRef,
7    DefaultHashBuilder,
8};
9
10use std::{
11    borrow::Borrow,
12    hash::{BuildHasher, Hash},
13    ptr,
14    sync::atomic::{self, AtomicUsize, Ordering},
15};
16
17use crossbeam_epoch::Atomic;
18
19/// A lock-free hash map implemented with segmented bucket pointer arrays, open
20/// addressing, and linear probing.
21///
22/// This struct is re-exported as `moka_cht::SegmentedHashMap`.
23///
24/// # Examples
25///
26/// ```rust
27/// use moka_cht::SegmentedHashMap;
28/// use std::{sync::Arc, thread};
29///
30/// let map = Arc::new(SegmentedHashMap::with_num_segments(4));
31///
32/// let threads: Vec<_> = (0..16)
33///     .map(|i| {
34///         let map = map.clone();
35///
36///         thread::spawn(move || {
37///             const NUM_INSERTIONS: usize = 64;
38///
39///             for j in (i * NUM_INSERTIONS)..((i + 1) * NUM_INSERTIONS) {
40///                 map.insert_and(j, j, |_prev| unreachable!());
41///             }
42///         })
43///     })
44///     .collect();
45///
46/// let _: Vec<_> = threads.into_iter().map(|t| t.join()).collect();
47/// ```
48///
49/// The number of segments can be specified on a per-`HashMap` basis using the
50/// following methods:
51///
52/// - [`with_num_segments`]
53/// - [`with_num_segments_and_capacity`]
54/// - [`with_num_segments_and_hasher`]
55/// - [`with_num_segments_capacity_and_hasher`]
56///
57/// By default, the `num-cpus` feature is enabled so the following methods will be
58/// available:
59///
60/// - [`new`]
61/// - [`with_capacity`]
62/// - [`with_hasher`]
63/// - [`with_capacity_and_hasher`]
64///
65/// They will create maps with twice as many segments as the system has CPUs.
66///
67/// # Hashing Algorithm
68///
69/// By default, `HashMap` uses a hashing algorithm selected to provide resistance
70/// against HashDoS attacks. It will the same one used by
71/// `std::collections::HashMap`, which is currently SipHash 1-3.
72///
73/// While SipHash's performance is very competitive for medium sized keys, other
74/// hashing algorithms will outperform it for small keys such as integers as well as
75/// large keys such as long strings. However those algorithms will typically not
76/// protect against attacks such as HashDoS.
77///
78/// The hashing algorithm can be replaced on a per-`HashMap` basis using one of the
79/// following methods:
80///
81/// - [`default`]
82/// - [`with_hasher`]
83/// - [`with_capacity_and_hasher`]
84/// - [`with_num_segments_and_hasher`]
85/// - [`with_num_segments_capacity_and_hasher`]
86///
87/// Many alternative algorithms are available on crates.io, such as the [`aHash`]
88/// crate.
89///
90/// It is required that the keys implement the [`Eq`] and [`Hash`] traits,
91/// although this can frequently be achieved by using
92/// `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, it is
93/// important that the following property holds:
94///
95/// ```text
96/// k1 == k2 -> hash(k1) == hash(k2)
97/// ```
98///
99/// In other words, if two keys are equal, their hashes must be equal.
100///
101/// It is a logic error for a key to be modified in such a way that the key's
102/// hash, as determined by the [`Hash`] trait, or its equality, as determined by
103/// the [`Eq`] trait, changes while it is in the map. This is normally only
104/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
105///
106/// [`aHash`]: https://crates.io/crates/ahash
107/// [`default`]: #method.default
108/// [`with_hasher`]: #method.with_hasher
109/// [`with_capacity`]: #method.with_capacity
110/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher
111/// [`with_num_segments_and_hasher`]: #method.with_num_segments_and_hasher
112/// [`with_num_segments_capacity_and_hasher`]: #method.with_num_segments_capacity_and_hasher
113/// [`with_num_segments`]: #method.with_num_segments
114/// [`with_num_segments_and_capacity`]: #method.with_num_segments_and_capacity
115/// [`new`]: #method.new
116/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
117/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
118/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Ref.html
119/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html
120pub struct HashMap<K, V, S = DefaultHashBuilder> {
121    segments: Box<[Segment<K, V>]>,
122    build_hasher: S,
123    len: AtomicUsize,
124    segment_shift: u32,
125}
126
127#[cfg(feature = "num-cpus")]
128impl<K, V> HashMap<K, V, DefaultHashBuilder> {
129    /// Creates an empty `HashMap`.
130    ///
131    /// The hash map is initially created with a capacity of 0, so it will not
132    /// allocate bucket pointer arrays until it is first inserted into. However,
133    /// it will always allocate memory for segment pointers and lengths.
134    ///
135    /// The `HashMap` will be created with at least twice as many segments as
136    /// the system has CPUs.
137    pub fn new() -> Self {
138        Self::with_num_segments_capacity_and_hasher(
139            default_num_segments(),
140            0,
141            DefaultHashBuilder::default(),
142        )
143    }
144
145    /// Creates an empty `HashMap` with the specified capacity.
146    ///
147    /// The hash map will be able to hold at least `capacity` elements without
148    /// reallocating any bucket pointer arrays. If `capacity` is 0, the hash map
149    /// will not allocate any bucket pointer arrays. However, it will always
150    /// allocate memory for segment pointers and lengths.
151    ///
152    /// The `HashMap` will be created with at least twice as many segments as
153    /// the system has CPUs.
154    pub fn with_capacity(capacity: usize) -> Self {
155        Self::with_num_segments_capacity_and_hasher(
156            default_num_segments(),
157            capacity,
158            DefaultHashBuilder::default(),
159        )
160    }
161}
162
163#[cfg(feature = "num-cpus")]
164impl<K, V, S: BuildHasher> HashMap<K, V, S> {
165    /// Creates an empty `HashMap` which will use the given hash builder to hash
166    /// keys.
167    ///
168    /// The hash map is initially created with a capacity of 0, so it will not
169    /// allocate bucket pointer arrays until it is first inserted into. However,
170    /// it will always allocate memory for segment pointers and lengths.
171    ///
172    /// The `HashMap` will be created with at least twice as many segments as
173    /// the system has CPUs.
174    pub fn with_hasher(build_hasher: S) -> Self {
175        Self::with_num_segments_capacity_and_hasher(default_num_segments(), 0, build_hasher)
176    }
177
178    /// Creates an empty `HashMap` with the specified capacity, using
179    /// `build_hasher` to hash the keys.
180    ///
181    /// The hash map will be able to hold at least `capacity` elements without
182    /// reallocating any bucket pointer arrays. If `capacity` is 0, the hash map
183    /// will not allocate any bucket pointer arrays. However, it will always
184    /// allocate memory for segment pointers and lengths.
185    ///
186    /// The `HashMap` will be created with at least twice as many segments as
187    /// the system has CPUs.
188    pub fn with_capacity_and_hasher(capacity: usize, build_hasher: S) -> Self {
189        Self::with_num_segments_capacity_and_hasher(default_num_segments(), capacity, build_hasher)
190    }
191}
192
193impl<K, V> HashMap<K, V, DefaultHashBuilder> {
194    /// Creates an empty `HashMap` with the specified number of segments.
195    ///
196    /// The hash map is initially created with a capacity of 0, so it will not
197    /// allocate bucket pointer arrays until it is first inserted into. However,
198    /// it will always allocate memory for segment pointers and lengths.
199    ///
200    /// # Panics
201    ///
202    /// Panics if `num_segments` is 0.
203    pub fn with_num_segments(num_segments: usize) -> Self {
204        Self::with_num_segments_capacity_and_hasher(num_segments, 0, DefaultHashBuilder::default())
205    }
206
207    /// Creates an empty `HashMap` with the specified number of segments and
208    /// capacity.
209    ///
210    /// The hash map will be able to hold at least `capacity` elements without
211    /// reallocating any bucket pointer arrays. If `capacity` is 0, the hash map
212    /// will not allocate any bucket pointer arrays. However, it will always
213    /// allocate memory for segment pointers and lengths.
214    ///
215    /// # Panics
216    ///
217    /// Panics if `num_segments` is 0.
218    pub fn with_num_segments_and_capacity(num_segments: usize, capacity: usize) -> Self {
219        Self::with_num_segments_capacity_and_hasher(
220            num_segments,
221            capacity,
222            DefaultHashBuilder::default(),
223        )
224    }
225}
226
227impl<K, V, S> HashMap<K, V, S> {
228    /// Creates an empty `HashMap` with the specified number of segments, using
229    /// `build_hasher` to hash the keys.
230    ///
231    /// The hash map is initially created with a capacity of 0, so it will not
232    /// allocate bucket pointer arrays until it is first inserted into. However,
233    /// it will always allocate memory for segment pointers and lengths.
234    ///
235    /// # Panics
236    ///
237    /// Panics if `num_segments` is 0.
238    pub fn with_num_segments_and_hasher(num_segments: usize, build_hasher: S) -> Self {
239        Self::with_num_segments_capacity_and_hasher(num_segments, 0, build_hasher)
240    }
241
242    /// Creates an empty `HashMap` with the specified number of segments and
243    /// capacity, using `build_hasher` to hash the keys.
244    ///
245    /// The hash map will be able to hold at least `capacity` elements without
246    /// reallocating any bucket pointer arrays. If `capacity` is 0, the hash map
247    /// will not allocate any bucket pointer arrays. However, it will always
248    /// allocate memory for segment pointers and lengths.
249    ///
250    /// # Panics
251    ///
252    /// Panics if `num_segments` is 0.
253    pub fn with_num_segments_capacity_and_hasher(
254        num_segments: usize,
255        capacity: usize,
256        build_hasher: S,
257    ) -> Self {
258        assert!(num_segments > 0);
259
260        let actual_num_segments = num_segments.next_power_of_two();
261        let segment_shift = 64 - actual_num_segments.trailing_zeros();
262
263        let mut segments = Vec::with_capacity(actual_num_segments);
264
265        if capacity == 0 {
266            unsafe {
267                ptr::write_bytes(segments.as_mut_ptr(), 0, actual_num_segments);
268                segments.set_len(actual_num_segments);
269            }
270        } else {
271            let actual_capacity = (capacity * 2).next_power_of_two();
272
273            for _ in 0..actual_num_segments {
274                segments.push(Segment {
275                    bucket_array: Atomic::new(BucketArray::with_length(0, actual_capacity)),
276                    len: AtomicUsize::new(0),
277                });
278            }
279        }
280
281        let segments = segments.into_boxed_slice();
282
283        Self {
284            segments,
285            build_hasher,
286            len: AtomicUsize::new(0),
287            segment_shift,
288        }
289    }
290
291    /// Returns the number of elements in the map.
292    ///
293    /// # Safety
294    ///
295    /// This method on its own is safe, but other threads can add or remove
296    /// elements at any time.
297    pub fn len(&self) -> usize {
298        self.len.load(Ordering::Relaxed)
299    }
300
301    /// Returns `true` if the map contains no elements.
302    ///
303    /// # Safety
304    ///
305    /// This method on its own is safe, but other threads can add or remove
306    /// elements at any time.
307    pub fn is_empty(&self) -> bool {
308        self.len() == 0
309    }
310
311    /// Returns the number of elements the map can hold without reallocating any
312    /// bucket pointer arrays.
313    ///
314    /// Note that all mutating operations except removal will result in a bucket
315    /// being allocated or reallocated.
316    ///
317    /// # Safety
318    ///
319    /// This method on its own is safe, but other threads can increase the
320    /// capacity of each segment at any time by adding elements.
321    pub fn capacity(&self) -> usize {
322        let guard = &crossbeam_epoch::pin();
323
324        self.segments
325            .iter()
326            .map(|s| s.bucket_array.load_consume(guard))
327            .map(|p| unsafe { p.as_ref() })
328            .map(|a| a.map(BucketArray::capacity).unwrap_or(0))
329            .min()
330            .unwrap()
331    }
332
333    /// Returns the number of elements the `index`-th segment of the map can
334    /// hold without reallocating a bucket pointer array.
335    ///
336    /// Note that all mutating operations, with the exception of removing
337    /// elements, will result in an allocation for a new bucket.
338    ///
339    /// # Safety
340    ///
341    /// This method on its own is safe, but other threads can increase the
342    /// capacity of a segment at any time by adding elements.
343    pub fn segment_capacity(&self, index: usize) -> usize {
344        assert!(index < self.segments.len());
345
346        let guard = &crossbeam_epoch::pin();
347
348        unsafe {
349            self.segments[index]
350                .bucket_array
351                .load_consume(guard)
352                .as_ref()
353        }
354        .map(BucketArray::capacity)
355        .unwrap_or(0)
356    }
357
358    /// Returns the number of segments in the map.
359    pub fn num_segments(&self) -> usize {
360        self.segments.len()
361    }
362}
363
364impl<K, V, S: BuildHasher> HashMap<K, V, S> {
365    /// Returns the index of the segment that `key` would belong to if inserted
366    /// into the map.
367    pub fn segment_index<Q: Hash>(&self, key: &Q) -> usize
368    where
369        K: Borrow<Q>,
370    {
371        let hash = bucket::hash(&self.build_hasher, key);
372
373        self.segment_index_from_hash(hash)
374    }
375}
376
377impl<K: Hash + Eq, V, S: BuildHasher> HashMap<K, V, S> {
378    /// Returns a clone of the value corresponding to the key.
379    ///
380    /// The key may be any borrowed form of the map's key type, but
381    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
382    /// the key type.
383    ///
384    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
385    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
386    #[inline]
387    pub fn get<Q: Hash + Eq + ?Sized>(&self, key: &Q) -> Option<V>
388    where
389        K: Borrow<Q>,
390        V: Clone,
391    {
392        self.get_key_value_and(key, |_, v| v.clone())
393    }
394
395    /// Returns a clone of the the key-value pair corresponding to the supplied
396    /// key.
397    ///
398    /// The supplied key may be any borrowed form of the map's key type, but
399    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for the key
400    /// type.
401    ///
402    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
403    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
404    #[inline]
405    pub fn get_key_value<Q: Hash + Eq + ?Sized>(&self, key: &Q) -> Option<(K, V)>
406    where
407        K: Borrow<Q> + Clone,
408        V: Clone,
409    {
410        self.get_key_value_and(key, |k, v| (k.clone(), v.clone()))
411    }
412
413    /// Returns the result of invoking a function with a reference to the value
414    /// corresponding to the key.
415    ///
416    /// The key may be any borrowed form of the map's key type, but
417    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
418    /// the key type.
419    ///
420    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
421    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
422    #[inline]
423    pub fn get_and<Q: Hash + Eq + ?Sized, F: FnOnce(&V) -> T, T>(
424        &self,
425        key: &Q,
426        with_value: F,
427    ) -> Option<T>
428    where
429        K: Borrow<Q>,
430    {
431        self.get_key_value_and(key, move |_, v| with_value(v))
432    }
433
434    /// Returns the result of invoking a function with a reference to the
435    /// key-value pair corresponding to the supplied key.
436    ///
437    /// The supplied key may be any borrowed form of the map's key type, but
438    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for the key
439    /// type.
440    ///
441    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
442    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
443    #[inline]
444    pub fn get_key_value_and<Q: Hash + Eq + ?Sized, F: FnOnce(&K, &V) -> T, T>(
445        &self,
446        key: &Q,
447        with_entry: F,
448    ) -> Option<T>
449    where
450        K: Borrow<Q>,
451    {
452        let hash = bucket::hash(&self.build_hasher, &key);
453
454        self.bucket_array_ref(hash)
455            .get_key_value_and(key, hash, with_entry)
456    }
457
458    /// Inserts a key-value pair into the map, returning a clone of the value
459    /// previously corresponding to the key.
460    ///
461    /// If the map did have this key present, both the key and value are
462    /// updated.
463    #[inline]
464    pub fn insert(&self, key: K, value: V) -> Option<V>
465    where
466        V: Clone,
467    {
468        self.insert_entry_and(key, value, |_, v| v.clone())
469    }
470
471    /// Inserts a key-value pair into the map, returning a clone of the
472    /// key-value pair previously corresponding to the supplied key.
473    ///
474    /// If the map did have this key present, both the key and value are
475    /// updated.
476    #[inline]
477    pub fn insert_entry(&self, key: K, value: V) -> Option<(K, V)>
478    where
479        K: Clone,
480        V: Clone,
481    {
482        self.insert_entry_and(key, value, |k, v| (k.clone(), v.clone()))
483    }
484
485    /// Inserts a key-value pair into the map, returning the result of invoking
486    /// a function with a reference to the value previously corresponding to the
487    /// key.
488    ///
489    /// If the map did have this key present, both the key and value are
490    /// updated.
491    #[inline]
492    pub fn insert_and<F: FnOnce(&V) -> T, T>(
493        &self,
494        key: K,
495        value: V,
496        with_previous_value: F,
497    ) -> Option<T> {
498        self.insert_entry_and(key, value, move |_, v| with_previous_value(v))
499    }
500
501    /// Inserts a key-value pair into the map, returning the result of invoking
502    /// a function with a reference to the key-value pair previously
503    /// corresponding to the supplied key.
504    ///
505    /// If the map did have this key present, both the key and value are
506    /// updated.
507    #[inline]
508    pub fn insert_entry_and<F: FnOnce(&K, &V) -> T, T>(
509        &self,
510        key: K,
511        value: V,
512        with_previous_entry: F,
513    ) -> Option<T> {
514        let hash = bucket::hash(&self.build_hasher, &key);
515
516        let result =
517            self.bucket_array_ref(hash)
518                .insert_entry_and(key, hash, value, with_previous_entry);
519
520        if result.is_none() {
521            self.len.fetch_add(1, Ordering::Relaxed);
522        }
523
524        result
525    }
526
527    /// Removes a key from the map, returning a clone of the value previously
528    /// corresponding to the key.
529    ///
530    /// The key may be any borrowed form of the map's key type, but
531    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
532    /// the key type.
533    ///
534    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
535    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
536    #[inline]
537    pub fn remove<Q: Hash + Eq + ?Sized>(&self, key: &Q) -> Option<V>
538    where
539        K: Borrow<Q>,
540        V: Clone,
541    {
542        self.remove_entry_if_and(key, |_, _| true, |_, v| v.clone())
543    }
544
545    /// Removes a key from the map, returning a clone of the key-value pair
546    /// previously corresponding to the key.
547    ///
548    /// The key may be any borrowed form of the map's key type, but
549    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
550    /// the key type.
551    ///
552    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
553    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
554    #[inline]
555    pub fn remove_entry<Q: Hash + Eq + ?Sized>(&self, key: &Q) -> Option<(K, V)>
556    where
557        K: Borrow<Q> + Clone,
558        V: Clone,
559    {
560        self.remove_entry_if_and(key, |_, _| true, |k, v| (k.clone(), v.clone()))
561    }
562
563    /// Remove a key from the map, returning the result of invoking a function
564    /// with a reference to the value previously corresponding to the key.
565    ///
566    /// The key may be any borrowed form of the map's key type, but
567    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
568    /// the key type.
569    ///
570    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
571    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
572    #[inline]
573    pub fn remove_and<Q: Hash + Eq + ?Sized, F: FnOnce(&V) -> T, T>(
574        &self,
575        key: &Q,
576        with_previous_value: F,
577    ) -> Option<T>
578    where
579        K: Borrow<Q>,
580    {
581        self.remove_entry_if_and(key, |_, _| true, move |_, v| with_previous_value(v))
582    }
583
584    /// Removes a key from the map, returning the result of invoking a function
585    /// with a reference to the key-value pair previously corresponding to the
586    /// key.
587    ///
588    /// The key may be any borrowed form of the map's key type, but
589    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
590    /// the key type.
591    ///
592    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
593    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
594    #[inline]
595    pub fn remove_entry_and<Q: Hash + Eq + ?Sized, F: FnOnce(&K, &V) -> T, T>(
596        &self,
597        key: &Q,
598        with_previous_entry: F,
599    ) -> Option<T>
600    where
601        K: Borrow<Q>,
602    {
603        self.remove_entry_if_and(key, |_, _| true, with_previous_entry)
604    }
605
606    /// Removes a key from the map if a condition is met, returning a clone of
607    /// the value previously corresponding to the key.
608    ///
609    /// `condition` will be invoked at least once if [`Some`] is returned. It
610    /// may also be invoked one or more times if [`None`] is returned.
611    ///
612    /// The key may be any borrowed form of the map's key type, but
613    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
614    /// the key type.
615    ///
616    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
617    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
618    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
619    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
620    pub fn remove_if<Q: Hash + Eq + ?Sized, F: FnMut(&K, &V) -> bool>(
621        &self,
622        key: &Q,
623        condition: F,
624    ) -> Option<V>
625    where
626        K: Borrow<Q>,
627        V: Clone,
628    {
629        self.remove_entry_if_and(key, condition, move |_, v| v.clone())
630    }
631
632    /// Removes a key from the map if a condition is met, returning a clone of
633    /// the key-value pair previously corresponding to the key.
634    ///
635    /// `condition` will be invoked at least once if [`Some`] is returned. It
636    /// may also be invoked one or more times if [`None`] is returned.
637    ///
638    /// The key may be any borrowed form of the map's key type, but
639    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
640    /// the key type.
641    ///
642    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
643    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
644    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
645    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
646    #[inline]
647    pub fn remove_entry_if<Q: Hash + Eq + ?Sized, F: FnMut(&K, &V) -> bool>(
648        &self,
649        key: &Q,
650        condition: F,
651    ) -> Option<(K, V)>
652    where
653        K: Clone + Borrow<Q>,
654        V: Clone,
655    {
656        self.remove_entry_if_and(key, condition, move |k, v| (k.clone(), v.clone()))
657    }
658
659    /// Remove a key from the map if a condition is met, returning the result of
660    /// invoking a function with a reference to the value previously
661    /// corresponding to the key.
662    ///
663    /// `condition` will be invoked at least once if [`Some`] is returned. It
664    /// may also be invoked one or more times if [`None`] is returned.
665    ///
666    /// The key may be any borrowed form of the map's key type, but
667    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
668    /// the key type.
669    ///
670    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
671    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
672    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
673    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
674    #[inline]
675    pub fn remove_if_and<Q: Hash + Eq + ?Sized, F: FnMut(&K, &V) -> bool, G: FnOnce(&V) -> T, T>(
676        &self,
677        key: &Q,
678        condition: F,
679        with_previous_value: G,
680    ) -> Option<T>
681    where
682        K: Borrow<Q>,
683    {
684        self.remove_entry_if_and(key, condition, move |_, v| with_previous_value(v))
685    }
686
687    /// Removes a key from the map if a condition is met, returning the result
688    /// of invoking a function with a reference to the key-value pair previously
689    /// corresponding to the key.
690    ///
691    /// `condition` will be invoked at least once if [`Some`] is returned. It
692    /// may also be invoked one or more times if [`None`] is returned.
693    ///
694    /// The key may be any borrowed form of the map's key type, but
695    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
696    /// the key type.
697    ///
698    /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
699    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
700    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
701    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
702    #[inline]
703    pub fn remove_entry_if_and<
704        Q: Hash + Eq + ?Sized,
705        F: FnMut(&K, &V) -> bool,
706        G: FnOnce(&K, &V) -> T,
707        T,
708    >(
709        &self,
710        key: &Q,
711        condition: F,
712        with_previous_entry: G,
713    ) -> Option<T>
714    where
715        K: Borrow<Q>,
716    {
717        let hash = bucket::hash(&self.build_hasher, &key);
718
719        self.bucket_array_ref(hash)
720            .remove_entry_if_and(key, hash, condition, move |k, v| {
721                self.len.fetch_sub(1, Ordering::Relaxed);
722
723                with_previous_entry(k, v)
724            })
725    }
726
727    /// If no value corresponds to the key, insert a new key-value pair into
728    /// the map. Otherwise, modify the existing value and return a clone of the
729    /// value previously corresponding to the key.
730    ///
731    /// `on_modify` will be invoked at least once if [`Some`] is returned. It
732    /// may also be invoked one or more times if [`None`] is returned.
733    ///
734    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
735    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
736    #[inline]
737    pub fn insert_or_modify<F: FnMut(&K, &V) -> V>(
738        &self,
739        key: K,
740        value: V,
741        on_modify: F,
742    ) -> Option<V>
743    where
744        V: Clone,
745    {
746        self.insert_with_or_modify_entry_and(key, move || value, on_modify, |_, v| v.clone())
747    }
748
749    /// If no value corresponds to the key, insert a new key-value pair into
750    /// the map. Otherwise, modify the existing value and return a clone of the
751    /// key-value pair previously corresponding to the key.
752    ///
753    /// `on_modify` will be invoked at least once if [`Some`] is returned. It
754    /// may also be invoked one or more times if [`None`] is returned.
755    ///
756    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
757    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
758    #[inline]
759    pub fn insert_or_modify_entry<F: FnMut(&K, &V) -> V>(
760        &self,
761        key: K,
762        value: V,
763        on_modify: F,
764    ) -> Option<(K, V)>
765    where
766        K: Clone,
767        V: Clone,
768    {
769        self.insert_with_or_modify_entry_and(
770            key,
771            move || value,
772            on_modify,
773            |k, v| (k.clone(), v.clone()),
774        )
775    }
776
777    /// If no value corresponds to the key, invoke a default function to insert
778    /// a new key-value pair into the map. Otherwise, modify the existing value
779    /// and return a clone of the value previously corresponding to the key.
780    ///
781    /// `on_insert` may be invoked, even if [`None`] is returned.
782    ///
783    /// `on_modify` will be invoked at least once if [`Some`] is returned. It
784    /// may also be invoked one or more times if [`None`] is returned.
785    ///
786    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
787    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
788    #[inline]
789    pub fn insert_with_or_modify<F: FnOnce() -> V, G: FnMut(&K, &V) -> V>(
790        &self,
791        key: K,
792        on_insert: F,
793        on_modify: G,
794    ) -> Option<V>
795    where
796        V: Clone,
797    {
798        self.insert_with_or_modify_entry_and(key, on_insert, on_modify, |_, v| v.clone())
799    }
800
801    /// If no value corresponds to the key, invoke a default function to insert
802    /// a new key-value pair into the map. Otherwise, modify the existing value
803    /// and return a clone of the key-value pair previously corresponding to the
804    /// key.
805    ///
806    /// `on_insert` may be invoked, even if [`None`] is returned.
807    ///
808    /// `on_modify` will be invoked at least once if [`Some`] is returned. It
809    /// may also be invoked one or more times if [`None`] is returned.
810    ///
811    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
812    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
813    #[inline]
814    pub fn insert_with_or_modify_entry<F: FnOnce() -> V, G: FnMut(&K, &V) -> V>(
815        &self,
816        key: K,
817        on_insert: F,
818        on_modify: G,
819    ) -> Option<(K, V)>
820    where
821        K: Clone,
822        V: Clone,
823    {
824        self.insert_with_or_modify_entry_and(key, on_insert, on_modify, |k, v| {
825            (k.clone(), v.clone())
826        })
827    }
828
829    /// If no value corresponds to the key, insert a new key-value pair into
830    /// the map. Otherwise, modify the existing value and return the result of
831    /// invoking a function with a reference to the value previously
832    /// corresponding to the key.
833    ///
834    /// `on_modify` will be invoked at least once if [`Some`] is returned. It
835    /// may also be invoked one or more times if [`None`] is returned.
836    ///
837    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
838    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
839    #[inline]
840    pub fn insert_or_modify_and<F: FnMut(&K, &V) -> V, G: FnOnce(&V) -> T, T>(
841        &self,
842        key: K,
843        value: V,
844        on_modify: F,
845        with_old_value: G,
846    ) -> Option<T> {
847        self.insert_with_or_modify_entry_and(
848            key,
849            move || value,
850            on_modify,
851            move |_, v| with_old_value(v),
852        )
853    }
854
855    /// If no value corresponds to the key, insert a new key-value pair into
856    /// the map. Otherwise, modify the existing value and return the result of
857    /// invoking a function with a reference to the key-value pair previously
858    /// corresponding to the supplied key.
859    ///
860    /// `on_modify` will be invoked at least once if [`Some`] is returned. It
861    /// may also be invoked one or more times if [`None`] is returned.
862    ///
863    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
864    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
865    #[inline]
866    pub fn insert_or_modify_entry_and<F: FnMut(&K, &V) -> V, G: FnOnce(&K, &V) -> T, T>(
867        &self,
868        key: K,
869        value: V,
870        on_modify: F,
871        with_old_entry: G,
872    ) -> Option<T> {
873        self.insert_with_or_modify_entry_and(key, move || value, on_modify, with_old_entry)
874    }
875
876    /// If no value corresponds to the key, invoke a default function to insert
877    /// a new key-value pair into the map. Otherwise, modify the existing value
878    /// and return the result of invoking a function with a reference to the
879    /// value previously corresponding to the key.
880    ///
881    /// `on_insert` may be invoked, even if [`None`] is returned.
882    ///
883    /// `on_modify` will be invoked at least once if [`Some`] is returned. It
884    /// may also be invoked one or more times if [`None`] is returned.
885    ///
886    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
887    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
888    #[inline]
889    pub fn insert_with_or_modify_and<
890        F: FnOnce() -> V,
891        G: FnMut(&K, &V) -> V,
892        H: FnOnce(&V) -> T,
893        T,
894    >(
895        &self,
896        key: K,
897        on_insert: F,
898        on_modify: G,
899        with_old_value: H,
900    ) -> Option<T> {
901        self.insert_with_or_modify_entry_and(key, on_insert, on_modify, move |_, v| {
902            with_old_value(v)
903        })
904    }
905
906    /// If no value corresponds to the key, invoke a default function to insert
907    /// a new key-value pair into the map. Otherwise, modify the existing value
908    /// and return the result of invoking a function with a reference to the
909    /// key-value pair previously corresponding to the supplied key.
910    ///
911    /// `on_insert` may be invoked, even if [`None`] is returned.
912    ///
913    /// `on_modify` will be invoked at least once if [`Some`] is returned. It
914    /// may also be invoked one or more times if [`None`] is returned.
915    ///
916    /// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
917    /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
918    #[inline]
919    pub fn insert_with_or_modify_entry_and<
920        F: FnOnce() -> V,
921        G: FnMut(&K, &V) -> V,
922        H: FnOnce(&K, &V) -> T,
923        T,
924    >(
925        &self,
926        key: K,
927        on_insert: F,
928        on_modify: G,
929        with_old_entry: H,
930    ) -> Option<T> {
931        let hash = bucket::hash(&self.build_hasher, &key);
932
933        let result = self.bucket_array_ref(hash).insert_with_or_modify_entry_and(
934            key,
935            hash,
936            on_insert,
937            on_modify,
938            with_old_entry,
939        );
940
941        if result.is_none() {
942            self.len.fetch_add(1, Ordering::Relaxed);
943        }
944
945        result
946    }
947
948    /// Modifies the value corresponding to a key, returning a clone of the
949    /// value previously corresponding to that key.
950    #[inline]
951    pub fn modify<F: FnMut(&K, &V) -> V>(&self, key: K, on_modify: F) -> Option<V>
952    where
953        V: Clone,
954    {
955        self.modify_entry_and(key, on_modify, |_, v| v.clone())
956    }
957
958    /// Modifies the value corresponding to a key, returning a clone of the
959    /// key-value pair previously corresponding to that key.
960    #[inline]
961    pub fn modify_entry<F: FnMut(&K, &V) -> V>(&self, key: K, on_modify: F) -> Option<(K, V)>
962    where
963        K: Clone,
964        V: Clone,
965    {
966        self.modify_entry_and(key, on_modify, |k, v| (k.clone(), v.clone()))
967    }
968
969    /// Modifies the value corresponding to a key, returning the result of
970    /// invoking a function with a reference to the value previously
971    /// corresponding to the key.
972    #[inline]
973    pub fn modify_and<F: FnMut(&K, &V) -> V, G: FnOnce(&V) -> T, T>(
974        &self,
975        key: K,
976        on_modify: F,
977        with_old_value: G,
978    ) -> Option<T> {
979        self.modify_entry_and(key, on_modify, move |_, v| with_old_value(v))
980    }
981
982    /// Modifies the value corresponding to a key, returning the result of
983    /// invoking a function with a reference to the key-value pair previously
984    /// corresponding to the supplied key.
985    #[inline]
986    pub fn modify_entry_and<F: FnMut(&K, &V) -> V, G: FnOnce(&K, &V) -> T, T>(
987        &self,
988        key: K,
989        on_modify: F,
990        with_old_entry: G,
991    ) -> Option<T> {
992        let hash = bucket::hash(&self.build_hasher, &key);
993
994        self.bucket_array_ref(hash)
995            .modify_entry_and(key, hash, on_modify, with_old_entry)
996    }
997}
998
999#[cfg(feature = "num-cpus")]
1000impl<K, V, S: Default> Default for HashMap<K, V, S> {
1001    fn default() -> Self {
1002        HashMap::with_num_segments_capacity_and_hasher(default_num_segments(), 0, S::default())
1003    }
1004}
1005
1006impl<K, V, S> Drop for HashMap<K, V, S> {
1007    fn drop(&mut self) {
1008        let guard = unsafe { &crossbeam_epoch::unprotected() };
1009        atomic::fence(Ordering::Acquire);
1010
1011        for Segment {
1012            bucket_array: this_bucket_array,
1013            ..
1014        } in self.segments.iter()
1015        {
1016            let mut current_ptr = this_bucket_array.load(Ordering::Relaxed, guard);
1017
1018            while let Some(current_ref) = unsafe { current_ptr.as_ref() } {
1019                let next_ptr = current_ref.next.load(Ordering::Relaxed, guard);
1020
1021                for this_bucket_ptr in current_ref
1022                    .buckets
1023                    .iter()
1024                    .map(|b| b.load(Ordering::Relaxed, guard))
1025                    .filter(|p| !p.is_null())
1026                    .filter(|p| next_ptr.is_null() || p.tag() & bucket::TOMBSTONE_TAG == 0)
1027                {
1028                    // only delete tombstones from the newest bucket array
1029                    // the only way this becomes a memory leak is if there was a panic during a rehash,
1030                    // in which case i'm going to say that running destructors and freeing memory is
1031                    // best-effort, and my best effort is to not do it
1032                    unsafe { bucket::defer_acquire_destroy(guard, this_bucket_ptr) };
1033                }
1034
1035                unsafe { bucket::defer_acquire_destroy(guard, current_ptr) };
1036
1037                current_ptr = next_ptr;
1038            }
1039        }
1040    }
1041}
1042
1043impl<K, V, S> HashMap<K, V, S> {
1044    #[inline]
1045    fn bucket_array_ref(&'_ self, hash: u64) -> BucketArrayRef<'_, K, V, S> {
1046        let index = self.segment_index_from_hash(hash);
1047
1048        let Segment {
1049            ref bucket_array,
1050            ref len,
1051        } = self.segments[index];
1052
1053        BucketArrayRef {
1054            bucket_array,
1055            build_hasher: &self.build_hasher,
1056            len,
1057        }
1058    }
1059
1060    #[inline]
1061    fn segment_index_from_hash(&'_ self, hash: u64) -> usize {
1062        if self.segment_shift == 64 {
1063            0
1064        } else {
1065            (hash >> self.segment_shift) as usize
1066        }
1067    }
1068}
1069
1070struct Segment<K, V> {
1071    bucket_array: Atomic<BucketArray<K, V>>,
1072    len: AtomicUsize,
1073}
1074
1075#[cfg(feature = "num-cpus")]
1076fn default_num_segments() -> usize {
1077    num_cpus::get() * 2
1078}
1079
1080#[cfg(test)]
1081mod tests {
1082    use crate::write_test_cases_for_me;
1083
1084    use super::*;
1085
1086    write_test_cases_for_me!(HashMap);
1087
1088    #[test]
1089    fn single_segment() {
1090        let map = HashMap::with_num_segments(1);
1091
1092        assert!(map.is_empty());
1093        assert_eq!(map.len(), 0);
1094
1095        assert_eq!(map.insert("foo", 5), None);
1096        assert_eq!(map.get("foo"), Some(5));
1097
1098        assert!(!map.is_empty());
1099        assert_eq!(map.len(), 1);
1100
1101        assert_eq!(map.remove("foo"), Some(5));
1102        assert!(map.is_empty());
1103        assert_eq!(map.len(), 0);
1104    }
1105}