1#[cfg(not(feature = "std"))]
2use alloc::{boxed::Box, vec::Vec};
3
4use crate::sync::atomic::{AtomicPtr, Ordering};
5use crate::sync::index_types::{AtomicIndex, IndexType, EMPTY, TOMBSTONE, TAG_SHIFT, INDEX_MASK};
6use core::ptr;
7
8pub struct Node<K, V> {
10 pub key: K,
11 pub value: V,
12 pub expire_at: u32,
14 pub g_idx: u32,
16}
17
18pub struct Cache<K, V> {
25 pub(crate) index_mask: usize,
26 pub(crate) index: Box<[AtomicIndex]>,
27 pub(crate) nodes: Box<[AtomicPtr<Node<K, V>>]>,
28}
29
30unsafe impl<K: Send, V: Send> Send for Cache<K, V> {}
31unsafe impl<K: Send + Sync, V: Send + Sync> Sync for Cache<K, V> {}
32
33impl<K, V> Cache<K, V> {
34 pub fn new(capacity: usize) -> Self {
35 let index_size = (capacity * 2).next_power_of_two();
36 let mut index = Vec::with_capacity(index_size);
37 for _ in 0..index_size {
38 index.push(AtomicIndex::new(EMPTY));
39 }
40
41 let mut nodes = Vec::with_capacity(capacity);
42 for _ in 0..capacity {
43 nodes.push(AtomicPtr::new(ptr::null_mut()));
44 }
45
46 Self {
47 index_mask: index_size - 1,
48 index: index.into_boxed_slice(),
49 nodes: nodes.into_boxed_slice(),
50 }
51 }
52
53 #[inline(always)]
54 pub fn index_probe(&self, hash: u64, tag: u16) -> Option<usize> {
55 let mut idx = hash as usize & self.index_mask;
56 for _ in 0..16 {
57 let entry = self.index[idx].load(Ordering::Acquire);
58 if entry == EMPTY {
59 return None;
60 }
61 if entry != TOMBSTONE && (entry >> TAG_SHIFT) as u16 == tag {
62 return Some((entry & INDEX_MASK) as usize);
63 }
64 idx = (idx + 1) & self.index_mask;
65 }
66 None
67 }
68
69 #[inline(always)]
70 pub fn index_store(&self, hash: u64, tag: u16, entry: IndexType) {
71 let mut idx = hash as usize & self.index_mask;
72 for i in 0..16 {
73 let prev = self.index[idx].load(Ordering::Acquire);
74 if prev == EMPTY || prev == TOMBSTONE || (prev >> TAG_SHIFT) == (tag as IndexType) {
75 self.index[idx].store(entry, Ordering::Release);
76 return;
77 }
78 if i == 15 {
79 self.index[hash as usize & self.index_mask].store(entry, Ordering::Release);
80 }
81 idx = (idx + 1) & self.index_mask;
82 }
83 }
84
85 #[inline(always)]
86 pub fn index_remove(&self, hash: u64, tag: u16, g_idx: usize) {
87 let mut idx = hash as usize & self.index_mask;
88 for _ in 0..16 {
89 let entry = self.index[idx].load(Ordering::Acquire);
90 if entry == EMPTY {
91 return;
92 }
93 if entry != TOMBSTONE
94 && (entry >> TAG_SHIFT) as u16 == tag
95 && (entry & INDEX_MASK) == (g_idx as IndexType)
96 {
97 self.index[idx].store(TOMBSTONE, Ordering::Release);
98 return;
99 }
100 idx = (idx + 1) & self.index_mask;
101 }
102 }
103
104 #[inline(always)]
105 pub fn index_clear_at(&self, idx: usize) {
106 self.index[idx].store(EMPTY, Ordering::Relaxed);
107 }
108
109 #[inline(always)]
110 pub fn index_len(&self) -> usize {
111 self.index.len()
112 }
113
114 #[inline(always)]
115 pub fn get_node<'a>(&self, idx: usize) -> Option<&'a Node<K, V>> {
116 let ptr = self.nodes[idx].load(Ordering::Acquire);
117 if ptr.is_null() {
118 None
119 } else {
120 Some(unsafe { &*ptr })
122 }
123 }
124
125 #[inline(always)]
126 pub fn node_get_full(&self, idx: usize, key: &K, current_epoch: u32) -> Option<V>
127 where
128 K: Eq,
129 V: Clone,
130 {
131 let ptr = self.nodes[idx].load(Ordering::Acquire);
132 if ptr.is_null() {
133 return None;
134 }
135 let node = unsafe { &*ptr };
137 if node.key == *key {
138 if node.expire_at > 0 && node.expire_at < current_epoch {
139 return None;
140 }
141 Some(node.value.clone())
142 } else {
143 None
144 }
145 }
146
147 pub fn clear(&self) {
148 for i in 0..self.index.len() {
149 self.index[i].store(EMPTY, Ordering::Relaxed);
150 }
151 for i in 0..self.nodes.len() {
152 self.nodes[i].store(ptr::null_mut(), Ordering::Release);
153 }
154 }
155}
156
157impl<K, V> Drop for Cache<K, V> {
158 fn drop(&mut self) {
159 for node_ptr in self.nodes.iter() {
160 let ptr = node_ptr.swap(ptr::null_mut(), Ordering::Relaxed);
161 if !ptr.is_null() {
162 unsafe {
163 let _ = Box::from_raw(ptr);
164 }
165 }
166 }
167 }
168}