1use crate::{
2 EntityAllocConsumeIter, EntityAllocEditIter, EntityAllocReadIter, PtrID,
3 bitalloc::IBitAlloc,
4 chunk::Chunk,
5 id::IndexedID,
6 policy::{AllocPolicy256, IAllocPolicy},
7};
8use std::cell::{BorrowMutError, Cell, RefCell};
9
10pub struct EntityAlloc<E, P: IAllocPolicy = AllocPolicy256> {
11 pub(crate) chunks: RefCell<Vec<Chunk<E, P>>>,
12 pub(crate) free_head: Cell<u32>,
13 pub(crate) num_allocated: Cell<usize>,
14}
15
16impl<E, P: IAllocPolicy> AsRef<EntityAlloc<E, P>> for EntityAlloc<E, P> {
17 fn as_ref(&self) -> &EntityAlloc<E, P> {
18 self
19 }
20}
21impl<E, P: IAllocPolicy> AsMut<EntityAlloc<E, P>> for EntityAlloc<E, P> {
22 fn as_mut(&mut self) -> &mut EntityAlloc<E, P> {
23 self
24 }
25}
26
27impl<E, P: IAllocPolicy> EntityAlloc<E, P> {
28 pub fn new() -> Self {
29 Self {
30 chunks: RefCell::new(Vec::new()),
31 free_head: Cell::new(0),
32 num_allocated: Cell::new(0),
33 }
34 }
35 pub fn with_capacity(cap: usize) -> Self {
36 let chunks = {
37 let nchunks = cap.next_multiple_of(P::CHUNK_SIZE) / P::CHUNK_SIZE;
38 let mut chunks = Vec::with_capacity(nchunks);
39 for chunk_id in 0..(nchunks as u32) {
40 let chunk = Chunk::new(chunk_id, chunk_id + 1);
41 chunks.push(chunk);
42 }
43 RefCell::new(chunks)
44 };
45 Self {
46 chunks,
47 free_head: Cell::new(0),
48 num_allocated: Cell::new(0),
49 }
50 }
51 pub fn allocate(&self, val: E) -> PtrID<E, P> {
52 match self.try_allocate(val) {
53 Ok(ptr) => ptr,
54 Err(_) => panic!(
55 "Cannot borrow EntityAlloc:{self:p} mutably for allocation. Are you traversing it now?"
56 ),
57 }
58 }
59 pub fn try_allocate(&self, val: E) -> Result<PtrID<E, P>, (BorrowMutError, E)> {
60 let mut chunks = match self.chunks.try_borrow_mut() {
61 Ok(c) => c,
62 Err(e) => return Err((e, val)),
63 };
64 let chunk = Self::find_chunk(self.free_head.get(), &mut chunks);
65 let Ok((ptr, _)) = chunk.allocate(val) else {
66 panic!("Allocation error!");
67 };
68 self.num_allocated.set(self.num_allocated.get() + 1);
69 if chunk.is_full() {
70 self.free_head.set(chunk.free_next);
71 }
72 Ok(unsafe { PtrID::from_raw_ptr(ptr as *mut _) })
73 }
74 pub fn next_indexed(&self) -> IndexedID<E, P> {
76 let chunks = self.chunks.borrow();
77 let free_head = self.free_head.get() as usize;
78 let Some(chunk) = chunks.get(free_head) else {
79 return IndexedID::from(free_head << P::CHUNK_SIZE_LOG2);
80 };
81 let unit_id = chunk.next_available().unwrap();
82 IndexedID::from(chunk.indexed_id_of_unit(unit_id))
83 }
84 fn find_chunk(free: u32, chunks: &mut Vec<Chunk<E, P>>) -> &mut Chunk<E, P> {
85 let free = free as usize;
86 while chunks.len() <= free {
87 let id = chunks.len() as u32;
88 chunks.push(Chunk::new(id, id + 1));
89 }
90 &mut chunks[free]
91 }
92 pub fn free_indexed(&mut self, indexed: usize) -> Option<E> {
93 let chunks = self.chunks.get_mut();
94 let chunk_id = P::chunk_of_indexed_id(indexed);
95 let unit_id = P::unit_of_indexed_id(indexed);
96 let chunk = chunks.get_mut(chunk_id as usize)?;
97 let chunk_full = chunk.is_full();
98 let e = chunk.deallocate_unit_id(unit_id)?;
99 if chunk_full {
101 chunk.free_next = self.free_head.get();
102 self.free_head.set(chunk_id);
103 }
104 self.num_allocated.set(self.num_allocated.get() - 1);
105 Some(e)
106 }
107 pub fn free_ptr(&mut self, ptr: PtrID<E, P>) -> Option<E> {
108 let indexed = ptr.get_index(self)?;
109 self.free_indexed(indexed)
110 }
111
112 pub fn remake_free_chain(&mut self) {
113 let chunks = self.chunks.get_mut();
114 let free_chunks = {
115 let mut free_chunks = Vec::with_capacity(chunks.len());
116 for chunk in chunks.iter_mut() {
117 if !chunk.is_full() {
118 free_chunks.push(chunk.chunk_id);
119 }
120 }
121 free_chunks
122 };
123 for i in 1..free_chunks.len() {
124 let chunk_id = free_chunks[i - 1];
125 let next_chunk_id = free_chunks[i];
126 let chunk = &mut chunks[chunk_id as usize];
127 chunk.free_next = next_chunk_id;
128 }
129 if let Some(&chunk_id) = free_chunks.first() {
130 self.free_head.set(chunk_id);
131 } else {
132 self.free_head.set(chunks.len() as u32);
133 }
134 }
135}
136
137impl<E, P: IAllocPolicy> EntityAlloc<E, P> {
138 pub fn free_if(&mut self, pred: impl FnMut(&E, PtrID<E, P>, IndexedID<E, P>) -> bool) {
139 self.fully_free_if(pred, drop);
140 }
141 pub fn fully_free_if(
142 &mut self,
143 mut should_free: impl FnMut(&E, PtrID<E, P>, IndexedID<E, P>) -> bool,
144 mut consume: impl FnMut(E),
145 ) {
146 let chunks = self.chunks.get_mut();
147 let mut num_last = self.num_allocated.get();
148 for chunk in chunks.iter_mut() {
149 if chunk.is_empty() {
150 continue;
151 }
152 if num_last == 0 {
153 break;
154 }
155 let chunk_full_previously = chunk.is_full();
156 let chunk_num_allocated = chunk.num_allocated as usize;
157 let num_freed = if chunk_num_allocated * 3 >= P::CHUNK_SIZE {
158 Self::densely_free_chunk(&mut should_free, &mut consume, chunk)
159 } else {
160 Self::sparsely_free_chunk(&mut should_free, &mut consume, chunk)
161 };
162
163 num_last -= chunk_num_allocated;
164 if num_freed > 0 {
166 self.num_allocated
167 .set(self.num_allocated.get().saturating_sub(num_freed));
168 }
169 if chunk_full_previously && !chunk.is_full() {
171 chunk.free_next = self.free_head.get();
172 self.free_head.set(chunk.chunk_id);
173 }
174 }
175 }
176
177 fn densely_free_chunk(
178 should_free: &mut impl FnMut(&E, PtrID<E, P>, IndexedID<E, P>) -> bool,
179 consume: &mut impl FnMut(E),
180 chunk: &mut Chunk<E, P>,
181 ) -> usize {
182 let mut num_freed = 0;
183 let mut count_down = chunk.num_allocated;
184 for unit_id in 0..(P::CHUNK_SIZE as u16) {
185 if count_down == 0 {
186 break;
187 }
188 let index = chunk.indexed_id_of_unit(unit_id);
189 if !chunk.allocated.is_allocated(unit_id) {
190 continue;
191 }
192 count_down -= 1;
193
194 let unit = chunk.unit(unit_id);
195 let ptr: PtrID<E, P> = PtrID::from_ref(unit);
196 let elem = unit.as_init_ref().unwrap();
197 if !should_free(elem, ptr, IndexedID::from(index)) {
198 continue;
199 }
200 let Some(e) = chunk.deallocate_unit_id(unit_id) else {
201 unreachable!("Deallocation failed unexpectedly");
202 };
203 consume(e);
204 num_freed += 1;
205 }
206 num_freed
207 }
208 fn sparsely_free_chunk(
209 should_free: &mut impl FnMut(&E, PtrID<E, P>, IndexedID<E, P>) -> bool,
210 consume: &mut impl FnMut(E),
211 chunk: &mut Chunk<E, P>,
212 ) -> usize {
213 let mut num_freed = 0usize;
215 let mut next = chunk.allocated.next_allocated(0);
216 while let Some(unit_id) = next {
217 let index = chunk.indexed_id_of_unit(unit_id);
218 let unit = chunk.unit(unit_id);
219 let ptr: PtrID<E, P> = PtrID::from_ref(unit);
220 let elem = unit.as_init_ref().unwrap();
221 if should_free(elem, ptr, IndexedID::from(index)) {
222 if let Some(e) = chunk.deallocate_unit_id(unit_id) {
223 consume(e);
224 num_freed += 1;
225 } else {
226 unreachable!("Deallocation failed unexpectedly");
227 }
228 let next_start = unit_id.saturating_add(1);
230 next = chunk.allocated.next_allocated(next_start);
231 } else {
232 let next_start = unit_id.saturating_add(1);
234 next = chunk.allocated.next_allocated(next_start);
235 }
236 }
237 num_freed
238 }
239
240 #[inline]
241 pub fn len(&self) -> usize {
242 self.num_allocated.get()
243 }
244 #[inline]
245 pub fn capacity(&self) -> usize {
246 self.chunks.borrow().len() * P::CHUNK_SIZE
247 }
248 #[inline]
249 pub fn is_empty(&self) -> bool {
250 self.len() == 0
251 }
252
253 pub fn clear(&mut self) {
254 self.chunks.get_mut().clear();
255 self.free_head.set(0);
256 self.num_allocated.set(0);
257 }
258
259 #[inline]
260 pub fn iter(&self) -> EntityAllocReadIter<'_, E, P> {
261 EntityAllocReadIter::new(self)
262 }
263 #[inline]
264 pub fn iter_mut(&mut self) -> EntityAllocEditIter<'_, E, P> {
265 EntityAllocEditIter::new(self)
266 }
267}
268
269impl<'alloc, E, P: IAllocPolicy> IntoIterator for &'alloc EntityAlloc<E, P> {
270 type Item = (usize, PtrID<E, P>, &'alloc E);
271 type IntoIter = EntityAllocReadIter<'alloc, E, P>;
272
273 fn into_iter(self) -> Self::IntoIter {
274 self.iter()
275 }
276}
277impl<'alloc, E, P: IAllocPolicy> IntoIterator for &'alloc mut EntityAlloc<E, P> {
278 type Item = (usize, PtrID<E, P>, &'alloc mut E);
279 type IntoIter = EntityAllocEditIter<'alloc, E, P>;
280
281 fn into_iter(self) -> Self::IntoIter {
282 self.iter_mut()
283 }
284}
285impl<E, P: IAllocPolicy> IntoIterator for EntityAlloc<E, P> {
286 type Item = (usize, E);
287 type IntoIter = EntityAllocConsumeIter<E, P>;
288
289 fn into_iter(self) -> Self::IntoIter {
290 EntityAllocConsumeIter::new(self)
291 }
292}