Loading...
Searching...
No Matches
ComponentHierarchy.hpp
1#pragma once
2#include <score/application/ApplicationComponents.hpp>
3#include <score/model/ComponentSerialization.hpp>
4#include <score/tools/IdentifierGeneration.hpp>
5
6#include <ossia/detail/algorithms.hpp>
7
8#include <nano_observer.hpp>
9
10#include <vector>
11
12namespace score
13{
25template <typename ParentComponent_T, typename ChildModel_T, typename ChildComponent_T>
27 : public ParentComponent_T
28 , public Nano::Observer
29{
30public:
32
33 struct ChildPair
34 {
35 ChildPair(ChildModel_T* m, ChildComponent_T* c)
36 : model{m}
37 , component{c}
38 {
39 }
40 ChildModel_T* model{};
41 ChildComponent_T* component{};
42 };
43
44 template <typename... Args>
45 ComponentHierarchyManager(Args&&... args)
46 : ParentComponent_T{std::forward<Args>(args)...}
47 {
48 init();
49 }
50
51 template <typename... Args>
53 : ParentComponent_T{std::forward<Args>(args)...}
54 {
55 }
56
57 void init()
58 {
59 auto& child_models = ParentComponent_T::template models<ChildModel_T>();
60 for(auto& child_model : child_models)
61 {
62 add(child_model);
63 }
64
65 child_models.mutable_added.template connect<&hierarchy_t::add>(this);
66
67 child_models.removing.template connect<&hierarchy_t::remove>(this);
68 }
69
70 const auto& children() const { return m_children; }
71
72#if defined(SCORE_SERIALIZABLE_COMPONENTS)
73 void add(ChildModel_T& element)
74 {
75 add(element, typename score::is_component_serializable<ChildComponent_T>::type{});
76 }
77
78 void add(ChildModel_T& element, score::serializable_tag)
79 {
80 // Since the component may be serializable, we first look if
81 // we can deserialize it.
82 auto comp = score::deserialize_component<ChildComponent_T>(
83 element.components(), [&](auto&& deserializer) {
84 ParentComponent_T::template load<ChildComponent_T>(deserializer, element);
85 });
86
87 // Maybe we could not deserialize it
88 if(!comp)
89 {
90 comp = ParentComponent_T::template make<ChildComponent_T>(
91 getStrongId(element.components()), element);
92 }
93
94 // We try to add it
95 if(comp)
96 {
97 element.components().add(comp);
98 m_children.emplace_back(ChildPair{&element, comp});
99 }
100 }
101 void add(ChildModel_T& model, score::not_serializable_tag)
102#else
103 void add(ChildModel_T& model)
104#endif
105 {
106 // The subclass should provide this function to construct
107 // the correct component relative to this process.
108 auto proc_comp = ParentComponent_T::make(getStrongId(model.components()), model);
109 if(proc_comp)
110 {
111 model.components().add(proc_comp);
112 m_children.emplace_back(ChildPair{&model, proc_comp});
113 }
114 }
115
116 void remove(const ChildModel_T& model)
117 {
118 auto it
119 = ossia::find_if(m_children, [&](auto pair) { return pair.model == &model; });
120
121 if(it != m_children.end())
122 {
123 cleanup(*it);
124 m_children.erase(it);
125 }
126 }
127
128 void cleanup(const ChildPair& pair)
129 {
130 ParentComponent_T::removing(*pair.model, *pair.component);
131 pair.model->components().remove(*pair.component);
132 }
133
134 void clear()
135 {
136 for(const auto& element : m_children)
137 {
138 cleanup(element);
139 }
140 m_children.clear();
141 }
142
143 ~ComponentHierarchyManager() { clear(); }
144
145private:
146 std::vector<ChildPair> m_children; // todo map ? multi_index with both index
147 // of the component and of the process ?
148};
149
159template <
160 typename ParentComponent_T, typename ChildModel_T, typename ChildComponent_T,
161 typename ChildComponentFactoryList_T, bool HasOwnership = true>
163 : public ParentComponent_T
164 , public Nano::Observer
165{
166public:
168
170 {
171 ChildPair(ChildModel_T* m, ChildComponent_T* c)
172 : model{m}
173 , component{c}
174 {
175 }
176 ChildModel_T* model{};
177 ChildComponent_T* component{};
178 };
179
180 template <typename... Args>
182 : ParentComponent_T{std::forward<Args>(args)...}
183 , m_componentFactory{
184 score::AppComponents().template interfaces<ChildComponentFactoryList_T>()}
185 {
186 init_hierarchy();
187 }
188
189 template <typename... Args>
191 : ParentComponent_T{std::forward<Args>(args)...}
192 , m_componentFactory{
193 score::AppComponents().template interfaces<ChildComponentFactoryList_T>()}
194 {
195 }
196
197 void init_hierarchy()
198 {
199 auto& child_models = ParentComponent_T::template models<ChildModel_T>();
200 for(auto& child_model : child_models)
201 {
202 add(child_model);
203 }
204
205 child_models.mutable_added.template connect<&hierarchy_t::add>(this);
206
207 child_models.removing.template connect<&hierarchy_t::remove>(this);
208 }
209 const auto& children() const { return m_children; }
210
211 void add(ChildModel_T& element)
212 {
213#if defined(SCORE_SERIALIZABLE_COMPONENTS)
214 add_impl(
215 element, typename score::is_component_serializable<ChildComponent_T>::type{});
216#else
217 add_impl(element);
218#endif
219 }
220 void remove(const ChildModel_T& model)
221 {
222 auto it
223 = ossia::find_if(m_children, [&](auto pair) { return pair.model == &model; });
224
225 if(it != m_children.end())
226 {
227 do_cleanup(*it);
228 m_children.erase(it);
229 }
230 }
231
232 void clear()
233 {
234 for(const auto& element : m_children)
235 {
236 do_cleanup(element);
237 }
238 m_children.clear();
239 }
240
241 ~PolymorphicComponentHierarchyManager() { clear(); }
242
243private:
244#if defined(SCORE_SERIALIZABLE_COMPONENTS)
245 // TODO remove these useless templates when MSVC grows some brains
246 template <typename TheChild>
247 void add_impl(TheChild& model, score::serializable_tag)
248 {
249 // Will return a factory for the given process if available
250 if(auto factory = m_componentFactory.factory(model))
251 {
252 // Since the component may be serializable, we first look if
253 // we can deserialize it.
254 ChildComponent_T* comp = score::deserialize_component<ChildComponent_T>(
255 model.components(), [&](auto&& deserializer) {
256 ParentComponent_T::template load<ChildComponent_T>(
257 deserializer, *factory, model);
258 });
259
260 // Maybe we could not deserialize it
261 if(!comp)
262 {
263 comp = ParentComponent_T::template make<ChildComponent_T>(
264 getStrongId(model.components()), *factory, model);
265 }
266
267 // We try to add it
268 if(comp)
269 {
270 model.components().add(comp);
271 m_children.emplace_back(ChildPair{&model, comp});
272 ParentComponent_T::added(*comp);
273 }
274 }
275 }
276
277 template <typename TheChild>
278 void add_impl(TheChild& model, score::not_serializable_tag)
279#else
280 template <typename TheChild>
281 void add_impl(TheChild& model)
282#endif
283 {
284 // Will return a factory for the given process if available
285 if(auto factory = m_componentFactory.factory(model))
286 {
287 // The subclass should provide this function to construct
288 // the correct component relative to this process.
289 auto comp = ParentComponent_T::make(*factory, model);
290 if(comp)
291 {
292 model.components().push_back(comp);
293 m_children.emplace_back(ChildPair{&model, comp});
294 ParentComponent_T::added(*comp);
295 }
296 }
297 else
298 {
299 auto comp = ParentComponent_T::make(model);
300 if(comp)
301 {
302 model.components().push_back(comp);
303 m_children.emplace_back(ChildPair{&model, comp});
304 ParentComponent_T::added(*comp);
305 }
306 }
307 }
308
309 void do_cleanup(const ChildPair& pair)
310 {
311 if constexpr(HasOwnership)
312 {
313 ParentComponent_T::removing(*pair.model, *pair.component);
314 pair.model->components().remove(*pair.component);
315 }
316 else
317 {
318 auto t = ParentComponent_T::removing(*pair.model, *pair.component);
319 pair.model->components().erase(*pair.component);
320 ParentComponent_T::removed(*pair.model, *pair.component, std::move(t));
321 }
322 }
323
324 const ChildComponentFactoryList_T& m_componentFactory;
325
326 std::vector<ChildPair> m_children; // todo map ? multi_index with both index
327 // of the component and of the process ?
328};
329
330template <typename Component>
331using ComponentHierarchy = ComponentHierarchyManager<
332 Component, typename Component::model_t, typename Component::component_t>;
333
334template <typename Component, bool HasOwnership = true>
335using PolymorphicComponentHierarchy = PolymorphicComponentHierarchyManager<
336 Component, typename Component::model_t, typename Component::component_t,
337 typename Component::component_factory_list_t, HasOwnership>;
338}
Manages simple hierarchies of components.
Definition ComponentHierarchy.hpp:29
Manages polymorphic hierarchies of components.
Definition ComponentHierarchy.hpp:165
Base toolkit upon which the software is built.
Definition Application.cpp:90
STL namespace.
Definition ComponentHierarchy.hpp:34
Definition ComponentHierarchy.hpp:170
Definition lib/score/model/Component.hpp:16