Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : /*
4 : : MIT License
5 : :
6 : : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7 : :
8 : : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : of this software and associated documentation files (the "Software"), to deal
10 : : in the Software without restriction, including without limitation the rights
11 : : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : copies of the Software, and to permit persons to whom the Software is
13 : : furnished to do so, subject to the following conditions:
14 : :
15 : : The above copyright notice and this permission notice shall be included in all
16 : : copies or substantial portions of the Software.
17 : :
18 : : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : : SOFTWARE.
25 : : */
26 : :
27 : : // ezGraph is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28 : :
29 : : #include <set>
30 : : #include <type_traits>
31 : : #include <vector>
32 : : #include <string>
33 : : #include <memory>
34 : : #include <cassert>
35 : : #include <functional>
36 : :
37 : : namespace ez {
38 : :
39 : : /////////////////////////////////////
40 : : ///// Utils /////////////////////////
41 : : /////////////////////////////////////
42 : :
43 : : namespace Utils {
44 : : // if the shared_ptr exit in the container return the iterator
45 : : template <typename T>
46 : : typename std::vector<std::shared_ptr<T>>::iterator //
47 : 11 : isSharedPtrExistInVector(const std::shared_ptr<T> &vPtr, std::vector<std::shared_ptr<T>> &vContainer) {
48 : 11 : auto ret = vContainer.end();
49 [ + - ][ + - ]: 11 : if (vPtr != nullptr) {
50 : 11 : ret = vContainer.begin();
51 [ + - ][ + + ]: 12 : for (; ret != vContainer.end(); ++ret) {
52 [ + - ][ + + ]: 7 : if (*ret == vPtr) {
53 : 6 : break;
54 : 6 : }
55 : 7 : }
56 : 11 : }
57 : 11 : return ret;
58 : 11 : }
59 : :
60 : : // if the weak_ptr exit in the container return the iterator
61 : : template <typename T>
62 : : typename std::vector<std::weak_ptr<T>>::iterator //
63 : 7 : isWeakPtrExistInVector(const std::weak_ptr<T> &vWeak, std::vector<std::weak_ptr<T>> &vContainer) {
64 : 7 : auto ret = vContainer.end();
65 [ + - ][ + - ]: 7 : if (!vWeak.expired()) {
66 : 7 : auto ptr = vWeak.lock();
67 : 7 : ret = vContainer.begin();
68 [ + - ][ + + ]: 7 : for (; ret != vContainer.end(); ++ret) {
69 [ + - ][ + - ]: 6 : if (ret->lock() == ptr) {
70 : 6 : break;
71 : 6 : }
72 : 6 : }
73 : 7 : }
74 : 7 : return ret;
75 : 7 : }
76 : : } // namespace Utils
77 : :
78 : : /////////////////////////////////////
79 : : ///// DEFS //////////////////////////
80 : : /////////////////////////////////////
81 : :
82 : : enum class SlotDir { INPUT = 0, OUTPUT, Count };
83 : : enum class RetCodes {
84 : : SUCCESS = 0,
85 : : FAILED,
86 : : FAILED_GRAPH_PTR_NULL,
87 : : FAILED_SLOT_PTR_NULL,
88 : : FAILED_SLOT_ALREADY_EXIST,
89 : : FAILED_SLOT_NOT_FOUND,
90 : : FAILED_NODE_PTR_NULL,
91 : : FAILED_NODE_ALREADY_EXIST,
92 : : FAILED_NODE_NOT_FOUND,
93 : : Count
94 : : };
95 : :
96 : : class Slot;
97 : : typedef std::shared_ptr<Slot> SlotPtr;
98 : : typedef std::weak_ptr<Slot> SlotWeak;
99 : :
100 : : class Node;
101 : : typedef std::shared_ptr<Node> NodePtr;
102 : : typedef std::weak_ptr<Node> NodeWeak;
103 : :
104 : : class Graph;
105 : : typedef std::shared_ptr<Graph> GraphPtr;
106 : : typedef std::weak_ptr<Graph> GraphWeak;
107 : :
108 : : typedef uintptr_t Uuid;
109 : :
110 : : typedef void *UserDatas;
111 : :
112 : : /////////////////////////////////////
113 : : ///// UUID //////////////////////////
114 : : /////////////////////////////////////
115 : :
116 : : class UUID {
117 : : Uuid m_Uuid = 0U;
118 : :
119 : : public:
120 : 9 : explicit UUID(void *vPtr) { m_Uuid = reinterpret_cast<Uuid>(vPtr); }
121 : 9 : virtual ~UUID() = default;
122 : : template <typename T = Uuid>
123 : 8 : T getUuid() const {
124 : 8 : return static_cast<T>(m_Uuid);
125 : 8 : }
126 : 8 : virtual void setUuid(const Uuid vUUID) {
127 : 8 : m_Uuid = vUUID;
128 : 8 : }
129 : : };
130 : :
131 : : /////////////////////////////////////
132 : : ///// SLOT //////////////////////////
133 : : /////////////////////////////////////
134 : :
135 : : struct SlotDatas {
136 : : std::string name;
137 : : std::string type;
138 : : UserDatas userDatas = nullptr;
139 : : SlotDir dir = SlotDir::INPUT;
140 : 2 : SlotDatas() = default;
141 : : SlotDatas(const std::string &vName, const std::string &vType, const SlotDir vSlotDir, UserDatas vUserDatas = nullptr)
142 : 0 : : name(std::move(vName)), type(std::move(vType)), userDatas(vUserDatas), dir(vSlotDir) {}
143 : : };
144 : :
145 : : struct EvalDatas {
146 : : size_t frame = 0U;
147 : : };
148 : :
149 : : class Slot : public UUID {
150 : : friend class Node;
151 : : friend class Graph;
152 : :
153 : : protected:
154 : : SlotWeak m_This;
155 : : NodeWeak m_ParentNode;
156 : : std::shared_ptr<SlotDatas> mp_SlotDatas;
157 : : std::vector<SlotWeak> m_ConnectedSlots;
158 : : EvalDatas m_LastEvaluatedDatas;
159 : :
160 : : public:
161 : 0 : Slot() : UUID(this) {}
162 : : template <typename T = SlotDatas>
163 : 5 : explicit Slot(const T &vDatas) : UUID(this), mp_SlotDatas(std::make_shared<T>(vDatas)) {
164 : 5 : static_assert(std::is_base_of<SlotDatas, T>::value, "T must derive of ez::SlotDatas");
165 : 5 : }
166 : 5 : ~Slot() override { unit(); }
167 : :
168 : 5 : virtual bool init() {
169 : : //assert(!m_This.expired() && "m_This msut be defined with m_setThis during the creation");
170 : 5 : return true;
171 : 5 : }
172 : 8 : virtual void unit() {
173 : : // we must rsdet slots
174 : 8 : m_ConnectedSlots.clear();
175 : : // befaore datas
176 : 8 : mp_SlotDatas.reset();
177 : 8 : }
178 : :
179 : : template <typename T = SlotDatas>
180 : 5 : const T &getDatas() const {
181 : : // remove the need to use a slow dynamic_cast
182 : 5 : static_assert(std::is_base_of<SlotDatas, T>::value, "T must derive of ez::SlotDatas");
183 : 5 : return static_cast<const T &>(*mp_SlotDatas);
184 : 5 : }
185 : :
186 : : template <typename T = SlotDatas>
187 : : T &getDatasRef() {
188 : : // remove the need to use a slow dynamic_cast
189 : : static_assert(std::is_base_of<SlotDatas, T>::value, "T must derive of ez::SlotDatas");
190 : : return static_cast<T &>(*mp_SlotDatas);
191 : : }
192 : :
193 : 5 : void setParentNode(NodeWeak vNodeWeak) { m_ParentNode = std::move(vNodeWeak); }
194 : : template <typename T = Node>
195 : 3 : std::weak_ptr<T> getParentNode() {
196 : : // remove the need to use a slow dynamic_cast
197 : 3 : static_assert(std::is_base_of<Node, T>::value, "T must derive of ez::Node");
198 : 3 : return std::static_pointer_cast<T>(m_ParentNode.lock());
199 : 3 : }
200 : 2 : const std::vector<SlotWeak> &m_getConnectedSlots() { return m_ConnectedSlots; }
201 : 1 : void setLastEvaluatedDatas(const EvalDatas vUserDatas) { m_LastEvaluatedDatas = vUserDatas; }
202 : 1 : const EvalDatas &getLastEvaluatedDatas() const { return m_LastEvaluatedDatas; }
203 : :
204 : : protected:
205 : : template <typename T = Slot>
206 : : std::weak_ptr<T> m_getThis() {
207 : : static_assert(std::is_base_of<Slot, T>::value, "T must derive of ez::Slot");
208 : : assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
209 : : return std::static_pointer_cast<T>(m_This.lock());
210 : : }
211 : 5 : void m_setThis(const SlotWeak &vThis) { m_This = vThis; }
212 : :
213 : : template <typename T = SlotDatas>
214 : : explicit Slot(std::shared_ptr<T> vpDatas) : UUID(this), mp_SlotDatas(std::move(vpDatas)) {
215 : : static_assert(std::is_base_of<SlotDatas, T>::value, "T must derive of ez::SlotDatas");
216 : : }
217 : :
218 : 4 : RetCodes m_connectSlot(const SlotWeak &vSlot) {
219 : 4 : auto ret = RetCodes::FAILED_SLOT_PTR_NULL;
220 [ + - ]: 4 : if (!vSlot.expired()) {
221 : 4 : m_ConnectedSlots.push_back(vSlot);
222 : 4 : ret = RetCodes::SUCCESS;
223 : 4 : }
224 : 4 : return ret;
225 : 4 : }
226 : :
227 : 0 : RetCodes m_disconnectSlot(const SlotWeak &vSlot) {
228 : 0 : auto ret = RetCodes::FAILED_SLOT_ALREADY_EXIST;
229 : 0 : const auto it = Utils::isWeakPtrExistInVector(vSlot, m_ConnectedSlots);
230 : 0 : if (it != m_ConnectedSlots.end()) {
231 : 0 : m_ConnectedSlots.erase(it);
232 : 0 : ret = RetCodes::SUCCESS;
233 : 0 : }
234 : 0 : return ret;
235 : 0 : }
236 : :
237 : 0 : void m_disconnect() { m_ConnectedSlots.clear(); }
238 : : };
239 : :
240 : : /////////////////////////////////////
241 : : ///// NODE //////////////////////////
242 : : /////////////////////////////////////
243 : :
244 : : struct NodeDatas {
245 : : std::string name;
246 : : std::string type;
247 : : UserDatas userDatas = nullptr;
248 : : NodeDatas() = default;
249 : : NodeDatas(const std::string &vName, const std::string &vType, UserDatas vUserDatas = nullptr)
250 : 3 : : name(std::move(vName)), type(std::move(vType)), userDatas(vUserDatas) {}
251 : : };
252 : :
253 : : class Node : public UUID {
254 : : friend class Graph;
255 : : NodeWeak m_This;
256 : : GraphWeak m_ParentGraph;
257 : : bool dirty = false;
258 : : std::shared_ptr<NodeDatas> mp_NodeDatas;
259 : : std::vector<SlotPtr> m_Inputs;
260 : : std::vector<SlotWeak> m_InputWeaks;
261 : : std::vector<SlotPtr> m_Outputs;
262 : : std::vector<SlotWeak> m_OutputWeaks;
263 : :
264 : : public:
265 : 0 : Node() : UUID(this) {}
266 : : template <typename T = NodeDatas>
267 : 3 : explicit Node(const T &vDatas) : UUID(this), mp_NodeDatas(std::make_shared<T>(vDatas)) {
268 : 3 : static_assert(std::is_base_of<NodeDatas, T>::value, "T must derive of ez::NodeDatas");
269 : 3 : }
270 : 3 : ~Node() override { unit(); }
271 : :
272 : 6 : virtual bool init() {
273 : : //assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
274 : 6 : return true;
275 : 6 : }
276 : 6 : virtual void unit() {
277 : : // we must reset slots
278 : 6 : m_Inputs.clear();
279 : 6 : m_InputWeaks.clear();
280 : 6 : m_Outputs.clear();
281 : 6 : m_OutputWeaks.clear();
282 : : // before reset this ans parentGraph
283 : 6 : m_This.reset();
284 : 6 : m_ParentGraph.reset();
285 : 6 : mp_NodeDatas.reset();
286 : 6 : }
287 : :
288 : : // Datas
289 : 3 : void setParentGraph(const GraphWeak &vParentGraph) { m_ParentGraph = vParentGraph; }
290 : : template <typename T = Graph>
291 : : std::weak_ptr<T> getParentGraph() {
292 : : // remove the need to use a slow dynamic_cast
293 : : static_assert(std::is_base_of<Graph, T>::value, "T must derive of ez::Graph");
294 : : return std::static_pointer_cast<T>(m_ParentGraph.lock());
295 : : }
296 : :
297 : : template <typename T = NodeDatas>
298 : 12 : const T &getDatas() const {
299 : : // remove the need to use a slow dynamic_cast
300 : 12 : static_assert(std::is_base_of<NodeDatas, T>::value, "T must derive of ez::NodeDatas");
301 : 12 : return static_cast<const T &>(*mp_NodeDatas);
302 : 12 : }
303 : :
304 : : template <typename T = NodeDatas>
305 : 3 : T &getDatasRef() {
306 : : // remove the need to use a slow dynamic_cast
307 : 3 : static_assert(std::is_base_of<NodeDatas, T>::value, "T must derive of ez::NodeDatas");
308 : 3 : return static_cast<T &>(*mp_NodeDatas);
309 : 3 : }
310 : 0 : void setDirty(const bool vFlag) { dirty = vFlag; }
311 : 0 : bool isDirty() const { return dirty; }
312 : :
313 : : protected: // Node
314 : : template <typename T = Node>
315 : 5 : std::weak_ptr<T> m_getThis() {
316 : 5 : static_assert(std::is_base_of<Node, T>::value, "T must derive of ez::Node");
317 : 5 : assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
318 : 5 : return std::static_pointer_cast<T>(m_This.lock());
319 : 5 : }
320 : 6 : void m_setThis(const NodeWeak &vThis) { m_This = vThis; }
321 : :
322 : 0 : void m_setSlotThis(SlotPtr vSlotPtr) {
323 : 0 : if (vSlotPtr != nullptr) {
324 : 0 : vSlotPtr->m_setThis(vSlotPtr);
325 : 0 : }
326 : 0 : }
327 : :
328 : : template <typename T = NodeDatas>
329 : : explicit Node(std::shared_ptr<T> vpDatas) : UUID(this), mp_NodeDatas(std::move(vpDatas)) {
330 : : static_assert(std::is_base_of<NodeDatas, T>::value, "T must derive of ez::NodeDatas");
331 : : }
332 : :
333 : : // Slots
334 : 10 : RetCodes m_addSlot(const SlotPtr &vSlotPtr) {
335 : 10 : auto ret = RetCodes::FAILED;
336 [ + + ]: 10 : if (vSlotPtr != nullptr) {
337 : 5 : vSlotPtr->m_setThis(vSlotPtr);
338 : 5 : vSlotPtr->setUuid(vSlotPtr->getUuid()); // call the virtual setUuid for derived classes
339 : 5 : const auto &datas = vSlotPtr->getDatas<SlotDatas>();
340 [ + + ]: 5 : if (datas.dir == SlotDir::INPUT) {
341 : 2 : const auto it = Utils::isSharedPtrExistInVector(vSlotPtr, m_Inputs);
342 [ + - ]: 2 : if (it == m_Inputs.end()) {
343 : 2 : vSlotPtr->setParentNode(m_getThis());
344 : 2 : m_Inputs.push_back(vSlotPtr);
345 : 2 : m_InputWeaks.push_back(vSlotPtr);
346 : 2 : ret = RetCodes::SUCCESS;
347 : 2 : } else {
348 : 0 : ret = RetCodes::FAILED_SLOT_ALREADY_EXIST;
349 : 0 : }
350 [ + - ]: 3 : } else if (datas.dir == SlotDir::OUTPUT) {
351 : 3 : const auto it = Utils::isSharedPtrExistInVector(vSlotPtr, m_Outputs);
352 [ + - ]: 3 : if (it == m_Outputs.end()) {
353 : 3 : vSlotPtr->setParentNode(m_getThis());
354 : 3 : m_Outputs.push_back(vSlotPtr);
355 : 3 : m_OutputWeaks.push_back(vSlotPtr);
356 : 3 : ret = RetCodes::SUCCESS;
357 : 3 : } else {
358 : 0 : ret = RetCodes::FAILED_SLOT_ALREADY_EXIST;
359 : 0 : }
360 : 3 : }
361 : 5 : }
362 : 10 : return ret;
363 : 10 : }
364 : :
365 : : template <typename T = Slot>
366 : : std::shared_ptr<T> m_addSlot(const SlotDatas &vSlotDatas, RetCodes *vOutRetCodes) {
367 : : static_assert(std::is_base_of<Slot, T>::value, "T must derive of ez::Slot");
368 : : if (vOutRetCodes != nullptr) {
369 : : *vOutRetCodes = RetCodes::FAILED_NODE_PTR_NULL;
370 : : }
371 : : auto slot_ptr = std::make_shared<T>(vSlotDatas);
372 : : const auto ret_code = m_addSlot(slot_ptr);
373 : : if (vOutRetCodes != nullptr) {
374 : : *vOutRetCodes = ret_code;
375 : : }
376 : : return slot_ptr;
377 : : }
378 : :
379 : 3 : RetCodes m_delSlot(const SlotWeak &vSlot) {
380 : 3 : auto ret = m_delInputSlot(vSlot);
381 [ + + ]: 3 : if (ret != RetCodes::SUCCESS) {
382 : 1 : ret = m_delOutputSlot(vSlot);
383 : 1 : }
384 : 3 : return ret;
385 : 3 : }
386 : :
387 : 3 : RetCodes m_delInputSlot(const SlotWeak &vSlot) {
388 : 3 : auto ret = RetCodes::FAILED_SLOT_NOT_FOUND;
389 : : // we must detroy the weak before the related shared ptr
390 : 3 : auto itWeak = Utils::isWeakPtrExistInVector(vSlot, m_InputWeaks);
391 [ + + ]: 3 : if (itWeak != m_InputWeaks.end()) {
392 : 2 : m_InputWeaks.erase(itWeak);
393 : : // so next, the shared ptr
394 : 2 : auto itShared = Utils::isSharedPtrExistInVector(vSlot.lock(), m_Inputs);
395 [ + - ]: 2 : if (itShared != m_Inputs.end()) {
396 : 2 : itShared->get()->unit();
397 : 2 : m_Inputs.erase(itShared);
398 : 2 : ret = RetCodes::SUCCESS;
399 : 2 : }
400 : 2 : }
401 : 3 : return ret;
402 : 3 : }
403 : :
404 : 1 : RetCodes m_delOutputSlot(const SlotWeak &vSlot) {
405 : 1 : auto ret = RetCodes::FAILED_SLOT_NOT_FOUND;
406 : : // we must detroy the weak before the related shared ptr
407 : 1 : auto itWeak = Utils::isWeakPtrExistInVector(vSlot, m_OutputWeaks);
408 [ + - ]: 1 : if (itWeak != m_OutputWeaks.end()) {
409 : 1 : m_OutputWeaks.erase(itWeak);
410 : : // so next, the shared ptr
411 : 1 : const auto itShared = Utils::isSharedPtrExistInVector(vSlot.lock(), m_Outputs);
412 [ + - ]: 1 : if (itShared != m_Outputs.end()) {
413 : 1 : itShared->get()->unit();
414 : 1 : m_Outputs.erase(itShared);
415 : 1 : ret = RetCodes::SUCCESS;
416 : 1 : }
417 : 1 : }
418 : 1 : return ret;
419 : 1 : }
420 : :
421 : 0 : const std::vector<SlotWeak> &m_getInputSlots() { return m_InputWeaks; }
422 : 1 : std::vector<SlotWeak> &m_getInputSlotsRef() { return m_InputWeaks; }
423 : :
424 : 0 : const std::vector<SlotWeak> &m_getOutputSlots() { return m_OutputWeaks; }
425 : 0 : std::vector<SlotWeak> &m_getOutputSlotsRef() { return m_OutputWeaks; }
426 : : };
427 : :
428 : : /////////////////////////////////////
429 : : ///// GRAPH /////////////////////////
430 : : /////////////////////////////////////
431 : :
432 : : struct GraphDatas {
433 : : std::string name;
434 : : std::string type;
435 : : UserDatas userDatas = nullptr;
436 : : GraphDatas() = default;
437 : : GraphDatas(const std::string &vName, const std::string &vType, UserDatas vUserDatas = nullptr)
438 : 1 : : name(std::move(vName)), type(std::move(vType)), userDatas(vUserDatas) {}
439 : : };
440 : :
441 : : class Graph : public UUID {
442 : : GraphWeak m_This;
443 : : NodeWeak m_ParentNode;
444 : : bool dirty = false;
445 : : std::shared_ptr<GraphDatas> mp_GraphDatas;
446 : : std::vector<NodePtr> m_Nodes;
447 : : std::vector<NodeWeak> m_NodeWeaks;
448 : :
449 : : public:
450 : 0 : Graph() : UUID(this) {}
451 : : template <typename T = GraphDatas>
452 : 1 : explicit Graph(const T &vDatas) : UUID(this), mp_GraphDatas(std::make_shared<T>(vDatas)) {
453 : 1 : static_assert(std::is_base_of<GraphDatas, T>::value, "T must derive of ez::GraphDatas");
454 : 1 : }
455 : 1 : ~Graph() override { unit(); }
456 : :
457 : 1 : virtual bool init() {
458 : : //assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
459 : 1 : return true;
460 : 1 : }
461 : 1 : virtual void unit() {
462 : 1 : m_This.reset();
463 : 1 : m_ParentNode.reset();
464 : 1 : mp_GraphDatas.reset();
465 : 1 : clear();
466 : 1 : }
467 : :
468 : 1 : virtual void clear() {
469 : 1 : m_Nodes.clear();
470 : 1 : m_NodeWeaks.clear();
471 : 1 : }
472 : :
473 : : // Datas
474 : 0 : void setParentNode(const NodeWeak &vParentNode) { m_ParentNode = vParentNode; }
475 : : template <typename T = Node>
476 : : std::weak_ptr<T> getParentNode() {
477 : : // remove the need to use a slow dynamic_cast
478 : : static_assert(std::is_base_of<Node, T>::value, "T must derive of ez::Node");
479 : : return std::static_pointer_cast<T>(m_ParentNode.lock());
480 : : }
481 : :
482 : : template <typename T = GraphDatas>
483 : 7 : const T &getDatas() const {
484 : : // remove the need to use a slow dynamic_cast
485 : 7 : static_assert(std::is_base_of<GraphDatas, T>::value, "T must derive of ez::GraphDatas");
486 : 7 : return static_cast<const T &>(*mp_GraphDatas);
487 : 7 : }
488 : :
489 : : template <typename T = GraphDatas>
490 : 1 : T &getDatasRef() {
491 : : // remove the need to use a slow dynamic_cast
492 : 1 : static_assert(std::is_base_of<GraphDatas, T>::value, "T must derive of ez::GraphDatas");
493 : 1 : return static_cast<T &>(*mp_GraphDatas);
494 : 1 : }
495 : :
496 : 0 : const std::vector<NodeWeak> &getNodes() const { return m_NodeWeaks; }
497 : 0 : std::vector<NodeWeak> &getNodesRef() { return m_NodeWeaks; }
498 : :
499 : 0 : void setDirty(const bool vFlag) { dirty = vFlag; }
500 : 0 : bool isDirty() const { return dirty; }
501 : :
502 : : protected: // Node
503 : : template <typename T = Graph>
504 : 3 : std::weak_ptr<T> m_getThis() {
505 : 3 : static_assert(std::is_base_of<Graph, T>::value, "T must derive of ez::Graph");
506 : 3 : assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
507 : 3 : return std::static_pointer_cast<T>(m_This.lock());
508 : 3 : }
509 : 1 : void m_setThis(const GraphWeak &vThis) { m_This = vThis; }
510 : :
511 : 0 : void m_setNodeThis(NodePtr vNodePtr) {
512 : 0 : if (vNodePtr != nullptr) {
513 : 0 : vNodePtr->m_setThis(vNodePtr);
514 : 0 : }
515 : 0 : }
516 : :
517 : : template <typename T = GraphDatas>
518 : : explicit Graph(std::shared_ptr<T> vpDatas) : UUID(this), mp_GraphDatas(std::move(vpDatas)) {
519 : : static_assert(std::is_base_of<GraphDatas, T>::value, "T must derive of ez::GraphDatas");
520 : : }
521 : :
522 : 6 : RetCodes m_addNode(const NodePtr &vNodePtr) {
523 : 6 : auto ret = RetCodes::FAILED_NODE_PTR_NULL;
524 [ + + ]: 6 : if (vNodePtr != nullptr) {
525 : 3 : vNodePtr->m_setThis(vNodePtr);
526 : 3 : vNodePtr->setUuid(vNodePtr->getUuid()); // call the virtual setUuid for derived classes
527 : 3 : vNodePtr->setParentGraph(m_getThis());
528 : 3 : m_Nodes.push_back(vNodePtr);
529 : 3 : m_NodeWeaks.push_back(vNodePtr);
530 : 3 : ret = RetCodes::SUCCESS;
531 : 3 : }
532 : 6 : return ret;
533 : 6 : }
534 : :
535 : 3 : RetCodes m_delNode(const NodeWeak &vNode) {
536 : 3 : auto ret = RetCodes::FAILED_NODE_NOT_FOUND;
537 : 3 : const auto itShared = Utils::isSharedPtrExistInVector(vNode.lock(), m_Nodes);
538 [ + - ]: 3 : if (itShared != m_Nodes.end()) {
539 : 3 : itShared->get()->unit();
540 : 3 : m_Nodes.erase(itShared);
541 : 3 : auto itWeak = Utils::isWeakPtrExistInVector(vNode, m_NodeWeaks);
542 [ + - ]: 3 : if (itWeak != m_NodeWeaks.end()) {
543 : 3 : m_NodeWeaks.erase(itWeak);
544 : 3 : ret = RetCodes::SUCCESS;
545 : 3 : }
546 : 3 : }
547 : 3 : return ret;
548 : 3 : }
549 : :
550 : 4 : static RetCodes m_connectSlots(const SlotWeak &vFrom, const SlotWeak &vTo) {
551 : 4 : auto ret = RetCodes::FAILED_SLOT_PTR_NULL;
552 [ + + ][ + + ]: 4 : if (!vFrom.expired() && !vTo.expired()) {
553 : 2 : const auto fromPtr = vFrom.lock();
554 : 2 : const auto toPtr = vTo.lock();
555 [ + - ][ + - ]: 2 : if (fromPtr != nullptr && toPtr != nullptr) {
556 : 2 : ret = fromPtr->m_connectSlot(vTo);
557 [ + - ]: 2 : if (ret == RetCodes::SUCCESS) {
558 : 2 : ret = toPtr->m_connectSlot(vFrom);
559 [ - + ]: 2 : if (ret != RetCodes::SUCCESS) {
560 : 0 : fromPtr->m_connectSlot(vTo);
561 : 0 : }
562 : 2 : }
563 : 2 : }
564 : 2 : }
565 : 4 : return ret;
566 : 4 : }
567 : :
568 : 0 : static RetCodes m_disconnectSlots(const SlotWeak &vFrom, const SlotWeak &vTo) {
569 : 0 : auto ret = RetCodes::FAILED_SLOT_PTR_NULL;
570 : 0 : const auto fromPtr = vFrom.lock();
571 : 0 : const auto toPtr = vTo.lock();
572 : 0 : if (fromPtr != nullptr) {
573 : 0 : ret = fromPtr->m_disconnectSlot(vTo);
574 : 0 : }
575 : 0 : if (toPtr != nullptr) {
576 : 0 : ret = toPtr->m_disconnectSlot(vFrom);
577 : 0 : }
578 : 0 : return ret;
579 : 0 : }
580 : : };
581 : :
582 : : } // namespace ez
|