1use alloc::vec::Vec;
2use core::{
3 any::TypeId,
4 hash::{BuildHasher, Hash, Hasher},
5};
6
7use hashbrown::hash_map::{Entry, HashMap, RawEntryMut};
8
9use crate::{
10 archetype::Archetype,
11 bundle::{Bundle, BundleDesc},
12 cold,
13 component::{ComponentInfo, ComponentRegistry},
14 hash::MulHasherBuilder,
15};
16
17use super::ArchetypeSet;
18
19pub(super) struct Edges {
20 add_one: HashMap<(u32, TypeId), u32, MulHasherBuilder>,
22
23 add_key: HashMap<(u32, TypeId), u32, MulHasherBuilder>,
25
26 add_ids: HashMap<(u32, Vec<TypeId>), u32, MulHasherBuilder>,
28
29 sub_one: HashMap<(u32, TypeId), u32, MulHasherBuilder>,
31
32 sub_key: HashMap<(u32, TypeId), u32, MulHasherBuilder>,
34
35 sub_ids: HashMap<(u32, Vec<TypeId>), u32, MulHasherBuilder>,
37}
38
39impl Edges {
40 #[must_use]
41 pub fn new() -> Edges {
42 Edges {
43 add_one: HashMap::with_hasher(MulHasherBuilder),
44 add_key: HashMap::with_hasher(MulHasherBuilder),
45 add_ids: HashMap::with_hasher(MulHasherBuilder),
46 sub_one: HashMap::with_hasher(MulHasherBuilder),
47 sub_key: HashMap::with_hasher(MulHasherBuilder),
48 sub_ids: HashMap::with_hasher(MulHasherBuilder),
49 }
50 }
51}
52
53impl Edges {
54 #[must_use]
55 pub fn insert<F>(
56 &mut self,
57 registry: &mut ComponentRegistry,
58 archetypes: &mut ArchetypeSet,
59 src: u32,
60 ty: TypeId,
61 register_component: F,
62 ) -> u32
63 where
64 F: FnOnce(&mut ComponentRegistry) -> &ComponentInfo,
65 {
66 let slow = || {
67 cold();
68 match archetypes.iter().position(|a| {
69 let ids = archetypes[src as usize].ids().chain(Some(ty));
70 a.matches(ids)
71 }) {
72 None => {
73 cold();
74 archetypes.add_with(|archetypes| {
75 let info = register_component(registry);
76 Archetype::new(archetypes[src as usize].infos().chain(Some(info)))
77 })
78 }
79 Some(idx) => idx as u32,
80 }
81 };
82
83 match self.add_one.entry((src, ty)) {
84 Entry::Occupied(entry) => *entry.get(),
85 Entry::Vacant(entry) => {
86 let idx = slow();
87 entry.insert(idx);
88 idx
89 }
90 }
91 }
92
93 #[must_use]
94 pub fn insert_bundle<B, F>(
95 &mut self,
96 registry: &mut ComponentRegistry,
97 archetypes: &mut ArchetypeSet,
98 src: u32,
99 bundle: &B,
100 register_components: F,
101 ) -> u32
102 where
103 B: BundleDesc,
104 F: FnOnce(&mut ComponentRegistry),
105 {
106 let very_slow = || {
107 cold();
108 match archetypes.iter().position(|a| {
109 bundle.with_ids(|ids| {
110 let ids = archetypes[src as usize].ids().chain(ids.iter().copied());
111 a.matches(ids)
112 })
113 }) {
114 None => {
115 cold();
116 archetypes.add_with(|archetypes| {
117 register_components(registry);
118
119 bundle.with_ids(|ids| {
120 Archetype::new(
121 archetypes[src as usize]
122 .ids()
123 .filter(|aid| ids.iter().all(|id| *id != *aid))
124 .chain(ids.iter().copied())
125 .map(|id| match registry.get_info(id) {
126 None => panic!("Component {:?} is not registered", id),
127 Some(info) => info,
128 }),
129 )
130 })
131 })
132 }
133 Some(idx) => idx as u32,
134 }
135 };
136
137 let add_ids = &mut self.add_ids;
138 let slow = || {
139 cold();
140 let raw_entry = bundle.with_ids(move |ids| {
141 let mut hasher = add_ids.hasher().build_hasher();
142 (src, ids).hash(&mut hasher);
143 let hash = hasher.finish();
144
145 add_ids
146 .raw_entry_mut()
147 .from_hash(hash, |(key_src, key_ids)| *key_src == src && key_ids == ids)
148 });
149
150 match raw_entry {
151 RawEntryMut::Occupied(entry) => *entry.get(),
152 RawEntryMut::Vacant(entry) => {
153 let idx = very_slow();
154 entry.insert((src, bundle.with_ids(|ids| Vec::from(ids))), idx);
155 idx
156 }
157 }
158 };
159
160 match B::key() {
161 None => slow(),
162 Some(key) => match self.add_key.entry((src, key)) {
163 Entry::Occupied(entry) => *entry.get(),
164 Entry::Vacant(entry) => {
165 let idx = slow();
166 entry.insert(idx);
167 idx
168 }
169 },
170 }
171 }
172
173 #[must_use]
174 pub fn remove(&mut self, archetypes: &mut ArchetypeSet, src: u32, ty: TypeId) -> u32 {
175 let mut slow = || {
176 cold();
177 match archetypes.iter().position(|a| {
178 let ids = archetypes[src as usize].ids().filter(|id| *id != ty);
179 a.matches(ids)
180 }) {
181 None => {
182 cold();
183 archetypes.add_with(|archetypes| {
184 Archetype::new(
185 archetypes[src as usize]
186 .infos()
187 .filter(|info| info.id() != ty),
188 )
189 })
190 }
191 Some(idx) => idx as u32,
192 }
193 };
194
195 match self.sub_one.entry((src, ty)) {
196 Entry::Occupied(entry) => *entry.get(),
197 Entry::Vacant(entry) => {
198 let idx = slow();
199 entry.insert(idx);
200 idx
201 }
202 }
203 }
204
205 #[must_use]
206 pub fn remove_bundle<B>(&mut self, archetypes: &mut ArchetypeSet, src: u32) -> u32
207 where
208 B: Bundle,
209 {
210 let mut very_slow = || {
211 cold();
212 let ids = archetypes[src as usize]
213 .ids()
214 .filter(|id| !B::static_contains_id(*id));
215
216 match archetypes.iter().position(|a| a.matches(ids.clone())) {
217 None => {
218 cold();
219 drop(ids);
220
221 archetypes.add_with(|archetypes| {
222 Archetype::new(
223 archetypes[src as usize]
224 .infos()
225 .filter(|info| !B::static_contains_id(info.id())),
226 )
227 })
228 }
229 Some(idx) => idx as u32,
230 }
231 };
232
233 let sub_ids = &mut self.sub_ids;
234 let slow = || {
235 cold();
236 let raw_entry = B::static_with_ids(move |ids| {
237 let mut hasher = sub_ids.hasher().build_hasher();
238 (src, ids).hash(&mut hasher);
239 let hash = hasher.finish();
240
241 sub_ids
242 .raw_entry_mut()
243 .from_hash(hash, |(key_src, key_ids)| *key_src == src && key_ids == ids)
244 });
245
246 match raw_entry {
247 RawEntryMut::Occupied(entry) => *entry.get(),
248 RawEntryMut::Vacant(entry) => {
249 let idx = very_slow();
250 entry.insert((src, B::static_with_ids(|ids| ids.into())), idx);
251 idx
252 }
253 }
254 };
255
256 match B::key() {
257 None => slow(),
258 Some(key) => match self.sub_key.entry((src, key)) {
259 Entry::Occupied(entry) => *entry.get(),
260 Entry::Vacant(entry) => {
261 let idx = slow();
262 entry.insert(idx);
263 idx
264 }
265 },
266 }
267 }
268}