mod map_entities;
pub use map_entities::*;
use crate::{archetype::ArchetypeId, storage::SparseSetIndex};
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, fmt, mem, sync::atomic::Ordering};
#[cfg(target_has_atomic = "64")]
use std::sync::atomic::AtomicI64 as AtomicIdCursor;
#[cfg(target_has_atomic = "64")]
type IdCursor = i64;
#[cfg(not(target_has_atomic = "64"))]
use std::sync::atomic::AtomicIsize as AtomicIdCursor;
#[cfg(not(target_has_atomic = "64"))]
type IdCursor = isize;
#[derive(Clone, Copy, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Entity {
pub(crate) generation: u32,
pub(crate) index: u32,
}
pub enum AllocAtWithoutReplacement {
Exists(EntityLocation),
DidNotExist,
ExistsWithWrongGeneration,
}
impl Entity {
pub const fn from_raw(index: u32) -> Entity {
Entity {
index,
generation: 0,
}
}
pub const fn to_bits(self) -> u64 {
(self.generation as u64) << 32 | self.index as u64
}
pub const fn from_bits(bits: u64) -> Self {
Self {
generation: (bits >> 32) as u32,
index: bits as u32,
}
}
#[inline]
pub const fn index(self) -> u32 {
self.index
}
#[inline]
pub const fn generation(self) -> u32 {
self.generation
}
}
impl fmt::Debug for Entity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}v{}", self.index, self.generation)
}
}
impl SparseSetIndex for Entity {
fn sparse_set_index(&self) -> usize {
self.index() as usize
}
fn get_sparse_set_index(value: usize) -> Self {
Entity::from_raw(value as u32)
}
}
pub struct ReserveEntitiesIterator<'a> {
meta: &'a [EntityMeta],
index_iter: std::slice::Iter<'a, u32>,
index_range: std::ops::Range<u32>,
}
impl<'a> Iterator for ReserveEntitiesIterator<'a> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
self.index_iter
.next()
.map(|&index| Entity {
generation: self.meta[index as usize].generation,
index,
})
.or_else(|| {
self.index_range.next().map(|index| Entity {
generation: 0,
index,
})
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.index_iter.len() + self.index_range.len();
(len, Some(len))
}
}
impl<'a> core::iter::ExactSizeIterator for ReserveEntitiesIterator<'a> {}
impl<'a> core::iter::FusedIterator for ReserveEntitiesIterator<'a> {}
#[derive(Debug, Default)]
pub struct Entities {
pub(crate) meta: Vec<EntityMeta>,
pending: Vec<u32>,
free_cursor: AtomicIdCursor,
len: u32,
}
impl Entities {
pub fn reserve_entities(&self, count: u32) -> ReserveEntitiesIterator {
let range_end = self
.free_cursor
.fetch_sub(IdCursor::try_from(count).unwrap(), Ordering::Relaxed);
let range_start = range_end - IdCursor::try_from(count).unwrap();
let freelist_range = range_start.max(0) as usize..range_end.max(0) as usize;
let (new_id_start, new_id_end) = if range_start >= 0 {
(0, 0)
} else {
let base = self.meta.len() as IdCursor;
let new_id_end = u32::try_from(base - range_start).expect("too many entities");
let new_id_start = (base - range_end.min(0)) as u32;
(new_id_start, new_id_end)
};
ReserveEntitiesIterator {
meta: &self.meta[..],
index_iter: self.pending[freelist_range].iter(),
index_range: new_id_start..new_id_end,
}
}
pub fn reserve_entity(&self) -> Entity {
let n = self.free_cursor.fetch_sub(1, Ordering::Relaxed);
if n > 0 {
let index = self.pending[(n - 1) as usize];
Entity {
generation: self.meta[index as usize].generation,
index,
}
} else {
Entity {
generation: 0,
index: u32::try_from(self.meta.len() as IdCursor - n).expect("too many entities"),
}
}
}
fn verify_flushed(&mut self) {
debug_assert!(
!self.needs_flush(),
"flush() needs to be called before this operation is legal"
);
}
pub fn alloc(&mut self) -> Entity {
self.verify_flushed();
self.len += 1;
if let Some(index) = self.pending.pop() {
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
Entity {
generation: self.meta[index as usize].generation,
index,
}
} else {
let index = u32::try_from(self.meta.len()).expect("too many entities");
self.meta.push(EntityMeta::EMPTY);
Entity {
generation: 0,
index,
}
}
}
pub fn alloc_at(&mut self, entity: Entity) -> Option<EntityLocation> {
self.verify_flushed();
let loc = if entity.index as usize >= self.meta.len() {
self.pending.extend((self.meta.len() as u32)..entity.index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.meta
.resize(entity.index as usize + 1, EntityMeta::EMPTY);
self.len += 1;
None
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.index) {
self.pending.swap_remove(index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len += 1;
None
} else {
Some(mem::replace(
&mut self.meta[entity.index as usize].location,
EntityMeta::EMPTY.location,
))
};
self.meta[entity.index as usize].generation = entity.generation;
loc
}
pub fn alloc_at_without_replacement(&mut self, entity: Entity) -> AllocAtWithoutReplacement {
self.verify_flushed();
let result = if entity.index as usize >= self.meta.len() {
self.pending.extend((self.meta.len() as u32)..entity.index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.meta
.resize(entity.index as usize + 1, EntityMeta::EMPTY);
self.len += 1;
AllocAtWithoutReplacement::DidNotExist
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.index) {
self.pending.swap_remove(index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len += 1;
AllocAtWithoutReplacement::DidNotExist
} else {
let current_meta = &mut self.meta[entity.index as usize];
if current_meta.location.archetype_id == ArchetypeId::INVALID {
AllocAtWithoutReplacement::DidNotExist
} else if current_meta.generation == entity.generation {
AllocAtWithoutReplacement::Exists(current_meta.location)
} else {
return AllocAtWithoutReplacement::ExistsWithWrongGeneration;
}
};
self.meta[entity.index as usize].generation = entity.generation;
result
}
pub fn free(&mut self, entity: Entity) -> Option<EntityLocation> {
self.verify_flushed();
let meta = &mut self.meta[entity.index as usize];
if meta.generation != entity.generation {
return None;
}
meta.generation += 1;
let loc = mem::replace(&mut meta.location, EntityMeta::EMPTY.location);
self.pending.push(entity.index);
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len -= 1;
Some(loc)
}
pub fn reserve(&mut self, additional: u32) {
self.verify_flushed();
let freelist_size = *self.free_cursor.get_mut();
let shortfall = IdCursor::try_from(additional).unwrap() - freelist_size;
if shortfall > 0 {
self.meta.reserve(shortfall as usize);
}
}
pub fn contains(&self, entity: Entity) -> bool {
self.resolve_from_id(entity.index())
.map_or(false, |e| e.generation() == entity.generation)
}
pub fn clear(&mut self) {
self.meta.clear();
self.pending.clear();
*self.free_cursor.get_mut() = 0;
self.len = 0;
}
pub fn get(&self, entity: Entity) -> Option<EntityLocation> {
if (entity.index as usize) < self.meta.len() {
let meta = &self.meta[entity.index as usize];
if meta.generation != entity.generation
|| meta.location.archetype_id == ArchetypeId::INVALID
{
return None;
}
Some(meta.location)
} else {
None
}
}
pub fn resolve_from_id(&self, index: u32) -> Option<Entity> {
let idu = index as usize;
if let Some(&EntityMeta { generation, .. }) = self.meta.get(idu) {
Some(Entity { generation, index })
} else {
let free_cursor = self.free_cursor.load(Ordering::Relaxed);
let num_pending = usize::try_from(-free_cursor).ok()?;
(idu < self.meta.len() + num_pending).then_some(Entity {
generation: 0,
index,
})
}
}
fn needs_flush(&mut self) -> bool {
*self.free_cursor.get_mut() != self.pending.len() as IdCursor
}
pub unsafe fn flush(&mut self, mut init: impl FnMut(Entity, &mut EntityLocation)) {
let free_cursor = self.free_cursor.get_mut();
let current_free_cursor = *free_cursor;
let new_free_cursor = if current_free_cursor >= 0 {
current_free_cursor as usize
} else {
let old_meta_len = self.meta.len();
let new_meta_len = old_meta_len + -current_free_cursor as usize;
self.meta.resize(new_meta_len, EntityMeta::EMPTY);
self.len += -current_free_cursor as u32;
for (index, meta) in self.meta.iter_mut().enumerate().skip(old_meta_len) {
init(
Entity {
index: index as u32,
generation: meta.generation,
},
&mut meta.location,
);
}
*free_cursor = 0;
0
};
self.len += (self.pending.len() - new_free_cursor) as u32;
for index in self.pending.drain(new_free_cursor..) {
let meta = &mut self.meta[index as usize];
init(
Entity {
index,
generation: meta.generation,
},
&mut meta.location,
);
}
}
pub fn flush_as_invalid(&mut self) {
unsafe {
self.flush(|_entity, location| {
location.archetype_id = ArchetypeId::INVALID;
});
}
}
pub unsafe fn flush_and_reserve_invalid_assuming_no_entities(&mut self, count: usize) {
let free_cursor = self.free_cursor.get_mut();
*free_cursor = 0;
self.meta.reserve(count);
self.meta.as_mut_ptr().write_bytes(u8::MAX, count);
self.meta.set_len(count);
self.len = count as u32;
}
#[inline]
pub fn meta_len(&self) -> usize {
self.meta.len()
}
#[inline]
pub fn len(&self) -> u32 {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct EntityMeta {
pub generation: u32,
pub location: EntityLocation,
}
impl EntityMeta {
const EMPTY: EntityMeta = EntityMeta {
generation: 0,
location: EntityLocation {
archetype_id: ArchetypeId::INVALID,
index: usize::MAX, },
};
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct EntityLocation {
pub archetype_id: ArchetypeId,
pub index: usize,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn entity_bits_roundtrip() {
let e = Entity {
generation: 0xDEADBEEF,
index: 0xBAADF00D,
};
assert_eq!(Entity::from_bits(e.to_bits()), e);
}
#[test]
fn reserve_entity_len() {
let mut e = Entities::default();
e.reserve_entity();
unsafe { e.flush(|_, _| {}) };
assert_eq!(e.len(), 1);
}
#[test]
fn get_reserved_and_invalid() {
let mut entities = Entities::default();
let e = entities.reserve_entity();
assert!(entities.contains(e));
assert!(entities.get(e).is_none());
unsafe {
entities.flush(|_entity, _location| {
});
};
assert!(entities.contains(e));
assert!(entities.get(e).is_none());
}
#[test]
fn entity_const() {
const C1: Entity = Entity::from_raw(42);
assert_eq!(42, C1.index);
assert_eq!(0, C1.generation);
const C2: Entity = Entity::from_bits(0x0000_00ff_0000_00cc);
assert_eq!(0x0000_00cc, C2.index);
assert_eq!(0x0000_00ff, C2.generation);
const C3: u32 = Entity::from_raw(33).index();
assert_eq!(33, C3);
const C4: u32 = Entity::from_bits(0x00dd_00ff_0000_0000).generation();
assert_eq!(0x00dd_00ff, C4);
}
}