Loading...
Searching...
No Matches
IdentifiedObjectMap.hpp
1#pragma once
2#include <score/model/IdentifiedObject.hpp>
3#include <score/tools/std/IndirectContainer.hpp>
4
5#include <ossia/detail/hash_map.hpp>
6
7#include <list>
8#include <vector>
9// This file contains a fast map for items based on their identifier,
10// based on boost's multi-index maps.
11
15template <class Element, class Model = Element, bool Order = false>
17
18// We have to write two implementations since const_mem_fun does not handle
19// inheritance.
20
31template <typename Element, typename Model>
32 requires std::is_base_of_v<IdentifiedObject<Model>, Element>
33class IdContainer<Element, Model, true>
34{
35public:
36 using model_type = Model;
37 using order_t = std::list<Element*>;
38 using map_t
39 = ossia::hash_map<Id<Model>, std::pair<Element*, typename order_t::iterator>>;
40 map_t m_map;
41 order_t m_order;
42
43 using value_type = Element;
48
49 IdContainer() INLINE_EXPORT = default;
50 IdContainer(const IdContainer& other) = delete;
51 IdContainer(IdContainer&& other) noexcept = delete;
52 IdContainer& operator=(const IdContainer& other) = delete;
53 IdContainer& operator=(IdContainer&& other) = delete;
54
55 ~IdContainer() INLINE_EXPORT
56 {
57 // To ensure that children are deleted before their parents
58 for(auto elt : m_order)
59 {
60 delete elt;
61 }
62 }
63
64 OSSIA_INLINE auto& ordered() INLINE_EXPORT { return m_order; }
65
66 OSSIA_INLINE const_iterator begin() const INLINE_EXPORT
67 {
68 return score::make_indirect_iterator(this->m_order.begin());
69 }
70 OSSIA_INLINE const_reverse_iterator rbegin() const INLINE_EXPORT
71 {
72 return score::make_indirect_iterator(this->m_order.rbegin());
73 }
74 OSSIA_INLINE const_iterator cbegin() const INLINE_EXPORT
75 {
76 return score::make_indirect_iterator(this->m_order.cbegin());
77 }
78 OSSIA_INLINE const_iterator end() const INLINE_EXPORT
79 {
80 return score::make_indirect_iterator(this->m_order.end());
81 }
82 OSSIA_INLINE const_reverse_iterator rend() const INLINE_EXPORT
83 {
84 return score::make_indirect_iterator(this->m_order.rend());
85 }
86 OSSIA_INLINE const_iterator cend() const INLINE_EXPORT
87 {
88 return score::make_indirect_iterator(this->m_order.cend());
89 }
90
91 OSSIA_INLINE std::size_t size() const INLINE_EXPORT { return m_map.size(); }
92
93 bool empty() const INLINE_EXPORT { return m_map.empty(); }
94
95 std::vector<Element*> as_vec() const INLINE_EXPORT
96 {
97 return std::vector<Element*>(m_order.begin(), m_order.end());
98 }
99
100 score::IndirectContainer<Element> as_indirect_vec() const INLINE_EXPORT
101 {
102 return score::IndirectContainer<Element>(m_order.begin(), m_order.end());
103 }
104
105 void insert(value_type* t) INLINE_EXPORT
106 {
107 SCORE_ASSERT(m_map.find(t->id()) == m_map.end());
108 m_order.push_front(t);
109 m_map.insert({t->id(), {t, m_order.begin()}});
110 }
111
112 void remove(typename map_t::iterator it) INLINE_EXPORT
113 {
114 // No delete : it is done in EntityMap.
115
116 if(it != this->m_map.end())
117 {
118 m_order.erase(it->second.second);
119 m_map.erase(it);
120 }
121 }
122 void remove(typename map_t::const_iterator it) INLINE_EXPORT
123 {
124 // No delete : it is done in EntityMap.
125
126 if(it != this->m_map.end())
127 {
128 m_order.erase(it->second.second);
129 m_map.erase(it);
130 }
131 }
132
133 void remove(const Id<Model>& id) INLINE_EXPORT { remove(m_map.find(id)); }
134
135 void clear() INLINE_EXPORT
136 {
137 m_map.clear();
138 m_order.clear();
139 // TODO why no delete ?!
140 // e.g. in some cases (Curve::Model::clear()) it deletes afterwards
141 // but not in Scenario destructor
142 }
143
144 const_iterator find(const Id<Model>& id) const INLINE_EXPORT
145 {
146 auto it = this->m_map.find(id);
147 if(it != this->m_map.end())
148 {
149 return score::make_indirect_iterator(
150 (typename order_t::const_iterator)it->second.second);
151 }
152 else
153 {
154 return score::make_indirect_iterator(this->m_order.end());
155 }
156 }
157
158 Element& at(const Id<Model>& id) const INLINE_EXPORT
159 {
160 if(id.m_ptr)
161 {
162 SCORE_ASSERT(id.m_ptr->parent() == this->m_map.find(id)->second.first->parent());
163 return safe_cast<Element&>(*id.m_ptr);
164 }
165 auto item = this->m_map.find(id);
166 SCORE_ASSERT(item != this->m_map.end());
167
168 id.m_ptr = item->second.first;
169 return safe_cast<Element&>(*item->second.first);
170 }
171};
172
176template <typename Element, typename Model>
177 requires std::is_base_of_v<IdentifiedObject<Model>, Element>
178class IdContainer<Element, Model, false>
179{
180public:
181 using model_type = Model;
182 using map_t = ossia::hash_map<Id<Model>, Element*>;
183 map_t m_map;
184
185 using value_type = Element;
188 // using reverse_iterator = score::indirect_iterator<typename map_t::reverse_iterator>;
189
190 IdContainer() INLINE_EXPORT = default;
191 IdContainer(const IdContainer& other) = delete;
192 IdContainer(IdContainer&& other) noexcept = delete;
193 IdContainer& operator=(const IdContainer& other) = delete;
194 IdContainer& operator=(IdContainer&& other) = delete;
195
196 ~IdContainer() INLINE_EXPORT
197 {
198 // To ensure that children are deleted before their parents
199 for(const auto& elt : m_map)
200 {
201 delete elt.second;
202 }
203 }
204
205 OSSIA_INLINE const_iterator begin() const INLINE_EXPORT
206 {
207 return score::make_indirect_map_iterator(this->m_map.begin());
208 }
209 /*
210 OSSIA_INLINE reverse_iterator rbegin() const INLINE_EXPORT
211 {
212 return score::make_indirect_map_iterator(this->m_map.rbegin());
213 }
214 */
215 OSSIA_INLINE const_iterator cbegin() const INLINE_EXPORT
216 {
217 return score::make_indirect_map_iterator(this->m_map.cbegin());
218 }
219 OSSIA_INLINE const_iterator end() const INLINE_EXPORT
220 {
221 return score::make_indirect_map_iterator(this->m_map.end());
222 }
223 /*
224 OSSIA_INLINE reverse_iterator rend() const INLINE_EXPORT
225 {
226 return score::make_indirect_map_iterator(this->m_map.rend());
227 }
228 */
229 OSSIA_INLINE const_iterator cend() const INLINE_EXPORT
230 {
231 return score::make_indirect_map_iterator(this->m_map.cend());
232 }
233
234 OSSIA_INLINE std::size_t size() const INLINE_EXPORT { return m_map.size(); }
235
236 OSSIA_INLINE bool empty() const INLINE_EXPORT { return m_map.empty(); }
237
238 std::vector<Element*> as_vec() const INLINE_EXPORT
239 {
240 std::vector<Element*> e;
241 e.reserve(m_map.size());
242 for(auto& [key, val] : m_map)
243 {
244 e.push_back(val);
245 }
246 return e;
247 }
248
249 score::IndirectContainer<Element> as_indirect_vec() const INLINE_EXPORT
250 {
252 e.reserve(m_map.size());
253 for(auto& [key, val] : m_map)
254 {
255 e.push_back(val);
256 }
257 return e;
258 }
259
260 void insert(value_type* t) INLINE_EXPORT
261 {
262 SCORE_ASSERT(m_map.find(t->id()) == m_map.end());
263 m_map.insert({t->id(), t});
264 }
265
266 void remove(typename map_t::iterator it) INLINE_EXPORT
267 {
268 // No delete : it is done in EntityMap.
269 if(it != this->m_map.end())
270 {
271 m_map.erase(it);
272 }
273 }
274 void remove(typename map_t::const_iterator it) INLINE_EXPORT
275 {
276 // No delete : it is done in EntityMap.
277 if(it != this->m_map.end())
278 {
279 m_map.erase(it);
280 }
281 }
282
283 void remove(const Id<Model>& id) INLINE_EXPORT { remove(m_map.find(id)); }
284
285 void clear() INLINE_EXPORT
286 {
287 m_map.clear();
288 // TODO why no delete ?!
289 // e.g. in some cases (Curve::Model::clear()) it deletes afterwards
290 // but not in Scenario destructor
291 }
292
293 const_iterator find(const Id<Model>& id) const INLINE_EXPORT
294 {
295 auto it = this->m_map.find(id);
296 if(it != this->m_map.end())
297 {
298 return score::make_indirect_map_iterator(it);
299 }
300 else
301 {
302 return score::make_indirect_map_iterator(this->m_map.end());
303 }
304 }
305
306 Element& at(const Id<Model>& id) const INLINE_EXPORT
307 {
308 if(id.m_ptr)
309 {
310 SCORE_ASSERT(id.m_ptr->parent() == this->m_map.find(id)->second->parent());
311 return safe_cast<Element&>(*id.m_ptr);
312 }
313 auto item = this->m_map.find(id);
314 SCORE_ASSERT(item != this->m_map.end());
315
316 id.m_ptr = item->second;
317 return safe_cast<Element&>(*item->second);
318 }
319};
320
324template <typename Element, typename Model>
325 requires(!std::is_base_of_v<IdentifiedObject<Model>, Element>)
327{
328public:
329 using model_type = Model;
330 ossia::hash_map<Id<Model>, Element*> m_map;
331
332 std::vector<Element*> as_vec() const INLINE_EXPORT
333 {
334 std::vector<Element*> v;
335 const auto N = m_map.size();
336 v.reserve(N);
337 for(auto& e : m_map)
338 {
339 v.push_back(e.second);
340 }
341 return v;
342 }
343
344 OSSIA_INLINE auto begin() const INLINE_EXPORT
345 {
346 return score::make_indirect_map_iterator(this->m_map.begin());
347 }
348 OSSIA_INLINE auto rbegin() const INLINE_EXPORT
349 {
350 return score::make_indirect_map_iterator(this->m_map.begin());
351 }
352 OSSIA_INLINE auto cbegin() const INLINE_EXPORT
353 {
354 return score::make_indirect_map_iterator(this->m_map.cbegin());
355 }
356 OSSIA_INLINE auto end() const INLINE_EXPORT
357 {
358 return score::make_indirect_map_iterator(this->m_map.end());
359 }
360 OSSIA_INLINE auto rend() const INLINE_EXPORT
361 {
362 return score::make_indirect_map_iterator(this->m_map.end());
363 }
364 OSSIA_INLINE auto cend() const INLINE_EXPORT
365 {
366 return score::make_indirect_map_iterator(this->m_map.cend());
367 }
368
369 auto find(const Id<Model>& id) const INLINE_EXPORT
370 {
371 return score::make_indirect_map_iterator(this->m_map.find(id));
372 }
373
374 void insert(Element* t) INLINE_EXPORT
375 {
376 SCORE_ASSERT(m_map.find(t->id()) == m_map.end());
377 m_map.insert({t->id(), t});
378 }
379
380 void erase(const Id<Model>& id) INLINE_EXPORT
381 {
382 auto it = m_map.find(id);
383 if(it != m_map.end())
384 {
385 auto ptr = it->second;
386 m_map.erase(it);
387 delete ptr;
388 }
389 }
390
391 void remove_all() INLINE_EXPORT
392 {
393 for(auto& e : m_map)
394 {
395 delete e.second;
396 }
397 m_map.clear();
398 }
399
400 auto& at(const Id<Model>& id) const INLINE_EXPORT
401 {
402 auto item = this->m_map.find(id);
403 SCORE_ASSERT(item != this->m_map.end());
404 return *item->second;
405 }
406};
A map to access child objects through their id.
Definition IdentifiedObjectMap.hpp:16
The id_base_t class.
Definition Identifier.hpp:57
Definition IndirectContainer.hpp:129
Definition IndirectContainer.hpp:10
Definition IndirectContainer.hpp:89