dualcache_ff/static_cache/
static_cache.rs1use core::hash::{BuildHasher, Hash, Hasher};
2use ahash::RandomState;
3
4#[derive(Debug)]
8pub struct CacheSlot<K, V> {
9 lock: core::sync::atomic::AtomicBool,
10 data: core::cell::UnsafeCell<Option<(K, V)>>,
11}
12
13unsafe impl<K: Send, V: Send> Send for CacheSlot<K, V> {}
16unsafe impl<K: Sync, V: Sync> Sync for CacheSlot<K, V> {}
17
18impl<K, V> CacheSlot<K, V> {
19 #[inline]
21 pub const fn new() -> Self {
22 Self {
23 lock: core::sync::atomic::AtomicBool::new(false),
24 data: core::cell::UnsafeCell::new(None),
25 }
26 }
27}
28
29#[derive(Debug)]
34pub struct StaticDualCache<K, V, const N: usize, S = RandomState> {
35 hasher: S,
36 slots: [CacheSlot<K, V>; N],
37}
38
39unsafe impl<K: Send, V: Send, const N: usize, S: Send> Send for StaticDualCache<K, V, N, S> {}
41unsafe impl<K: Sync, V: Sync, const N: usize, S: Sync> Sync for StaticDualCache<K, V, N, S> {}
42
43impl<K, V, const N: usize> StaticDualCache<K, V, N, RandomState> {
44 #[inline]
46 pub fn new(_config: crate::Config) -> Self {
47 Self {
48 hasher: RandomState::new(),
49 slots: [const { CacheSlot::new() }; N],
50 }
51 }
52
53 #[inline]
55 pub fn new_headless(_config: crate::Config) -> (Self, ()) {
56 (
57 Self::new(_config),
58 (),
59 )
60 }
61}
62
63impl<K, V, const N: usize, S> StaticDualCache<K, V, N, S>
64where
65 K: Hash + Eq + Clone,
66 V: Clone,
67 S: BuildHasher,
68{
69 #[inline]
71 pub fn with_hasher(hasher: S) -> Self {
72 Self {
73 hasher,
74 slots: [const { CacheSlot::new() }; N],
75 }
76 }
77
78 #[inline(always)]
79 fn get_slot_idx(&self, key: &K) -> usize {
80 let mut s = self.hasher.build_hasher();
81 key.hash(&mut s);
82 (s.finish() as usize) % N
83 }
84
85 pub fn get(&self, key: &K) -> Option<V> {
87 let idx = self.get_slot_idx(key);
88 let slot = &self.slots[idx];
89
90 while slot.lock.compare_exchange_weak(
92 false,
93 true,
94 core::sync::atomic::Ordering::Acquire,
95 core::sync::atomic::Ordering::Relaxed,
96 ).is_err() {
97 core::hint::spin_loop();
98 }
99
100 let data = unsafe { &*slot.data.get() };
102 let res = match data {
103 Some((k, v)) if k == key => Some(v.clone()),
104 _ => None,
105 };
106
107 slot.lock.store(false, core::sync::atomic::Ordering::Release);
109
110 res
111 }
112
113 pub fn insert(&self, key: K, value: V) {
115 let idx = self.get_slot_idx(&key);
116 let slot = &self.slots[idx];
117
118 while slot.lock.compare_exchange_weak(
120 false,
121 true,
122 core::sync::atomic::Ordering::Acquire,
123 core::sync::atomic::Ordering::Relaxed,
124 ).is_err() {
125 core::hint::spin_loop();
126 }
127
128 let data = unsafe { &mut *slot.data.get() };
130 *data = Some((key, value));
131
132 slot.lock.store(false, core::sync::atomic::Ordering::Release);
134 }
135
136 pub fn remove(&self, key: &K) {
138 let idx = self.get_slot_idx(key);
139 let slot = &self.slots[idx];
140
141 while slot.lock.compare_exchange_weak(
143 false,
144 true,
145 core::sync::atomic::Ordering::Acquire,
146 core::sync::atomic::Ordering::Relaxed,
147 ).is_err() {
148 core::hint::spin_loop();
149 }
150
151 let data = unsafe { &mut *slot.data.get() };
153 if let Some((k, _)) = data {
154 if k == key {
155 *data = None;
156 }
157 }
158
159 slot.lock.store(false, core::sync::atomic::Ordering::Release);
161 }
162
163 pub fn clear(&self) {
165 for slot in &self.slots {
166 while slot.lock.compare_exchange_weak(
168 false,
169 true,
170 core::sync::atomic::Ordering::Acquire,
171 core::sync::atomic::Ordering::Relaxed,
172 ).is_err() {
173 core::hint::spin_loop();
174 }
175
176 let data = unsafe { &mut *slot.data.get() };
178 *data = None;
179
180 slot.lock.store(false, core::sync::atomic::Ordering::Release);
182 }
183 }
184
185 #[inline(always)]
187 pub fn sync(&self) {}
188}