playit_agent_core/utils/
id_slab.rs1use std::{mem::{ManuallyDrop, MaybeUninit}, u32};
2
3pub struct IdSlab<T> {
4 entries: Vec<Entry<T>>,
5 free_slots: Vec<usize>,
6}
7
8struct Entry<T> {
9 id: u64,
10 value: MaybeUninit<T>,
11}
12
13pub struct IdSlabVacantEntry<'a, T> {
14 slab: &'a mut IdSlab<T>,
15 id: u64,
16 slot: usize,
17}
18
19const EMPTY_BIT: u64 = 1u64 << 63;
20const EMPTY_BIT_NEG: u64 = !EMPTY_BIT;
21const USE_NUM: u64 = (u32::MAX as u64) + 1;
22const SLOT_MASK: u64 = 0x00000000FFFFFFFF;
23
24impl<T> IdSlab<T> {
25 pub fn with_capacity(capacity: usize) -> Self {
26 let mut slab = IdSlab {
27 entries: Vec::with_capacity(capacity),
28 free_slots: Vec::with_capacity(capacity),
29 };
30
31 for pos in 0..capacity {
32 slab.entries.push(Entry {
33 id: EMPTY_BIT | (pos as u64),
34 value: MaybeUninit::uninit(),
35 });
36
37 slab.free_slots.push(capacity - (pos + 1));
38 }
39
40 slab
41 }
42
43 pub fn capacity(&self) -> usize {
44 self.entries.len()
45 }
46
47 pub fn len(&self) -> usize {
48 self.entries.len() - self.free_slots.len()
49 }
50
51 pub fn available(&self) -> usize {
52 self.free_slots.len()
53 }
54
55 pub fn get(&self, id: u64) -> Option<&T> {
56 let slot = self.slot(id)?;
57
58 let entry = &self.entries[slot];
59 if (entry.id & EMPTY_BIT) == EMPTY_BIT {
60 return None;
61 }
62
63 unsafe { Some(entry.value.assume_init_ref()) }
64 }
65
66 pub fn get_mut(&mut self, id: u64) -> Option<&mut T> {
67 let slot = self.slot(id)?;
68
69 let entry = &mut self.entries[slot];
70 if (entry.id & EMPTY_BIT) == EMPTY_BIT {
71 return None;
72 }
73
74 unsafe { Some(entry.value.assume_init_mut()) }
75 }
76
77 pub fn remove(&mut self, id: u64) -> Option<T> {
78 let slot = self.slot(id)?;
79
80 let entry = &mut self.entries[slot];
81 if (entry.id & EMPTY_BIT) == EMPTY_BIT {
82 return None;
83 }
84
85 entry.id = EMPTY_BIT | (entry.id + USE_NUM);
86 assert_eq!(entry.id & EMPTY_BIT, EMPTY_BIT);
87
88 self.free_slots.push(slot);
89
90 Some(unsafe {
91 std::mem::replace(&mut entry.value, MaybeUninit::uninit()).assume_init()
92 })
93 }
94
95 fn slot(&self, id: u64) -> Option<usize> {
96 let slot = (id & SLOT_MASK) as usize;
97 if self.entries.len() <= slot {
98 return None;
99 }
100 Some(slot)
101 }
102
103 pub fn insert(&mut self, value: T) -> Result<u64, T> {
104 let slot = match self.free_slots.pop() {
105 Some(v) => v,
106 None => return Err(value),
107 };
108
109 let entry = &mut self.entries[slot];
110 assert!((entry.id & EMPTY_BIT) == EMPTY_BIT);
111
112 entry.id = EMPTY_BIT_NEG & entry.id;
113 assert!((entry.id & EMPTY_BIT) == 0);
114
115 entry.value.write(value);
116 Ok(entry.id)
117 }
118
119 pub fn vacant_entry(&mut self) -> Option<IdSlabVacantEntry<T>> {
120 let slot = self.free_slots.pop()?;
121 let id = self.entries[slot].id & EMPTY_BIT_NEG;
122
123 Some(IdSlabVacantEntry {
124 slab: self,
125 id,
126 slot,
127 })
128 }
129
130 pub fn iter(&self) -> IdSlabIter<T> {
131 IdSlabIter {
132 slab: self,
133 slot: 0,
134 remaining: self.len(),
135 }
136 }
137
138 pub fn iter_mut(&mut self) -> IdSlabIterMut<T> {
139 let remaining = self.len();
140 IdSlabIterMut { slab: self, slot: 0, remaining }
141 }
142}
143
144impl<'a, T> IdSlabVacantEntry<'a, T> {
145 pub fn id(&self) -> u64 {
146 self.id
147 }
148
149 pub fn insert(self, value: T) -> u64 {
150 let entry = &mut self.slab.entries[self.slot];
151 assert!(entry.id & EMPTY_BIT == EMPTY_BIT);
152
153 let id = EMPTY_BIT_NEG & entry.id;
154 assert!((id & EMPTY_BIT) == 0);
155
156 entry.id = id;
157 entry.value.write(value);
158
159 let _ = ManuallyDrop::new(self);
160 id
161 }
162}
163
164impl<'a, T> Drop for IdSlabVacantEntry<'a, T> {
165 fn drop(&mut self) {
166 self.slab.free_slots.push(self.slot);
167 }
168}
169
170pub struct IdSlabIter<'a, T> {
171 slab: &'a IdSlab<T>,
172 slot: usize,
173 remaining: usize,
174}
175
176impl<'a, T> Iterator for IdSlabIter<'a, T> {
177 type Item = &'a T;
178
179 fn next(&mut self) -> Option<Self::Item> {
180 while self.slot < self.slab.entries.len() && self.remaining > 0 {
181 let entry = &self.slab.entries[self.slot];
182 self.slot += 1;
183
184 if (entry.id & EMPTY_BIT) == EMPTY_BIT {
185 continue;
186 }
187
188 self.remaining -= 1;
189 return Some(unsafe { entry.value.assume_init_ref() });
190 }
191
192 None
193 }
194}
195
196pub struct IdSlabIterMut<'a, T> {
197 slab: &'a mut IdSlab<T>,
198 slot: usize,
199 remaining: usize,
200}
201
202impl<'a, T> Iterator for IdSlabIterMut<'a, T> {
203 type Item = &'a mut T;
204
205 fn next(&mut self) -> Option<Self::Item> {
206 let len = self.slab.entries.len();
207
208 while self.slot < len && self.remaining > 0 {
209 let entry = &mut self.slab.entries[self.slot];
210 self.slot += 1;
211
212 if (entry.id & EMPTY_BIT) == EMPTY_BIT {
213 continue;
214 }
215
216 self.remaining -= 1;
217 return Some(unsafe { std::mem::transmute(entry.value.assume_init_mut()) });
218 }
219
220 None
221 }
222}
223
224#[cfg(test)]
225mod test {
226 use std::collections::HashSet;
227
228 use rand::{seq::SliceRandom, thread_rng};
229
230 use super::IdSlab;
231
232 #[test]
233 fn test() {
234 let mut slab = IdSlab::<String>::with_capacity(16);
235 let world_id = slab.insert("hello world".to_string()).unwrap();
236
237 let mut old_ids = HashSet::new();
238 let mut ids = Vec::new();
239
240 for i in 0..100 {
241 for j in 0..8 {
242 let entry = slab.vacant_entry().unwrap();
243 assert!(old_ids.insert(entry.id()));
244
245 ids.push(entry.insert(format!("{} - {}", i, j)));
246 assert_eq!(slab.len(), ids.len() + 1);
247 }
248
249 ids.shuffle(&mut thread_rng());
250 while 7 < ids.len() {
251 let id = ids.pop().unwrap();
252
253 slab.remove(id).unwrap();
254 assert_eq!(slab.len(), ids.len() + 1);
255 }
256 }
257
258 assert_eq!(slab.get(world_id).unwrap(), "hello world");
259 for id in ids {
260 slab.remove(id).unwrap();
261 }
262 }
263}