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 
15 template <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 
31 template <typename Element, typename Model>
32  requires std::is_base_of_v<IdentifiedObject<Model>, Element>
33 class IdContainer<Element, Model, true>
34 {
35 public:
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 
176 template <typename Element, typename Model>
177  requires std::is_base_of_v<IdentifiedObject<Model>, Element>
178 class IdContainer<Element, Model, false>
179 {
180 public:
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 
324 template <typename Element, typename Model>
325  requires(!std::is_base_of_v<IdentifiedObject<Model>, Element>)
326 class IdContainer<Element, Model, false>
327 {
328 public:
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