mtb_entity_slab/
alloc.rs

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    /// Every allocatable item should define an allocation policy type.
15    type AllocatePolicyT: IEntityAllocPolicy<Self>;
16
17    /// Pointer ID type used by this allocatable item.
18    /// Normally you can put `PtrID<Self>` here. While you have special needs,
19    /// you can define your own pointer ID structure and hide the `PtrID` inside ir.
20    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    /// 下一次分配时, 返回下一个可用的索引
131    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        // 如果之前是满的,现在有空位了,加入空闲链表
163        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}