oxihuman_core/
slab_allocator.rs1#![allow(dead_code)]
3
4#[allow(dead_code)]
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub struct SlabKey {
10 index: u32,
11 generation: u32,
12}
13
14#[allow(dead_code)]
15impl SlabKey {
16 pub fn index(&self) -> u32 {
17 self.index
18 }
19 pub fn generation(&self) -> u32 {
20 self.generation
21 }
22}
23
24#[allow(dead_code)]
25#[derive(Debug)]
26enum SlabEntry<T> {
27 Occupied {
28 value: T,
29 generation: u32,
30 },
31 Vacant {
32 next_free: Option<u32>,
33 generation: u32,
34 },
35}
36
37#[allow(dead_code)]
39#[derive(Debug)]
40pub struct SlabAllocator<T> {
41 entries: Vec<SlabEntry<T>>,
42 free_head: Option<u32>,
43 count: usize,
44}
45
46#[allow(dead_code)]
47impl<T> SlabAllocator<T> {
48 pub fn new() -> Self {
49 Self {
50 entries: Vec::new(),
51 free_head: None,
52 count: 0,
53 }
54 }
55
56 pub fn with_capacity(cap: usize) -> Self {
57 Self {
58 entries: Vec::with_capacity(cap),
59 free_head: None,
60 count: 0,
61 }
62 }
63
64 pub fn insert(&mut self, value: T) -> SlabKey {
65 self.count += 1;
66 if let Some(idx) = self.free_head {
67 let i = idx as usize;
68 match &self.entries[i] {
69 SlabEntry::Vacant {
70 next_free,
71 generation,
72 } => {
73 let gen = *generation + 1;
74 let nf = *next_free;
75 self.entries[i] = SlabEntry::Occupied {
76 value,
77 generation: gen,
78 };
79 self.free_head = nf;
80 SlabKey {
81 index: idx,
82 generation: gen,
83 }
84 }
85 _ => unreachable!(),
86 }
87 } else {
88 let idx = self.entries.len() as u32;
89 self.entries.push(SlabEntry::Occupied {
90 value,
91 generation: 1,
92 });
93 SlabKey {
94 index: idx,
95 generation: 1,
96 }
97 }
98 }
99
100 pub fn remove(&mut self, key: SlabKey) -> Option<T> {
101 let i = key.index as usize;
102 if i >= self.entries.len() {
103 return None;
104 }
105 match &self.entries[i] {
106 SlabEntry::Occupied { generation, .. } if *generation == key.generation => {
107 let gen = *generation;
108 let old = std::mem::replace(
109 &mut self.entries[i],
110 SlabEntry::Vacant {
111 next_free: self.free_head,
112 generation: gen,
113 },
114 );
115 self.free_head = Some(key.index);
116 self.count -= 1;
117 match old {
118 SlabEntry::Occupied { value, .. } => Some(value),
119 _ => unreachable!(),
120 }
121 }
122 _ => None,
123 }
124 }
125
126 pub fn get(&self, key: SlabKey) -> Option<&T> {
127 match self.entries.get(key.index as usize)? {
128 SlabEntry::Occupied { value, generation } if *generation == key.generation => {
129 Some(value)
130 }
131 _ => None,
132 }
133 }
134
135 pub fn get_mut(&mut self, key: SlabKey) -> Option<&mut T> {
136 match self.entries.get_mut(key.index as usize)? {
137 SlabEntry::Occupied { value, generation } if *generation == key.generation => {
138 Some(value)
139 }
140 _ => None,
141 }
142 }
143
144 pub fn contains(&self, key: SlabKey) -> bool {
145 self.get(key).is_some()
146 }
147
148 pub fn len(&self) -> usize {
149 self.count
150 }
151 pub fn is_empty(&self) -> bool {
152 self.count == 0
153 }
154 pub fn capacity(&self) -> usize {
155 self.entries.len()
156 }
157}
158
159impl<T> Default for SlabAllocator<T> {
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn test_insert_get() {
171 let mut slab = SlabAllocator::new();
172 let k = slab.insert(42);
173 assert_eq!(slab.get(k), Some(&42));
174 }
175
176 #[test]
177 fn test_remove() {
178 let mut slab = SlabAllocator::new();
179 let k = slab.insert(10);
180 assert_eq!(slab.remove(k), Some(10));
181 assert_eq!(slab.get(k), None);
182 }
183
184 #[test]
185 fn test_generation() {
186 let mut slab = SlabAllocator::new();
187 let k1 = slab.insert(1);
188 slab.remove(k1);
189 let k2 = slab.insert(2);
190 assert_eq!(slab.get(k1), None);
191 assert_eq!(slab.get(k2), Some(&2));
192 assert_eq!(k1.index(), k2.index()); }
194
195 #[test]
196 fn test_multiple() {
197 let mut slab = SlabAllocator::new();
198 let a = slab.insert("a");
199 let b = slab.insert("b");
200 let c = slab.insert("c");
201 assert_eq!(slab.len(), 3);
202 slab.remove(b);
203 assert_eq!(slab.len(), 2);
204 assert!(!slab.contains(b));
205 assert!(slab.contains(a));
206 assert!(slab.contains(c));
207 }
208
209 #[test]
210 fn test_get_mut() {
211 let mut slab = SlabAllocator::new();
212 let k = slab.insert(100);
213 *slab.get_mut(k).expect("should succeed") = 200;
214 assert_eq!(slab.get(k), Some(&200));
215 }
216
217 #[test]
218 fn test_empty() {
219 let slab: SlabAllocator<i32> = SlabAllocator::new();
220 assert!(slab.is_empty());
221 }
222
223 #[test]
224 fn test_remove_invalid() {
225 let mut slab: SlabAllocator<i32> = SlabAllocator::new();
226 let fake = SlabKey {
227 index: 99,
228 generation: 1,
229 };
230 assert_eq!(slab.remove(fake), None);
231 }
232
233 #[test]
234 fn test_capacity() {
235 let mut slab = SlabAllocator::new();
236 slab.insert(1);
237 slab.insert(2);
238 assert_eq!(slab.capacity(), 2);
239 }
240
241 #[test]
242 fn test_reuse_chain() {
243 let mut slab = SlabAllocator::new();
244 let a = slab.insert(1);
245 let b = slab.insert(2);
246 slab.remove(a);
247 slab.remove(b);
248 let c = slab.insert(3);
249 let d = slab.insert(4);
250 assert_eq!(slab.len(), 2);
251 assert!(slab.contains(c));
252 assert!(slab.contains(d));
253 }
254
255 #[test]
256 fn test_with_capacity() {
257 let slab: SlabAllocator<i32> = SlabAllocator::with_capacity(100);
258 assert!(slab.is_empty());
259 }
260}