1use core::ops::Index;
2#[derive(Debug)]
6pub struct Cache<T, const N: usize> {
7 vals: [T; N],
9 len: usize,
13 next_head: usize,
15}
16impl<T, const N: usize> Cache<T, N> {
17 #[inline]
21 pub const fn len(&self) -> usize {
22 self.len
23 }
24 #[inline]
26 pub const fn is_empty(&self) -> bool {
27 self.len == 0
28 }
29}
30macro_rules! cache {
35 ( $( $x:literal),* ) => {
36 $(
37impl<T> Cache<T, $x> {
38 #[inline]
43 pub fn get(&self, idx: usize) -> Option<&T> {
44 (idx < self.len).then(|| self.vals.index(self.next_head.wrapping_sub(1).wrapping_sub(idx) & ($x - 1)))
45 }
46 #[inline]
55 pub fn get_unchecked(&self, idx: usize) -> &T {
56 self.vals.index(self.next_head.wrapping_sub(1).wrapping_sub(idx) & ($x - 1))
57 }
58 #[expect(clippy::arithmetic_side_effects, reason = "must, and overflow is not possible")]
61 #[expect(clippy::indexing_slicing, reason = "wont panic since next_head is always correct")]
62 #[inline]
63 pub fn push(&mut self, val: T) {
64 if self.len < $x {
65 self.len += 1;
66 }
67 self.vals[self.next_head] = val;
70 self.next_head = (self.next_head + 1) & ($x - 1);
71 }
72}
73impl<T> Index<usize> for Cache<T, $x> {
74 type Output = T;
75 #[inline]
76 fn index(&self, index: usize) -> &Self::Output {
77 self.get(index).unwrap()
78 }
79}
80 )*
81 };
82}
83cache!(
85 0x1,
86 0x2,
87 0x4,
88 0x8,
89 0x10,
90 0x20,
91 0x40,
92 0x80,
93 0x100,
94 0x200,
95 0x400,
96 0x800,
97 0x1000,
98 0x2000,
99 0x4000,
100 0x8000,
101 0x0001_0000,
102 0x0002_0000,
103 0x0004_0000,
104 0x0008_0000,
105 0x0010_0000,
106 0x0020_0000,
107 0x0040_0000,
108 0x0080_0000,
109 0x0100_0000,
110 0x0200_0000,
111 0x0400_0000,
112 0x0800_0000,
113 0x1000_0000,
114 0x2000_0000,
115 0x4000_0000,
116 0x8000_0000,
117 0x0001_0000_0000,
118 0x0002_0000_0000,
119 0x0004_0000_0000,
120 0x0008_0000_0000,
121 0x0010_0000_0000,
122 0x0020_0000_0000,
123 0x0040_0000_0000,
124 0x0080_0000_0000,
125 0x0100_0000_0000,
126 0x0200_0000_0000,
127 0x0400_0000_0000,
128 0x0800_0000_0000,
129 0x1000_0000_0000,
130 0x2000_0000_0000,
131 0x4000_0000_0000,
132 0x8000_0000_0000,
133 0x0001_0000_0000_0000,
134 0x0002_0000_0000_0000,
135 0x0004_0000_0000_0000,
136 0x0008_0000_0000_0000,
137 0x0010_0000_0000_0000,
138 0x0020_0000_0000_0000,
139 0x0040_0000_0000_0000,
140 0x0080_0000_0000_0000,
141 0x0100_0000_0000_0000,
142 0x0200_0000_0000_0000,
143 0x0400_0000_0000_0000,
144 0x0800_0000_0000_0000,
145 0x1000_0000_0000_0000,
146 0x2000_0000_0000_0000,
147 0x4000_0000_0000_0000,
148 0x8000_0000_0000_0000
149);
150impl<T, const N: usize> Cache<T, N>
151where
152 [T; N]: Default,
153{
154 #[inline]
159 #[must_use]
160 pub fn new() -> Self {
161 Self::default()
162 }
163}
164impl<T, const N: usize> Default for Cache<T, N>
165where
166 [T; N]: Default,
167{
168 #[inline]
169 fn default() -> Self {
170 Self {
171 vals: Default::default(),
172 len: 0,
173 next_head: 0,
174 }
175 }
176}
177#[cfg(test)]
178mod tests {
179 use super::Cache;
180 #[test]
181 fn test_len() {
182 let mut c = Cache::<bool, 1>::new();
183 assert_eq!(0, c.len());
184 c.push(false);
185 assert_eq!(1, c.len());
186 c.push(false);
187 assert_eq!(1, c.len());
188 }
189 #[test]
190 fn test_is_empty() {
191 let mut c = Cache::<bool, 1>::new();
192 assert!(c.is_empty());
193 c.push(false);
194 assert!(!c.is_empty());
195 }
196 #[test]
197 fn test_get() {
198 let mut c = Cache::<bool, 4>::new();
199 assert!(c.get(0).is_none());
200 assert!(c.get(1).is_none());
201 assert!(c.get(2).is_none());
202 assert!(c.get(3).is_none());
203 assert!(c.get(4).is_none());
204 assert!(c.get(5).is_none());
205 assert!(c.get(usize::MAX).is_none());
206 c.push(true);
207 assert!(c.get(0).unwrap());
208 assert!(c.get(1).is_none());
209 assert!(c.get(2).is_none());
210 assert!(c.get(3).is_none());
211 assert!(c.get(4).is_none());
212 assert!(c.get(5).is_none());
213 assert!(c.get(usize::MAX).is_none());
214 c.push(false);
215 assert!(!c.get(0).unwrap());
216 assert!(c.get(1).unwrap());
217 assert!(c.get(2).is_none());
218 assert!(c.get(3).is_none());
219 assert!(c.get(4).is_none());
220 assert!(c.get(5).is_none());
221 assert!(c.get(usize::MAX).is_none());
222 c.push(false);
223 assert!(!c.get(0).unwrap());
224 assert!(!c.get(1).unwrap());
225 assert!(c.get(2).unwrap());
226 assert!(c.get(3).is_none());
227 assert!(c.get(4).is_none());
228 assert!(c.get(5).is_none());
229 assert!(c.get(usize::MAX).is_none());
230 c.push(true);
231 assert!(c.get(0).unwrap());
232 assert!(!c.get(1).unwrap());
233 assert!(!c.get(2).unwrap());
234 assert!(c.get(3).unwrap());
235 assert!(c.get(4).is_none());
236 assert!(c.get(5).is_none());
237 assert!(c.get(usize::MAX).is_none());
238 c.push(true);
239 assert!(c.get(0).unwrap());
240 assert!(c.get(1).unwrap());
241 assert!(!c.get(2).unwrap());
242 assert!(!c.get(3).unwrap());
243 assert!(c.get(4).is_none());
244 assert!(c.get(5).is_none());
245 assert!(c.get(usize::MAX).is_none());
246 }
247 #[test]
248 fn test_get_unsafe() {
249 let mut c = Cache::<bool, 4>::new();
250 assert!(!c.get_unchecked(0));
251 assert!(!c.get_unchecked(1));
252 assert!(!c.get_unchecked(2));
253 assert!(!c.get_unchecked(3));
254 assert!(!c.get_unchecked(4));
255 c.push(true);
256 assert!(c.get_unchecked(0));
257 assert!(!c.get_unchecked(1));
258 assert!(!c.get_unchecked(2));
259 assert!(!c.get_unchecked(3));
260 assert!(c.get_unchecked(4));
261 }
262 #[test]
263 fn test_index() {
264 let mut c = Cache::<bool, 4>::new();
265 c.push(true);
266 assert!(c[0]);
267 }
268 #[test]
269 #[should_panic]
270 fn test_index_panic() {
271 let c = Cache::<bool, 4>::new();
272 assert!(c[0]);
273 }
274 #[test]
275 fn test_push() {
276 let mut c = Cache::<bool, 4>::new();
277 c.push(true);
278 assert!(c[0]);
279 c.push(true);
280 assert!(c[0]);
281 c.push(false);
282 assert!(!c[0]);
283 c.push(true);
284 assert!(c[0]);
285 c.push(false);
286 assert!(!c[0]);
287 c.push(false);
288 assert!(!c[0]);
289 }
290 #[test]
291 fn test_new() {
292 _ = Cache::<bool, 0>::new();
293 _ = Cache::<bool, 32>::new();
294 _ = Cache::<bool, 31>::new();
295 }
296}