Skip to main content

EntityAlloc

Struct EntityAlloc 

Source
pub struct EntityAlloc<E, P: IAllocPolicy = AllocPolicy256> { /* private fields */ }
Expand description

Entity slab allocator for entities of type E using allocation policy P.

This allocator maintains a growable vector of fixed-size Chunk<E, P> slabs. Each Chunk stores up to P::CHUNK_SIZE units and keeps per-unit generation indices plus a bitset of allocated slots. EntityAlloc provides fast allocation/deallocation inside chunks, keeps a free-chain of chunks that have available slots (free_head), and tracks the total number of allocated entities (num_allocated).

Primary responsibilities and guarantees:

  • Allocate and deallocate entities with O(1) operations inside a chunk; the allocator grows by creating new Chunks when needed.
  • Maintain a free_head pointing to a chunk with available slots to avoid scanning all chunks on each allocation.
  • Expose helper methods that return either raw unit pointers or generation- aware indexes (GenIndex). Callers must respect generation checks to avoid use-after-free; the allocator provides checks in unit_ptr_of_indexed and related helpers.

Concurrency and safety notes:

  • EntityAlloc uses interior mutability (RefCell and Cell) and is not Sync; external synchronization is required for concurrent access.
  • Several pub(crate) functions operate on raw pointers and rely on invariants (generation matching, non-null indexed values). Use the public crate APIs where possible; internal functions are optimized for performance and assume correct usage.

Field overview:

  • chunks: RefCell<Vec<Chunk<E, P>>> — growable storage of slab chunks.
  • free_head: Cell<u32> — index of the first chunk with free slots (or a sentinel when none available).
  • num_allocated: Cell<usize> — current count of allocated entities.

Usage tips:

  • Use remake_free_chain to rebuild the free-chain after bulk mutations.
  • Prefer free_if / fully_free_if for conditional freeing, they maintain allocator invariants and update num_allocated correctly.
  • Be careful when converting between raw unit pointers and GenIndex — always handle EntityAccessErr and SlicePtrErr reported by the helpers.

实体分配器详述(中文):

  • 管理一组可增长的 Chunk<E, P>,每个 Chunk 包含固定大小的单元、位图和 generation 信息,用于检测 use-after-free。
  • 在 chunk 内部的分配与释放为 O(1);当现有 chunk 全满时通过新增 chunk 增长容量。
  • 维护 free_head 指向含有空闲单元的 chunk,以加速分配。
  • num_allocated 跟踪当前分配数量;remake_free_chain 可在批量修改后重建空闲链表。
  • 结构体使用 RefCell/Cell 实现内部可变性,默认不安全以跨线程共享,若需要 并发访问请自行加锁或在上层保证互斥。

示例:

// 参见 crate 文档中的示例,通常通过 crate 提供的安全 API 分配/访问/释放实体。

Implementations§

Source§

impl<E, P: IAllocPolicy> EntityAlloc<E, P>

Source

pub fn new() -> Self

Create a new EntityAlloc with no preallocated capacity.

Source

pub fn with_capacity(cap: usize) -> Self

Create a new EntityAlloc with preallocated capacity for cap entities.

Source

pub fn remake_free_chain(&mut self)

Rebuild the free-chain of chunks with available slots.

Source§

impl<E, P: IAllocPolicy> EntityAlloc<E, P>

Source

pub fn free_if( &mut self, pred: impl FnMut(&E, PtrID<E, P>, IndexedID<E, P>) -> bool, )

Free entities that satisfy the given predicate.

Source

pub fn fully_free_if( &mut self, should_free: impl FnMut(&E, PtrID<E, P>, IndexedID<E, P>) -> bool, consume: impl FnMut(E), )

Free entities that satisfy the given predicate, consuming them with the provided closure.

This method automatically chooses between dense and sparse freeing strategies based on the chunk’s allocation density for efficiency.

Source

pub fn len(&self) -> usize

Get the number of currently allocated entities.

Note that this is not the length of the internal chunk vector or the “allocated” sections in chunks, but the actual count of live entities.

Source

pub fn capacity(&self) -> usize

Get the current capacity in terms of number of entities.

Source

pub fn is_empty(&self) -> bool

Check if there are no allocated entities.

Source

pub fn clear(&mut self)

Clear all allocated entities, resetting the allocator to an empty state.

Source

pub fn iter(&self) -> EntityAllocReadIter<'_, E, P>

Get an iterator over allocated entities for read-only access.

The iterator yields tuples of (IndexedID, PtrID, &E).

Source

pub fn iter_mut(&mut self) -> EntityAllocEditIter<'_, E, P>

Get an iterator over allocated entities for mutable access.

The iterator yields tuples of (IndexedID, PtrID, &mut E).

Trait Implementations§

Source§

impl<E, P: IAllocPolicy> Default for EntityAlloc<E, P>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'alloc, E, P: IAllocPolicy> IntoIterator for &'alloc EntityAlloc<E, P>

Source§

type Item = (IndexedID<E, P>, PtrID<E, P>, &'alloc E)

The type of the elements being iterated over.
Source§

type IntoIter = EntityAllocReadIter<'alloc, E, P>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<'alloc, E, P: IAllocPolicy> IntoIterator for &'alloc mut EntityAlloc<E, P>

Source§

type Item = (IndexedID<E, P>, PtrID<E, P>, &'alloc mut E)

The type of the elements being iterated over.
Source§

type IntoIter = EntityAllocEditIter<'alloc, E, P>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<E, P: IAllocPolicy> IntoIterator for EntityAlloc<E, P>

Source§

type Item = (GenIndex, E)

The type of the elements being iterated over.
Source§

type IntoIter = EntityAllocConsumeIter<E, P>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more

Auto Trait Implementations§

§

impl<E, P = AllocPolicy256> !Freeze for EntityAlloc<E, P>

§

impl<E, P = AllocPolicy256> !RefUnwindSafe for EntityAlloc<E, P>

§

impl<E, P> Send for EntityAlloc<E, P>
where <P as IAllocPolicy>::BitAlloc: Send, <P as IAllocPolicy>::Units<E>: Send,

§

impl<E, P = AllocPolicy256> !Sync for EntityAlloc<E, P>

§

impl<E, P> Unpin for EntityAlloc<E, P>
where <P as IAllocPolicy>::BitAlloc: Unpin,

§

impl<E, P> UnwindSafe for EntityAlloc<E, P>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.