score-plugin-nodal/Nodal/Executor.hpp
1 #pragma once
2 #include <Process/Execution/ProcessComponent.hpp>
3 
4 #include <Nodal/Process.hpp>
5 
6 #include <score/model/ComponentHierarchy.hpp>
7 
8 #include <ossia/dataflow/node_process.hpp>
9 #include <ossia/detail/hash_map.hpp>
10 namespace Nodal
11 {
13  : public Execution::ProcessComponent_T<Nodal::Model, ossia::node_process>
14 {
15  COMPONENT_METADATA("e85e0114-2a7e-4569-8a1d-f00c9fd22960")
16 public:
21 
22  NodalExecutorBase(Model& element, const Execution::Context& ctx, QObject* parent);
23 
25 
27  {
28  std::shared_ptr<Execution::ProcessComponent> comp;
29  };
30 
31  ossia::hash_map<Id<Process::ProcessModel>, RegisteredNode> m_nodes;
32 
35 
36  ::Execution::ProcessComponent* make(Process::ProcessModel& process) { return nullptr; }
37  void added(::Execution::ProcessComponent& e);
38 
39  std::function<void()>
40  removing(const Process::ProcessModel& e, ::Execution::ProcessComponent& c);
41 
42  template <typename Component_T, typename Element, typename Fun>
43  void removed(const Element& elt, const Component_T& comp, Fun f)
44  {
45  if(f)
46  f();
47  }
48 
49  template <typename Models>
50  auto& models() const
51  {
52  static_assert(
53  std::is_same<Models, Process::ProcessModel>::value,
54  "Node component must be passed Process::ProcessModel as child.");
55 
56  return process().nodes;
57  }
58 
59 private:
60  void reg(const RegisteredNode& fx, Execution::Transaction& vec);
61  void unreg(const RegisteredNode& fx, Execution::Transaction& vec);
62 };
63 
65  : public NodalExecutorBase
66  , public Nano::Observer
67 {
68 public:
74 
75  struct ChildPair
76  {
78  : model{m}
79  , component{c}
80  {
81  }
82  ChildModel_T* model{};
83  ChildComponent_T* component{};
84  };
85 
86  template <typename... Args>
87  HierarchyManager(Args&&... args)
88  : ParentComponent_T{std::forward<Args>(args)...}
89  , m_componentFactory{
90  score::AppComponents().template interfaces<ChildComponentFactoryList_T>()}
91  {
92  init_hierarchy();
93  }
94 
95  void init_hierarchy()
96  {
97  auto& child_models = process().nodes;
98  for(auto& child_model : child_models)
99  {
100  add(child_model);
101  }
102 
103  child_models.mutable_added.template connect<&hierarchy_t::add>(this);
104 
105  child_models.removing.template connect<&hierarchy_t::remove>(this);
106  }
107 
108  const auto& children() const { return m_children; }
109 
110  void add(Process::ProcessModel& model)
111  {
112  // Will return a factory for the given process if available
113  if(auto factory = m_componentFactory.factory(model))
114  {
115  // The subclass should provide this function to construct
116  // the correct component relative to this process.
117  auto comp = this->make(*factory, model);
118  if(comp)
119  {
120  model.components().add(comp);
121  m_children.emplace_back(ChildPair{&model, comp});
122  this->added(*comp);
123  }
124  }
125  else
126  {
127  auto comp = ParentComponent_T::make(model);
128  if(comp)
129  {
130  model.components().add(comp);
131  m_children.emplace_back(ChildPair{&model, comp});
132  ParentComponent_T::added(*comp);
133  }
134  }
135  }
136 
137  void remove(const ChildModel_T& model)
138  {
139  auto it
140  = ossia::find_if(m_children, [&](auto pair) { return pair.model == &model; });
141 
142  if(it != m_children.end())
143  {
144  do_cleanup(*it);
145  m_children.erase(it);
146  }
147  }
148 
149  void clear()
150  {
151  for(const auto& element : m_children)
152  {
153  do_cleanup(element);
154  }
155  m_children.clear();
156  }
157 
158  ~HierarchyManager() { clear(); }
159 
160 private:
161  void do_cleanup(const ChildPair& pair)
162  {
163  auto t = ParentComponent_T::removing(*pair.model, *pair.component);
164  pair.model->components().erase(*pair.component);
165  ParentComponent_T::removed(*pair.model, *pair.component, std::move(t));
166  }
167 
168  const ChildComponentFactoryList_T& m_componentFactory;
169 
170  std::vector<ChildPair> m_children; // todo map ? multi_index with both index
171  // of the component and of the process ?
172 };
173 
174 class NodalExecutor final : public HierarchyManager
175 {
176 public:
177  NodalExecutor(Nodal::Model& element, const ::Execution::Context& ctx, QObject* parent)
178  : HierarchyManager{element, ctx, parent}
179  {
180  // TODO passthrough ?
181  }
182 
183  void cleanup() override;
184 
185  NodalExecutor(const NodalExecutor&) = delete;
186  NodalExecutor(NodalExecutor&&) = delete;
187  NodalExecutor& operator=(const NodalExecutor&) = delete;
188  NodalExecutor& operator=(NodalExecutor&&) = delete;
189  ~NodalExecutor();
190 };
191 
194 }
Definition: Process/Execution/ProcessComponent.hpp:119
Definition: Process/Execution/ProcessComponent.hpp:102
Definition: Process/Execution/ProcessComponent.hpp:154
Definition: Process/Execution/ProcessComponent.hpp:48
Definition: score-plugin-nodal/Nodal/Executor.hpp:67
Definition: score-plugin-nodal/Nodal/Process.hpp:14
Definition: score-plugin-nodal/Nodal/Executor.hpp:14
Definition: score-plugin-nodal/Nodal/Executor.hpp:175
The Process class.
Definition: score-lib-process/Process/Process.hpp:61
A component that has a reference to a specific context object.
Definition: lib/score/model/Component.hpp:58
Base toolkit upon which the software is built.
Definition: Application.cpp:90
Definition: ExecutionContext.hpp:76
Definition: Process/Execution/ProcessComponent.hpp:89
Definition: ExecutionTransaction.hpp:18
Definition: score-plugin-nodal/Nodal/Executor.hpp:76
Definition: score-plugin-nodal/Nodal/Executor.hpp:27