1use super::freelist::*;
2use std::ptr::NonNull;
3
4#[derive(Debug)]
5pub struct IntArrayFreeList {
6 pub head: i32,
7 pub heads: i32,
8 pub table: Option<Vec<i32>>,
9 parent: Option<NonNull<IntArrayFreeList>>,
10}
11
12unsafe impl Send for IntArrayFreeList {}
13unsafe impl Sync for IntArrayFreeList {}
14
15impl FreeList for IntArrayFreeList {
16 fn head(&self) -> i32 {
17 self.head
18 }
19 fn heads(&self) -> i32 {
20 self.heads
21 }
22 fn get_entry(&self, index: i32) -> i32 {
23 self.table()[index as usize]
24 }
25 fn set_entry(&mut self, index: i32, value: i32) {
26 self.table_mut()[index as usize] = value;
27 }
28}
29
30impl IntArrayFreeList {
31 pub fn new(units: usize, grain: i32, heads: usize) -> Self {
32 debug_assert!(units <= MAX_UNITS as usize && heads <= MAX_HEADS as usize);
33 let len = (units + 1 + heads) << 1;
35 let mut iafl = IntArrayFreeList {
36 head: -1,
37 heads: heads as _,
38 table: Some(vec![0; len]), parent: None,
40 };
41 iafl.initialize_heap(units as _, grain);
42 iafl
43 }
44 pub fn from_parent(parent: &IntArrayFreeList, ordinal: i32) -> Self {
45 let parent_ptr = std::ptr::NonNull::from(parent);
46 let iafl = IntArrayFreeList {
47 head: -(1 + ordinal),
48 heads: parent.heads,
49 table: None,
50 parent: Some(parent_ptr),
51 };
52 debug_assert!(-iafl.head <= iafl.heads);
53 iafl
54 }
55 pub(crate) fn get_ordinal(&self) -> i32 {
56 -self.head - 1
57 }
58 fn table(&self) -> &Vec<i32> {
59 match self.parent {
60 Some(p) => unsafe { p.as_ref().table() },
61 None => self.table.as_ref().unwrap(),
62 }
63 }
64
65 fn table_mut(&mut self) -> &mut Vec<i32> {
68 match self.parent {
69 Some(mut p) => unsafe { p.as_mut().table_mut() },
70 None => self.table.as_mut().unwrap(),
71 }
72 }
73 pub fn resize_freelist(&mut self, units: usize, grain: i32) {
74 *self.table_mut() = vec![0; (units + 1 + self.heads as usize) << 1];
76 self.initialize_heap(units as _, grain);
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::FreeList;
83 use super::*;
84
85 const LIST_SIZE: usize = 5;
86 const TOP_SENTINEL: i32 = -1;
87 const FIRST_UNIT: i32 = 0;
88 const LAST_UNIT: i32 = LIST_SIZE as i32 - 1;
89 const BOTTOM_SENTINEL: i32 = LIST_SIZE as i32;
90
91 #[test]
92 #[allow(clippy::cognitive_complexity)] fn new_free_list_grain1() {
94 let l = IntArrayFreeList::new(LIST_SIZE, 1, 1);
95 assert_eq!(l.head(), TOP_SENTINEL);
96
97 assert_eq!(l.get_prev(TOP_SENTINEL), LAST_UNIT);
98 assert_eq!(l.get_next(TOP_SENTINEL), FIRST_UNIT);
99
100 assert_eq!(l.get_size(FIRST_UNIT), 1);
101 assert_eq!(l.get_left(FIRST_UNIT), -1);
102 assert_eq!(l.get_prev(FIRST_UNIT), -1);
103 assert_eq!(l.get_right(FIRST_UNIT), 1);
104 assert_eq!(l.get_next(FIRST_UNIT), 1);
105 assert!(l.is_free(FIRST_UNIT));
106 assert!(l.is_coalescable(FIRST_UNIT));
107 assert!(!l.is_multi(FIRST_UNIT));
108
109 assert_eq!(l.get_size(1), 1);
110 assert_eq!(l.get_left(1), 0);
111 assert_eq!(l.get_prev(1), 0);
112 assert_eq!(l.get_right(1), 2);
113 assert_eq!(l.get_next(1), 2);
114 assert!(l.is_free(1));
115 assert!(l.is_coalescable(1));
116 assert!(!l.is_multi(1));
117
118 assert_eq!(l.get_size(LAST_UNIT), 1);
119 assert_eq!(l.get_left(LAST_UNIT), LAST_UNIT - 1);
120 assert_eq!(l.get_prev(LAST_UNIT), LAST_UNIT - 1);
121 assert_eq!(l.get_right(LAST_UNIT), BOTTOM_SENTINEL);
122 assert_eq!(l.get_next(LAST_UNIT), -1);
123 assert!(l.is_free(LAST_UNIT));
124 assert!(l.is_coalescable(LAST_UNIT));
125 assert!(!l.is_multi(LAST_UNIT));
126
127 assert_eq!(l.get_prev(BOTTOM_SENTINEL), BOTTOM_SENTINEL);
128 assert_eq!(l.get_next(BOTTOM_SENTINEL), BOTTOM_SENTINEL);
129 }
130
131 #[test]
132 #[allow(clippy::cognitive_complexity)] fn new_free_list_grain2() {
134 let l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
135 assert_eq!(l.head(), TOP_SENTINEL);
136
137 assert_eq!(l.get_prev(TOP_SENTINEL), LAST_UNIT);
138 assert_eq!(l.get_next(TOP_SENTINEL), FIRST_UNIT);
139
140 assert_eq!(l.get_size(FIRST_UNIT), 2);
141 assert_eq!(l.get_left(FIRST_UNIT), -1);
142 assert_eq!(l.get_prev(FIRST_UNIT), -1);
143 assert_eq!(l.get_right(FIRST_UNIT), 2);
144 assert_eq!(l.get_next(FIRST_UNIT), 2);
145 assert!(l.is_free(FIRST_UNIT));
146 assert!(l.is_coalescable(FIRST_UNIT));
147 assert!(l.is_multi(FIRST_UNIT));
148
149 assert_eq!(l.get_size(2), 2);
150 assert_eq!(l.get_left(2), 0);
151 assert_eq!(l.get_prev(2), 0);
152 assert_eq!(l.get_right(2), 4);
153 assert_eq!(l.get_next(2), 4);
154 assert!(l.is_free(2));
155 assert!(l.is_coalescable(2));
156 assert!(l.is_multi(2));
157
158 assert_eq!(l.get_size(LAST_UNIT), 1);
159 assert_eq!(l.get_left(LAST_UNIT), LAST_UNIT - 2);
160 assert_eq!(l.get_prev(LAST_UNIT), LAST_UNIT - 2);
161 assert_eq!(l.get_right(LAST_UNIT), BOTTOM_SENTINEL);
162 assert_eq!(l.get_next(LAST_UNIT), -1);
163 assert!(l.is_free(LAST_UNIT));
164 assert!(l.is_coalescable(LAST_UNIT));
165 assert!(!l.is_multi(LAST_UNIT));
166
167 assert_eq!(l.get_prev(BOTTOM_SENTINEL), BOTTOM_SENTINEL);
168 assert_eq!(l.get_next(BOTTOM_SENTINEL), BOTTOM_SENTINEL);
169 }
170
171 #[test]
172 #[should_panic]
173 fn free_list_access_out_of_bounds() {
174 let l = IntArrayFreeList::new(LIST_SIZE, 1, 1);
175 l.get_size((LIST_SIZE + 1) as i32);
176 }
177
178 #[test]
179 fn alloc_fit() {
180 let mut l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
181 let result = l.alloc(2);
182 assert_eq!(result, 0);
183
184 const NEXT: i32 = 2;
185
186 assert_eq!(l.get_prev(TOP_SENTINEL), LAST_UNIT);
187 assert_eq!(l.get_next(TOP_SENTINEL), NEXT);
188
189 assert_eq!(l.get_size(FIRST_UNIT), 2);
190 assert_eq!(l.get_left(FIRST_UNIT), -1);
191 assert_eq!(l.get_prev(FIRST_UNIT), -1);
192 assert_eq!(l.get_right(FIRST_UNIT), 2);
193 assert_eq!(l.get_next(FIRST_UNIT), 2);
194 assert!(!l.is_free(FIRST_UNIT)); assert!(l.is_coalescable(FIRST_UNIT));
196 assert!(l.is_multi(FIRST_UNIT));
197
198 assert_eq!(l.get_size(2), 2);
199 assert_eq!(l.get_left(2), 0);
200 assert_eq!(l.get_prev(2), -1); assert_eq!(l.get_right(2), 4);
202 assert_eq!(l.get_next(2), 4);
203 assert!(l.is_free(2));
204 assert!(l.is_coalescable(2));
205 assert!(l.is_multi(2));
206 }
207
208 #[test]
209 #[allow(clippy::cognitive_complexity)] fn alloc_split() {
211 let mut l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
212 let result = l.alloc(1);
213 assert_eq!(result, 0);
214
215 const NEXT: i32 = 1;
216 assert_eq!(l.get_prev(TOP_SENTINEL), LAST_UNIT);
217 assert_eq!(l.get_next(TOP_SENTINEL), NEXT);
218
219 assert_eq!(l.get_size(FIRST_UNIT), 1);
220 assert_eq!(l.get_left(FIRST_UNIT), -1);
221 assert_eq!(l.get_prev(FIRST_UNIT), 1); assert_eq!(l.get_right(FIRST_UNIT), 1); assert_eq!(l.get_next(FIRST_UNIT), 2);
224 assert!(!l.is_free(FIRST_UNIT)); assert!(l.is_coalescable(FIRST_UNIT));
226 assert!(!l.is_multi(FIRST_UNIT)); assert_eq!(l.get_size(1), 1);
229 assert_eq!(l.get_left(1), 0); assert_eq!(l.get_prev(1), -1); assert_eq!(l.get_right(1), 2);
232 assert_eq!(l.get_next(1), 2);
233 assert!(l.is_free(1)); assert!(l.is_coalescable(1));
235 assert!(!l.is_multi(1)); assert_eq!(l.get_size(2), 2);
238 assert_eq!(l.get_left(2), 1);
239 assert_eq!(l.get_prev(2), 1); assert_eq!(l.get_right(2), 4);
241 assert_eq!(l.get_next(2), 4);
242 assert!(l.is_free(2));
243 assert!(l.is_coalescable(2));
244 assert!(l.is_multi(2));
245 }
246
247 #[test]
248 fn alloc_split_twice() {
249 let mut l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
250 let res1 = l.alloc(1);
252 assert_eq!(res1, 0);
253 let res2 = l.alloc(1);
255 assert_eq!(res2, 1);
256
257 assert_eq!(l.get_prev(2), -1);
259 }
260
261 #[test]
262 fn alloc_skip() {
263 let mut l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
264 let res1 = l.alloc(1);
266 assert_eq!(res1, 0);
267 let res2 = l.alloc(2);
269 assert_eq!(res2, 2);
270
271 assert!(l.is_free(1));
273 assert_eq!(l.get_next(1), 4);
274 assert_eq!(l.get_prev(4), 1);
275 }
276
277 #[test]
278 fn alloc_exhaust() {
279 let mut l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
280 let res1 = l.alloc(2);
281 assert_eq!(res1, 0);
282 let res2 = l.alloc(2);
283 assert_eq!(res2, 2);
284 let res3 = l.alloc(2);
285 assert_eq!(res3, FAILURE);
286 }
287
288 #[test]
289 fn free_unit() {
290 let mut l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
291 let res1 = l.alloc(2);
292 assert_eq!(res1, 0);
293 let res2 = l.alloc(2);
294 assert_eq!(res2, 2);
295
296 assert_eq!(l.get_prev(4), -1);
298
299 let freed = l.free(res2, false);
301 assert_eq!(freed, res2);
302 assert!(l.is_free(res2));
303 }
304
305 #[test]
306 fn free_coalesce() {
307 let mut l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
308 let res1 = l.alloc(2);
309 assert_eq!(res1, 0);
310 let res2 = l.alloc(2);
311 assert_eq!(res2, 2);
312
313 let coalesced_size = l.free(res2, true);
315 assert_eq!(coalesced_size, 3);
316 }
317
318 #[test]
319 fn free_cant_coalesce() {
320 let mut l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
321 let res1 = l.alloc(2);
322 assert_eq!(res1, 0);
323 let res2 = l.alloc(2);
324 assert_eq!(res2, 2);
325 let res3 = l.alloc(1);
326 assert_eq!(res3, 4);
327
328 let coalesced_size = l.free(res2, true);
330 assert_eq!(coalesced_size, 2);
331 }
332
333 #[test]
334 fn free_realloc() {
335 let mut l = IntArrayFreeList::new(LIST_SIZE, 2, 1);
336 let res1 = l.alloc(2);
337 assert_eq!(res1, 0);
338 let res2 = l.alloc(2);
339 assert_eq!(res2, 2);
340
341 assert_eq!(l.get_prev(4), -1);
343
344 let freed = l.free(res2, false);
346 assert_eq!(freed, res2);
347 assert!(l.is_free(res2));
348
349 let res3 = l.alloc(2);
351 assert_eq!(res3, 2);
352 assert!(!l.is_free(res3));
353
354 let res4 = l.alloc(1);
355 assert_eq!(res4, 4);
356 }
357
358 #[test]
359 fn multi_heads_alloc_free() {
360 let parent = IntArrayFreeList::new(LIST_SIZE, 1, 2);
361 let mut child1 = IntArrayFreeList::from_parent(&parent, 0);
362 let child2 = IntArrayFreeList::from_parent(&parent, 1);
363
364 let res = child1.alloc(1);
366 assert_eq!(res, 0);
367 assert!(!parent.is_free(0));
368 assert!(!child1.is_free(0));
369 assert!(!child2.is_free(0));
370
371 child1.free(0, false);
373 assert!(parent.is_free(0));
374 assert!(child1.is_free(0));
375 assert!(child2.is_free(0));
376 }
377
378 #[test]
379 #[should_panic]
380 fn multi_heads_exceed_heads() {
381 let parent = IntArrayFreeList::new(LIST_SIZE, 1, 2);
382 let _child1 = IntArrayFreeList::from_parent(&parent, 0);
383 let _child2 = IntArrayFreeList::from_parent(&parent, 1);
384 let _child3 = IntArrayFreeList::from_parent(&parent, 2);
385 }
386}