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}