summaryrefslogtreecommitdiff
path: root/ecs/src/component/storage
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/component/storage')
-rw-r--r--ecs/src/component/storage/archetype.rs253
-rw-r--r--ecs/src/component/storage/graph.rs36
2 files changed, 230 insertions, 59 deletions
diff --git a/ecs/src/component/storage/archetype.rs b/ecs/src/component/storage/archetype.rs
index f6f8132..bb29701 100644
--- a/ecs/src/component/storage/archetype.rs
+++ b/ecs/src/component/storage/archetype.rs
@@ -1,18 +1,21 @@
+use std::any::Any;
+use std::array::IntoIter as ArrayIntoIter;
use std::hash::{DefaultHasher, Hash, Hasher};
+use std::iter::{Enumerate, Filter, Map, RepeatN, Zip};
+use std::option::IntoIter as OptionIntoIter;
use std::slice::Iter as SliceIter;
use hashbrown::HashMap;
-use crate::component::Metadata as ComponentMetadata;
+use crate::lock::Lock;
use crate::uid::{Kind as UidKind, Uid};
-use crate::util::HashMapExt;
-use crate::EntityComponent;
+use crate::util::{Either, HashMapExt};
#[derive(Debug)]
pub struct Archetype
{
id: Id,
- entities: Vec<ArchetypeEntity>,
+ entities: Vec<Entity>,
entity_index_lookup: HashMap<Uid, usize>,
component_index_lookup: HashMap<Uid, usize>,
component_ids: Vec<Uid>,
@@ -53,7 +56,7 @@ impl Archetype
.keys_is_subset(&other.component_index_lookup)
}
- pub fn get_entity_by_id(&self, entity_uid: Uid) -> Option<&ArchetypeEntity>
+ pub fn get_entity_by_id(&self, entity_uid: Uid) -> Option<&Entity>
{
let index = *self.entity_index_lookup.get(&entity_uid)?;
@@ -64,7 +67,7 @@ impl Archetype
}))
}
- pub fn push_entity(&mut self, entity: ArchetypeEntity)
+ pub fn push_entity(&mut self, entity: Entity)
{
self.entity_index_lookup
.insert(entity.uid, self.entities.len());
@@ -72,7 +75,7 @@ impl Archetype
self.entities.push(entity);
}
- pub fn remove_entity(&mut self, entity_uid: Uid) -> Option<ArchetypeEntity>
+ pub fn remove_entity(&mut self, entity_uid: Uid) -> Option<Entity>
{
//debug_assert_eq!(entity_uid.kind(), UidKind::Entity);
@@ -116,8 +119,54 @@ impl Archetype
self.component_index_lookup.len()
}
+ pub fn get_matching_component_indices(
+ &self,
+ component_id: Uid,
+ ) -> MatchingComponentIter
+ {
+ assert!(
+ component_id.kind() == UidKind::Component
+ || component_id.kind() == UidKind::Pair
+ );
+
+ if component_id.kind() == UidKind::Pair
+ && component_id.target_component() == Uid::wildcard()
+ {
+ return MatchingComponentIter {
+ inner: Either::A(
+ self.component_ids
+ .iter()
+ .enumerate()
+ .zip(std::iter::repeat_n(component_id, self.component_ids.len()))
+ .filter(
+ (|((_, other_comp_id), component_id)| {
+ other_comp_id.kind() == UidKind::Pair
+ && other_comp_id.has_same_relation_as(*component_id)
+ })
+ as MatchingComponentIterFilterFn,
+ )
+ .map(|((index, other_comp_id), _)| (*other_comp_id, index)),
+ ),
+ };
+ }
+
+ MatchingComponentIter {
+ inner: Either::B(
+ [component_id]
+ .into_iter()
+ .zip(self.get_index_for_component(component_id)),
+ ),
+ }
+ }
+
pub fn get_index_for_component(&self, component_id: Uid) -> Option<usize>
{
+ assert!(
+ component_id.kind() == UidKind::Component
+ || (component_id.kind() == UidKind::Pair
+ && component_id.target_component() != Uid::wildcard())
+ );
+
self.component_index_lookup.get(&component_id).copied()
}
@@ -131,23 +180,79 @@ impl Archetype
self.component_ids.iter().copied()
}
- pub fn has_component_with_id(&self, component_id: Uid) -> bool
+ pub fn contains_matching_component(&self, component_id: Uid) -> bool
{
- debug_assert_eq!(component_id.kind(), UidKind::Component);
+ let component_id_kind = component_id.kind();
+
+ debug_assert!(
+ component_id_kind == UidKind::Component || component_id_kind == UidKind::Pair
+ );
+
+ if component_id.kind() == UidKind::Pair
+ && component_id.target_component() == Uid::wildcard()
+ {
+ return self.component_ids.iter().any(|other_comp_id| {
+ other_comp_id.kind() == UidKind::Pair
+ && other_comp_id.has_same_relation_as(component_id)
+ });
+ }
+
+ self.contains_component_with_exact_id(component_id)
+ }
+
+ pub fn contains_component_with_exact_id(&self, component_id: Uid) -> bool
+ {
+ let component_id_kind = component_id.kind();
+
+ debug_assert!(
+ component_id_kind == UidKind::Component
+ || (component_id_kind == UidKind::Pair
+ && component_id.target_component() != Uid::wildcard())
+ );
self.component_index_lookup.contains_key(&component_id)
}
}
+type MatchingComponentIterFilterFn = fn(&((usize, &Uid), Uid)) -> bool;
+
+type MatchingComponentIterMapFn = fn(((usize, &Uid), Uid)) -> (Uid, usize);
+
+type InnerMatchingComponentIterA<'archetype> = Map<
+ Filter<
+ Zip<Enumerate<SliceIter<'archetype, Uid>>, RepeatN<Uid>>,
+ MatchingComponentIterFilterFn,
+ >,
+ MatchingComponentIterMapFn,
+>;
+
+type InnerMatchingComponentIterB = Zip<ArrayIntoIter<Uid, 1>, OptionIntoIter<usize>>;
+
+#[derive(Debug)]
+pub struct MatchingComponentIter<'archetype>
+{
+ inner: Either<InnerMatchingComponentIterA<'archetype>, InnerMatchingComponentIterB>,
+}
+
+impl Iterator for MatchingComponentIter<'_>
+{
+ type Item = (Uid, usize);
+
+ fn next(&mut self) -> Option<Self::Item>
+ {
+ self.inner.next()
+ }
+}
+
#[derive(Debug)]
pub struct EntityIter<'archetype>
{
- iter: SliceIter<'archetype, ArchetypeEntity>,
+ iter: SliceIter<'archetype, Entity>,
}
impl<'archetype> Iterator for EntityIter<'archetype>
{
- type Item = &'archetype ArchetypeEntity;
+ type Item = &'archetype Entity;
fn next(&mut self) -> Option<Self::Item>
{
@@ -156,71 +261,125 @@ impl<'archetype> Iterator for EntityIter<'archetype>
}
#[derive(Debug)]
-pub struct ArchetypeEntity
+pub struct Entity
{
- pub uid: Uid,
- pub components: Vec<EntityComponent>,
+ uid: Uid,
+ components: Vec<EntityComponent>,
}
-/// Archetype ID.
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Id
+impl Entity
{
- hash: u64,
+ pub fn new(uid: Uid, components: impl IntoIterator<Item = EntityComponent>) -> Self
+ {
+ Self {
+ uid,
+ components: components.into_iter().collect(),
+ }
+ }
+
+ pub fn uid(&self) -> Uid
+ {
+ self.uid
+ }
+
+ pub fn components(&self) -> &[EntityComponent]
+ {
+ &self.components
+ }
+
+ pub fn remove_component(&mut self, component_id: Uid, archetype: &Archetype)
+ {
+ let index = archetype
+ .get_index_for_component(component_id)
+ .expect("Archetype should contain component");
+
+ self.components.remove(index);
+ }
+
+ pub fn insert_component(
+ &mut self,
+ component_id: Uid,
+ component: EntityComponent,
+ archetype: &Archetype,
+ )
+ {
+ let index = archetype
+ .get_index_for_component(component_id)
+ .expect("Archetype should contain component");
+
+ self.components.insert(index, component);
+ }
}
-impl Id
+#[derive(Debug)]
+pub struct EntityComponent
{
- pub fn new(component_ids: &impl AsRef<[Uid]>) -> Self
+ id: Uid,
+ component: Lock<Box<dyn Any>>,
+}
+
+impl EntityComponent
+{
+ pub fn new(
+ component: Box<dyn Any>,
+ component_id: Uid,
+ component_name: &'static str,
+ ) -> Self
{
- if component_ids.as_ref().is_empty() {
- return Self { hash: 0 };
+ Self {
+ id: component_id,
+ component: Lock::new(component, component_name),
}
+ }
- debug_assert!(
- component_ids.as_ref().is_sorted(),
- "Cannot create archetype ID from unsorted component IDs"
- );
+ #[allow(dead_code)]
+ pub fn id(&self) -> Uid
+ {
+ self.id
+ }
- let mut hasher = DefaultHasher::new();
+ pub fn component(&self) -> &Lock<Box<dyn Any>>
+ {
+ &self.component
+ }
+}
- for component_id in component_ids.as_ref() {
- component_id.hash(&mut hasher);
- }
+/// Archetype ID.
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Id
+{
+ hash: u64,
+}
- Self { hash: hasher.finish() }
+impl Id
+{
+ pub fn new_empty() -> Self
+ {
+ Self { hash: 0 }
}
- pub fn from_components_metadata<'a>(
- components_metadata: impl IntoIterator<Item = &'a ComponentMetadata>,
- ) -> Self
+ pub fn new<'a>(component_ids: impl IntoIterator<Item = &'a Uid>) -> Self
{
let mut hasher = DefaultHasher::new();
let mut prev_component_id: Option<Uid> = None;
- let mut comp_metadata_iter = components_metadata.into_iter().peekable();
+ let mut component_id_iter = component_ids.into_iter().peekable();
- if comp_metadata_iter.peek().is_none() {
- return Self { hash: 0 };
+ if component_id_iter.peek().is_none() {
+ return Self::new_empty();
}
- for comp_metadata in comp_metadata_iter {
- if prev_component_id
- .is_some_and(|prev_comp_id| comp_metadata.id < prev_comp_id)
- {
+ for comp_id in component_id_iter {
+ if prev_component_id.is_some_and(|prev_comp_id| *comp_id < prev_comp_id) {
panic!(
"Cannot create archetype ID from a unsorted component metadata list"
);
}
- prev_component_id = Some(comp_metadata.id);
-
- if comp_metadata.is_optional {
- continue;
- }
+ prev_component_id = Some(*comp_id);
- comp_metadata.id.hash(&mut hasher);
+ comp_id.hash(&mut hasher);
}
Self { hash: hasher.finish() }
diff --git a/ecs/src/component/storage/graph.rs b/ecs/src/component/storage/graph.rs
index 11160e7..29fa937 100644
--- a/ecs/src/component/storage/graph.rs
+++ b/ecs/src/component/storage/graph.rs
@@ -140,19 +140,31 @@ impl Graph
}
fn create_missing_subset_node_edges(
- target_node: &ArchetypeNode,
+ target_node: &mut ArchetypeNode,
subset_node: &mut ArchetypeNode,
)
{
let uniq_comp_id = target_node
.archetype()
.component_ids_sorted()
- .find(|id| !subset_node.archetype().has_component_with_id(*id))
+ .find(|id| {
+ !subset_node
+ .archetype()
+ .contains_component_with_exact_id(*id)
+ })
.unwrap();
subset_node
.get_or_insert_edges(uniq_comp_id, ArchetypeEdges::default)
.add = Some(subset_node.make_add_edge(uniq_comp_id).0);
+
+ if target_node.archetype().component_cnt()
+ == subset_node.archetype().component_cnt() + 1
+ {
+ target_node
+ .get_or_insert_edges(uniq_comp_id, ArchetypeEdges::default)
+ .remove = Some(subset_node.archetype().id());
+ }
}
fn create_missing_superset_node_edges(
@@ -169,7 +181,7 @@ impl Graph
.find(|other_archetype_comp_id| {
!target_node
.archetype()
- .has_component_with_id(*other_archetype_comp_id)
+ .contains_component_with_exact_id(*other_archetype_comp_id)
})
.or_else(|| {
if target_node.archetype().component_cnt() != 0 {
@@ -196,7 +208,11 @@ impl Graph
let extra_comp_id = superset_node
.archetype()
.component_ids_unsorted()
- .find(|comp_id| !target_node.archetype().has_component_with_id(*comp_id))
+ .find(|comp_id| {
+ !target_node
+ .archetype()
+ .contains_component_with_exact_id(*comp_id)
+ })
.expect("Archetype should contain one extra component ID");
superset_node
@@ -234,7 +250,10 @@ impl ArchetypeNode
insert_fn: impl FnOnce() -> ArchetypeEdges,
) -> &mut ArchetypeEdges
{
- debug_assert_eq!(component_id.kind(), UidKind::Component);
+ debug_assert!(matches!(
+ component_id.kind(),
+ UidKind::Component | UidKind::Pair
+ ));
self.edges.entry(component_id).or_insert_with(insert_fn)
}
@@ -245,13 +264,6 @@ impl ArchetypeNode
self.edges.iter()
}
- pub fn get_edges_mut(&mut self, component_id: Uid) -> Option<&mut ArchetypeEdges>
- {
- debug_assert_eq!(component_id.kind(), UidKind::Component);
-
- self.edges.get_mut(&component_id)
- }
-
pub fn make_add_edge(&self, component_id: Uid) -> (ArchetypeId, Vec<Uid>)
{
let mut edge_comp_ids = self