INSTINCT Code Coverage Report


Directory: src/
File: internal/Node/Node.cpp
Date: 2025-06-02 15:19:59
Exec Total Coverage
Lines: 344 542 63.5%
Functions: 36 55 65.5%
Branches: 365 847 43.1%

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 6612 NAV::Node::Node(std::string name)
31
1/2
✓ Branch 14 taken 6612 times.
✗ Branch 15 not taken.
6612 : name(std::move(name))
32 {
33 LOG_TRACE("{}: called", nameId());
34
2/2
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 6272 times.
6612 if (_autostartWorker)
35 {
36
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 _worker = std::thread(workerThread, this);
37 }
38 6612 }
39
40 13220 NAV::Node::~Node()
41 {
42 LOG_TRACE("{}: called", nameId());
43
44
2/2
✓ Branch 0 taken 338 times.
✓ Branch 1 taken 6272 times.
13220 if (_autostartWorker)
45 {
46 676 _state = State::DoShutdown;
47 676 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 676 _worker.join();
55 }
56 13220 }
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 302 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 321 void NAV::Node::flush() {}
74
75 321 bool NAV::Node::resetNode()
76 {
77 LOG_TRACE("{}: called", nameId());
78
79 321 return initialize();
80 }
81
82 512 bool NAV::Node::onCreateLink(OutputPin& /*startPin*/, InputPin& /*endPin*/)
83 {
84 512 return true;
85 }
86
87 541 void NAV::Node::onDeleteLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {}
88
89 457 void NAV::Node::afterCreateLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {}
90
91 496 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 142 std::scoped_lock<std::mutex> NAV::Node::requestOutputValueLock(size_t pinIdx)
134 {
135 142 auto& outputPin = outputPins.at(pinIdx);
136 {
137
1/2
✓ Branch 1 taken 142 times.
✗ Branch 2 not taken.
142 std::unique_lock<std::mutex> lk(outputPin.dataAccessMutex);
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
142 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 142 }
145 142 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 361312 void NAV::Node::invokeCallbacks(size_t portIndex, const std::shared_ptr<const NAV::NodeData>& data)
181 {
182
2/2
✓ Branch 0 taken 361303 times.
✓ Branch 1 taken 9 times.
361312 if (callbacksEnabled)
183 {
184
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 361226 times.
361303 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
2/2
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 361113 times.
361226 if (data->insTime.empty())
190 {
191 LOG_DATA("{}: Tried to invokeCallbacks on pin {} without a InsTime. The time is mandatory though!!! ", nameId(), portIndex);
192 49 return;
193 }
194
195
3/4
✓ Branch 1 taken 360950 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 538035 times.
✓ Branch 9 taken 361256 times.
899653 for (const auto& link : outputPins.at(portIndex).links)
196 {
197
1/2
✓ Branch 1 taken 538441 times.
✗ Branch 2 not taken.
538157 auto* targetPin = link.getConnectedPin();
198
7/8
✓ Branch 1 taken 538460 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 490034 times.
✓ Branch 4 taken 48426 times.
✓ Branch 5 taken 463228 times.
✓ Branch 6 taken 26806 times.
✓ Branch 7 taken 463209 times.
✓ Branch 8 taken 75251 times.
538441 if (link.connectedNode->isInitialized() && !targetPin->queueBlocked)
199 {
200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 463209 times.
463209 if (NodeManager::showFlowWhenNotifyingValueChange)
201 {
202 FlowAnimation::Add(link.linkId);
203 }
204
205
1/2
✓ Branch 1 taken 463158 times.
✗ Branch 2 not taken.
463209 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 463289 times.
✗ Branch 2 not taken.
463158 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 72 size_t NAV::Node::inputPinIndexFromId(ax::NodeEditor::PinId pinId) const
234 {
235
1/2
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
147 for (size_t i = 0; i < inputPins.size(); i++)
236 {
237
2/2
✓ Branch 2 taken 72 times.
✓ Branch 3 taken 75 times.
147 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 159620 std::string NAV::Node::nameId() const
254 {
255
5/10
✓ Branch 1 taken 159604 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 159556 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 159547 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 159565 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 159529 times.
✗ Branch 14 not taken.
957491 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 663 std::string NAV::Node::toString(State state)
264 {
265
2/10
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 335 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 337 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
663 switch (state)
266 {
267 case State::Disabled:
268 return "Disabled";
269 case State::Deinitialized:
270 return "Deinitialized";
271 335 case State::DoInitialize:
272
1/2
✓ Branch 1 taken 332 times.
✗ Branch 2 not taken.
667 return "DoInitialize";
273 case State::Initializing:
274 return "Initializing";
275 case State::Initialized:
276 return "Initialized";
277 337 case State::DoDeinitialize:
278
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
674 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 5 NAV::Node::Mode NAV::Node::getMode() const
296 {
297 5 return _mode;
298 }
299
300 508 bool NAV::Node::doInitialize(bool wait)
301 {
302
1/2
✓ Branch 1 taken 508 times.
✗ Branch 2 not taken.
508 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 169 times.
✓ Branch 4 taken 339 times.
✗ Branch 5 not taken.
508 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 169 case State::DoInitialize:
325 case State::Initializing:
326
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
169 lk.unlock();
327 169 break;
328 339 case State::Deinitialized:
329 {
330 339 _state = State::DoInitialize;
331
1/2
✓ Branch 1 taken 339 times.
✗ Branch 2 not taken.
339 lk.unlock();
332
1/2
✓ Branch 1 taken 339 times.
✗ Branch 2 not taken.
339 wakeWorker();
333 339 break;
334 }
335 }
336
337
2/2
✓ Branch 0 taken 169 times.
✓ Branch 1 taken 339 times.
508 if (wait)
338 {
339
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
169 std::unique_lock lk(_workerMutex);
340
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
169 _workerConditionVariable.wait(lk, [&, this] {
341
1/2
✓ Branch 1 taken 365 times.
✗ Branch 2 not taken.
365 std::scoped_lock lks(_stateMutex);
342
4/4
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 196 times.
730 return _state == State::Initialized || _state == State::Deinitialized;
343 365 });
344
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
169 std::scoped_lock lks(_stateMutex);
345 169 return _state == State::Initialized;
346 169 }
347 339 return true;
348 508 }
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 361 bool NAV::Node::doDeinitialize(bool wait)
396 {
397
1/2
✓ Branch 1 taken 361 times.
✗ Branch 2 not taken.
361 std::unique_lock<std::mutex> lk(_stateMutex);
398 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
399
400
3/5
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 337 times.
✗ Branch 4 not taken.
361 switch (_state)
401 {
402 18 case State::Deinitialized:
403
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 lk.unlock();
404 18 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 337 case State::Initialized:
417 {
418 337 _state = State::DoDeinitialize;
419
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 lk.unlock();
420
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 wakeWorker();
421 337 break;
422 }
423 }
424
425
2/2
✓ Branch 0 taken 336 times.
✓ Branch 1 taken 1 times.
337 if (wait)
426 {
427
1/2
✓ Branch 1 taken 336 times.
✗ Branch 2 not taken.
336 std::unique_lock lk(_workerMutex);
428
1/2
✓ Branch 1 taken 336 times.
✗ Branch 2 not taken.
336 _workerConditionVariable.wait(lk, [&, this] {
429
1/2
✓ Branch 1 taken 672 times.
✗ Branch 2 not taken.
672 std::scoped_lock lks(_stateMutex);
430 672 return _state == State::Deinitialized;
431 672 });
432 336 }
433 337 return true;
434 361 }
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 465014 void NAV::Node::wakeWorker()
491 {
492 {
493
1/2
✓ Branch 1 taken 465066 times.
✗ Branch 2 not taken.
465014 std::scoped_lock lk(_workerMutex);
494 465066 _workerWakeup = true;
495 465066 }
496 465062 _workerConditionVariable.notify_all();
497 465165 }
498
499 359464 bool NAV::Node::isDisabled() const
500 {
501
1/2
✓ Branch 1 taken 359481 times.
✗ Branch 2 not taken.
359464 std::scoped_lock lk(_stateMutex);
502 359479 return _state == State::Disabled;
503 359481 }
504 1666874 bool NAV::Node::isInitialized() const
505 {
506
1/2
✓ Branch 1 taken 1665859 times.
✗ Branch 2 not taken.
1666874 std::scoped_lock lk(_stateMutex);
507 1665931 return _state == State::Initialized;
508 1665859 }
509 272897 bool NAV::Node::isTransient() const
510 {
511
1/2
✓ Branch 1 taken 272904 times.
✗ Branch 2 not taken.
272897 std::scoped_lock lk(_stateMutex);
512
1/3
✓ Branch 0 taken 272908 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
272904 switch (_state)
513 {
514 272908 case State::Disabled:
515 case State::Initialized:
516 case State::Deinitialized:
517 272908 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 272904 }
529 3 bool NAV::Node::isOnlyRealtime() const
530 {
531 3 return _onlyRealTime;
532 }
533
534 340 void NAV::Node::workerThread(Node* node)
535 {
536 LOG_TRACE("{}: Worker thread started.", node->nameId());
537
538
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 std::unique_lock<std::mutex> lk(node->_stateMutex);
539
3/6
✓ Branch 1 taken 273900 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 273900 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 273905 times.
✗ Branch 6 not taken.
547808 while ([]() { return true; }() && node->_state != State::Shutdown)
540 {
541
3/4
✓ Branch 1 taken 1016 times.
✓ Branch 2 taken 272908 times.
✓ Branch 4 taken 1016 times.
✗ Branch 5 not taken.
273905 if (lk.owns_lock()) { lk.unlock(); }
542
543
1/2
✓ Branch 1 taken 273894 times.
✗ Branch 2 not taken.
273924 if (std::unique_lock<std::mutex> lock(node->_stateMutex);
544
2/2
✓ Branch 0 taken 338 times.
✓ Branch 1 taken 273556 times.
273894 node->_state == State::DoShutdown)
545 {
546 LOG_TRACE("{}: Worker doing shutdown...", node->nameId());
547 338 node->_state = State::Shutdown;
548
1/2
✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
338 lock.unlock();
549 338 node->_workerConditionVariable.notify_all();
550 338 break;
551 273894 }
552
1/2
✓ Branch 1 taken 273565 times.
✗ Branch 2 not taken.
273563 if (std::unique_lock<std::mutex> lock(node->_stateMutex);
553
2/2
✓ Branch 0 taken 328 times.
✓ Branch 1 taken 273237 times.
273565 node->_state == State::DoInitialize)
554 {
555 LOG_TRACE("{}: Worker doing initialization...", node->nameId());
556
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
328 lock.unlock();
557
1/2
✓ Branch 1 taken 339 times.
✗ Branch 2 not taken.
330 node->workerInitializeNode();
558 LOG_TRACE("{}: Worker finished initialization, notifying all waiting threads (state = {})", node->nameId(), Node::toString(node->_state));
559 339 node->_workerConditionVariable.notify_all();
560
561
1/2
✓ Branch 1 taken 339 times.
✗ Branch 2 not taken.
339 lk.lock();
562 339 continue;
563 273576 }
564
1/2
✓ Branch 1 taken 273239 times.
✗ Branch 2 not taken.
273240 if (std::unique_lock<std::mutex> lock(node->_stateMutex);
565
2/2
✓ Branch 0 taken 337 times.
✓ Branch 1 taken 272902 times.
273239 node->_state == State::DoDeinitialize)
566 {
567 LOG_TRACE("{}: Worker doing deinitialization...", node->nameId());
568
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 lock.unlock();
569
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 node->workerDeinitializeNode();
570 LOG_TRACE("{}: Worker finished deinitialization, notifying all waiting threads (state = {})", node->nameId(), Node::toString(node->_state));
571 337 node->_workerConditionVariable.notify_all();
572
573
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 lk.lock();
574 337 continue;
575 273239 }
576
577
2/4
✓ Branch 1 taken 272900 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 272905 times.
✗ Branch 4 not taken.
272898 if (!node->isTransient())
578 {
579 // Wait for data or state change
580 LOG_DATA("{}: Worker going to sleep", node->nameId());
581 272905 bool timeout = false;
582 {
583
1/2
✓ Branch 1 taken 272904 times.
✗ Branch 2 not taken.
272905 std::unique_lock lk(node->_workerMutex);
584
1/2
✓ Branch 1 taken 272889 times.
✗ Branch 2 not taken.
809607 timeout = !node->_workerConditionVariable.wait_for(lk, node->_workerTimeout, [node] { return node->_workerWakeup; });
585 272889 node->_workerWakeup = false;
586 272889 }
587 LOG_DATA("{}: Worker woke up", node->nameId());
588
589
7/8
✓ Branch 1 taken 272722 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 271735 times.
✓ Branch 4 taken 987 times.
✓ Branch 5 taken 271441 times.
✓ Branch 6 taken 294 times.
✓ Branch 7 taken 271375 times.
✓ Branch 8 taken 1347 times.
272483 if (node->isInitialized() && node->callbacksEnabled)
590 {
591
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 271375 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
271375 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 271510 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 271337 times.
✓ Branch 4 taken 173 times.
271375 if (std::ranges::any_of(node->inputPins, [](const InputPin& inputPin) {
598 270884 return inputPin.isPinLinked();
599 }))
600 {
601
2/4
✓ Branch 1 taken 733941 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 733953 times.
✗ Branch 4 not taken.
734397 while (node->isInitialized())
602 {
603 // -------------------------- Data processing on input non-flow pins -----------------------------
604 733953 bool notifyTriggered = false;
605
2/2
✓ Branch 1 taken 2111613 times.
✓ Branch 2 taken 734458 times.
2846765 for (size_t i = 0; i < node->inputPins.size(); i++)
606 {
607 2111613 auto& inputPin = node->inputPins[i];
608
4/6
✓ Branch 1 taken 778 times.
✓ Branch 2 taken 2112034 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 778 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2112812 times.
2112977 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 734458 times.
734458 if (notifyTriggered) { continue; }
629
630 // ------------------------------ Process data on input flow pins --------------------------------
631
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 734458 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 734457 times.
✓ Branch 6 taken 1 times.
734458 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 734069 times.
✓ Branch 2 taken 32 times.
734457 if (node->_mode == Mode::POST_PROCESSING)
636 {
637 // Check if all input flow pins have data
638 734069 bool allInputPinsHaveData = !node->inputPins.empty();
639
2/2
✓ Branch 5 taken 2008905 times.
✓ Branch 6 taken 463421 times.
2473224 for (const auto& inputPin : node->inputPins)
640 {
641
9/10
✓ Branch 1 taken 2009155 times.
✓ Branch 2 taken 1626 times.
✓ Branch 3 taken 2009430 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1932367 times.
✓ Branch 6 taken 77063 times.
✓ Branch 8 taken 503082 times.
✓ Branch 9 taken 1429354 times.
✓ Branch 10 taken 503088 times.
✓ Branch 11 taken 1507762 times.
2009466 if (inputPin.type == Pin::Type::Flow && inputPin.neededForTemporalQueueCheck && !inputPin.queueBlocked && inputPin.queue.empty())
642 {
643
1/2
✓ Branch 1 taken 503074 times.
✗ Branch 2 not taken.
503088 if (auto* connectedPin = inputPin.link.getConnectedPin();
644
6/6
✓ Branch 0 taken 502870 times.
✓ Branch 1 taken 204 times.
✓ Branch 3 taken 271275 times.
✓ Branch 4 taken 231592 times.
✓ Branch 5 taken 271273 times.
✓ Branch 6 taken 231798 times.
503074 connectedPin && !connectedPin->noMoreDataAvailable)
645 {
646 271273 allInputPinsHaveData = false;
647 271273 break;
648 }
649 }
650 }
651
2/2
✓ Branch 0 taken 271274 times.
✓ Branch 1 taken 463420 times.
734694 if (!allInputPinsHaveData)
652 {
653 LOG_DATA("{}: Not all pins have data for temporal sorting", node->nameId());
654 271463 break;
655 }
656 LOG_DATA("{}: All pins have data for temporal sorting", node->nameId());
657 }
658
659 // Find pin with the earliest data
660 463452 InsTime earliestTime;
661 463452 size_t earliestInputPinIdx = 0;
662 463452 int earliestInputPinPriority = -1000;
663
2/2
✓ Branch 1 taken 1364453 times.
✓ Branch 2 taken 463451 times.
1828116 for (size_t i = 0; i < node->inputPins.size(); i++)
664 {
665 1364453 auto& inputPin = node->inputPins[i];
666
2/2
✓ Branch 2 taken 1141735 times.
✓ Branch 3 taken 222612 times.
2729437 if (inputPin.type == Pin::Type::Flow && !inputPin.queue.empty()
667
6/6
✓ Branch 0 taken 1364476 times.
✓ Branch 1 taken 508 times.
✓ Branch 3 taken 678619 times.
✓ Branch 4 taken 463055 times.
✓ Branch 5 taken 674775 times.
✓ Branch 6 taken 690136 times.
3408067 && (earliestTime.empty()
668
2/2
✓ Branch 3 taken 466912 times.
✓ Branch 4 taken 211487 times.
678619 || inputPin.queue.front()->insTime < earliestTime
669
4/4
✓ Branch 3 taken 391785 times.
✓ Branch 4 taken 75464 times.
✓ Branch 5 taken 215 times.
✓ Branch 6 taken 391570 times.
466912 || (inputPin.queue.front()->insTime == earliestTime && inputPin.priority > earliestInputPinPriority)))
670 {
671 674775 earliestTime = inputPin.queue.front()->insTime;
672 674528 earliestInputPinIdx = i;
673 674528 earliestInputPinPriority = inputPin.priority;
674 }
675 }
676
2/2
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 463270 times.
463451 if (earliestInputPinPriority == -1000) { break; }
677
678 463270 auto& inputPin = node->inputPins[earliestInputPinIdx];
679
6/8
✓ Branch 0 taken 463265 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 463271 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 463276 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 463268 times.
✓ Branch 8 taken 8 times.
463270 if (inputPin.firable && inputPin.firable(node, inputPin))
680 {
681
2/4
✓ Branch 1 taken 463223 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 463233 times.
✗ Branch 4 not taken.
463268 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 63640 times.
✓ Branch 6 taken 463180 times.
526874 for (const auto& watcherCallback : inputPin.watcherCallbacks)
686 {
687
3/6
✓ Branch 1 taken 63638 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63640 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 63639 times.
✗ Branch 8 not taken.
63640 if (auto watcherCall = std::get<InputPin::FlowFirableWatcherCallbackFunc>(watcherCallback))
688 {
689
1/2
✓ Branch 1 taken 63642 times.
✗ Branch 2 not taken.
63639 std::invoke(watcherCall, node, inputPin.queue, earliestInputPinIdx);
690 63642 }
691 }
692 #endif
693
1/2
✓ Branch 1 taken 463215 times.
✗ Branch 2 not taken.
463180 std::invoke(callback, node, inputPin.queue, earliestInputPinIdx);
694 }
695 }
696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 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 8 break; // Do not drop an item, but put the worker to sleep
705 }
706 }
707 else
708 {
709 1 break;
710 }
711 }
712 }
713
714 // Post-processing (FileReader/Simulator)
715
2/2
✓ Branch 1 taken 119 times.
✓ Branch 2 taken 271495 times.
271625 if (!node->pollEvents.empty())
716 {
717 119 std::multimap<InsTime, std::pair<OutputPin*, size_t>>::iterator it;
718
7/10
✓ Branch 3 taken 119159 times.
✓ Branch 4 taken 12 times.
✓ Branch 6 taken 119175 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 119175 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 119178 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 119176 times.
✓ Branch 13 taken 11 times.
119187 while (it = node->pollEvents.begin(), it != node->pollEvents.end() && node->isInitialized() && node->callbacksEnabled)
719 {
720 119176 OutputPin* outputPin = it->second.first;
721 119153 size_t outputPinIdx = it->second.second;
722 119166 Node* node = outputPin->parentNode;
723
724
2/2
✓ Branch 1 taken 52949 times.
✓ Branch 2 taken 66227 times.
119166 if (std::holds_alternative<OutputPin::PollDataFunc>(outputPin->data))
725 {
726 52949 auto* callback = std::get_if<OutputPin::PollDataFunc>(&outputPin->data);
727
3/4
✓ Branch 0 taken 52939 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52938 times.
✓ Branch 3 taken 1 times.
52935 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 52938 times.
✓ Branch 3 taken 52952 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 110 times.
✓ Branch 8 taken 52843 times.
52938 if ((node->**callback)() == nullptr)
731 {
732
1/2
✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
110 node->pollEvents.erase(it); // Delete the event if no more data on this pin
733 110 break;
734 }
735 }
736 }
737
1/2
✓ Branch 1 taken 66225 times.
✗ Branch 2 not taken.
66227 else if (std::holds_alternative<OutputPin::PeekPollDataFunc>(outputPin->data))
738 {
739 66225 auto* callback = std::get_if<OutputPin::PeekPollDataFunc>(&outputPin->data);
740
2/4
✓ Branch 0 taken 66220 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66221 times.
✗ Branch 3 not taken.
66217 if (callback != nullptr && *callback != nullptr)
741 {
742
1/2
✓ Branch 2 taken 66223 times.
✗ Branch 3 not taken.
66221 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 66227 times.
✗ Branch 4 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 66223 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 66223 times.
✓ Branch 3 taken 66230 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 66207 times.
✓ Branch 7 taken 18 times.
66223 if (auto obs = (node->**callback)(outputPinIdx, true))
754 {
755 // Check if data has a time
756
1/2
✓ Branch 2 taken 66207 times.
✗ Branch 3 not taken.
66207 if (!obs->insTime.empty())
757 {
758
1/2
✓ Branch 4 taken 66208 times.
✗ Branch 5 not taken.
66207 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 18 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 66228 times.
✗ Branch 2 not taken.
66226 node->pollEvents.erase(it);
781 }
782 }
783
784
1/2
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
121 if (node->pollEvents.empty())
785 {
786 LOG_TRACE("{}: Finished polling all pins.", node->nameId());
787
788 119 node->callbacksEnabled = false;
789
2/2
✓ Branch 5 taken 134 times.
✓ Branch 6 taken 119 times.
253 for (auto& outputPin : node->outputPins)
790 {
791
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 24 times.
134 if (!outputPin.noMoreDataAvailable)
792 {
793 LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin.name);
794 110 outputPin.noMoreDataAvailable = true;
795
2/2
✓ Branch 5 taken 112 times.
✓ Branch 6 taken 110 times.
222 for (auto& link : outputPin.links)
796 {
797
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 link.connectedNode->wakeWorker();
798 }
799 }
800 }
801 119 node->_mode = Node::Mode::REAL_TIME;
802
1/2
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
119 FlowExecutor::deregisterNode(node);
803 }
804 }
805 }
806
807 // Check if node finished
808
2/2
✓ Branch 1 taken 271480 times.
✓ Branch 2 taken 1410 times.
272961 if (node->_mode == Mode::POST_PROCESSING)
809 {
810
3/4
✓ Branch 1 taken 271486 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 213 times.
✓ Branch 4 taken 271273 times.
271480 if (std::ranges::all_of(node->inputPins, [](const InputPin& inputPin) {
811
6/8
✓ Branch 2 taken 357441 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 357439 times.
✓ Branch 5 taken 2 times.
✓ Branch 7 taken 357443 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 271509 times.
✓ Branch 10 taken 85934 times.
1072338 return inputPin.type != Pin::Type::Flow || !inputPin.isPinLinked() || inputPin.link.connectedNode->isDisabled()
812
3/4
✓ Branch 1 taken 271525 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 271524 times.
✓ Branch 5 taken 1 times.
271509 || !inputPin.link.getConnectedPin()->blocksConnectedNodeFromFinishing
813
7/8
✓ Branch 0 taken 357441 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 152708 times.
✓ Branch 4 taken 118803 times.
✓ Branch 6 taken 152713 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 245 times.
✓ Branch 10 taken 152469 times.
1072372 || (inputPin.queue.empty() && inputPin.link.getConnectedPin()->noMoreDataAvailable);
814 }))
815 {
816 LOG_TRACE("{}: Node finished", node->nameId());
817 213 node->callbacksEnabled = false;
818
2/2
✓ Branch 5 taken 125 times.
✓ Branch 6 taken 213 times.
338 for (auto& outputPin : node->outputPins)
819 {
820 LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin.name);
821 125 outputPin.noMoreDataAvailable = true;
822
2/2
✓ Branch 5 taken 120 times.
✓ Branch 6 taken 125 times.
245 for (auto& link : outputPin.links)
823 {
824
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 link.connectedNode->wakeWorker();
825 }
826 }
827 213 node->_mode = Node::Mode::REAL_TIME;
828
1/2
✓ Branch 1 taken 218 times.
✗ Branch 2 not taken.
213 FlowExecutor::deregisterNode(node);
829 }
830 }
831 }
832 }
833
834 LOG_TRACE("{}: Worker thread ended.", node->nameId());
835 322 }
836
837 322 bool NAV::Node::workerInitializeNode()
838 {
839 LOG_TRACE("{}: called", nameId());
840 {
841
1/2
✓ Branch 1 taken 328 times.
✗ Branch 2 not taken.
322 std::scoped_lock lk(_stateMutex);
842
6/14
✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 333 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 336 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 336 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 330 times.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
665 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 332 _state = Node::State::Initializing;
844 332 }
845 336 _mode = Node::Mode::REAL_TIME;
846
847
3/6
✓ Branch 1 taken 333 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 338 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 339 times.
✗ Branch 9 not taken.
336 LOG_DEBUG("{}: Initializing Node", nameId());
848
849 // Initialize Nodes connected to the input pins
850
2/2
✓ Branch 5 taken 281 times.
✓ Branch 6 taken 339 times.
620 for (const auto& inputPin : inputPins)
851 {
852
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 255 times.
281 if (inputPin.type != Pin::Type::Flow)
853 {
854
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 8 times.
26 if (Node* connectedNode = inputPin.link.connectedNode)
855 {
856
3/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 7 times.
18 if (!connectedNode->isInitialized())
857 {
858
5/10
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 11 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 11 times.
✗ Branch 15 not taken.
11 LOG_DEBUG("{}: Initializing connected Node '{}' on input Pin {}", nameId(), connectedNode->nameId(), size_t(inputPin.id));
859
2/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
11 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 339 _reinitialize = false;
875
876 // Initialize the node itself
877 LOG_TRACE("{}: calling initialize()", nameId());
878 339 bool initSucceeded = false;
879 {
880
1/2
✓ Branch 1 taken 339 times.
✗ Branch 2 not taken.
339 std::scoped_lock<std::mutex> guard(_configWindowMutex);
881
1/2
✓ Branch 1 taken 339 times.
✗ Branch 2 not taken.
339 initSucceeded = initialize();
882 339 }
883
2/2
✓ Branch 0 taken 337 times.
✓ Branch 1 taken 1 times.
338 if (initSucceeded)
884 {
885 LOG_TRACE("{}: initialize() was successful", nameId());
886
887
2/2
✓ Branch 4 taken 280 times.
✓ Branch 5 taken 338 times.
618 for (auto& inputPin : inputPins)
888 {
889 280 inputPin.queue.clear();
890 281 inputPin.queueBlocked = false;
891 }
892
893 338 pollEvents.clear();
894 LOG_TRACE("{}: calling resetNode()", nameId());
895 {
896
1/2
✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
338 std::scoped_lock<std::mutex> guard(_configWindowMutex);
897
1/2
✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
338 resetNode();
898 338 }
899 LOG_TRACE("{}: resetNode() was successful", nameId());
900
2/2
✓ Branch 5 taken 280 times.
✓ Branch 6 taken 338 times.
618 for (auto& outputPin : outputPins)
901 {
902 280 outputPin.noMoreDataAvailable = true;
903
2/2
✓ Branch 5 taken 268 times.
✓ Branch 6 taken 280 times.
548 for (auto& link : outputPin.links)
904 {
905 LOG_TRACE("{}: Waking connected node '{}'", nameId(), link.connectedNode->nameId());
906
1/2
✓ Branch 1 taken 268 times.
✗ Branch 2 not taken.
268 link.connectedNode->wakeWorker();
907 }
908 }
909
910
1/2
✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
338 std::scoped_lock lk(_stateMutex);
911
1/2
✓ Branch 0 taken 338 times.
✗ Branch 1 not taken.
338 if (_state == State::Initializing)
912 {
913 338 _state = Node::State::Initialized;
914 }
915 338 return true;
916 338 }
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 337 bool NAV::Node::workerDeinitializeNode()
928 {
929 LOG_TRACE("{}: called", nameId());
930 {
931
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 std::scoped_lock lk(_stateMutex);
932
5/14
✓ Branch 0 taken 337 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 337 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 337 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 337 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 337 times.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
674 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 337 _state = Node::State::Deinitializing;
935 }
936 337 }
937
3/6
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 337 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 337 times.
✗ Branch 9 not taken.
337 LOG_DEBUG("{}: Deinitializing Node", nameId());
938
939 337 callbacksEnabled = false;
940
941 // Re-/Deinitialize Nodes connected to the output pins
942
2/2
✓ Branch 5 taken 280 times.
✓ Branch 6 taken 337 times.
617 for (const auto& outputPin : outputPins)
943 {
944
2/2
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 215 times.
280 if (outputPin.type != Pin::Type::Flow)
945 {
946
2/2
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 65 times.
68 for (const auto& link : outputPin.links)
947 {
948
3/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
3 if (link.connectedNode->isInitialized())
949 {
950
6/12
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
1 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 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 if (_reinitialize) { link.connectedNode->doReinitialize(); }
953
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 else { link.connectedNode->doDeinitialize(); }
954 }
955 }
956 }
957 }
958
959 // Deinitialize the node itself
960 {
961
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 std::scoped_lock<std::mutex> guard(_configWindowMutex);
962
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 deinitialize();
963 337 }
964
965
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 std::scoped_lock lk(_stateMutex);
966
1/2
✓ Branch 0 taken 337 times.
✗ Branch 1 not taken.
337 if (_state == State::Deinitializing)
967 {
968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 337 times.
337 if (_disable)
969 {
970 _state = State::Disabled;
971 }
972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 337 times.
337 else if (_reinitialize)
973 {
974 _state = State::DoInitialize;
975 }
976 else
977 {
978 337 _state = State::Deinitialized;
979 }
980 }
981
982 337 return true;
983 337 }
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 680 void NAV::from_json(const json& j, Node& node)
1008 {
1009
3/6
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 680 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 680 times.
✗ Branch 8 not taken.
680 node.id = j.at("id").get<size_t>();
1010
1/2
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
680 if (j.contains("kind"))
1011 {
1012
3/6
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 680 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 680 times.
✗ Branch 8 not taken.
680 node.kind = Node::Kind(j.at("kind").get<std::string>());
1013 }
1014
1/2
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
680 if (j.contains("name"))
1015 {
1016 680 j.at("name").get_to(node.name);
1017 }
1018
1/2
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
680 if (j.contains("size"))
1019 {
1020 680 j.at("size").get_to(node._size);
1021
2/8
✗ Branch 1 not taken.
✓ Branch 2 taken 680 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 680 times.
680 if (node.kind == Node::Kind::GroupBox && gui::NodeEditorApplication::isUsingBigDefaultFont())
1022 {
1023 node._size.y -= 20;
1024 }
1025 }
1026
1/2
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
680 if (j.contains("enabled"))
1027 {
1028 680 bool enabled = j.at("enabled").get<bool>();
1029
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 678 times.
680 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 680 times.
✗ Branch 2 not taken.
680 if (j.contains("inputPins"))
1037 {
1038
2/4
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 680 times.
✗ Branch 5 not taken.
680 auto inputPins = j.at("inputPins").get<std::vector<InputPin>>();
1039
2/2
✓ Branch 1 taken 533 times.
✓ Branch 2 taken 634 times.
1167 for (size_t i = 0; i < inputPins.size(); ++i)
1040 {
1041
2/2
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 487 times.
533 if (node.inputPins.size() <= i)
1042 {
1043 46 break;
1044 }
1045
4/8
✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 487 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 487 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 487 times.
✗ Branch 11 not taken.
487 j.at("inputPins").at(i).get_to(node.inputPins.at(i));
1046 }
1047 680 }
1048
1049
1/2
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
680 if (j.contains("outputPins"))
1050 {
1051
2/4
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 680 times.
✗ Branch 5 not taken.
680 auto outputPins = j.at("outputPins").get<std::vector<OutputPin>>();
1052
2/2
✓ Branch 1 taken 547 times.
✓ Branch 2 taken 676 times.
1223 for (size_t i = 0; i < outputPins.size(); ++i)
1053 {
1054
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 543 times.
547 if (node.outputPins.size() <= i)
1055 {
1056 4 break;
1057 }
1058
4/8
✓ Branch 1 taken 543 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 543 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 543 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 543 times.
✗ Branch 11 not taken.
543 j.at("outputPins").at(i).get_to(node.outputPins.at(i));
1059 }
1060 680 }
1061 680 }
1062