Skip to main content

scc/
hash_cache.rs

1//! [`HashCache`] is an asynchronous/concurrent 32-way associative cache backed by
2//! [`HashMap`](super::HashMap).
3
4use std::collections::hash_map::RandomState;
5use std::fmt::{self, Debug};
6use std::hash::{BuildHasher, Hash};
7use std::mem::replace;
8use std::ops::{Deref, DerefMut, RangeInclusive};
9#[cfg(not(feature = "loom"))]
10use std::sync::atomic::AtomicUsize;
11use std::sync::atomic::Ordering::{Acquire, Relaxed};
12
13#[cfg(feature = "loom")]
14use loom::sync::atomic::AtomicUsize;
15use sdd::{AtomicRaw, Owned};
16
17use super::hash_table::MAXIMUM_CAPACITY_LIMIT;
18use super::hash_table::bucket::{CACHE, DoublyLinkedList, EntryPtr};
19use super::hash_table::bucket_array::BucketArray;
20use super::hash_table::{HashTable, LockedBucket};
21use super::utils::{fake_ref, get_owned};
22use super::{Equivalent, Guard};
23
24/// Scalable asynchronous/concurrent 32-way associative cache backed by [`HashMap`](super::HashMap).
25///
26/// [`HashCache`] is an asynchronous/concurrent 32-way associative cache based on the
27/// [`HashMap`](super::HashMap) implementation. [`HashCache`] does not keep track of the least
28/// recently used entry in the entire cache. Instead, each bucket maintains a doubly linked list of
29/// occupied entries, updated on access to entries to keep track of the least recently used entries
30/// within the bucket. Therefore, entries can be evicted before the cache is full.
31///
32/// [`HashCache`] and [`HashMap`](super::HashMap) share the same runtime characteristics, except
33/// that each entry in a [`HashCache`] additionally uses 2-byte space for a doubly linked list and a
34/// [`HashCache`] starts evicting least recently used entries if the bucket is full instead of
35/// allocating a linked list of entries.
36///
37/// ## Unwind safety
38///
39/// [`HashCache`] is impervious to out-of-memory errors and panics in user-specified code under one
40/// condition: `H::Hasher::hash`, `K::drop` and `V::drop` must not panic.
41pub struct HashCache<K, V, H = RandomState>
42where
43    H: BuildHasher,
44{
45    bucket_array: AtomicRaw<BucketArray<K, V, DoublyLinkedList, CACHE>>,
46    minimum_capacity: AtomicUsize,
47    maximum_capacity: usize,
48    build_hasher: H,
49}
50
51/// The default maximum capacity of a [`HashCache`] is `256`.
52pub const DEFAULT_MAXIMUM_CAPACITY: usize = 256;
53
54/// [`EvictedEntry`] is a type alias for `Option<(K, V)>`.
55pub type EvictedEntry<K, V> = Option<(K, V)>;
56
57/// [`Entry`] represents a single cache entry in a [`HashCache`].
58pub enum Entry<'h, K, V, H = RandomState>
59where
60    H: BuildHasher,
61{
62    /// An occupied entry.
63    Occupied(OccupiedEntry<'h, K, V, H>),
64    /// A vacant entry.
65    Vacant(VacantEntry<'h, K, V, H>),
66}
67
68/// [`OccupiedEntry`] is a view into an occupied cache entry in a [`HashCache`].
69pub struct OccupiedEntry<'h, K, V, H = RandomState>
70where
71    H: BuildHasher,
72{
73    hashcache: &'h HashCache<K, V, H>,
74    locked_bucket: LockedBucket<K, V, DoublyLinkedList, CACHE>,
75    entry_ptr: EntryPtr<K, V, CACHE>,
76}
77
78/// [`VacantEntry`] is a view into a vacant cache entry in a [`HashCache`].
79pub struct VacantEntry<'h, K, V, H = RandomState>
80where
81    H: BuildHasher,
82{
83    hashcache: &'h HashCache<K, V, H>,
84    key: K,
85    hash: u64,
86    locked_bucket: LockedBucket<K, V, DoublyLinkedList, CACHE>,
87}
88
89/// [`ConsumableEntry`] is a view into an occupied entry in a [`HashCache`] when iterating over
90/// entries in it.
91pub struct ConsumableEntry<'b, K, V> {
92    /// Holds an exclusive lock on the entry bucket.
93    locked_bucket: &'b mut LockedBucket<K, V, DoublyLinkedList, CACHE>,
94    /// Pointer to the entry.
95    entry_ptr: &'b mut EntryPtr<K, V, CACHE>,
96    /// Probes removal.
97    remove_probe: &'b mut bool,
98}
99
100/// [`ReplaceResult`] is the result type of the [`HashCache::replace_async`] and
101/// [`HashCache::replace_sync`] methods.
102pub enum ReplaceResult<'h, K, V, H = RandomState>
103where
104    H: BuildHasher,
105{
106    /// The key was replaced.
107    Replaced(OccupiedEntry<'h, K, V, H>, K),
108    /// The key did not exist in the [`HashCache`].
109    ///
110    /// An [`OccupiedEntry`] can be created from the [`VacantEntry`].
111    NotReplaced(VacantEntry<'h, K, V, H>),
112}
113
114impl<K, V, H> HashCache<K, V, H>
115where
116    H: BuildHasher,
117{
118    /// Creates an empty [`HashCache`] with the given [`BuildHasher`].
119    ///
120    /// The maximum capacity is set to [`DEFAULT_MAXIMUM_CAPACITY`].
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// use scc::HashCache;
126    /// use std::collections::hash_map::RandomState;
127    ///
128    /// let hashcache: HashCache<u64, u32, RandomState> = HashCache::with_hasher(RandomState::new());
129    /// ```
130    #[cfg(not(feature = "loom"))]
131    #[inline]
132    pub const fn with_hasher(build_hasher: H) -> Self {
133        HashCache {
134            bucket_array: AtomicRaw::null(),
135            minimum_capacity: AtomicUsize::new(0),
136            maximum_capacity: DEFAULT_MAXIMUM_CAPACITY,
137            build_hasher,
138        }
139    }
140
141    /// Creates an empty [`HashCache`] with the given [`BuildHasher`].
142    #[cfg(feature = "loom")]
143    #[inline]
144    pub fn with_hasher(build_hasher: H) -> Self {
145        Self {
146            bucket_array: AtomicRaw::null(),
147            minimum_capacity: AtomicUsize::new(0),
148            maximum_capacity: DEFAULT_MAXIMUM_CAPACITY,
149            build_hasher,
150        }
151    }
152
153    /// Creates an empty [`HashCache`] with the specified capacity and [`BuildHasher`].
154    ///
155    /// The actual capacity is equal to or greater than `minimum_capacity` unless it is greater than
156    /// `1 << (usize::BITS - 1)`.
157    ///
158    /// # Examples
159    ///
160    /// ```
161    /// use scc::HashCache;
162    /// use std::collections::hash_map::RandomState;
163    ///
164    /// let hashcache: HashCache<u64, u32, RandomState> =
165    ///     HashCache::with_capacity_and_hasher(1000, 2000, RandomState::new());
166    ///
167    /// let result = hashcache.capacity();
168    /// assert_eq!(result, 1024);
169    /// ```
170    #[inline]
171    pub fn with_capacity_and_hasher(
172        minimum_capacity: usize,
173        maximum_capacity: usize,
174        build_hasher: H,
175    ) -> Self {
176        let (array, minimum_capacity) = if minimum_capacity == 0 {
177            (AtomicRaw::null(), AtomicUsize::new(0))
178        } else {
179            let bucket_array = unsafe {
180                Owned::new_with_unchecked(|| {
181                    BucketArray::<K, V, DoublyLinkedList, CACHE>::new(
182                        minimum_capacity,
183                        AtomicRaw::null(),
184                    )
185                })
186            };
187            let minimum_capacity = bucket_array.num_slots();
188            (
189                AtomicRaw::new(bucket_array.into_raw()),
190                AtomicUsize::new(minimum_capacity),
191            )
192        };
193        let maximum_capacity = maximum_capacity
194            .max(minimum_capacity.load(Relaxed))
195            .max(BucketArray::<K, V, DoublyLinkedList, CACHE>::minimum_capacity())
196            .min(MAXIMUM_CAPACITY_LIMIT)
197            .next_power_of_two();
198        HashCache {
199            bucket_array: array,
200            minimum_capacity,
201            maximum_capacity,
202            build_hasher,
203        }
204    }
205}
206
207impl<K, V, H> HashCache<K, V, H>
208where
209    K: Eq + Hash,
210    H: BuildHasher,
211{
212    /// Gets the entry associated with the given key in the map for in-place manipulation.
213    ///
214    /// # Examples
215    ///
216    /// ```
217    /// use scc::HashCache;
218    ///
219    /// let hashcache: HashCache<char, u32> = HashCache::default();
220    ///
221    /// let future_entry = hashcache.entry_async('b');
222    /// ```
223    #[inline]
224    pub async fn entry_async(&self, key: K) -> Entry<'_, K, V, H> {
225        let hash = self.hash(&key);
226        let locked_bucket = self.writer_async(hash).await;
227        let entry_ptr = locked_bucket.search(&key, hash);
228        if entry_ptr.is_valid() {
229            Entry::Occupied(OccupiedEntry {
230                hashcache: self,
231                locked_bucket,
232                entry_ptr,
233            })
234        } else {
235            let vacant_entry = VacantEntry {
236                hashcache: self,
237                key,
238                hash,
239                locked_bucket,
240            };
241            Entry::Vacant(vacant_entry)
242        }
243    }
244
245    /// Gets the entry associated with the given key in the map for in-place manipulation.
246    ///
247    /// # Examples
248    ///
249    /// ```
250    /// use scc::HashCache;
251    ///
252    /// let hashcache: HashCache<char, u32> = HashCache::default();
253    ///
254    /// for ch in "a short treatise on fungi".chars() {
255    ///     hashcache.entry_sync(ch).and_modify(|counter| *counter += 1).or_put(1);
256    /// }
257    ///
258    /// assert_eq!(*hashcache.get_sync(&'s').unwrap().get(), 2);
259    /// assert_eq!(*hashcache.get_sync(&'t').unwrap().get(), 3);
260    /// assert!(hashcache.get_sync(&'y').is_none());
261    /// ```
262    #[inline]
263    pub fn entry_sync(&self, key: K) -> Entry<'_, K, V, H> {
264        let hash = self.hash(&key);
265        let locked_bucket = self.writer_sync(hash);
266        let entry_ptr = locked_bucket.search(&key, hash);
267        if entry_ptr.is_valid() {
268            Entry::Occupied(OccupiedEntry {
269                hashcache: self,
270                locked_bucket,
271                entry_ptr,
272            })
273        } else {
274            let vacant_entry = VacantEntry {
275                hashcache: self,
276                key,
277                hash,
278                locked_bucket,
279            };
280            Entry::Vacant(vacant_entry)
281        }
282    }
283
284    /// Tries to get the entry associated with the given key in the map for in-place manipulation.
285    ///
286    /// Returns `None` if the entry could not be locked.
287    ///
288    /// # Examples
289    ///
290    /// ```
291    /// use scc::HashCache;
292    ///
293    /// let hashcache: HashCache<usize, usize> = HashCache::default();
294    ///
295    /// assert!(hashcache.put_sync(0, 1).is_ok());
296    /// assert!(hashcache.try_entry(0).is_some());
297    /// ```
298    #[inline]
299    pub fn try_entry(&self, key: K) -> Option<Entry<'_, K, V, H>> {
300        let hash = self.hash(&key);
301        let guard = Guard::new();
302        let locked_bucket = self.try_reserve_bucket(hash, &guard)?;
303        let entry_ptr = locked_bucket.search(&key, hash);
304        if entry_ptr.is_valid() {
305            Some(Entry::Occupied(OccupiedEntry {
306                hashcache: self,
307                locked_bucket,
308                entry_ptr,
309            }))
310        } else {
311            Some(Entry::Vacant(VacantEntry {
312                hashcache: self,
313                key,
314                hash,
315                locked_bucket,
316            }))
317        }
318    }
319
320    /// Puts a key-value pair into the [`HashCache`].
321    ///
322    /// Returns `Some` if an entry was evicted for the new key-value pair.
323    ///
324    /// # Note
325    ///
326    /// If the key exists, the value is *not* updated.
327    ///
328    /// # Errors
329    ///
330    /// Returns an error containing the supplied key-value pair if the key exists.
331    ///
332    /// # Examples
333    ///
334    /// ```
335    /// use scc::HashCache;
336    ///
337    /// let hashcache: HashCache<u64, u32> = HashCache::default();
338    /// let future_put = hashcache.put_async(11, 17);
339    /// ```
340    #[inline]
341    pub async fn put_async(&self, key: K, val: V) -> Result<EvictedEntry<K, V>, (K, V)> {
342        let hash = self.hash(&key);
343        let locked_bucket = self.writer_async(hash).await;
344        if locked_bucket.search(&key, hash).is_valid() {
345            Err((key, val))
346        } else {
347            let evicted = locked_bucket.evict_lru_head(locked_bucket.data_block);
348            let entry_ptr = locked_bucket.insert(hash, (key, val));
349            locked_bucket.update_lru_tail(&entry_ptr);
350            Ok(evicted)
351        }
352    }
353
354    /// Puts a key-value pair into the [`HashCache`].
355    ///
356    /// Returns `Some` if an entry was evicted for the new key-value pair.
357    ///
358    /// # Note
359    ///
360    /// If the key exists, the value is *not* updated.
361    ///
362    /// # Errors
363    ///
364    /// Returns an error containing the supplied key-value pair if the key exists.
365    ///
366    /// # Examples
367    ///
368    /// ```
369    /// use scc::HashCache;
370    ///
371    /// let hashcache: HashCache<u64, u32> = HashCache::default();
372    ///
373    /// assert!(hashcache.put_sync(1, 0).is_ok());
374    /// assert_eq!(hashcache.put_sync(1, 1).unwrap_err(), (1, 1));
375    /// ```
376    #[inline]
377    pub fn put_sync(&self, key: K, val: V) -> Result<EvictedEntry<K, V>, (K, V)> {
378        let hash = self.hash(&key);
379        let locked_bucket = self.writer_sync(hash);
380        let entry_ptr = locked_bucket.search(&key, hash);
381        if entry_ptr.is_valid() {
382            Err((key, val))
383        } else {
384            let evicted = locked_bucket
385                .writer
386                .evict_lru_head(locked_bucket.data_block);
387            let entry_ptr = locked_bucket.insert(hash, (key, val));
388            locked_bucket.writer.update_lru_tail(&entry_ptr);
389            Ok(evicted)
390        }
391    }
392
393    /// Adds a key to the [`HashCache`], replacing the existing key, if any, that is equal to the
394    /// given one.
395    ///
396    /// # Examples
397    ///
398    /// ```
399    /// use std::cmp::{Eq, PartialEq};
400    /// use std::hash::{Hash, Hasher};
401    ///
402    /// use scc::HashCache;
403    /// use scc::hash_cache::ReplaceResult;
404    ///
405    /// #[derive(Debug)]
406    /// struct MaybeEqual(u64, u64);
407    ///
408    /// impl Eq for MaybeEqual {}
409    ///
410    /// impl Hash for MaybeEqual {
411    ///     fn hash<H: Hasher>(&self, state: &mut H) {
412    ///         // Do not read `self.1`.
413    ///         self.0.hash(state);
414    ///     }
415    /// }
416    ///
417    /// impl PartialEq for MaybeEqual {
418    ///     fn eq(&self, other: &Self) -> bool {
419    ///         // Do not compare `self.1`.
420    ///         self.0 == other.0
421    ///     }
422    /// }
423    ///
424    /// let hashcache: HashCache<MaybeEqual, usize> = HashCache::default();
425    ///
426    /// async {
427    ///     let ReplaceResult::NotReplaced(v) = hashcache.replace_async(MaybeEqual(11, 7)).await else {
428    ///         unreachable!();
429    ///     };
430    ///     drop(v.put_entry(17));
431    ///     let ReplaceResult::Replaced(_, k) = hashcache.replace_async(MaybeEqual(11, 11)).await else {
432    ///         unreachable!();
433    ///     };
434    ///     assert_eq!(k.1, 7);
435    /// };
436    /// ```
437    #[inline]
438    pub async fn replace_async(&self, key: K) -> ReplaceResult<'_, K, V, H> {
439        let hash = self.hash(&key);
440        let locked_bucket = self.writer_async(hash).await;
441        let entry_ptr = locked_bucket.search(&key, hash);
442        if entry_ptr.is_valid() {
443            let prev_key = replace(
444                unsafe { entry_ptr.key_ptr(locked_bucket.data_block).as_mut() },
445                key,
446            );
447            ReplaceResult::Replaced(
448                OccupiedEntry {
449                    hashcache: self,
450                    locked_bucket,
451                    entry_ptr,
452                },
453                prev_key,
454            )
455        } else {
456            ReplaceResult::NotReplaced(VacantEntry {
457                hashcache: self,
458                key,
459                hash,
460                locked_bucket,
461            })
462        }
463    }
464
465    /// Adds a key to the [`HashCache`], replacing the existing key, if any, that is equal to the
466    /// given one.
467    ///
468    /// # Examples
469    ///
470    /// ```
471    /// use std::cmp::{Eq, PartialEq};
472    /// use std::hash::{Hash, Hasher};
473    ///
474    /// use scc::HashCache;
475    /// use scc::hash_cache::ReplaceResult;
476    ///
477    /// #[derive(Debug)]
478    /// struct MaybeEqual(u64, u64);
479    ///
480    /// impl Eq for MaybeEqual {}
481    ///
482    /// impl Hash for MaybeEqual {
483    ///     fn hash<H: Hasher>(&self, state: &mut H) {
484    ///         // Do not read `self.1`.
485    ///         self.0.hash(state);
486    ///     }
487    /// }
488    ///
489    /// impl PartialEq for MaybeEqual {
490    ///     fn eq(&self, other: &Self) -> bool {
491    ///         // Do not compare `self.1`.
492    ///         self.0 == other.0
493    ///     }
494    /// }
495    ///
496    /// let hashcache: HashCache<MaybeEqual, usize> = HashCache::default();
497    ///
498    /// let ReplaceResult::NotReplaced(v) = hashcache.replace_sync(MaybeEqual(11, 7)) else {
499    ///     unreachable!();
500    /// };
501    /// drop(v.put_entry(17));
502    /// let ReplaceResult::Replaced(_, k) = hashcache.replace_sync(MaybeEqual(11, 11)) else {
503    ///     unreachable!();
504    /// };
505    /// assert_eq!(k.1, 7);
506    /// ```
507    #[inline]
508    pub fn replace_sync(&self, key: K) -> ReplaceResult<'_, K, V, H> {
509        let hash = self.hash(&key);
510        let locked_bucket = self.writer_sync(hash);
511        let entry_ptr = locked_bucket.search(&key, hash);
512        if entry_ptr.is_valid() {
513            let prev_key = replace(
514                unsafe { entry_ptr.key_ptr(locked_bucket.data_block).as_mut() },
515                key,
516            );
517            ReplaceResult::Replaced(
518                OccupiedEntry {
519                    hashcache: self,
520                    locked_bucket,
521                    entry_ptr,
522                },
523                prev_key,
524            )
525        } else {
526            ReplaceResult::NotReplaced(VacantEntry {
527                hashcache: self,
528                key,
529                hash,
530                locked_bucket,
531            })
532        }
533    }
534
535    /// Removes a key-value pair if the key exists.
536    ///
537    /// Returns `None` if the key does not exist.
538    ///
539    /// # Examples
540    ///
541    /// ```
542    /// use scc::HashCache;
543    ///
544    /// let hashcache: HashCache<u64, u32> = HashCache::default();
545    /// let future_put = hashcache.put_async(11, 17);
546    /// let future_remove = hashcache.remove_async(&11);
547    /// ```
548    #[inline]
549    pub async fn remove_async<Q>(&self, key: &Q) -> Option<(K, V)>
550    where
551        Q: Equivalent<K> + Hash + ?Sized,
552    {
553        self.remove_if_async(key, |_| true).await
554    }
555
556    /// Removes a key-value pair if the key exists.
557    ///
558    /// Returns `None` if the key does not exist.
559    ///
560    /// # Examples
561    ///
562    /// ```
563    /// use scc::HashCache;
564    ///
565    /// let hashcache: HashCache<u64, u32> = HashCache::default();
566    ///
567    /// assert!(hashcache.remove_sync(&1).is_none());
568    /// assert!(hashcache.put_sync(1, 0).is_ok());
569    /// assert_eq!(hashcache.remove_sync(&1).unwrap(), (1, 0));
570    /// ```
571    #[inline]
572    pub fn remove_sync<Q>(&self, key: &Q) -> Option<(K, V)>
573    where
574        Q: Equivalent<K> + Hash + ?Sized,
575    {
576        self.remove_if_sync(key, |_| true)
577    }
578
579    /// Gets an [`OccupiedEntry`] corresponding to the key for in-place modification.
580    ///
581    /// [`OccupiedEntry`] exclusively owns the entry, preventing others from gaining access to it:
582    /// use [`read_async`](Self::read_async) if read-only access is sufficient.
583    ///
584    /// Returns `None` if the key does not exist.
585    ///
586    /// # Examples
587    ///
588    /// ```
589    /// use scc::HashCache;
590    ///
591    /// let hashcache: HashCache<u64, u32> = HashCache::default();
592    /// let future_put = hashcache.put_async(11, 17);
593    /// let future_get = hashcache.get_async(&11);
594    /// ```
595    #[inline]
596    pub async fn get_async<Q>(&self, key: &Q) -> Option<OccupiedEntry<'_, K, V, H>>
597    where
598        Q: Equivalent<K> + Hash + ?Sized,
599    {
600        let hash = self.hash(key);
601        let locked_bucket = self.optional_writer_async(hash).await?;
602        let entry_ptr = locked_bucket.search(key, hash);
603        if entry_ptr.is_valid() {
604            locked_bucket.writer.update_lru_tail(&entry_ptr);
605            return Some(OccupiedEntry {
606                hashcache: self,
607                locked_bucket,
608                entry_ptr,
609            });
610        }
611        None
612    }
613
614    /// Gets an [`OccupiedEntry`] corresponding to the key for in-place modification.
615    ///
616    /// [`OccupiedEntry`] exclusively owns the entry, preventing others from gaining access to it:
617    /// use [`read_sync`](Self::read_sync) if read-only access is sufficient.
618    ///
619    /// Returns `None` if the key does not exist.
620    ///
621    /// # Examples
622    ///
623    /// ```
624    /// use scc::HashCache;
625    ///
626    /// let hashcache: HashCache<u64, u32> = HashCache::default();
627    ///
628    /// assert!(hashcache.get_sync(&1).is_none());
629    /// assert!(hashcache.put_sync(1, 10).is_ok());
630    /// assert_eq!(*hashcache.get_sync(&1).unwrap().get(), 10);
631    ///
632    /// *hashcache.get_sync(&1).unwrap() = 11;
633    /// assert_eq!(*hashcache.get_sync(&1).unwrap(), 11);
634    /// ```
635    #[inline]
636    pub fn get_sync<Q>(&self, key: &Q) -> Option<OccupiedEntry<'_, K, V, H>>
637    where
638        Q: Equivalent<K> + Hash + ?Sized,
639    {
640        let hash = self.hash(key);
641        let locked_bucket = self.optional_writer_sync(hash)?;
642        let entry_ptr = locked_bucket.search(key, hash);
643        if entry_ptr.is_valid() {
644            locked_bucket.writer.update_lru_tail(&entry_ptr);
645            return Some(OccupiedEntry {
646                hashcache: self,
647                locked_bucket,
648                entry_ptr,
649            });
650        }
651        None
652    }
653
654    /// Reads a key-value pair.
655    ///
656    /// Returns `None` if the key does not exist.
657    ///
658    /// # Examples
659    ///
660    /// ```
661    /// use scc::HashCache;
662    ///
663    /// let hashcache: HashCache<u64, u32> = HashCache::default();
664    /// let future_put = hashcache.put_async(11, 17);
665    /// let future_read = hashcache.read_async(&11, |_, v| *v);
666    /// ```
667    #[inline]
668    pub async fn read_async<Q, R, F: FnOnce(&K, &V) -> R>(&self, key: &Q, reader: F) -> Option<R>
669    where
670        Q: Equivalent<K> + Hash + ?Sized,
671    {
672        self.reader_async(key, reader).await
673    }
674
675    /// Reads a key-value pair.
676    ///
677    /// Returns `None` if the key does not exist.
678    ///
679    /// # Examples
680    ///
681    /// ```
682    /// use scc::HashCache;
683    ///
684    /// let hashcache: HashCache<u64, u32> = HashCache::default();
685    ///
686    /// assert!(hashcache.read_sync(&1, |_, v| *v).is_none());
687    /// assert!(hashcache.put_sync(1, 10).is_ok());
688    /// assert_eq!(hashcache.read_sync(&1, |_, v| *v).unwrap(), 10);
689    /// ```
690    #[inline]
691    pub fn read_sync<Q, R, F: FnOnce(&K, &V) -> R>(&self, key: &Q, reader: F) -> Option<R>
692    where
693        Q: Equivalent<K> + Hash + ?Sized,
694    {
695        self.reader_sync(key, reader)
696    }
697
698    /// Returns `true` if the [`HashCache`] contains a value for the specified key.
699    ///
700    /// # Examples
701    ///
702    /// ```
703    /// use scc::HashCache;
704    ///
705    /// let hashcache: HashCache<u64, u32> = HashCache::default();
706    ///
707    /// let future_contains = hashcache.contains_async(&1);
708    /// ```
709    #[inline]
710    pub async fn contains_async<Q>(&self, key: &Q) -> bool
711    where
712        Q: Equivalent<K> + Hash + ?Sized,
713    {
714        self.reader_async(key, |_, _| ()).await.is_some()
715    }
716
717    /// Returns `true` if the [`HashCache`] contains a value for the specified key.
718    ///
719    /// # Examples
720    ///
721    /// ```
722    /// use scc::HashCache;
723    ///
724    /// let hashcache: HashCache<u64, u32> = HashCache::default();
725    ///
726    /// assert!(!hashcache.contains_sync(&1));
727    /// assert!(hashcache.put_sync(1, 0).is_ok());
728    /// assert!(hashcache.contains_sync(&1));
729    /// ```
730    #[inline]
731    pub fn contains_sync<Q>(&self, key: &Q) -> bool
732    where
733        Q: Equivalent<K> + Hash + ?Sized,
734    {
735        self.read_sync(key, |_, _| ()).is_some()
736    }
737
738    /// Removes a key-value pair if the key exists and the given condition is met.
739    ///
740    /// Returns `None` if the key does not exist or the condition was not met.
741    ///
742    /// # Examples
743    ///
744    /// ```
745    /// use scc::HashCache;
746    ///
747    /// let hashcache: HashCache<u64, u32> = HashCache::default();
748    /// let future_put = hashcache.put_async(11, 17);
749    /// let future_remove = hashcache.remove_if_async(&11, |_| true);
750    /// ```
751    #[inline]
752    pub async fn remove_if_async<Q, F: FnOnce(&mut V) -> bool>(
753        &self,
754        key: &Q,
755        condition: F,
756    ) -> Option<(K, V)>
757    where
758        Q: Equivalent<K> + Hash + ?Sized,
759    {
760        let hash = self.hash(key);
761        let mut locked_bucket = self.optional_writer_async(hash).await?;
762        let mut entry_ptr = locked_bucket.search(key, hash);
763        if entry_ptr.is_valid() && condition(locked_bucket.entry_mut(&mut entry_ptr).1) {
764            Some(locked_bucket.remove(self, &mut entry_ptr))
765        } else {
766            None
767        }
768    }
769
770    /// Removes a key-value pair if the key exists and the given condition is met.
771    ///
772    /// Returns `None` if the key does not exist or the condition was not met.
773    ///
774    /// # Examples
775    ///
776    /// ```
777    /// use scc::HashCache;
778    ///
779    /// let hashcache: HashCache<u64, u32> = HashCache::default();
780    ///
781    /// assert!(hashcache.put_sync(1, 0).is_ok());
782    /// assert!(hashcache.remove_if_sync(&1, |v| { *v += 1; false }).is_none());
783    /// assert_eq!(hashcache.remove_if_sync(&1, |v| *v == 1).unwrap(), (1, 1));
784    /// ```
785    #[inline]
786    pub fn remove_if_sync<Q, F: FnOnce(&mut V) -> bool>(
787        &self,
788        key: &Q,
789        condition: F,
790    ) -> Option<(K, V)>
791    where
792        Q: Equivalent<K> + Hash + ?Sized,
793    {
794        let hash = self.hash(key);
795        let mut locked_bucket = self.optional_writer_sync(hash)?;
796        let mut entry_ptr = locked_bucket.search(key, hash);
797        if entry_ptr.is_valid() && condition(locked_bucket.entry_mut(&mut entry_ptr).1) {
798            Some(locked_bucket.remove(self, &mut entry_ptr))
799        } else {
800            None
801        }
802    }
803
804    /// Iterates over entries asynchronously for reading.
805    ///
806    /// Stops iterating when the closure returns `false`, and this method also returns `false`.
807    ///
808    /// # Examples
809    ///
810    /// ```
811    /// use scc::HashCache;
812    ///
813    /// let hashcache: HashCache<u64, u64> = HashCache::default();
814    ///
815    /// assert!(hashcache.put_sync(1, 0).is_ok());
816    ///
817    /// async {
818    ///     let result = hashcache.iter_async(|k, v| {
819    ///         false
820    ///     }).await;
821    ///     assert!(!result);
822    /// };
823    /// ```
824    #[inline]
825    pub async fn iter_async<F: FnMut(&K, &V) -> bool>(&self, mut f: F) -> bool {
826        let mut result = true;
827        self.for_each_reader_async(|reader, data_block| {
828            let mut entry_ptr = EntryPtr::null();
829            while entry_ptr.find_next(&reader) {
830                if !f(entry_ptr.key(data_block), entry_ptr.val(data_block)) {
831                    result = false;
832                    return false;
833                }
834            }
835            true
836        })
837        .await;
838        result
839    }
840
841    /// Iterates over entries synchronously for reading.
842    ///
843    /// Stops iterating when the closure returns `false`, and this method also returns `false`.
844    ///
845    /// # Examples
846    ///
847    /// ```
848    /// use scc::HashCache;
849    ///
850    /// let hashcache: HashCache<u64, u64> = HashCache::default();
851    ///
852    /// assert!(hashcache.put_sync(1, 0).is_ok());
853    /// assert!(hashcache.put_sync(2, 1).is_ok());
854    ///
855    /// let mut acc = 0_u64;
856    /// let result = hashcache.iter_sync(|k, v| {
857    ///     acc += *k;
858    ///     acc += *v;
859    ///     true
860    /// });
861    ///
862    /// assert!(result);
863    /// assert_eq!(acc, 4);
864    /// ```
865    #[inline]
866    pub fn iter_sync<F: FnMut(&K, &V) -> bool>(&self, mut f: F) -> bool {
867        let mut result = true;
868        let guard = Guard::new();
869        self.for_each_reader_sync(&guard, |reader, data_block| {
870            let mut entry_ptr = EntryPtr::null();
871            while entry_ptr.find_next(&reader) {
872                if !f(entry_ptr.key(data_block), entry_ptr.val(data_block)) {
873                    result = false;
874                    return false;
875                }
876            }
877            true
878        });
879        result
880    }
881
882    /// Iterates over entries asynchronously for modification.
883    ///
884    /// Stops iterating when the closure returns `false`, and this method also returns `false`.
885    ///
886    /// # Examples
887    ///
888    /// ```
889    /// use scc::HashCache;
890    ///
891    /// let hashcache: HashCache<u64, u32> = HashCache::default();
892    ///
893    /// assert!(hashcache.put_sync(1, 0).is_ok());
894    /// assert!(hashcache.put_sync(2, 1).is_ok());
895    ///
896    /// async {
897    ///     let result = hashcache.iter_mut_async(|e| {
898    ///         if *e.key() == 1 {
899    ///             e.consume();
900    ///             return false;
901    ///         }
902    ///         true
903    ///     }).await;
904    ///
905    ///     assert!(!result);
906    ///     assert_eq!(hashcache.len(), 1);
907    /// };
908    /// ```
909    #[inline]
910    pub async fn iter_mut_async<F: FnMut(ConsumableEntry<'_, K, V>) -> bool>(
911        &self,
912        mut f: F,
913    ) -> bool {
914        let mut result = true;
915        self.for_each_writer_async(0, 0, |mut locked_bucket, removed| {
916            let mut entry_ptr = EntryPtr::null();
917            while entry_ptr.find_next(&locked_bucket.writer) {
918                let consumable_entry = ConsumableEntry {
919                    locked_bucket: &mut locked_bucket,
920                    entry_ptr: &mut entry_ptr,
921                    remove_probe: removed,
922                };
923                if !f(consumable_entry) {
924                    result = false;
925                    return false;
926                }
927            }
928            true
929        })
930        .await;
931        result
932    }
933
934    /// Iterates over entries synchronously for modification.
935    ///
936    /// Stops iterating when the closure returns `false`, and this method also returns `false`.
937    ///
938    /// # Examples
939    ///
940    /// ```
941    /// use scc::HashCache;
942    ///
943    /// let hashcache: HashCache<u64, u32> = HashCache::default();
944    ///
945    /// assert!(hashcache.put_sync(1, 0).is_ok());
946    /// assert!(hashcache.put_sync(2, 1).is_ok());
947    /// assert!(hashcache.put_sync(3, 2).is_ok());
948    ///
949    /// let result = hashcache.iter_mut_sync(|e| {
950    ///     if *e.key() == 1 {
951    ///         e.consume();
952    ///         return false;
953    ///     }
954    ///     true
955    /// });
956    ///
957    /// assert!(!result);
958    /// assert!(!hashcache.contains_sync(&1));
959    /// assert_eq!(hashcache.len(), 2);
960    /// ```
961    #[inline]
962    pub fn iter_mut_sync<F: FnMut(ConsumableEntry<'_, K, V>) -> bool>(&self, mut f: F) -> bool {
963        let mut result = true;
964        let guard = Guard::new();
965        self.for_each_writer_sync(0, 0, &guard, |mut locked_bucket, removed| {
966            let mut entry_ptr = EntryPtr::null();
967            while entry_ptr.find_next(&locked_bucket.writer) {
968                let consumable_entry = ConsumableEntry {
969                    locked_bucket: &mut locked_bucket,
970                    entry_ptr: &mut entry_ptr,
971                    remove_probe: removed,
972                };
973                if !f(consumable_entry) {
974                    result = false;
975                    return false;
976                }
977            }
978            true
979        });
980        result
981    }
982
983    /// Retains the entries specified by the predicate.
984    ///
985    /// This method allows the predicate closure to modify the value field.
986    ///
987    /// Entries that have existed since the invocation of the method are guaranteed to be visited
988    /// if they are not removed, however the same entry can be visited more than once if the
989    /// [`HashCache`] gets resized by another thread.
990    ///
991    /// # Examples
992    ///
993    /// ```
994    /// use scc::HashCache;
995    ///
996    /// let hashcache: HashCache<u64, u32> = HashCache::default();
997    ///
998    /// let future_put = hashcache.put_async(1, 0);
999    /// let future_retain = hashcache.retain_async(|k, v| *k == 1);
1000    /// ```
1001    #[inline]
1002    pub async fn retain_async<F: FnMut(&K, &mut V) -> bool>(&self, mut pred: F) {
1003        self.iter_mut_async(|mut e| {
1004            let k = e.entry_ptr.key(e.locked_bucket.data_block);
1005            if !pred(k, &mut *e) {
1006                drop(e.consume());
1007            }
1008            true
1009        })
1010        .await;
1011    }
1012
1013    /// Retains the entries specified by the predicate.
1014    ///
1015    /// This method allows the predicate closure to modify the value field.
1016    ///
1017    /// Entries that have existed since the invocation of the method are guaranteed to be visited
1018    /// if they are not removed, however the same entry can be visited more than once if the
1019    /// [`HashCache`] gets resized by another thread.
1020    ///
1021    /// # Examples
1022    ///
1023    /// ```
1024    /// use scc::HashCache;
1025    ///
1026    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1027    ///
1028    /// assert!(hashcache.put_sync(1, 0).is_ok());
1029    /// assert!(hashcache.put_sync(2, 1).is_ok());
1030    /// assert!(hashcache.put_sync(3, 2).is_ok());
1031    ///
1032    /// hashcache.retain_sync(|k, v| *k == 1 && *v == 0);
1033    ///
1034    /// assert!(hashcache.contains_sync(&1));
1035    /// assert!(!hashcache.contains_sync(&2));
1036    /// assert!(!hashcache.contains_sync(&3));
1037    /// ```
1038    #[inline]
1039    pub fn retain_sync<F: FnMut(&K, &mut V) -> bool>(&self, mut pred: F) {
1040        self.iter_mut_sync(|mut e| {
1041            let k = e.entry_ptr.key(e.locked_bucket.data_block);
1042            if !pred(k, &mut *e) {
1043                drop(e.consume());
1044            }
1045            true
1046        });
1047    }
1048
1049    /// Clears the [`HashCache`] by removing all key-value pairs.
1050    ///
1051    /// # Examples
1052    ///
1053    /// ```
1054    /// use scc::HashCache;
1055    ///
1056    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1057    ///
1058    /// let future_put = hashcache.put_async(1, 0);
1059    /// let future_clear = hashcache.clear_async();
1060    /// ```
1061    #[inline]
1062    pub async fn clear_async(&self) {
1063        self.retain_async(|_, _| false).await;
1064    }
1065
1066    /// Clears the [`HashCache`] by removing all key-value pairs.
1067    ///
1068    /// # Examples
1069    ///
1070    /// ```
1071    /// use scc::HashCache;
1072    ///
1073    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1074    ///
1075    /// assert!(hashcache.put_sync(1, 0).is_ok());
1076    /// hashcache.clear_sync();
1077    ///
1078    /// assert!(!hashcache.contains_sync(&1));
1079    /// ```
1080    #[inline]
1081    pub fn clear_sync(&self) {
1082        self.retain_sync(|_, _| false);
1083    }
1084
1085    /// Returns the number of entries in the [`HashCache`].
1086    ///
1087    /// It reads the entire metadata area of the bucket array to calculate the number of valid
1088    /// entries, making its time complexity `O(N)`. Furthermore, it may overcount entries if an old
1089    /// bucket array has yet to be dropped.
1090    ///
1091    /// # Examples
1092    ///
1093    /// ```
1094    /// use scc::HashCache;
1095    ///
1096    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1097    ///
1098    /// assert!(hashcache.put_sync(1, 0).is_ok());
1099    /// assert_eq!(hashcache.len(), 1);
1100    /// ```
1101    #[inline]
1102    pub fn len(&self) -> usize {
1103        self.num_entries(&Guard::new())
1104    }
1105
1106    /// Returns `true` if the [`HashCache`] is empty.
1107    ///
1108    /// # Examples
1109    ///
1110    /// ```
1111    /// use scc::HashCache;
1112    ///
1113    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1114    ///
1115    /// assert!(hashcache.is_empty());
1116    /// assert!(hashcache.put_sync(1, 0).is_ok());
1117    /// assert!(!hashcache.is_empty());
1118    /// ```
1119    #[inline]
1120    pub fn is_empty(&self) -> bool {
1121        !self.has_entry(&Guard::new())
1122    }
1123
1124    /// Returns the capacity of the [`HashCache`].
1125    ///
1126    /// # Examples
1127    ///
1128    /// ```
1129    /// use scc::HashCache;
1130    ///
1131    /// let hashcache_default: HashCache<u64, u32> = HashCache::default();
1132    /// assert_eq!(hashcache_default.capacity(), 0);
1133    ///
1134    /// let hashcache: HashCache<u64, u32> = HashCache::with_capacity(1000, 2000);
1135    /// assert_eq!(hashcache.capacity(), 1024);
1136    /// ```
1137    #[inline]
1138    pub fn capacity(&self) -> usize {
1139        self.num_slots(&Guard::new())
1140    }
1141
1142    /// Returns the current capacity range of the [`HashCache`].
1143    ///
1144    /// # Examples
1145    ///
1146    /// ```
1147    /// use scc::HashCache;
1148    ///
1149    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1150    ///
1151    /// assert_eq!(hashcache.capacity_range(), 0..=256);
1152    /// ```
1153    #[inline]
1154    pub fn capacity_range(&self) -> RangeInclusive<usize> {
1155        self.minimum_capacity.load(Relaxed)..=self.maximum_capacity()
1156    }
1157}
1158
1159impl<K, V> HashCache<K, V, RandomState> {
1160    /// Creates an empty default [`HashCache`].
1161    ///
1162    /// The maximum capacity is set to [`DEFAULT_MAXIMUM_CAPACITY`].
1163    ///
1164    /// # Examples
1165    ///
1166    /// ```
1167    /// use scc::HashCache;
1168    ///
1169    /// let hashcache: HashCache<u64, u32> = HashCache::new();
1170    ///
1171    /// let result = hashcache.capacity();
1172    /// assert_eq!(result, 0);
1173    /// ```
1174    #[inline]
1175    #[must_use]
1176    pub fn new() -> Self {
1177        Self::default()
1178    }
1179
1180    /// Creates an empty [`HashCache`] with the specified capacity.
1181    ///
1182    /// The actual capacity is equal to or greater than `minimum_capacity` unless it is greater than
1183    /// `1 << (usize::BITS - 1)`.
1184    ///
1185    /// # Examples
1186    ///
1187    /// ```
1188    /// use scc::HashCache;
1189    ///
1190    /// let hashcache: HashCache<u64, u32> = HashCache::with_capacity(1000, 2000);
1191    ///
1192    /// let result = hashcache.capacity();
1193    /// assert_eq!(result, 1024);
1194    ///
1195    /// let hashcache: HashCache<u64, u32> = HashCache::with_capacity(0, 0);
1196    /// let result = hashcache.capacity_range();
1197    /// assert_eq!(result, 0..=64);
1198    /// ```
1199    #[inline]
1200    #[must_use]
1201    pub fn with_capacity(minimum_capacity: usize, maximum_capacity: usize) -> Self {
1202        Self::with_capacity_and_hasher(minimum_capacity, maximum_capacity, RandomState::new())
1203    }
1204}
1205
1206impl<K, V, H> Default for HashCache<K, V, H>
1207where
1208    H: BuildHasher + Default,
1209{
1210    /// Creates an empty default [`HashCache`].
1211    ///
1212    /// The maximum capacity is set to [`DEFAULT_MAXIMUM_CAPACITY`].
1213    ///
1214    /// # Examples
1215    ///
1216    /// ```
1217    /// use scc::HashCache;
1218    ///
1219    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1220    ///
1221    /// let result = hashcache.capacity();
1222    /// assert_eq!(result, 0);
1223    /// ```
1224    #[inline]
1225    fn default() -> Self {
1226        Self::with_hasher(H::default())
1227    }
1228}
1229
1230impl<K, V, H> Debug for HashCache<K, V, H>
1231where
1232    K: Debug + Eq + Hash,
1233    V: Debug,
1234    H: BuildHasher,
1235{
1236    /// Iterates over all the entries in the [`HashCache`] to print them.
1237    ///
1238    /// ## Locking behavior
1239    ///
1240    /// Shared locks on buckets are acquired during iteration, therefore any [`Entry`],
1241    /// [`OccupiedEntry`], or [`VacantEntry`] owned by the current thread will lead to a deadlock.
1242    #[inline]
1243    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1244        let mut d = f.debug_map();
1245        self.iter_sync(|k, v| {
1246            d.entry(k, v);
1247            true
1248        });
1249        d.finish()
1250    }
1251}
1252
1253impl<K, V, H> Drop for HashCache<K, V, H>
1254where
1255    H: BuildHasher,
1256{
1257    #[inline]
1258    fn drop(&mut self) {
1259        if let Some(bucket_array) = get_owned(self.bucket_array.load(Acquire, fake_ref(self))) {
1260            unsafe {
1261                // The entire array does not need to wait for an epoch change as no references will
1262                // remain outside the lifetime of the `HashCache`.
1263                bucket_array.drop_in_place();
1264            }
1265        }
1266        for _ in 0..4 {
1267            Guard::new().accelerate();
1268        }
1269    }
1270}
1271
1272impl<K, V, H> FromIterator<(K, V)> for HashCache<K, V, H>
1273where
1274    K: Eq + Hash,
1275    H: BuildHasher + Default,
1276{
1277    #[inline]
1278    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
1279        let into_iter = iter.into_iter();
1280        let size_hint = into_iter.size_hint();
1281        let hashcache = Self::with_capacity_and_hasher(
1282            size_hint.0,
1283            Self::capacity_from_size_hint(size_hint),
1284            H::default(),
1285        );
1286        into_iter.for_each(|e| {
1287            let _result = hashcache.put_sync(e.0, e.1);
1288        });
1289        hashcache
1290    }
1291}
1292
1293impl<K, V, H> HashTable<K, V, H, DoublyLinkedList, CACHE> for HashCache<K, V, H>
1294where
1295    K: Eq + Hash,
1296    H: BuildHasher,
1297{
1298    #[inline]
1299    fn hasher(&self) -> &H {
1300        &self.build_hasher
1301    }
1302
1303    #[inline]
1304    fn bucket_array_var(&self) -> &AtomicRaw<BucketArray<K, V, DoublyLinkedList, CACHE>> {
1305        &self.bucket_array
1306    }
1307
1308    #[inline]
1309    fn minimum_capacity_var(&self) -> &AtomicUsize {
1310        &self.minimum_capacity
1311    }
1312
1313    #[inline]
1314    fn maximum_capacity(&self) -> usize {
1315        self.maximum_capacity
1316    }
1317}
1318
1319impl<K, V, H> PartialEq for HashCache<K, V, H>
1320where
1321    K: Eq + Hash,
1322    V: PartialEq,
1323    H: BuildHasher,
1324{
1325    /// Compares two [`HashCache`] instances.
1326    ///
1327    /// ## Locking behavior
1328    ///
1329    /// Shared locks on buckets are acquired when comparing two instances of [`HashCache`], therefore
1330    /// this may lead to a deadlock if the instances are being modified by another thread.
1331    #[inline]
1332    fn eq(&self, other: &Self) -> bool {
1333        if self.iter_sync(|k, v| other.read_sync(k, |_, ov| v == ov) == Some(true)) {
1334            return other.iter_sync(|k, v| self.read_sync(k, |_, sv| v == sv) == Some(true));
1335        }
1336        false
1337    }
1338}
1339
1340impl<'h, K, V, H> Entry<'h, K, V, H>
1341where
1342    K: Eq + Hash,
1343    H: BuildHasher,
1344{
1345    /// Ensures a value is in the entry by putting the supplied instance if empty.
1346    ///
1347    /// # Examples
1348    ///
1349    /// ```
1350    /// use scc::HashCache;
1351    ///
1352    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1353    ///
1354    /// hashcache.entry_sync(3).or_put(7);
1355    /// assert_eq!(*hashcache.get_sync(&3).unwrap().get(), 7);
1356    /// ```
1357    #[inline]
1358    pub fn or_put(self, val: V) -> (EvictedEntry<K, V>, OccupiedEntry<'h, K, V, H>) {
1359        self.or_put_with(|| val)
1360    }
1361
1362    /// Ensures a value is in the entry by putting the result of the supplied closure if empty.
1363    ///
1364    /// # Examples
1365    ///
1366    /// ```
1367    /// use scc::HashCache;
1368    ///
1369    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1370    ///
1371    /// hashcache.entry_sync(19).or_put_with(|| 5);
1372    /// assert_eq!(*hashcache.get_sync(&19).unwrap().get(), 5);
1373    /// ```
1374    #[inline]
1375    pub fn or_put_with<F: FnOnce() -> V>(
1376        self,
1377        constructor: F,
1378    ) -> (EvictedEntry<K, V>, OccupiedEntry<'h, K, V, H>) {
1379        self.or_put_with_key(|_| constructor())
1380    }
1381
1382    /// Ensures a value is in the entry by putting the result of the supplied closure if empty.
1383    ///
1384    /// The reference to the moved key is provided, therefore cloning or copying the key is
1385    /// unnecessary.
1386    ///
1387    /// # Examples
1388    ///
1389    /// ```
1390    /// use scc::HashCache;
1391    ///
1392    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1393    ///
1394    /// hashcache.entry_sync(11).or_put_with_key(|k| if *k == 11 { 7 } else { 3 });
1395    /// assert_eq!(*hashcache.get_sync(&11).unwrap().get(), 7);
1396    /// ```
1397    #[inline]
1398    pub fn or_put_with_key<F: FnOnce(&K) -> V>(
1399        self,
1400        constructor: F,
1401    ) -> (EvictedEntry<K, V>, OccupiedEntry<'h, K, V, H>) {
1402        match self {
1403            Self::Occupied(o) => (None, o),
1404            Self::Vacant(v) => {
1405                let val = constructor(v.key());
1406                v.put_entry(val)
1407            }
1408        }
1409    }
1410
1411    /// Returns a reference to the key of this entry.
1412    ///
1413    /// # Examples
1414    ///
1415    /// ```
1416    /// use scc::HashCache;
1417    ///
1418    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1419    /// assert_eq!(hashcache.entry_sync(31).key(), &31);
1420    /// ```
1421    #[inline]
1422    pub fn key(&self) -> &K {
1423        match self {
1424            Self::Occupied(o) => o.key(),
1425            Self::Vacant(v) => v.key(),
1426        }
1427    }
1428
1429    /// Provides in-place mutable access to an occupied entry.
1430    ///
1431    /// # Examples
1432    ///
1433    /// ```
1434    /// use scc::HashCache;
1435    ///
1436    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1437    ///
1438    /// hashcache.entry_sync(37).and_modify(|v| { *v += 1 }).or_put(47);
1439    /// assert_eq!(*hashcache.get_sync(&37).unwrap().get(), 47);
1440    ///
1441    /// hashcache.entry_sync(37).and_modify(|v| { *v += 1 }).or_put(3);
1442    /// assert_eq!(*hashcache.get_sync(&37).unwrap().get(), 48);
1443    /// ```
1444    #[inline]
1445    #[must_use]
1446    pub fn and_modify<F>(self, f: F) -> Self
1447    where
1448        F: FnOnce(&mut V),
1449    {
1450        match self {
1451            Self::Occupied(mut o) => {
1452                f(o.get_mut());
1453                Self::Occupied(o)
1454            }
1455            Self::Vacant(_) => self,
1456        }
1457    }
1458
1459    /// Sets the value of the entry.
1460    ///
1461    /// # Examples
1462    ///
1463    /// ```
1464    /// use scc::HashCache;
1465    ///
1466    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1467    /// let entry = hashcache.entry_sync(11).put_entry(17).1;
1468    /// assert_eq!(entry.key(), &11);
1469    /// ```
1470    #[inline]
1471    pub fn put_entry(self, val: V) -> (EvictedEntry<K, V>, OccupiedEntry<'h, K, V, H>) {
1472        match self {
1473            Self::Occupied(mut o) => {
1474                o.put(val);
1475                (None, o)
1476            }
1477            Self::Vacant(v) => v.put_entry(val),
1478        }
1479    }
1480}
1481
1482impl<'h, K, V, H> Entry<'h, K, V, H>
1483where
1484    K: Eq + Hash,
1485    V: Default,
1486    H: BuildHasher,
1487{
1488    /// Ensures a value is in the entry by putting the default value if empty.
1489    ///
1490    /// # Examples
1491    ///
1492    /// ```
1493    /// use scc::HashCache;
1494    ///
1495    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1496    /// hashcache.entry_sync(11).or_default();
1497    /// assert_eq!(*hashcache.get_sync(&11).unwrap().get(), 0);
1498    /// ```
1499    #[inline]
1500    pub fn or_default(self) -> (EvictedEntry<K, V>, OccupiedEntry<'h, K, V, H>) {
1501        match self {
1502            Self::Occupied(o) => (None, o),
1503            Self::Vacant(v) => v.put_entry(Default::default()),
1504        }
1505    }
1506}
1507
1508impl<K, V, H> Debug for Entry<'_, K, V, H>
1509where
1510    K: Debug + Eq + Hash,
1511    V: Debug,
1512    H: BuildHasher,
1513{
1514    #[inline]
1515    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1516        match self {
1517            Self::Vacant(v) => f.debug_tuple("Entry").field(v).finish(),
1518            Self::Occupied(o) => f.debug_tuple("Entry").field(o).finish(),
1519        }
1520    }
1521}
1522
1523impl<K, V, H> OccupiedEntry<'_, K, V, H>
1524where
1525    K: Eq + Hash,
1526    H: BuildHasher,
1527{
1528    /// Gets a reference to the key in the entry.
1529    ///
1530    /// # Examples
1531    ///
1532    /// ```
1533    /// use scc::HashCache;
1534    ///
1535    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1536    ///
1537    /// assert_eq!(hashcache.entry_sync(29).or_default().1.key(), &29);
1538    /// ```
1539    #[inline]
1540    #[must_use]
1541    pub fn key(&self) -> &K {
1542        self.locked_bucket.entry(&self.entry_ptr).0
1543    }
1544
1545    /// Takes ownership of the key and value from the [`HashCache`].
1546    ///
1547    /// # Examples
1548    ///
1549    /// ```
1550    /// use scc::HashCache;
1551    /// use scc::hash_cache::Entry;
1552    ///
1553    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1554    ///
1555    /// hashcache.entry_sync(11).or_put(17);
1556    ///
1557    /// if let Entry::Occupied(o) = hashcache.entry_sync(11) {
1558    ///     assert_eq!(o.remove_entry(), (11, 17));
1559    /// };
1560    /// ```
1561    #[inline]
1562    #[must_use]
1563    pub fn remove_entry(mut self) -> (K, V) {
1564        self.locked_bucket
1565            .remove(self.hashcache, &mut self.entry_ptr)
1566    }
1567
1568    /// Gets a reference to the value in the entry.
1569    ///
1570    /// # Examples
1571    ///
1572    /// ```
1573    /// use scc::HashCache;
1574    /// use scc::hash_cache::Entry;
1575    ///
1576    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1577    ///
1578    /// hashcache.entry_sync(19).or_put(11);
1579    ///
1580    /// if let Entry::Occupied(o) = hashcache.entry_sync(19) {
1581    ///     assert_eq!(o.get(), &11);
1582    /// };
1583    /// ```
1584    #[inline]
1585    #[must_use]
1586    pub fn get(&self) -> &V {
1587        self.locked_bucket.entry(&self.entry_ptr).1
1588    }
1589
1590    /// Gets a mutable reference to the value in the entry.
1591    ///
1592    /// # Examples
1593    ///
1594    /// ```
1595    /// use scc::HashCache;
1596    /// use scc::hash_cache::Entry;
1597    ///
1598    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1599    ///
1600    /// hashcache.entry_sync(37).or_put(11);
1601    ///
1602    /// if let Entry::Occupied(mut o) = hashcache.entry_sync(37) {
1603    ///     *o.get_mut() += 18;
1604    ///     assert_eq!(*o.get(), 29);
1605    /// }
1606    ///
1607    /// assert_eq!(*hashcache.get_sync(&37).unwrap().get(), 29);
1608    /// ```
1609    #[inline]
1610    pub fn get_mut(&mut self) -> &mut V {
1611        self.locked_bucket.entry_mut(&mut self.entry_ptr).1
1612    }
1613
1614    /// Sets the value of the entry, and returns the old value.
1615    ///
1616    /// # Examples
1617    ///
1618    /// ```
1619    /// use scc::HashCache;
1620    /// use scc::hash_cache::Entry;
1621    ///
1622    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1623    ///
1624    /// hashcache.entry_sync(37).or_put(11);
1625    ///
1626    /// if let Entry::Occupied(mut o) = hashcache.entry_sync(37) {
1627    ///     assert_eq!(o.put(17), 11);
1628    /// }
1629    ///
1630    /// assert_eq!(*hashcache.get_sync(&37).unwrap().get(), 17);
1631    /// ```
1632    #[inline]
1633    pub fn put(&mut self, val: V) -> V {
1634        replace(self.get_mut(), val)
1635    }
1636
1637    /// Takes the value out of the entry, and returns it.
1638    ///
1639    /// # Examples
1640    ///
1641    /// ```
1642    /// use scc::HashCache;
1643    /// use scc::hash_cache::Entry;
1644    ///
1645    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1646    ///
1647    /// hashcache.entry_sync(11).or_put(17);
1648    ///
1649    /// if let Entry::Occupied(o) = hashcache.entry_sync(11) {
1650    ///     assert_eq!(o.remove(), 17);
1651    /// };
1652    /// ```
1653    #[inline]
1654    #[must_use]
1655    pub fn remove(self) -> V {
1656        self.remove_entry().1
1657    }
1658}
1659
1660impl<K, V, H> Debug for OccupiedEntry<'_, K, V, H>
1661where
1662    K: Debug + Eq + Hash,
1663    V: Debug,
1664    H: BuildHasher,
1665{
1666    #[inline]
1667    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1668        f.debug_struct("OccupiedEntry")
1669            .field("key", self.key())
1670            .field("value", self.get())
1671            .finish_non_exhaustive()
1672    }
1673}
1674
1675impl<K, V, H> Deref for OccupiedEntry<'_, K, V, H>
1676where
1677    K: Eq + Hash,
1678    H: BuildHasher,
1679{
1680    type Target = V;
1681
1682    #[inline]
1683    fn deref(&self) -> &Self::Target {
1684        self.get()
1685    }
1686}
1687
1688impl<K, V, H> DerefMut for OccupiedEntry<'_, K, V, H>
1689where
1690    K: Eq + Hash,
1691    H: BuildHasher,
1692{
1693    #[inline]
1694    fn deref_mut(&mut self) -> &mut Self::Target {
1695        self.get_mut()
1696    }
1697}
1698
1699impl<'h, K, V, H> VacantEntry<'h, K, V, H>
1700where
1701    K: Eq + Hash,
1702    H: BuildHasher,
1703{
1704    /// Gets a reference to the key.
1705    ///
1706    /// # Examples
1707    ///
1708    /// ```
1709    /// use scc::HashCache;
1710    ///
1711    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1712    /// assert_eq!(hashcache.entry_sync(11).key(), &11);
1713    /// ```
1714    #[inline]
1715    pub fn key(&self) -> &K {
1716        &self.key
1717    }
1718
1719    /// Takes ownership of the key.
1720    ///
1721    /// # Examples
1722    ///
1723    /// ```
1724    /// use scc::HashCache;
1725    /// use scc::hash_cache::Entry;
1726    ///
1727    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1728    ///
1729    /// if let Entry::Vacant(v) = hashcache.entry_sync(17) {
1730    ///     assert_eq!(v.into_key(), 17);
1731    /// };
1732    /// ```
1733    #[inline]
1734    pub fn into_key(self) -> K {
1735        self.key
1736    }
1737
1738    /// Sets the value of the entry with its key and returns an [`OccupiedEntry`].
1739    ///
1740    /// Returns a key-value pair if an entry was evicted for the new key-value pair.
1741    ///
1742    /// # Examples
1743    ///
1744    /// ```
1745    /// use scc::HashCache;
1746    /// use scc::hash_cache::Entry;
1747    ///
1748    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1749    ///
1750    /// if let Entry::Vacant(o) = hashcache.entry_sync(19) {
1751    ///     o.put_entry(29);
1752    /// }
1753    ///
1754    /// assert_eq!(*hashcache.get_sync(&19).unwrap().get(), 29);
1755    /// ```
1756    #[inline]
1757    pub fn put_entry(self, val: V) -> (EvictedEntry<K, V>, OccupiedEntry<'h, K, V, H>) {
1758        let evicted = self
1759            .locked_bucket
1760            .writer
1761            .evict_lru_head(self.locked_bucket.data_block);
1762        let entry_ptr = self.locked_bucket.insert(self.hash, (self.key, val));
1763        self.locked_bucket.writer.update_lru_tail(&entry_ptr);
1764        let occupied = OccupiedEntry {
1765            hashcache: self.hashcache,
1766            locked_bucket: self.locked_bucket,
1767            entry_ptr,
1768        };
1769        (evicted, occupied)
1770    }
1771}
1772
1773impl<K, V, H> Debug for VacantEntry<'_, K, V, H>
1774where
1775    K: Debug + Eq + Hash,
1776    V: Debug,
1777    H: BuildHasher,
1778{
1779    #[inline]
1780    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1781        f.debug_tuple("VacantEntry").field(self.key()).finish()
1782    }
1783}
1784
1785impl<K, V> ConsumableEntry<'_, K, V> {
1786    /// Consumes the entry by moving out the key and value.
1787    ///
1788    /// # Examples
1789    ///
1790    /// ```
1791    /// use scc::HashCache;
1792    ///
1793    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1794    ///
1795    /// assert!(hashcache.put_sync(1, 0).is_ok());
1796    /// assert!(hashcache.put_sync(2, 1).is_ok());
1797    /// assert!(hashcache.put_sync(3, 2).is_ok());
1798    ///
1799    /// let mut consumed = None;
1800    ///
1801    /// hashcache.iter_mut_sync(|mut e| {
1802    ///     if *e.key() == 1 {
1803    ///         *e = 2;
1804    ///         consumed.replace(e.consume().1);
1805    ///     }
1806    ///     true
1807    /// });
1808    ///
1809    /// assert!(!hashcache.contains_sync(&1));
1810    /// assert_eq!(consumed, Some(2));
1811    /// ```
1812    #[inline]
1813    #[must_use]
1814    pub fn consume(self) -> (K, V) {
1815        *self.remove_probe |= true;
1816        self.locked_bucket
1817            .writer
1818            .remove(self.locked_bucket.data_block, self.entry_ptr)
1819    }
1820
1821    /// Returns a reference to the entry.
1822    ///
1823    /// # Examples
1824    ///
1825    /// ```
1826    /// use scc::HashCache;
1827    ///
1828    /// let hashcache: HashCache<u64, u32> = HashCache::default();
1829    ///
1830    /// assert!(hashcache.put_sync(1, 0).is_ok());
1831    /// assert!(hashcache.put_sync(2, 1).is_ok());
1832    /// assert!(hashcache.put_sync(3, 2).is_ok());
1833    ///
1834    /// hashcache.iter_mut_sync(|e| {
1835    ///     if *e.key() == 1 {
1836    ///         assert_eq!(*e, 0);
1837    ///     }
1838    ///     true
1839    /// });
1840    /// ```
1841    #[inline]
1842    #[must_use]
1843    pub fn key(&self) -> &K {
1844        self.entry_ptr.key(self.locked_bucket.data_block)
1845    }
1846}
1847
1848impl<K, V> Deref for ConsumableEntry<'_, K, V> {
1849    type Target = V;
1850
1851    #[inline]
1852    fn deref(&self) -> &Self::Target {
1853        self.entry_ptr.val(self.locked_bucket.data_block)
1854    }
1855}
1856
1857impl<K, V> DerefMut for ConsumableEntry<'_, K, V> {
1858    #[inline]
1859    fn deref_mut(&mut self) -> &mut Self::Target {
1860        unsafe {
1861            self.entry_ptr
1862                .val_ptr(self.locked_bucket.data_block)
1863                .as_mut()
1864        }
1865    }
1866}