tempo_precompiles/storage/types/
cache.rs1use alloy_primitives::map::HashMap;
2use std::{cell::RefCell, hash::Hash};
3
4const CACHE_THRESHOLD: usize = 100;
5
6#[derive(Debug)]
7pub(crate) struct LinearCache<K, H> {
8 entries: Vec<(K, Box<H>)>,
9}
10
11impl<K, H> Default for LinearCache<K, H> {
12 #[inline]
13 fn default() -> Self {
14 Self {
15 entries: Vec::new(),
16 }
17 }
18}
19
20impl<K: Eq + Clone, H> LinearCache<K, H> {
21 #[inline]
22 fn len(&self) -> usize {
23 self.entries.len()
24 }
25
26 #[inline]
27 fn find(&self, key: &K) -> Option<*const H> {
28 self.entries
29 .iter()
30 .find(|(candidate, _)| candidate == key)
31 .map(|(_, boxed)| boxed.as_ref() as *const H)
32 }
33
34 #[inline]
35 fn find_mut(&mut self, key: &K) -> Option<*mut H> {
36 self.entries
37 .iter_mut()
38 .find(|(candidate, _)| candidate == key)
39 .map(|(_, boxed)| boxed.as_mut() as *mut H)
40 }
41
42 #[inline]
43 fn insert(&mut self, key: &K, f: impl FnOnce() -> H) -> *const H {
44 self.entries.push((key.clone(), Box::new(f())));
45 self.entries
46 .last()
47 .expect("just pushed handler cache entry")
48 .1
49 .as_ref() as *const H
50 }
51
52 #[inline]
53 fn insert_mut(&mut self, key: &K, f: impl FnOnce() -> H) -> *mut H {
54 self.entries.push((key.clone(), Box::new(f())));
55 self.entries
56 .last_mut()
57 .expect("just pushed handler cache entry")
58 .1
59 .as_mut() as *mut H
60 }
61
62 #[inline]
63 fn drain_into_map(&mut self, map: &mut MapCache<K, H>)
64 where
65 K: Hash,
66 {
67 for (key, value) in self.entries.drain(..) {
68 map.insert_boxed(key, value);
69 }
70 }
71}
72
73#[derive(Debug)]
74pub(crate) struct MapCache<K, H> {
75 entries: HashMap<K, Box<H>>,
76}
77
78impl<K, H> Default for MapCache<K, H> {
79 #[inline]
80 fn default() -> Self {
81 Self {
82 entries: HashMap::default(),
83 }
84 }
85}
86
87impl<K: Hash + Eq + Clone, H> MapCache<K, H> {
88 #[inline]
89 fn reserve(&mut self, additional: usize) {
90 self.entries.reserve(additional);
91 }
92
93 #[inline]
94 fn insert_boxed(&mut self, key: K, value: Box<H>) {
95 self.entries.insert(key, value);
96 }
97
98 #[inline]
99 fn get_or_insert(&mut self, key: &K, f: impl FnOnce() -> H) -> *const H {
100 if let Some(boxed) = self.entries.get(key) {
101 boxed.as_ref() as *const H
102 } else {
103 self.entries
104 .entry(key.clone())
105 .or_insert_with(|| Box::new(f()))
106 .as_ref() as *const H
107 }
108 }
109
110 #[inline]
111 fn get_or_insert_mut(&mut self, key: &K, f: impl FnOnce() -> H) -> *mut H {
112 if let Some(boxed) = self.entries.get_mut(key) {
113 boxed.as_mut() as *mut H
114 } else {
115 self.entries
116 .entry(key.clone())
117 .or_insert_with(|| Box::new(f()))
118 .as_mut() as *mut H
119 }
120 }
121}
122
123#[derive(Debug)]
124enum HandlerCacheState<K, H> {
125 Linear(LinearCache<K, H>),
126 Mapped(MapCache<K, H>),
127}
128
129#[derive(Debug)]
137pub(crate) struct HandlerCache<K, H, const THRESHOLD: usize = CACHE_THRESHOLD> {
138 inner: RefCell<HandlerCacheState<K, H>>,
139}
140
141impl<K, H, const THRESHOLD: usize> HandlerCache<K, H, THRESHOLD> {
142 #[inline]
144 pub(super) fn new() -> Self {
145 Self {
146 inner: RefCell::new(HandlerCacheState::Linear(LinearCache::default())),
147 }
148 }
149}
150
151impl<K, H, const THRESHOLD: usize> HandlerCache<K, H, THRESHOLD>
152where
153 K: Eq + Hash + Clone,
154{
155 #[inline]
156 fn promote_to_map(linear: &mut LinearCache<K, H>) -> MapCache<K, H> {
157 let mut map = MapCache::default();
158 map.reserve(THRESHOLD * 2);
159 linear.drain_into_map(&mut map);
160 map
161 }
162
163 #[inline]
165 pub(super) fn get_or_insert(&self, key: &K, f: impl FnOnce() -> H) -> &H {
166 let mut cache = self.inner.borrow_mut();
167 let ptr = match &mut *cache {
168 HandlerCacheState::Linear(linear) => {
169 if let Some(ptr) = linear.find(key) {
170 ptr
171 } else if linear.len() < THRESHOLD {
172 linear.insert(key, f)
173 } else {
174 let map = Self::promote_to_map(linear);
175 *cache = HandlerCacheState::Mapped(map);
176 match &mut *cache {
177 HandlerCacheState::Mapped(map) => map.get_or_insert(key, f),
178 HandlerCacheState::Linear(_) => unreachable!("handler cache was promoted"),
179 }
180 }
181 }
182 HandlerCacheState::Mapped(map) => map.get_or_insert(key, f),
183 };
184 unsafe { &*ptr }
186 }
187
188 #[inline]
190 pub(super) fn get_or_insert_mut(&mut self, key: &K, f: impl FnOnce() -> H) -> &mut H {
191 let mut cache = self.inner.borrow_mut();
192 let ptr = match &mut *cache {
193 HandlerCacheState::Linear(linear) => {
194 if let Some(ptr) = linear.find_mut(key) {
195 ptr
196 } else if linear.len() < THRESHOLD {
197 linear.insert_mut(key, f)
198 } else {
199 let map = Self::promote_to_map(linear);
200 *cache = HandlerCacheState::Mapped(map);
201 match &mut *cache {
202 HandlerCacheState::Mapped(map) => map.get_or_insert_mut(key, f),
203 HandlerCacheState::Linear(_) => unreachable!("handler cache was promoted"),
204 }
205 }
206 }
207 HandlerCacheState::Mapped(map) => map.get_or_insert_mut(key, f),
208 };
209 unsafe { &mut *ptr }
211 }
212}
213
214impl<K, H, const THRESHOLD: usize> Clone for HandlerCache<K, H, THRESHOLD> {
215 fn clone(&self) -> Self {
217 Self::new()
218 }
219}