1use crate::{
2 EntityAllocConsumeIter, EntityAllocEditIter, EntityAllocReadIter, IEntityAllocPolicy,
3 IndexedID, PtrID,
4 chunk::{Chunk, NULL_INDEXED_ID},
5 iter::EntitySlotIter,
6};
7use std::{
8 cell::{BorrowMutError, Cell, RefCell},
9 marker::PhantomData,
10 ptr::NonNull,
11};
12
13pub trait IEntityAllocatable: Sized {
14 type AllocatePolicyT: IEntityAllocPolicy<Self>;
16
17 type PtrID: Copy + Eq + From<PtrID<Self>> + Into<PtrID<Self>>;
21
22 const CHUNK_SIZE: usize = Self::AllocatePolicyT::CHUNK_SIZE;
23 const BITSET_LEN: usize = Self::AllocatePolicyT::BITSET_LEN;
24
25 fn compose_indexed_id(chunk_id: u32, unit_id: u16) -> usize {
26 Self::AllocatePolicyT::compose_indexed_id(chunk_id, unit_id)
27 }
28 fn split_indexed_id(indexed_id: usize) -> (u32, u16) {
29 Self::AllocatePolicyT::split_indexed_id(indexed_id)
30 }
31 fn unit_of_indexed_id(indexed_id: usize) -> u16 {
32 Self::AllocatePolicyT::unit_of_indexed_id(indexed_id)
33 }
34 fn chunk_of_indexed_id(indexed_id: usize) -> u32 {
35 Self::AllocatePolicyT::chunk_of_indexed_id(indexed_id)
36 }
37
38 fn ptr_of_id(id: Self::PtrID) -> PtrID<Self> {
39 id.into()
40 }
41 fn id_of_ptr(ptr: PtrID<Self>) -> Self::PtrID {
42 Self::PtrID::from(ptr)
43 }
44}
45
46pub struct EntityAlloc<E: IEntityAllocatable> {
47 pub(crate) chunks: RefCell<Vec<Chunk<E, E::AllocatePolicyT>>>,
48 pub(crate) free_head: Cell<u32>,
49 pub(crate) num_allocated: Cell<usize>,
50}
51
52impl<'alloc, E: IEntityAllocatable> IntoIterator for &'alloc EntityAlloc<E> {
53 type Item = (usize, E::PtrID, &'alloc E);
54 type IntoIter = EntityAllocReadIter<'alloc, E>;
55
56 #[inline]
57 fn into_iter(self) -> Self::IntoIter {
58 EntityAllocReadIter::new(self)
59 }
60}
61impl<'alloc, E: IEntityAllocatable> IntoIterator for &'alloc mut EntityAlloc<E> {
62 type Item = (usize, E::PtrID, &'alloc mut E);
63 type IntoIter = EntityAllocEditIter<'alloc, E>;
64
65 #[inline]
66 fn into_iter(self) -> Self::IntoIter {
67 EntityAllocEditIter::new(self)
68 }
69}
70impl<E: IEntityAllocatable> IntoIterator for EntityAlloc<E> {
71 type Item = (usize, E);
72 type IntoIter = EntityAllocConsumeIter<E>;
73
74 #[inline]
75 fn into_iter(self) -> Self::IntoIter {
76 EntityAllocConsumeIter::new(self)
77 }
78}
79
80impl<E: IEntityAllocatable> EntityAlloc<E> {
81 pub fn new() -> Self {
82 Self {
83 chunks: RefCell::new(Vec::new()),
84 free_head: Cell::new(0),
85 num_allocated: Cell::new(0),
86 }
87 }
88
89 pub fn with_capacity(cap: usize) -> Self {
90 let cap = cap.next_multiple_of(E::AllocatePolicyT::CHUNK_SIZE);
91 let chunks = {
92 let nchunks = cap / E::AllocatePolicyT::CHUNK_SIZE;
93 let mut chunks = Vec::with_capacity(nchunks);
94 for chunk_id in 0..(nchunks as u32) {
95 let chunk = Chunk::new(chunk_id, chunk_id + 1);
96 chunks.push(chunk);
97 }
98 RefCell::new(chunks)
99 };
100 Self {
101 chunks,
102 free_head: Cell::new(0),
103 num_allocated: Cell::new(0),
104 }
105 }
106
107 pub fn allocate(&self, val: E) -> PtrID<E> {
108 let Ok(ptr) = self.try_allocate(val) else {
109 panic!(
110 "Cannot borrow EntityAlloc {self:p} mutably for allocation. Are you traversing it now?"
111 );
112 };
113 ptr
114 }
115 pub fn try_allocate(&self, val: E) -> Result<PtrID<E>, (BorrowMutError, E)> {
116 let mut chunks = match self.chunks.try_borrow_mut() {
117 Ok(c) => c,
118 Err(e) => return Err((e, val)),
119 };
120 let chunk = Self::find_chunk(self.free_head.get(), &mut chunks);
121 let Ok((ptr, _)) = chunk.allocate(val) else {
122 panic!("Allocation error!");
123 };
124 self.num_allocated.set(self.num_allocated.get() + 1);
125 if chunk.is_full() {
126 self.free_head.set(chunk.free_next);
127 }
128 Ok(PtrID(NonNull::new(ptr as *mut _).unwrap()))
129 }
130 pub fn next_indexed(&self) -> IndexedID<E> {
132 let chunks = self.chunks.borrow();
133 let free_head = self.free_head.get() as usize;
134 let Some(chunk) = chunks.get(free_head) else {
135 return IndexedID(
136 free_head << E::AllocatePolicyT::CHUNK_SIZE_LOG2,
137 PhantomData,
138 );
139 };
140 let unit_id = chunk.next_available().unwrap();
141 IndexedID(chunk.indexed_id_of_unit(unit_id), PhantomData)
142 }
143 fn find_chunk(
144 free: u32,
145 chunks: &mut Vec<Chunk<E, E::AllocatePolicyT>>,
146 ) -> &mut Chunk<E, E::AllocatePolicyT> {
147 let free = free as usize;
148 while chunks.len() <= free {
149 let id = chunks.len() as u32;
150 chunks.push(Chunk::new(id, id + 1));
151 }
152 &mut chunks[free]
153 }
154
155 pub fn free_indexed(&mut self, indexed: usize) -> Option<E> {
156 let chunks = self.chunks.get_mut();
157 let chunk_id = E::chunk_of_indexed_id(indexed);
158 let unit_id = E::unit_of_indexed_id(indexed);
159 let chunk = chunks.get_mut(chunk_id as usize)?;
160 let chunk_full = chunk.is_full();
161 let e = chunk.deallocate_unit_id(unit_id)?;
162 if chunk_full {
164 chunk.free_next = self.free_head.get();
165 self.free_head.set(chunk_id);
166 }
167 self.num_allocated.set(self.num_allocated.get() - 1);
168 Some(e)
169 }
170 pub fn free_ptr(&mut self, ptr: PtrID<E>) -> Option<E> {
171 if cfg!(debug_assertions) && !ptr.check_validity(self.chunks.get_mut()) {
172 return None;
173 }
174 let indexed = unsafe { ptr.direct_get_indexed() };
175 if indexed == NULL_INDEXED_ID {
176 return None;
177 }
178 self.free_indexed(indexed)
179 }
180 pub fn free_if(&mut self, pred: impl Fn(&E, PtrID<E>, IndexedID<E>) -> bool) {
181 self.fully_free_if(pred, drop);
182 }
183 pub fn fully_free_if(
184 &mut self,
185 pred: impl Fn(&E, PtrID<E>, IndexedID<E>) -> bool,
186 mut consume: impl FnMut(E),
187 ) {
188 let mut num_allocated_dec = self.num_allocated.get();
189 let mut num_allocated_inc = 0;
190 for slot in EntitySlotIter::new(self) {
191 let (ptr, indexed_id) = unsafe { slot.copy_release_all() };
192 if pred(slot.get().unwrap(), ptr, indexed_id) {
193 let elem = unsafe { slot.raw_free() };
194 let Some(elem) = elem else {
195 continue;
196 };
197 consume(elem);
198 num_allocated_dec -= 1;
199 } else {
200 num_allocated_inc += 1;
201 }
202 }
203 assert_eq!(
204 num_allocated_dec, num_allocated_inc,
205 "Length maintenance error in fully_free_if"
206 );
207 self.num_allocated.set(num_allocated_dec);
208 }
209
210 #[inline]
211 pub fn len(&self) -> usize {
212 self.num_allocated.get()
213 }
214 #[inline]
215 pub fn capacity(&self) -> usize {
216 self.chunks.borrow().len() * E::AllocatePolicyT::CHUNK_SIZE
217 }
218 #[inline]
219 pub fn is_empty(&self) -> bool {
220 self.len() == 0
221 }
222
223 pub fn clear(&mut self) {
224 self.chunks.get_mut().clear();
225 self.free_head.set(0);
226 self.num_allocated.set(0);
227 }
228
229 #[inline]
230 pub fn iter(&self) -> EntityAllocReadIter<'_, E> {
231 EntityAllocReadIter::new(self)
232 }
233 #[inline]
234 pub fn iter_mut(&mut self) -> EntityAllocEditIter<'_, E> {
235 EntityAllocEditIter::new(self)
236 }
237}