INSTINCT Code Coverage Report


Directory: src/
File: internal/Node/Node.cpp
Date: 2025-07-19 10:51:51
Exec Total Coverage
Lines: 340 542 62.7%
Functions: 35 55 63.6%
Branches: 368 861 42.7%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "Node.hpp"
10
11 #include <stdexcept>
12
13 #include "util/Logger.hpp"
14 #include "util/StringUtil.hpp"
15 #include "util/Assert.h"
16
17 #include "internal/FlowExecutor.hpp"
18 #include "internal/gui/FlowAnimation.hpp"
19 #include "internal/NodeManager.hpp"
20 namespace nm = NAV::NodeManager;
21 #include "util/Json.hpp"
22 #include "internal/gui/NodeEditorApplication.hpp"
23
24 #include <imgui_node_editor.h>
25 namespace ed = ax::NodeEditor;
26 #ifdef TESTING
27 #include <catch2/catch_test_macros.hpp>
28 #endif
29
30 6855 NAV::Node::Node(std::string name)
31
1/2
✓ Branch 14 taken 6855 times.
✗ Branch 15 not taken.
6855 : name(std::move(name))
32 {
33 LOG_TRACE("{}: called", nameId());
34
2/2
✓ Branch 0 taken 357 times.
✓ Branch 1 taken 6498 times.
6855 if (_autostartWorker)
35 {
36
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 _worker = std::thread(workerThread, this);
37 }
38 6855 }
39
40 13706 NAV::Node::~Node()
41 {
42 LOG_TRACE("{}: called", nameId());
43
44
2/2
✓ Branch 0 taken 355 times.
✓ Branch 1 taken 6498 times.
13706 if (_autostartWorker)
45 {
46 710 _state = State::DoShutdown;
47 710 wakeWorker();
48
49 // // wait for the worker
50 // {
51 // std::unique_lock lk(_workerMutex);
52 // _workerConditionVariable.wait(lk, [&, this] { return _state == State::Shutdown; });
53 // }
54 710 _worker.join();
55 }
56 13706 }
57
58 void NAV::Node::guiConfig() {}
59
60 json NAV::Node::save() const { return {}; }
61
62 53 void NAV::Node::restore(const json& /*j*/) {}
63
64 315 void NAV::Node::restoreAtferLink(const json& /*j*/) {}
65
66 158 bool NAV::Node::initialize()
67 {
68 158 return true;
69 }
70
71 92 void NAV::Node::deinitialize() {}
72
73 334 void NAV::Node::flush() {}
74
75 333 bool NAV::Node::resetNode()
76 {
77 LOG_TRACE("{}: called", nameId());
78
79 333 return initialize();
80 }
81
82 554 bool NAV::Node::onCreateLink(OutputPin& /*startPin*/, InputPin& /*endPin*/)
83 {
84 554 return true;
85 }
86
87 583 void NAV::Node::onDeleteLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {}
88
89 490 void NAV::Node::afterCreateLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {}
90
91 538 void NAV::Node::afterDeleteLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {}
92
93 void NAV::Node::notifyOutputValueChanged(size_t pinIdx, const InsTime& insTime, const std::scoped_lock<std::mutex>&& /* guard */)
94 {
95 if (callbacksEnabled && isInitialized())
96 {
97 auto& outputPin = outputPins.at(pinIdx);
98
99 if (!outputPin.isPinLinked()) { return; }
100
101 for (auto& link : outputPin.links)
102 {
103 auto* targetPin = link.getConnectedPin();
104 if (link.connectedNode->isInitialized() && !targetPin->queueBlocked)
105 {
106 outputPin.dataAccessCounter++;
107 link.dataChangeNotification = true;
108 LOG_DATA("{}: Increasing data access counter on output pin '{}'. Value now {}.", nameId(), outputPin.name, outputPin.dataAccessCounter);
109
110 if (nm::showFlowWhenNotifyingValueChange)
111 {
112 FlowAnimation::Add(link.linkId);
113 }
114
115 auto data = std::make_shared<NodeData>();
116 data->insTime = insTime;
117
118 targetPin->queue.push_back(data);
119 }
120 }
121 for (const auto& link : outputPin.links)
122 {
123 auto* targetPin = link.getConnectedPin();
124 if (link.connectedNode->isInitialized() && !targetPin->queueBlocked)
125 {
126 LOG_DATA("{}: Waking up worker of node '{}'. New data on pin '{}'", nameId(), link.connectedNode->nameId(), targetPin->name);
127 link.connectedNode->wakeWorker();
128 }
129 }
130 }
131 }
132
133 150 std::scoped_lock<std::mutex> NAV::Node::requestOutputValueLock(size_t pinIdx)
134 {
135 150 auto& outputPin = outputPins.at(pinIdx);
136 {
137
1/2
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
150 std::unique_lock<std::mutex> lk(outputPin.dataAccessMutex);
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 150 times.
150 if (outputPin.dataAccessCounter > 0)
139 {
140 LOG_DATA("{}: Requesting lock on output pin '{}', {} threads accessing still.", nameId(), outputPin.name, outputPin.dataAccessCounter);
141 outputPin.dataAccessConditionVariable.wait(lk, [&outputPin]() { return outputPin.dataAccessCounter == 0; });
142 LOG_DATA("{}: Lock on output pin '{}' acquired.", nameId(), outputPin.name);
143 }
144 150 }
145 150 return std::scoped_lock(outputPin.dataAccessMutex);
146 }
147
148 void NAV::Node::releaseInputValue(size_t portIndex)
149 {
150 if (OutputPin* outputPin = inputPins.at(portIndex).link.getConnectedPin())
151 {
152 std::scoped_lock<std::mutex> lk(outputPin->dataAccessMutex);
153 if (outputPin->dataAccessCounter > 0)
154 {
155 auto outgoingLink = std::ranges::find_if(outputPin->links, [&](const OutputPin::OutgoingLink& link) {
156 return link.connectedPinId == inputPins.at(portIndex).id;
157 });
158 if (outgoingLink != outputPin->links.end() && outgoingLink->dataChangeNotification)
159 {
160 outgoingLink->dataChangeNotification = false;
161 outputPin->dataAccessCounter--;
162
163 if (outputPin->dataAccessCounter == 0)
164 {
165 LOG_DATA("{}: Notifying node '{}' connected to pin {} that all data is read.", nameId(), outputPin->parentNode->nameId(), outputPin->name);
166 outputPin->dataAccessConditionVariable.notify_all();
167 }
168 }
169 }
170 }
171 }
172
173 bool NAV::Node::hasInputPinWithSameTime(const InsTime& insTime) const
174 {
175 return std::ranges::any_of(inputPins, [&insTime](const InputPin& pin) {
176 return !pin.queue.empty() && pin.queue.front()->insTime == insTime;
177 });
178 }
179
180 370881 void NAV::Node::invokeCallbacks(size_t portIndex, const std::shared_ptr<const NAV::NodeData>& data)
181 {
182
1/2
✓ Branch 0 taken 370882 times.
✗ Branch 1 not taken.
370881 if (callbacksEnabled)
183 {
184
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 370666 times.
370882 if (data == nullptr)
185 {
186 LOG_DEBUG("{}: Tried to invokeCallbacks on pin {} with a nullptr, which is not allowed!!!", nameId(), portIndex);
187 return;
188 }
189
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 370669 times.
370666 if (data->insTime.empty())
190 {
191 LOG_DATA("{}: Tried to invokeCallbacks on pin {} without a InsTime. The time is mandatory though!!! ", nameId(), portIndex);
192 return;
193 }
194
195
3/4
✓ Branch 1 taken 370376 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 555650 times.
✓ Branch 9 taken 370881 times.
927224 for (const auto& link : outputPins.at(portIndex).links)
196 {
197
1/2
✓ Branch 1 taken 556439 times.
✗ Branch 2 not taken.
555784 auto* targetPin = link.getConnectedPin();
198
7/8
✓ Branch 1 taken 556493 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 508058 times.
✓ Branch 4 taken 48435 times.
✓ Branch 5 taken 481258 times.
✓ Branch 6 taken 26800 times.
✓ Branch 7 taken 481258 times.
✓ Branch 8 taken 75235 times.
556439 if (link.connectedNode->isInitialized() && !targetPin->queueBlocked)
199 {
200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 481258 times.
481258 if (NodeManager::showFlowWhenNotifyingValueChange)
201 {
202 FlowAnimation::Add(link.linkId);
203 }
204
205
1/2
✓ Branch 1 taken 481060 times.
✗ Branch 2 not taken.
481258 targetPin->queue.push_back(data);
206 LOG_DATA("{}: Waking up worker of node {}. New data on pin '{}'", nameId(), size_t(link.connectedNode->id), targetPin->name);
207
1/2
✓ Branch 1 taken 481320 times.
✗ Branch 2 not taken.
481060 link.connectedNode->wakeWorker();
208 }
209 }
210 }
211 }
212
213 NAV::InputPin& NAV::Node::inputPinFromId(ax::NodeEditor::PinId pinId)
214 {
215 for (auto& inputPin : inputPins)
216 {
217 if (pinId == inputPin.id) { return inputPin; }
218 }
219
220 throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str());
221 }
222
223 NAV::OutputPin& NAV::Node::outputPinFromId(ax::NodeEditor::PinId pinId)
224 {
225 for (auto& outputPin : outputPins)
226 {
227 if (pinId == outputPin.id) { return outputPin; }
228 }
229
230 throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str());
231 }
232
233 83 size_t NAV::Node::inputPinIndexFromId(ax::NodeEditor::PinId pinId) const
234 {
235
1/2
✓ Branch 1 taken 179 times.
✗ Branch 2 not taken.
179 for (size_t i = 0; i < inputPins.size(); i++)
236 {
237
2/2
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 96 times.
179 if (pinId == inputPins.at(i).id) { return i; }
238 }
239
240 throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str());
241 }
242
243 7 size_t NAV::Node::outputPinIndexFromId(ax::NodeEditor::PinId pinId) const
244 {
245
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 for (size_t i = 0; i < outputPins.size(); i++)
246 {
247
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 if (pinId == outputPins.at(i).id) { return i; }
248 }
249
250 throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str());
251 }
252
253 134399 std::string NAV::Node::nameId() const
254 {
255
6/12
✓ Branch 1 taken 134395 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 134394 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 134392 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 134400 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 134396 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 134395 times.
✗ Branch 17 not taken.
671976 return fmt::format("{} ({})", str::replaceAll_copy(name, "\n", ""), size_t(id));
256 }
257
258 const ImVec2& NAV::Node::getSize() const
259 {
260 return _size;
261 }
262
263 698 std::string NAV::Node::toString(State state)
264 {
265
2/10
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 352 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 350 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
698 switch (state)
266 {
267 case State::Disabled:
268 return "Disabled";
269 case State::Deinitialized:
270 return "Deinitialized";
271 352 case State::DoInitialize:
272
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
702 return "DoInitialize";
273 case State::Initializing:
274 return "Initializing";
275 case State::Initialized:
276 return "Initialized";
277 350 case State::DoDeinitialize:
278
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
700 return "DoDeinitialize";
279 case State::Deinitializing:
280 return "Deinitializing";
281 case State::DoShutdown:
282 return "DoShutdown";
283 case State::Shutdown:
284 return "Shutdown";
285 }
286 return "";
287 }
288
289 NAV::Node::State NAV::Node::getState() const
290 {
291 std::scoped_lock lk(_stateMutex);
292 return _state;
293 }
294
295 8 NAV::Node::Mode NAV::Node::getMode() const
296 {
297 8 return _mode;
298 }
299
300 526 bool NAV::Node::doInitialize(bool wait)
301 {
302
1/2
✓ Branch 1 taken 526 times.
✗ Branch 2 not taken.
526 std::unique_lock<std::mutex> lk(_stateMutex);
303 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
304
305
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 174 times.
✓ Branch 4 taken 352 times.
✗ Branch 5 not taken.
526 switch (_state)
306 {
307 case State::Initialized:
308 lk.unlock();
309 return true;
310 case State::Disabled:
311 case State::DoShutdown:
312 case State::Shutdown:
313 lk.unlock();
314 return false;
315 case State::DoDeinitialize:
316 case State::Deinitializing:
317 if (_reinitialize)
318 {
319 lk.unlock();
320 break;
321 }
322 lk.unlock();
323 return false;
324 174 case State::DoInitialize:
325 case State::Initializing:
326
1/2
✓ Branch 1 taken 174 times.
✗ Branch 2 not taken.
174 lk.unlock();
327 174 break;
328 352 case State::Deinitialized:
329 {
330 352 _state = State::DoInitialize;
331
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 lk.unlock();
332
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 wakeWorker();
333 352 break;
334 }
335 }
336
337
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 352 times.
526 if (wait)
338 {
339
1/2
✓ Branch 1 taken 174 times.
✗ Branch 2 not taken.
174 std::unique_lock lk(_workerMutex);
340
1/2
✓ Branch 1 taken 174 times.
✗ Branch 2 not taken.
174 _workerConditionVariable.wait(lk, [&, this] {
341
1/2
✓ Branch 1 taken 379 times.
✗ Branch 2 not taken.
379 std::scoped_lock lks(_stateMutex);
342
4/4
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 173 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 205 times.
758 return _state == State::Initialized || _state == State::Deinitialized;
343 379 });
344
1/2
✓ Branch 1 taken 174 times.
✗ Branch 2 not taken.
174 std::scoped_lock lks(_stateMutex);
345 174 return _state == State::Initialized;
346 174 }
347 352 return true;
348 526 }
349
350 bool NAV::Node::doReinitialize(bool wait)
351 {
352 std::unique_lock<std::mutex> lk(_stateMutex);
353 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
354
355 switch (_state)
356 {
357 case State::Disabled:
358 case State::DoShutdown:
359 case State::Shutdown:
360 lk.unlock();
361 return false;
362 case State::DoDeinitialize:
363 case State::Deinitializing:
364 _reinitialize = true;
365 lk.unlock();
366 break;
367 case State::DoInitialize:
368 case State::Initializing:
369 lk.unlock();
370 break;
371 case State::Deinitialized:
372 lk.unlock();
373 return doInitialize(wait);
374 case State::Initialized:
375 _state = State::DoDeinitialize;
376 _reinitialize = true;
377 lk.unlock();
378 wakeWorker();
379 break;
380 }
381
382 if (wait)
383 {
384 std::unique_lock lk(_workerMutex);
385 _workerConditionVariable.wait(lk, [&, this] {
386 std::scoped_lock lks(_stateMutex);
387 return _state == State::Initialized || _state == State::Deinitialized;
388 });
389 std::scoped_lock lks(_stateMutex);
390 return _state == State::Initialized;
391 }
392 return true;
393 }
394
395 378 bool NAV::Node::doDeinitialize(bool wait)
396 {
397
1/2
✓ Branch 1 taken 378 times.
✗ Branch 2 not taken.
378 std::unique_lock<std::mutex> lk(_stateMutex);
398 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
399
400
3/5
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 350 times.
✗ Branch 4 not taken.
378 switch (_state)
401 {
402 22 case State::Deinitialized:
403
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 lk.unlock();
404 22 return true;
405 6 case State::Disabled:
406 case State::DoShutdown:
407 case State::Shutdown:
408 case State::DoInitialize:
409 case State::Initializing:
410
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 lk.unlock();
411 6 return false;
412 case State::DoDeinitialize:
413 case State::Deinitializing:
414 lk.unlock();
415 break;
416 350 case State::Initialized:
417 {
418 350 _state = State::DoDeinitialize;
419
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 lk.unlock();
420
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 wakeWorker();
421 350 break;
422 }
423 }
424
425
2/2
✓ Branch 0 taken 347 times.
✓ Branch 1 taken 3 times.
350 if (wait)
426 {
427
1/2
✓ Branch 1 taken 347 times.
✗ Branch 2 not taken.
347 std::unique_lock lk(_workerMutex);
428
1/2
✓ Branch 1 taken 347 times.
✗ Branch 2 not taken.
347 _workerConditionVariable.wait(lk, [&, this] {
429
1/2
✓ Branch 1 taken 694 times.
✗ Branch 2 not taken.
694 std::scoped_lock lks(_stateMutex);
430 694 return _state == State::Deinitialized;
431 694 });
432 347 }
433 350 return true;
434 378 }
435
436 bool NAV::Node::doDisable(bool wait)
437 {
438 std::unique_lock<std::mutex> lk(_stateMutex);
439 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
440
441 switch (_state)
442 {
443 case State::Disabled:
444 lk.unlock();
445 return true;
446 case State::DoShutdown:
447 case State::Shutdown:
448 case State::Initializing:
449 lk.unlock();
450 return false;
451 case State::Initialized:
452 case State::DoDeinitialize:
453 case State::Deinitializing:
454 _disable = true;
455 lk.unlock();
456 doDeinitialize();
457 break;
458 case State::DoInitialize:
459 case State::Deinitialized:
460 {
461 _state = State::Disabled;
462 lk.unlock();
463 break;
464 }
465 }
466
467 if (wait)
468 {
469 std::unique_lock lk(_workerMutex);
470 _workerConditionVariable.wait(lk, [&, this] {
471 std::scoped_lock lks(_stateMutex);
472 return _state == State::Deinitialized;
473 });
474 }
475 return true;
476 }
477
478 bool NAV::Node::doEnable()
479 {
480 std::scoped_lock lk(_stateMutex);
481 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
482
483 if (_state == State::Disabled)
484 {
485 _state = State::Deinitialized;
486 }
487 return true;
488 }
489
490 483015 void NAV::Node::wakeWorker()
491 {
492 {
493
1/2
✓ Branch 1 taken 483099 times.
✗ Branch 2 not taken.
483015 std::scoped_lock lk(_workerMutex);
494 483099 _workerWakeup = true;
495 483099 }
496 483102 _workerConditionVariable.notify_all();
497 483288 }
498
499 388746 bool NAV::Node::isDisabled() const
500 {
501
1/2
✓ Branch 1 taken 388760 times.
✗ Branch 2 not taken.
388746 std::scoped_lock lk(_stateMutex);
502 388774 return _state == State::Disabled;
503 388760 }
504 1765460 bool NAV::Node::isInitialized() const
505 {
506
1/2
✓ Branch 1 taken 1764118 times.
✗ Branch 2 not taken.
1765460 std::scoped_lock lk(_stateMutex);
507 1764494 return _state == State::Initialized;
508 1764118 }
509 300265 bool NAV::Node::isTransient() const
510 {
511
1/2
✓ Branch 1 taken 300270 times.
✗ Branch 2 not taken.
300265 std::scoped_lock lk(_stateMutex);
512
1/3
✓ Branch 0 taken 300280 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
300270 switch (_state)
513 {
514 300280 case State::Disabled:
515 case State::Initialized:
516 case State::Deinitialized:
517 300280 return false;
518 case State::DoShutdown:
519 case State::Shutdown:
520 case State::Initializing:
521 case State::DoDeinitialize:
522 case State::Deinitializing:
523 case State::DoInitialize:
524 return true;
525 }
526
527 return true;
528 300270 }
529 bool NAV::Node::isOnlyRealtime() const
530 {
531 return _onlyRealTime;
532 }
533
534 357 void NAV::Node::workerThread(Node* node)
535 {
536 LOG_TRACE("{}: Worker thread started.", node->nameId());
537
538
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 std::unique_lock<std::mutex> lk(node->_stateMutex);
539
4/6
✓ Branch 1 taken 301336 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 301339 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 301341 times.
✗ Branch 6 not taken.
602678 while ([]() { return true; }() && node->_state != State::Shutdown)
540 {
541
3/4
✓ Branch 1 taken 1059 times.
✓ Branch 2 taken 300275 times.
✓ Branch 4 taken 1059 times.
✗ Branch 5 not taken.
301341 if (lk.owns_lock()) { lk.unlock(); }
542
543
1/2
✓ Branch 1 taken 301314 times.
✗ Branch 2 not taken.
301334 if (std::unique_lock<std::mutex> lock(node->_stateMutex);
544
2/2
✓ Branch 0 taken 355 times.
✓ Branch 1 taken 300959 times.
301314 node->_state == State::DoShutdown)
545 {
546 LOG_TRACE("{}: Worker doing shutdown...", node->nameId());
547 355 node->_state = State::Shutdown;
548
1/2
✓ Branch 1 taken 355 times.
✗ Branch 2 not taken.
355 lock.unlock();
549 355 node->_workerConditionVariable.notify_all();
550 355 break;
551 301314 }
552
1/2
✓ Branch 1 taken 300957 times.
✗ Branch 2 not taken.
300970 if (std::unique_lock<std::mutex> lock(node->_stateMutex);
553
2/2
✓ Branch 0 taken 344 times.
✓ Branch 1 taken 300613 times.
300957 node->_state == State::DoInitialize)
554 {
555 LOG_TRACE("{}: Worker doing initialization...", node->nameId());
556
1/2
✓ Branch 1 taken 345 times.
✗ Branch 2 not taken.
344 lock.unlock();
557
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
345 node->workerInitializeNode();
558 LOG_TRACE("{}: Worker finished initialization, notifying all waiting threads (state = {})", node->nameId(), Node::toString(node->_state));
559 352 node->_workerConditionVariable.notify_all();
560
561
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 lk.lock();
562 352 continue;
563 300965 }
564
1/2
✓ Branch 1 taken 300623 times.
✗ Branch 2 not taken.
300618 if (std::unique_lock<std::mutex> lock(node->_stateMutex);
565
2/2
✓ Branch 0 taken 350 times.
✓ Branch 1 taken 300273 times.
300623 node->_state == State::DoDeinitialize)
566 {
567 LOG_TRACE("{}: Worker doing deinitialization...", node->nameId());
568
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 lock.unlock();
569
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 node->workerDeinitializeNode();
570 LOG_TRACE("{}: Worker finished deinitialization, notifying all waiting threads (state = {})", node->nameId(), Node::toString(node->_state));
571 350 node->_workerConditionVariable.notify_all();
572
573
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 lk.lock();
574 350 continue;
575 300623 }
576
577
2/4
✓ Branch 1 taken 300275 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 300279 times.
✗ Branch 4 not taken.
300276 if (!node->isTransient())
578 {
579 // Wait for data or state change
580 LOG_DATA("{}: Worker going to sleep", node->nameId());
581 300279 bool timeout = false;
582 {
583
1/2
✓ Branch 1 taken 300271 times.
✗ Branch 2 not taken.
300279 std::unique_lock lk(node->_workerMutex);
584
1/2
✓ Branch 1 taken 300234 times.
✗ Branch 2 not taken.
888622 timeout = !node->_workerConditionVariable.wait_for(lk, node->_workerTimeout, [node] { return node->_workerWakeup; });
585 300234 node->_workerWakeup = false;
586 300234 }
587 LOG_DATA("{}: Worker woke up", node->nameId());
588
589
7/8
✓ Branch 1 taken 300118 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 298945 times.
✓ Branch 4 taken 1173 times.
✓ Branch 5 taken 298741 times.
✓ Branch 6 taken 204 times.
✓ Branch 7 taken 298553 times.
✓ Branch 8 taken 1565 times.
299763 if (node->isInitialized() && node->callbacksEnabled)
590 {
591
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 298553 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
298553 if (timeout && node->callbacksEnabled) // Timeout reached
592 {
593 node->workerTimeoutHandler();
594 }
595
596 // Check input pin for data and trigger callbacks
597
3/4
✓ Branch 1 taken 297953 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 297743 times.
✓ Branch 4 taken 210 times.
298553 if (std::ranges::any_of(node->inputPins, [](const InputPin& inputPin) {
598 297901 return inputPin.isPinLinked();
599 }))
600 {
601
2/4
✓ Branch 1 taken 779048 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 779089 times.
✗ Branch 4 not taken.
778573 while (node->isInitialized())
602 {
603 // -------------------------- Data processing on input non-flow pins -----------------------------
604 779089 bool notifyTriggered = false;
605
2/2
✓ Branch 1 taken 2300693 times.
✓ Branch 2 taken 779713 times.
3081577 for (size_t i = 0; i < node->inputPins.size(); i++)
606 {
607 2300693 auto& inputPin = node->inputPins[i];
608
4/6
✓ Branch 1 taken 4463 times.
✓ Branch 2 taken 2298025 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4463 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2302488 times.
2302327 if (inputPin.type != Pin::Type::Flow && !inputPin.queue.empty())
609 {
610 if (auto callback = std::get<InputPin::DataChangedNotifyFunc>(inputPin.callback))
611 {
612 LOG_DATA("{}: Invoking notify callback on input pin '{}'", node->nameId(), inputPin.name);
613 InsTime insTime = inputPin.queue.extract_front()->insTime;
614 #ifdef TESTING
615 for (const auto& watcherCallback : inputPin.watcherCallbacks)
616 {
617 if (auto watcherCall = std::get<InputPin::DataChangedWatcherNotifyFunc>(watcherCallback))
618 {
619 std::invoke(watcherCall, node, insTime, i);
620 }
621 }
622 #endif
623 std::invoke(callback, node, insTime, i);
624 notifyTriggered = true;
625 }
626 }
627 }
628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 779713 times.
779713 if (notifyTriggered) { continue; }
629
630 // ------------------------------ Process data on input flow pins --------------------------------
631
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 779713 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 779682 times.
✓ Branch 6 taken 31 times.
779713 if (node->callbacksEnabled || node->_mode == Node::Mode::REAL_TIME)
632 {
633 LOG_DATA("{}: Checking for firable input pins", node->nameId());
634
635
2/2
✓ Branch 1 taken 778592 times.
✓ Branch 2 taken 4 times.
779682 if (node->_mode == Mode::POST_PROCESSING)
636 {
637 // Check if all input flow pins have data
638 778592 bool allInputPinsHaveData = !node->inputPins.empty();
639
2/2
✓ Branch 5 taken 2148105 times.
✓ Branch 6 taken 481466 times.
2630590 for (const auto& inputPin : node->inputPins)
640 {
641
9/10
✓ Branch 1 taken 2144410 times.
✓ Branch 2 taken 5861 times.
✓ Branch 3 taken 2144900 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2067825 times.
✓ Branch 6 taken 77075 times.
✓ Branch 8 taken 543709 times.
✓ Branch 9 taken 1524399 times.
✓ Branch 10 taken 543710 times.
✓ Branch 11 taken 1606844 times.
2148764 if (inputPin.type == Pin::Type::Flow && inputPin.neededForTemporalQueueCheck && !inputPin.queueBlocked && inputPin.queue.empty())
642 {
643
1/2
✓ Branch 1 taken 543682 times.
✗ Branch 2 not taken.
543710 if (auto* connectedPin = inputPin.link.getConnectedPin();
644
6/6
✓ Branch 0 taken 543491 times.
✓ Branch 1 taken 191 times.
✓ Branch 3 taken 298538 times.
✓ Branch 4 taken 244934 times.
✓ Branch 5 taken 298539 times.
✓ Branch 6 taken 245124 times.
543682 connectedPin && !connectedPin->noMoreDataAvailable)
645 {
646 298539 allInputPinsHaveData = false;
647 298539 break;
648 }
649 }
650 }
651
2/2
✓ Branch 0 taken 298539 times.
✓ Branch 1 taken 481466 times.
780005 if (!allInputPinsHaveData)
652 {
653 LOG_DATA("{}: Not all pins have data for temporal sorting", node->nameId());
654 298727 break;
655 }
656 LOG_DATA("{}: All pins have data for temporal sorting", node->nameId());
657 }
658
659 // Find pin with the earliest data
660 481470 InsTime earliestTime;
661 481470 size_t earliestInputPinIdx = 0;
662 481470 int earliestInputPinPriority = -1000;
663
2/2
✓ Branch 1 taken 1453742 times.
✓ Branch 2 taken 481479 times.
1935418 for (size_t i = 0; i < node->inputPins.size(); i++)
664 {
665 1453742 auto& inputPin = node->inputPins[i];
666
2/2
✓ Branch 2 taken 1217911 times.
✓ Branch 3 taken 232277 times.
2904663 if (inputPin.type == Pin::Type::Flow && !inputPin.queue.empty()
667
6/6
✓ Branch 0 taken 1450284 times.
✓ Branch 1 taken 4106 times.
✓ Branch 3 taken 736815 times.
✓ Branch 4 taken 481028 times.
✓ Branch 5 taken 709988 times.
✓ Branch 6 taken 744222 times.
3641377 && (earliestTime.empty()
668
2/2
✓ Branch 3 taken 507727 times.
✓ Branch 4 taken 228638 times.
736815 || inputPin.queue.front()->insTime < earliestTime
669
4/4
✓ Branch 3 taken 415806 times.
✓ Branch 4 taken 92355 times.
✓ Branch 5 taken 347 times.
✓ Branch 6 taken 415459 times.
507727 || (inputPin.queue.front()->insTime == earliestTime && inputPin.priority > earliestInputPinPriority)))
670 {
671 709988 earliestTime = inputPin.queue.front()->insTime;
672 709726 earliestInputPinIdx = i;
673 709726 earliestInputPinPriority = inputPin.priority;
674 }
675 }
676
2/2
✓ Branch 0 taken 188 times.
✓ Branch 1 taken 481291 times.
481479 if (earliestInputPinPriority == -1000) { break; }
677
678 481291 auto& inputPin = node->inputPins[earliestInputPinIdx];
679
5/8
✓ Branch 0 taken 481291 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 481294 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 481295 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 481295 times.
✗ Branch 8 not taken.
481292 if (inputPin.firable && inputPin.firable(node, inputPin))
680 {
681
2/4
✓ Branch 1 taken 481247 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 481249 times.
✗ Branch 4 not taken.
481295 if (auto callback = std::get<InputPin::FlowFirableCallbackFunc>(inputPin.callback))
682 {
683 LOG_DATA("{}: Invoking callback on input pin '{}'", node->nameId(), inputPin.name);
684 #ifdef TESTING
685
2/2
✓ Branch 5 taken 63647 times.
✓ Branch 6 taken 481194 times.
544898 for (const auto& watcherCallback : inputPin.watcherCallbacks)
686 {
687
3/6
✓ Branch 1 taken 63647 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63648 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 63648 times.
✗ Branch 8 not taken.
63647 if (auto watcherCall = std::get<InputPin::FlowFirableWatcherCallbackFunc>(watcherCallback))
688 {
689
1/2
✓ Branch 1 taken 63649 times.
✗ Branch 2 not taken.
63648 std::invoke(watcherCall, node, inputPin.queue, earliestInputPinIdx);
690 63649 }
691 }
692 #endif
693
1/2
✓ Branch 1 taken 481190 times.
✗ Branch 2 not taken.
481194 std::invoke(callback, node, inputPin.queue, earliestInputPinIdx);
694 }
695 }
696 else if (inputPin.dropQueueIfNotFirable)
697 {
698 LOG_DATA("{}: Dropping message on input pin '{}'", node->nameId(), inputPin.name);
699 inputPin.queue.pop_front();
700 }
701 else
702 {
703 LOG_DATA("{}: Skipping message on input pin '{}'", node->nameId(), inputPin.name);
704 break; // Do not drop an item, but put the worker to sleep
705 }
706 }
707 else
708 {
709 31 break;
710 }
711 }
712 }
713
714 // Post-processing (FileReader/Simulator)
715
2/2
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 298771 times.
298927 if (!node->pollEvents.empty())
716 {
717 125 std::multimap<InsTime, std::pair<OutputPin*, size_t>>::iterator it;
718
7/10
✓ Branch 3 taken 126987 times.
✓ Branch 4 taken 10 times.
✓ Branch 6 taken 126998 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 126998 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 126999 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 126999 times.
✓ Branch 13 taken 9 times.
127009 while (it = node->pollEvents.begin(), it != node->pollEvents.end() && node->isInitialized() && node->callbacksEnabled)
719 {
720 126999 OutputPin* outputPin = it->second.first;
721 126990 size_t outputPinIdx = it->second.second;
722 126993 Node* node = outputPin->parentNode;
723
724
2/2
✓ Branch 1 taken 60771 times.
✓ Branch 2 taken 66223 times.
126993 if (std::holds_alternative<OutputPin::PollDataFunc>(outputPin->data))
725 {
726 60771 auto* callback = std::get_if<OutputPin::PollDataFunc>(&outputPin->data);
727
2/4
✓ Branch 0 taken 60764 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60765 times.
✗ Branch 3 not taken.
60760 if (callback != nullptr && *callback != nullptr)
728 {
729 LOG_DATA("{}: Polling data from output pin '{}'", node->nameId(), str::replaceAll_copy(outputPin->name, "\n", ""));
730
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 60765 times.
✓ Branch 3 taken 60773 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 116 times.
✓ Branch 8 taken 60659 times.
60765 if ((node->**callback)() == nullptr)
731 {
732
1/2
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
116 node->pollEvents.erase(it); // Delete the event if no more data on this pin
733 116 break;
734 }
735 }
736 }
737
1/2
✓ Branch 1 taken 66223 times.
✗ Branch 2 not taken.
66223 else if (std::holds_alternative<OutputPin::PeekPollDataFunc>(outputPin->data))
738 {
739 66223 auto* callback = std::get_if<OutputPin::PeekPollDataFunc>(&outputPin->data);
740
3/4
✓ Branch 0 taken 66222 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 66224 times.
✗ Branch 3 not taken.
66224 if (callback != nullptr && *callback != nullptr)
741 {
742
1/2
✓ Branch 2 taken 66223 times.
✗ Branch 3 not taken.
66224 if (!it->first.empty())
743 {
744 LOG_DATA("{}: Polling data from output pin '{}'", node->nameId(), str::replaceAll_copy(outputPin->name, "\n", ""));
745 // Trigger the already peeked observation and invoke it's callbacks (peek = false)
746
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 66223 times.
✓ Branch 3 taken 66226 times.
✗ Branch 4 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 66226 times.
66223 if ((node->**callback)(outputPinIdx, false) == nullptr)
747 {
748 LOG_ERROR("{}: {} could not poll its observation despite being able to peek it.", node->nameId(), outputPin->name);
749 }
750 }
751
752 // Check if data available (peek = true)
753
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 66225 times.
✓ Branch 3 taken 66229 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 66205 times.
✓ Branch 7 taken 17 times.
66225 if (auto obs = (node->**callback)(outputPinIdx, true))
754 {
755 // Check if data has a time
756
1/2
✓ Branch 2 taken 66206 times.
✗ Branch 3 not taken.
66205 if (!obs->insTime.empty())
757 {
758
1/2
✓ Branch 4 taken 66208 times.
✗ Branch 5 not taken.
66206 node->pollEvents.insert(std::make_pair(obs->insTime, std::make_pair(outputPin, outputPinIdx)));
759 }
760 else // If no time, call the object and remove it
761 {
762 (node->**callback)(outputPinIdx, false);
763 continue; // Do not erase the iterator, because this pin needs to be called again
764 }
765 }
766 else // nullptr -> no more data incoming on this pin
767 {
768 LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin->name);
769 17 outputPin->noMoreDataAvailable = true;
770
2/2
✓ Branch 5 taken 25 times.
✓ Branch 6 taken 18 times.
43 for (auto& link : outputPin->links)
771 {
772
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
25 link.connectedNode->wakeWorker();
773 }
774 66226 }
775 66226 }
776 else
777 {
778 LOG_ERROR("{} - {}: Callback is not valid anymore", node->nameId(), size_t(outputPin->id));
779 }
780
1/2
✓ Branch 1 taken 66230 times.
✗ Branch 2 not taken.
66226 node->pollEvents.erase(it);
781 }
782 }
783
784
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
125 if (node->pollEvents.empty())
785 {
786 LOG_TRACE("{}: Finished polling all pins.", node->nameId());
787
788 125 node->callbacksEnabled = false;
789
2/2
✓ Branch 5 taken 141 times.
✓ Branch 6 taken 125 times.
266 for (auto& outputPin : node->outputPins)
790 {
791
2/2
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 25 times.
141 if (!outputPin.noMoreDataAvailable)
792 {
793 LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin.name);
794 116 outputPin.noMoreDataAvailable = true;
795
2/2
✓ Branch 5 taken 122 times.
✓ Branch 6 taken 116 times.
238 for (auto& link : outputPin.links)
796 {
797
1/2
✓ Branch 1 taken 122 times.
✗ Branch 2 not taken.
122 link.connectedNode->wakeWorker();
798 }
799 }
800 }
801 125 node->_mode = Node::Mode::REAL_TIME;
802
1/2
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
125 FlowExecutor::deregisterNode(node);
803 }
804 }
805 }
806
807 // Check if node finished
808
2/2
✓ Branch 1 taken 298748 times.
✓ Branch 2 taken 1509 times.
300461 if (node->_mode == Mode::POST_PROCESSING)
809 {
810
3/4
✓ Branch 1 taken 298784 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 220 times.
✓ Branch 4 taken 298564 times.
298748 if (std::ranges::all_of(node->inputPins, [](const InputPin& inputPin) {
811
6/8
✓ Branch 2 taken 386635 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 386634 times.
✓ Branch 5 taken 1 times.
✓ Branch 7 taken 386650 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 298816 times.
✓ Branch 10 taken 87834 times.
1159926 return inputPin.type != Pin::Type::Flow || !inputPin.isPinLinked() || inputPin.link.connectedNode->isDisabled()
812
3/4
✓ Branch 1 taken 298812 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 298804 times.
✓ Branch 5 taken 4 times.
298816 || !inputPin.link.getConnectedPin()->blocksConnectedNodeFromFinishing
813
7/8
✓ Branch 0 taken 386624 times.
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 167452 times.
✓ Branch 4 taken 131360 times.
✓ Branch 6 taken 167474 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 271 times.
✓ Branch 10 taken 167204 times.
1159963 || (inputPin.queue.empty() && inputPin.link.getConnectedPin()->noMoreDataAvailable);
814 }))
815 {
816 LOG_TRACE("{}: Node finished", node->nameId());
817 220 node->callbacksEnabled = false;
818
2/2
✓ Branch 5 taken 130 times.
✓ Branch 6 taken 220 times.
350 for (auto& outputPin : node->outputPins)
819 {
820 LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin.name);
821 130 outputPin.noMoreDataAvailable = true;
822
2/2
✓ Branch 5 taken 129 times.
✓ Branch 6 taken 130 times.
259 for (auto& link : outputPin.links)
823 {
824
1/2
✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
129 link.connectedNode->wakeWorker();
825 }
826 }
827 220 node->_mode = Node::Mode::REAL_TIME;
828
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
220 FlowExecutor::deregisterNode(node);
829 }
830 }
831 }
832 }
833
834 LOG_TRACE("{}: Worker thread ended.", node->nameId());
835 352 }
836
837 333 bool NAV::Node::workerInitializeNode()
838 {
839 LOG_TRACE("{}: called", nameId());
840 {
841
1/2
✓ Branch 1 taken 345 times.
✗ Branch 2 not taken.
333 std::scoped_lock lk(_stateMutex);
842
6/16
✓ Branch 0 taken 345 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 351 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 350 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 350 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 350 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 349 times.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
345 INS_ASSERT_USER_ERROR(_state == State::DoInitialize, fmt::format("Worker can only initialize the node if the state is set to DoInitialize, but it is {}.", toString(_state)).c_str());
843 349 _state = Node::State::Initializing;
844 349 }
845 349 _mode = Node::Mode::REAL_TIME;
846
847
3/6
✓ Branch 1 taken 339 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 349 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 352 times.
✗ Branch 9 not taken.
349 LOG_DEBUG("{}: Initializing Node", nameId());
848
849 // Initialize Nodes connected to the input pins
850
2/2
✓ Branch 5 taken 300 times.
✓ Branch 6 taken 352 times.
652 for (const auto& inputPin : inputPins)
851 {
852
2/2
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 270 times.
300 if (inputPin.type != Pin::Type::Flow)
853 {
854
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 8 times.
30 if (Node* connectedNode = inputPin.link.connectedNode)
855 {
856
3/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 7 times.
22 if (!connectedNode->isInitialized())
857 {
858
5/10
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 15 times.
✗ Branch 15 not taken.
15 LOG_DEBUG("{}: Initializing connected Node '{}' on input Pin {}", nameId(), connectedNode->nameId(), size_t(inputPin.id));
859
2/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
15 if (!connectedNode->doInitialize(true))
860 {
861 LOG_ERROR("{}: Could not initialize connected node {}", nameId(), connectedNode->nameId());
862 std::scoped_lock lk(_stateMutex);
863 if (_state == State::Initializing)
864 {
865 _state = Node::State::Deinitialized;
866 }
867 return false;
868 }
869 }
870 }
871 }
872 }
873
874 352 _reinitialize = false;
875
876 // Initialize the node itself
877 LOG_TRACE("{}: calling initialize()", nameId());
878 352 bool initSucceeded = false;
879 {
880
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 std::scoped_lock<std::mutex> guard(_configWindowMutex);
881
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
352 initSucceeded = initialize();
882 352 }
883
2/2
✓ Branch 0 taken 351 times.
✓ Branch 1 taken 1 times.
352 if (initSucceeded)
884 {
885 LOG_TRACE("{}: initialize() was successful", nameId());
886
887
2/2
✓ Branch 4 taken 300 times.
✓ Branch 5 taken 351 times.
651 for (auto& inputPin : inputPins)
888 {
889 300 inputPin.queue.clear();
890 300 inputPin.queueBlocked = false;
891 }
892
893 351 pollEvents.clear();
894 LOG_TRACE("{}: calling resetNode()", nameId());
895 {
896
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 std::scoped_lock<std::mutex> guard(_configWindowMutex);
897
1/2
✓ Branch 1 taken 351 times.
✗ Branch 2 not taken.
350 resetNode();
898 351 }
899 LOG_TRACE("{}: resetNode() was successful", nameId());
900
2/2
✓ Branch 5 taken 292 times.
✓ Branch 6 taken 350 times.
643 for (auto& outputPin : outputPins)
901 {
902 291 outputPin.noMoreDataAvailable = true;
903
2/2
✓ Branch 5 taken 287 times.
✓ Branch 6 taken 292 times.
579 for (auto& link : outputPin.links)
904 {
905 LOG_TRACE("{}: Waking connected node '{}'", nameId(), link.connectedNode->nameId());
906
1/2
✓ Branch 1 taken 287 times.
✗ Branch 2 not taken.
287 link.connectedNode->wakeWorker();
907 }
908 }
909
910
1/2
✓ Branch 1 taken 351 times.
✗ Branch 2 not taken.
350 std::scoped_lock lk(_stateMutex);
911
1/2
✓ Branch 0 taken 351 times.
✗ Branch 1 not taken.
351 if (_state == State::Initializing)
912 {
913 351 _state = Node::State::Initialized;
914 }
915 351 return true;
916 351 }
917
918 LOG_TRACE("{}: initialize() failed", nameId());
919
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::scoped_lock lk(_stateMutex);
920
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (_state == State::Initializing)
921 {
922 1 _state = Node::State::Deinitialized;
923 }
924 1 return false;
925 1 }
926
927 350 bool NAV::Node::workerDeinitializeNode()
928 {
929 LOG_TRACE("{}: called", nameId());
930 {
931
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 std::scoped_lock lk(_stateMutex);
932
6/16
✓ Branch 0 taken 350 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 350 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 350 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 350 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 350 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 350 times.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
350 INS_ASSERT_USER_ERROR(_state == State::DoDeinitialize, fmt::format("Worker can only deinitialize the node if the state is set to DoDeinitialize, but it is {}.", toString(_state)).c_str());
933 {
934 350 _state = Node::State::Deinitializing;
935 }
936 350 }
937
3/6
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 350 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 350 times.
✗ Branch 9 not taken.
350 LOG_DEBUG("{}: Deinitializing Node", nameId());
938
939 350 callbacksEnabled = false;
940
941 // Re-/Deinitialize Nodes connected to the output pins
942
2/2
✓ Branch 5 taken 292 times.
✓ Branch 6 taken 350 times.
642 for (const auto& outputPin : outputPins)
943 {
944
2/2
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 224 times.
292 if (outputPin.type != Pin::Type::Flow)
945 {
946
2/2
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 68 times.
75 for (const auto& link : outputPin.links)
947 {
948
3/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 4 times.
7 if (link.connectedNode->isInitialized())
949 {
950
6/12
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
3 LOG_DEBUG("{}: {} connected Node '{}' on output Pin {}", nameId(),
951 _reinitialize ? "Reinitializing" : "Deinitializing", link.connectedNode->nameId(), size_t(outputPin.id));
952
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 if (_reinitialize) { link.connectedNode->doReinitialize(); }
953
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 else { link.connectedNode->doDeinitialize(); }
954 }
955 }
956 }
957 }
958
959 // Deinitialize the node itself
960 {
961
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 std::scoped_lock<std::mutex> guard(_configWindowMutex);
962
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 deinitialize();
963 350 }
964
965
1/2
✓ Branch 1 taken 350 times.
✗ Branch 2 not taken.
350 std::scoped_lock lk(_stateMutex);
966
1/2
✓ Branch 0 taken 350 times.
✗ Branch 1 not taken.
350 if (_state == State::Deinitializing)
967 {
968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
350 if (_disable)
969 {
970 _state = State::Disabled;
971 }
972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
350 else if (_reinitialize)
973 {
974 _state = State::DoInitialize;
975 }
976 else
977 {
978 350 _state = State::Deinitialized;
979 }
980 }
981
982 350 return true;
983 350 }
984
985 void NAV::Node::workerTimeoutHandler()
986 {
987 LOG_TRACE("{}: called", nameId());
988 }
989
990 void NAV::to_json(json& j, const Node& node)
991 {
992 ImVec2 realSize = ed::GetNodeSize(node.id);
993 realSize.x -= 16;
994 realSize.y -= 38.0F;
995 j = json{
996 { "id", size_t(node.id) },
997 { "type", node.type() },
998 { "kind", std::string(node.kind) },
999 { "name", node.name },
1000 { "size", node._size.x == 0 && node._size.y == 0 ? node._size : realSize },
1001 { "pos", ed::GetNodePosition(node.id) },
1002 { "enabled", !node.isDisabled() },
1003 { "inputPins", node.inputPins },
1004 { "outputPins", node.outputPins },
1005 };
1006 }
1007 714 void NAV::from_json(const json& j, Node& node)
1008 {
1009
3/6
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 714 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 714 times.
✗ Branch 8 not taken.
714 node.id = j.at("id").get<size_t>();
1010
1/2
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
714 if (j.contains("kind"))
1011 {
1012
3/6
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 714 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 714 times.
✗ Branch 8 not taken.
714 node.kind = Node::Kind(j.at("kind").get<std::string>());
1013 }
1014
1/2
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
714 if (j.contains("name"))
1015 {
1016 714 j.at("name").get_to(node.name);
1017 }
1018
1/2
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
714 if (j.contains("size"))
1019 {
1020 714 j.at("size").get_to(node._size);
1021
6/8
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 706 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 706 times.
714 if (node.kind == Node::Kind::GroupBox && gui::NodeEditorApplication::isUsingBigDefaultFont())
1022 {
1023 8 node._size.y -= 20;
1024 }
1025 }
1026
1/2
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
714 if (j.contains("enabled"))
1027 {
1028 714 bool enabled = j.at("enabled").get<bool>();
1029
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 712 times.
714 if (!enabled)
1030 {
1031
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 std::scoped_lock lk(node._stateMutex);
1032 2 node._state = Node::State::Disabled;
1033 2 }
1034 }
1035
1036
1/2
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
714 if (j.contains("inputPins"))
1037 {
1038
2/4
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 714 times.
✗ Branch 5 not taken.
714 auto inputPins = j.at("inputPins").get<std::vector<InputPin>>();
1039
2/2
✓ Branch 1 taken 566 times.
✓ Branch 2 taken 664 times.
1230 for (size_t i = 0; i < inputPins.size(); ++i)
1040 {
1041
2/2
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 516 times.
566 if (node.inputPins.size() <= i)
1042 {
1043 50 break;
1044 }
1045
4/8
✓ Branch 1 taken 516 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 516 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 516 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 516 times.
✗ Branch 11 not taken.
516 j.at("inputPins").at(i).get_to(node.inputPins.at(i));
1046 }
1047 714 }
1048
1049
1/2
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
714 if (j.contains("outputPins"))
1050 {
1051
2/4
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 714 times.
✗ Branch 5 not taken.
714 auto outputPins = j.at("outputPins").get<std::vector<OutputPin>>();
1052
2/2
✓ Branch 1 taken 571 times.
✓ Branch 2 taken 710 times.
1281 for (size_t i = 0; i < outputPins.size(); ++i)
1053 {
1054
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 567 times.
571 if (node.outputPins.size() <= i)
1055 {
1056 4 break;
1057 }
1058
4/8
✓ Branch 1 taken 567 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 567 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 567 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 567 times.
✗ Branch 11 not taken.
567 j.at("outputPins").at(i).get_to(node.outputPins.at(i));
1059 }
1060 714 }
1061 714 }
1062