quick_cache/
linked_slab.rs1pub type Token = std::num::NonZeroU32;
2
3#[derive(Debug, Clone)]
4struct Entry<T> {
5 item: Option<T>,
6 next: Token,
9 prev: Token,
12}
13
14#[derive(Debug, Clone)]
16pub struct LinkedSlab<T> {
17 entries: Vec<Entry<T>>,
18 next_free: Token,
19}
20
21impl<T> LinkedSlab<T> {
22 pub fn with_capacity(capacity: usize) -> Self {
23 Self {
24 entries: Vec::with_capacity(capacity),
25 next_free: Token::new(1).unwrap(),
26 }
27 }
28
29 #[cfg(fuzzing)]
30 pub fn len(&self) -> usize {
31 self.entries.iter().filter(|e| e.item.is_some()).count()
32 }
33
34 #[cfg(any(fuzzing, test))]
35 pub fn iter_entries(&self) -> impl Iterator<Item = &T> + '_ {
36 self.entries.iter().filter_map(|e| e.item.as_ref())
37 }
38
39 #[cfg(any(fuzzing, test))]
40 pub fn validate(&self) {
41 let mut freelist = std::collections::HashSet::new();
42 let mut next_free = self.next_free;
43 while next_free.get() as usize - 1 != self.entries.len() {
44 freelist.insert(next_free.get() as usize);
45 let e = &self.entries[next_free.get() as usize - 1];
46 assert!(e.item.is_none(), "{next_free} is in freelist but has item");
47 next_free = e.next;
48 }
49 for (i, e) in self.entries.iter().enumerate() {
50 if e.item.is_some() {
51 assert!(!freelist.contains(&(i + 1)));
52 assert!(!freelist.contains(&(e.prev.get() as usize)));
53 assert!(!freelist.contains(&(e.next.get() as usize)));
54 }
55 }
56 }
57
58 pub fn insert(&mut self, item: T) -> Token {
64 let token = self.next_free;
65 let idx = (token.get() - 1) as usize;
67 if idx < self.entries.len() {
68 let entry = &mut self.entries[idx];
69 self.next_free = entry.next;
70 (entry.prev, entry.next) = (token, token);
71 debug_assert!(entry.item.is_none());
72 entry.item = Some(item);
73 } else {
74 debug_assert_eq!(idx, self.entries.len());
75 self.next_free = Token::new(token.get().wrapping_add(1)).expect("Capacity overflow");
76 self.entries.push(Entry {
77 next: token,
78 prev: token,
79 item: Some(item),
80 });
81 }
82 token
83 }
84
85 #[inline]
87 pub fn get(&self, index: Token) -> Option<(&T, Token)> {
88 if let Some(entry) = self.entries.get((index.get() - 1) as usize) {
89 if let Some(v) = &entry.item {
90 return Some((v, entry.next));
91 }
92 }
93 None
94 }
95
96 #[inline]
98 pub fn get_mut(&mut self, index: Token) -> Option<(&mut T, Token)> {
99 if let Some(entry) = self.entries.get_mut((index.get() - 1) as usize) {
100 if let Some(v) = &mut entry.item {
101 return Some((v, entry.next));
102 }
103 }
104 None
105 }
106
107 #[inline]
109 pub unsafe fn get_unchecked(&self, index: Token) -> (&T, Token) {
110 unsafe {
111 let entry = self.entries.get_unchecked((index.get() - 1) as usize);
112 let v = entry.item.as_ref().unwrap_unchecked();
113 (v, entry.next)
114 }
115 }
116
117 #[inline]
119 pub unsafe fn get_mut_unchecked(&mut self, index: Token) -> (&mut T, Token) {
120 unsafe {
121 let entry = self.entries.get_unchecked_mut((index.get() - 1) as usize);
122 let v = entry.item.as_mut().unwrap_unchecked();
123 (v, entry.next)
124 }
125 }
126
127 pub fn link(&mut self, idx: Token, target_head: Option<Token>) -> Token {
134 let (prev, next) = if let Some(target_head) = target_head {
136 let head = &mut self.entries[(target_head.get() - 1) as usize];
137 debug_assert!(head.item.is_some());
138 if head.prev == target_head {
139 head.prev = idx;
141 head.next = idx;
142 (target_head, target_head)
143 } else {
144 let before_head_idx = head.prev;
145 head.prev = idx;
146 let before_head = &mut self.entries[(before_head_idx.get() - 1) as usize];
147 debug_assert!(before_head.item.is_some());
148 debug_assert_eq!(before_head.next, target_head);
149 before_head.next = idx;
150 (before_head_idx, target_head)
151 }
152 } else {
153 (idx, idx)
154 };
155
156 let entry = &mut self.entries[(idx.get() - 1) as usize];
157 debug_assert!(entry.item.is_some());
158 debug_assert_eq!(entry.next, idx);
159 debug_assert_eq!(entry.prev, idx);
160 (entry.prev, entry.next) = (prev, next);
161 next
162 }
163
164 pub fn unlink(&mut self, idx: Token) -> Option<Token> {
171 let entry = &mut self.entries[(idx.get() - 1) as usize];
173 debug_assert!(entry.item.is_some());
174 let (prev_idx, next_idx) = (entry.prev, entry.next);
175 if next_idx == idx {
176 debug_assert_eq!(prev_idx, idx);
177 None
179 } else {
180 (entry.prev, entry.next) = (idx, idx);
181 let next = &mut self.entries[(next_idx.get() - 1) as usize];
182 debug_assert!(next.item.is_some());
183 debug_assert_eq!(next.prev, idx);
184 next.prev = prev_idx;
185 let prev = &mut self.entries[(prev_idx.get() - 1) as usize];
186 debug_assert!(prev.item.is_some());
187 debug_assert_eq!(prev.next, idx);
188 prev.next = next_idx;
189 Some(next_idx)
190 }
191 }
192
193 pub fn remove(&mut self, idx: Token) -> Option<(T, Option<Token>)> {
199 let next = self.unlink(idx);
201 let entry = &mut self.entries[(idx.get() - 1) as usize];
202 let old_item = entry.item.take()?;
203 entry.next = self.next_free;
204 self.next_free = idx;
205 Some((old_item, next))
206 }
207
208 pub fn next_free(&self) -> Token {
210 self.next_free
211 }
212
213 pub fn drain(&mut self) -> impl Iterator<Item = T> + '_ {
217 self.next_free = Token::new(1).unwrap();
218 self.entries.drain(..).flat_map(|i| i.item)
219 }
220
221 pub fn iter(&self) -> impl Iterator<Item = &'_ T> + '_ {
223 self.entries.iter().flat_map(|i| i.item.as_ref())
224 }
225
226 pub fn iter_from(
228 &self,
229 continuation: Option<Token>,
230 ) -> impl Iterator<Item = (Token, &'_ T)> + '_ {
231 let skip = continuation.map_or(0, |c| c.get() as usize);
232 self.entries
233 .iter()
234 .skip(skip)
235 .enumerate()
236 .filter_map(move |(i, e)| {
237 if let Some(item) = &e.item {
238 Some((Token::new((skip + i + 1) as u32)?, item))
239 } else {
240 None
241 }
242 })
243 }
244
245 pub fn memory_used(&self) -> usize {
250 self.entries.len() * size_of::<Entry<T>>()
251 }
252}