1use crate::{
2 linked_slab::Token,
3 options::*,
4 shard::{self, CacheShard, InsertStrategy},
5 DefaultHashBuilder, Equivalent, Lifecycle, UnitWeighter, Weighter,
6};
7use std::hash::{BuildHasher, Hash};
8
9#[derive(Clone)]
11pub struct Cache<
12 Key,
13 Val,
14 We = UnitWeighter,
15 B = DefaultHashBuilder,
16 L = DefaultLifecycle<Key, Val>,
17> {
18 shard: CacheShard<Key, Val, We, B, L, SharedPlaceholder>,
19}
20
21impl<Key: Eq + Hash, Val> Cache<Key, Val> {
22 pub fn new(items_capacity: usize) -> Self {
24 Self::with(
25 items_capacity,
26 items_capacity as u64,
27 Default::default(),
28 Default::default(),
29 Default::default(),
30 )
31 }
32}
33
34impl<Key: Eq + Hash, Val, We: Weighter<Key, Val>> Cache<Key, Val, We> {
35 pub fn with_weighter(
36 estimated_items_capacity: usize,
37 weight_capacity: u64,
38 weighter: We,
39 ) -> Self {
40 Self::with(
41 estimated_items_capacity,
42 weight_capacity,
43 weighter,
44 Default::default(),
45 Default::default(),
46 )
47 }
48}
49
50impl<Key: Eq + Hash, Val, We: Weighter<Key, Val>, B: BuildHasher, L: Lifecycle<Key, Val>>
51 Cache<Key, Val, We, B, L>
52{
53 pub fn with(
57 estimated_items_capacity: usize,
58 weight_capacity: u64,
59 weighter: We,
60 hash_builder: B,
61 lifecycle: L,
62 ) -> Self {
63 Self::with_options(
64 OptionsBuilder::new()
65 .estimated_items_capacity(estimated_items_capacity)
66 .weight_capacity(weight_capacity)
67 .build()
68 .unwrap(),
69 weighter,
70 hash_builder,
71 lifecycle,
72 )
73 }
74
75 pub fn with_options(options: Options, weighter: We, hash_builder: B, lifecycle: L) -> Self {
94 let shard = CacheShard::new(
95 options.hot_allocation,
96 options.ghost_allocation,
97 options.estimated_items_capacity,
98 options.weight_capacity,
99 weighter,
100 hash_builder,
101 lifecycle,
102 );
103 Self { shard }
104 }
105
106 pub fn is_empty(&self) -> bool {
108 self.shard.len() == 0
109 }
110
111 pub fn len(&self) -> usize {
113 self.shard.len()
114 }
115
116 pub fn weight(&self) -> u64 {
118 self.shard.weight()
119 }
120
121 pub fn capacity(&self) -> u64 {
123 self.shard.capacity()
124 }
125
126 #[cfg(feature = "stats")]
128 pub fn misses(&self) -> u64 {
129 self.shard.misses()
130 }
131
132 #[cfg(feature = "stats")]
134 pub fn hits(&self) -> u64 {
135 self.shard.hits()
136 }
137
138 pub fn reserve(&mut self, additional: usize) {
141 self.shard.reserve(additional);
142 }
143
144 pub fn contains_key<Q>(&self, key: &Q) -> bool
146 where
147 Q: Hash + Equivalent<Key> + ?Sized,
148 {
149 self.shard.contains(self.shard.hash(key), key)
150 }
151
152 pub fn get<Q>(&self, key: &Q) -> Option<&Val>
154 where
155 Q: Hash + Equivalent<Key> + ?Sized,
156 {
157 self.shard.get(self.shard.hash(key), key)
158 }
159
160 pub fn get_mut<Q>(&mut self, key: &Q) -> Option<RefMut<'_, Key, Val, We, B, L>>
164 where
165 Q: Hash + Equivalent<Key> + ?Sized,
166 {
167 self.shard.get_mut(self.shard.hash(key), key).map(RefMut)
168 }
169
170 pub fn peek<Q>(&self, key: &Q) -> Option<&Val>
172 where
173 Q: Hash + Equivalent<Key> + ?Sized,
174 {
175 self.shard.peek(self.shard.hash(key), key)
176 }
177
178 pub fn peek_mut<Q>(&mut self, key: &Q) -> Option<RefMut<'_, Key, Val, We, B, L>>
182 where
183 Q: Hash + Equivalent<Key> + ?Sized,
184 {
185 self.shard.peek_mut(self.shard.hash(key), key).map(RefMut)
186 }
187
188 pub fn remove<Q>(&mut self, key: &Q) -> Option<(Key, Val)>
191 where
192 Q: Hash + Equivalent<Key> + ?Sized,
193 {
194 self.shard.remove(self.shard.hash(key), key)
195 }
196
197 pub fn replace(&mut self, key: Key, value: Val, soft: bool) -> Result<(), (Key, Val)> {
203 let lcs = self.replace_with_lifecycle(key, value, soft)?;
204 self.shard.lifecycle.end_request(lcs);
205 Ok(())
206 }
207
208 pub fn replace_with_lifecycle(
214 &mut self,
215 key: Key,
216 value: Val,
217 soft: bool,
218 ) -> Result<L::RequestState, (Key, Val)> {
219 let mut lcs = self.shard.lifecycle.begin_request();
220 self.shard.insert(
221 &mut lcs,
222 self.shard.hash(&key),
223 key,
224 value,
225 InsertStrategy::Replace { soft },
226 )?;
227 Ok(lcs)
228 }
229
230 pub fn retain<F>(&mut self, f: F)
234 where
235 F: Fn(&Key, &Val) -> bool,
236 {
237 self.shard.retain(f);
238 }
239
240 pub fn get_or_insert_with<Q, E>(
245 &mut self,
246 key: &Q,
247 with: impl FnOnce() -> Result<Val, E>,
248 ) -> Result<Option<&Val>, E>
249 where
250 Q: Hash + Equivalent<Key> + ToOwned<Owned = Key> + ?Sized,
251 {
252 let idx = match self.shard.upsert_placeholder(self.shard.hash(key), key) {
253 Ok((idx, _)) => idx,
254 Err((plh, _)) => {
255 let v = with()?;
256 let mut lcs = self.shard.lifecycle.begin_request();
257 let replaced = self.shard.replace_placeholder(&mut lcs, &plh, false, v);
258 self.shard.lifecycle.end_request(lcs);
259 debug_assert!(replaced.is_ok(), "unsync replace_placeholder can't fail");
260 plh.idx
261 }
262 };
263 Ok(self.shard.peek_token(idx))
264 }
265
266 pub fn get_mut_or_insert_with<'a, Q, E>(
271 &'a mut self,
272 key: &Q,
273 with: impl FnOnce() -> Result<Val, E>,
274 ) -> Result<Option<RefMut<'a, Key, Val, We, B, L>>, E>
275 where
276 Q: Hash + Equivalent<Key> + ToOwned<Owned = Key> + ?Sized,
277 {
278 let idx = match self.shard.upsert_placeholder(self.shard.hash(key), key) {
279 Ok((idx, _)) => idx,
280 Err((plh, _)) => {
281 let v = with()?;
282 let mut lcs = self.shard.lifecycle.begin_request();
283 let replaced = self.shard.replace_placeholder(&mut lcs, &plh, false, v);
284 debug_assert!(replaced.is_ok(), "unsync replace_placeholder can't fail");
285 self.shard.lifecycle.end_request(lcs);
286 plh.idx
287 }
288 };
289 Ok(self.shard.peek_token_mut(idx).map(RefMut))
290 }
291
292 pub fn get_ref_or_guard<Q>(&mut self, key: &Q) -> Result<&Val, Guard<'_, Key, Val, We, B, L>>
296 where
297 Q: Hash + Equivalent<Key> + ToOwned<Owned = Key> + ?Sized,
298 {
299 match self.shard.upsert_placeholder(self.shard.hash(key), key) {
301 Ok((_, v)) => unsafe {
302 let v: *const Val = v;
305 Ok(&*v)
306 },
307 Err((placeholder, _)) => Err(Guard {
308 cache: self,
309 placeholder,
310 inserted: false,
311 }),
312 }
313 }
314
315 pub fn get_mut_or_guard<'a, Q>(
319 &'a mut self,
320 key: &Q,
321 ) -> Result<Option<RefMut<'a, Key, Val, We, B, L>>, Guard<'a, Key, Val, We, B, L>>
322 where
323 Q: Hash + Equivalent<Key> + ToOwned<Owned = Key> + ?Sized,
324 {
325 match self.shard.upsert_placeholder(self.shard.hash(key), key) {
327 Ok((idx, _)) => Ok(self.shard.peek_token_mut(idx).map(RefMut)),
328 Err((placeholder, _)) => Err(Guard {
329 cache: self,
330 placeholder,
331 inserted: false,
332 }),
333 }
334 }
335
336 pub fn insert(&mut self, key: Key, value: Val) {
338 let lcs = self.insert_with_lifecycle(key, value);
339 self.shard.lifecycle.end_request(lcs);
340 }
341
342 pub fn insert_with_lifecycle(&mut self, key: Key, value: Val) -> L::RequestState {
344 let mut lcs = self.shard.lifecycle.begin_request();
345 let result = self.shard.insert(
346 &mut lcs,
347 self.shard.hash(&key),
348 key,
349 value,
350 InsertStrategy::Insert,
351 );
352 debug_assert!(result.is_ok());
354 lcs
355 }
356
357 pub fn clear(&mut self) {
359 self.shard.clear();
360 }
361
362 pub fn iter(&self) -> impl Iterator<Item = (&'_ Key, &'_ Val)> + '_ {
364 self.shard.iter()
366 }
367
368 pub fn drain(&mut self) -> impl Iterator<Item = (Key, Val)> + '_ {
372 self.shard.drain()
374 }
375
376 #[cfg(any(fuzzing, test))]
377 pub fn validate(&self, accept_overweight: bool) {
378 self.shard.validate(accept_overweight);
379 }
380}
381
382impl<Key, Val, We, B, L> std::fmt::Debug for Cache<Key, Val, We, B, L> {
383 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
384 f.debug_struct("Cache").finish_non_exhaustive()
385 }
386}
387
388pub struct DefaultLifecycle<Key, Val>(std::marker::PhantomData<(Key, Val)>);
390
391impl<Key, Val> std::fmt::Debug for DefaultLifecycle<Key, Val> {
392 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
393 f.debug_tuple("DefaultLifecycle").finish()
394 }
395}
396
397impl<Key, Val> Default for DefaultLifecycle<Key, Val> {
398 #[inline]
399 fn default() -> Self {
400 Self(Default::default())
401 }
402}
403
404impl<Key, Val> Clone for DefaultLifecycle<Key, Val> {
405 #[inline]
406 fn clone(&self) -> Self {
407 Self(Default::default())
408 }
409}
410
411impl<Key, Val> Lifecycle<Key, Val> for DefaultLifecycle<Key, Val> {
412 type RequestState = ();
413
414 #[inline]
415 fn begin_request(&self) -> Self::RequestState {}
416
417 #[inline]
418 fn on_evict(&self, _state: &mut Self::RequestState, _key: Key, _val: Val) {}
419}
420
421#[derive(Debug, Clone)]
422struct SharedPlaceholder {
423 hash: u64,
424 idx: Token,
425}
426
427pub struct Guard<'a, Key, Val, We, B, L> {
428 cache: &'a mut Cache<Key, Val, We, B, L>,
429 placeholder: SharedPlaceholder,
430 inserted: bool,
431}
432
433impl<Key: Eq + Hash, Val, We: Weighter<Key, Val>, B: BuildHasher, L: Lifecycle<Key, Val>>
434 Guard<'_, Key, Val, We, B, L>
435{
436 pub fn insert(self, value: Val) {
438 self.insert_internal(value, false);
439 }
440
441 pub fn insert_with_lifecycle(self, value: Val) -> L::RequestState {
443 self.insert_internal(value, true).unwrap()
444 }
445
446 #[inline]
447 fn insert_internal(mut self, value: Val, return_lcs: bool) -> Option<L::RequestState> {
448 let mut lcs = self.cache.shard.lifecycle.begin_request();
449 let replaced =
450 self.cache
451 .shard
452 .replace_placeholder(&mut lcs, &self.placeholder, false, value);
453 debug_assert!(replaced.is_ok(), "unsync replace_placeholder can't fail");
454 self.inserted = true;
455 if return_lcs {
456 Some(lcs)
457 } else {
458 self.cache.shard.lifecycle.end_request(lcs);
459 None
460 }
461 }
462}
463
464impl<Key, Val, We, B, L> Drop for Guard<'_, Key, Val, We, B, L> {
465 #[inline]
466 fn drop(&mut self) {
467 #[cold]
468 fn drop_slow<Key, Val, We, B, L>(this: &mut Guard<'_, Key, Val, We, B, L>) {
469 this.cache.shard.remove_placeholder(&this.placeholder);
470 }
471 if !self.inserted {
472 drop_slow(self);
473 }
474 }
475}
476
477pub struct RefMut<'cache, Key, Val, We: Weighter<Key, Val>, B, L>(
478 crate::shard::RefMut<'cache, Key, Val, We, B, L, SharedPlaceholder>,
479);
480
481impl<Key, Val, We: Weighter<Key, Val>, B, L> std::ops::Deref for RefMut<'_, Key, Val, We, B, L> {
482 type Target = Val;
483
484 #[inline]
485 fn deref(&self) -> &Self::Target {
486 self.0.pair().1
487 }
488}
489
490impl<Key, Val, We: Weighter<Key, Val>, B, L> std::ops::DerefMut for RefMut<'_, Key, Val, We, B, L> {
491 #[inline]
492 fn deref_mut(&mut self) -> &mut Self::Target {
493 self.0.value_mut()
494 }
495}
496
497impl shard::SharedPlaceholder for SharedPlaceholder {
498 #[inline]
499 fn new(hash: u64, idx: Token) -> Self {
500 Self { hash, idx }
501 }
502
503 #[inline]
504 fn same_as(&self, _other: &Self) -> bool {
505 true
506 }
507
508 #[inline]
509 fn hash(&self) -> u64 {
510 self.hash
511 }
512
513 #[inline]
514 fn idx(&self) -> Token {
515 self.idx
516 }
517}
518
519#[cfg(test)]
520mod tests {
521 use super::*;
522
523 struct Weighter;
524
525 impl crate::Weighter<u32, u32> for Weighter {
526 fn weight(&self, _key: &u32, val: &u32) -> u64 {
527 *val as u64
528 }
529 }
530
531 #[test]
532 fn test_zero_weights() {
533 let mut cache = Cache::with_weighter(100, 100, Weighter);
534 cache.insert(0, 0);
535 assert_eq!(cache.weight(), 0);
536 for i in 1..100 {
537 cache.insert(i, i);
538 cache.insert(i, i);
539 }
540 assert_eq!(cache.get(&0).copied(), Some(0));
541 assert!(cache.contains_key(&0));
542 let a = cache.weight();
543 *cache.get_mut(&0).unwrap() += 1;
544 assert_eq!(cache.weight(), a + 1);
545 for i in 1..100 {
546 cache.insert(i, i);
547 cache.insert(i, i);
548 }
549 assert_eq!(cache.get(&0), None);
550 assert!(!cache.contains_key(&0));
551
552 cache.insert(0, 1);
553 let a = cache.weight();
554 *cache.get_mut(&0).unwrap() -= 1;
555 assert_eq!(cache.weight(), a - 1);
556 for i in 1..100 {
557 cache.insert(i, i);
558 cache.insert(i, i);
559 }
560 assert_eq!(cache.get(&0).copied(), Some(0));
561 assert!(cache.contains_key(&0));
562 }
563}