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