Gaia-ECS v1.0.0
A simple and powerful entity component system
Loading...
Searching...
No Matches
pair_lookup.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include "gaia/cnt/darray_ext.h"
5#include "gaia/cnt/map.h"
6#include "gaia/cnt/set.h"
7#include "gaia/ecs/id.h"
8
10namespace gaia {
11 namespace ecs {
12 using PairLookupMap = cnt::map<EntityLookupKey, cnt::set<EntityLookupKey>>;
13
14 class PairLookup {
16 PairLookupMap m_relToTgt;
18 PairLookupMap m_tgtToRel;
19
20 public:
22 void clear() {
23 m_relToTgt = {};
24 m_tgtToRel = {};
25 }
26
30 GAIA_NODISCARD const cnt::set<EntityLookupKey>* targets(Entity relation) const {
31 const auto it = m_relToTgt.find(EntityLookupKey(relation));
32 if (it == m_relToTgt.end())
33 return nullptr;
34
35 return &it->second;
36 }
37
41 GAIA_NODISCARD const cnt::set<EntityLookupKey>* relations(Entity target) const {
42 const auto it = m_tgtToRel.find(EntityLookupKey(target));
43 if (it == m_tgtToRel.end())
44 return nullptr;
45
46 return &it->second;
47 }
48
51 GAIA_NODISCARD auto relation_begin() const {
52 return m_relToTgt.begin();
53 }
54
57 GAIA_NODISCARD auto relation_end() const {
58 return m_relToTgt.end();
59 }
60
64 void add_pair(Entity relation, Entity target) {
65 const auto relKey = EntityLookupKey(relation);
66 const auto tgtKey = EntityLookupKey(target);
67 const auto allKey = EntityLookupKey(All);
68
69 auto& relTargets = m_relToTgt[relKey];
70 const bool relHadTargets = !relTargets.empty();
71 relTargets.insert(tgtKey);
72
73 auto& tgtRelations = m_tgtToRel[tgtKey];
74 const bool tgtHadRelations = !tgtRelations.empty();
75 tgtRelations.insert(relKey);
76
77 if (!tgtHadRelations)
78 m_relToTgt[allKey].insert(tgtKey);
79 if (!relHadTargets)
80 m_tgtToRel[allKey].insert(relKey);
81 }
82
88 static bool del_bucket_entry(PairLookupMap& map, EntityLookupKey source, EntityLookupKey remove) {
89 auto itTargets = map.find(source);
90 if (itTargets == map.end())
91 return false;
92
93 auto& targets = itTargets->second;
94 targets.erase(remove);
95 return targets.empty();
96 }
97
102 static void collect_bucket_entries(
103 const PairLookupMap& map, EntityLookupKey source, cnt::darray_ext<EntityLookupKey, 64>& out) {
104 const auto it = map.find(source);
105 if (it == map.end())
106 return;
107
108 for (auto entry: it->second)
109 out.push_back(entry);
110 }
111
115 void del_pair(Entity relation, Entity target) {
116 const auto relKey = EntityLookupKey(relation);
117 const auto tgtKey = EntityLookupKey(target);
118 const auto allKey = EntityLookupKey(All);
119
120 const bool relEmpty = del_bucket_entry(m_relToTgt, relKey, tgtKey);
121 const bool tgtEmpty = del_bucket_entry(m_tgtToRel, tgtKey, relKey);
122 if (tgtEmpty)
123 (void)del_bucket_entry(m_relToTgt, allKey, tgtKey);
124 if (relEmpty)
125 (void)del_bucket_entry(m_tgtToRel, allKey, relKey);
126 }
127
130 void del_entity_pairs(Entity entity) {
131 const auto key = EntityLookupKey(entity);
132
133 cnt::darray_ext<EntityLookupKey, 64> targets;
134 cnt::darray_ext<EntityLookupKey, 64> relations;
135 collect_bucket_entries(m_relToTgt, key, targets);
136 collect_bucket_entries(m_tgtToRel, key, relations);
137
138 for (auto target: targets)
139 del_pair(entity, target.entity());
140 for (auto relation: relations)
141 del_pair(relation.entity(), entity);
142
143 m_relToTgt.erase(key);
144 m_tgtToRel.erase(key);
145 }
146 };
147 } // namespace ecs
148} // namespace gaia