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/StringUtil.hpp" | ||
14 | #include "util/Assert.h" | ||
15 | |||
16 | #include "internal/FlowExecutor.hpp" | ||
17 | #include "internal/gui/FlowAnimation.hpp" | ||
18 | #include "internal/NodeManager.hpp" | ||
19 | namespace nm = NAV::NodeManager; | ||
20 | #include "util/Json.hpp" | ||
21 | #include "internal/gui/NodeEditorApplication.hpp" | ||
22 | |||
23 | #include <imgui_node_editor.h> | ||
24 | namespace ed = ax::NodeEditor; | ||
25 | #ifdef TESTING | ||
26 | #include <catch2/catch_test_macros.hpp> | ||
27 | #endif | ||
28 | |||
29 | 6394 | NAV::Node::Node(std::string name) | |
30 |
1/2✓ Branch 14 taken 6394 times.
✗ Branch 15 not taken.
|
6394 | : name(std::move(name)) |
31 | { | ||
32 | LOG_TRACE("{}: called", nameId()); | ||
33 |
2/2✓ Branch 0 taken 346 times.
✓ Branch 1 taken 6048 times.
|
6394 | if (_autostartWorker) |
34 | { | ||
35 |
1/2✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
|
346 | _worker = std::thread(workerThread, this); |
36 | } | ||
37 | 6394 | } | |
38 | |||
39 | 12784 | NAV::Node::~Node() | |
40 | { | ||
41 | LOG_TRACE("{}: called", nameId()); | ||
42 | |||
43 |
2/2✓ Branch 0 taken 344 times.
✓ Branch 1 taken 6048 times.
|
12784 | if (_autostartWorker) |
44 | { | ||
45 | 688 | _state = State::DoShutdown; | |
46 | 688 | wakeWorker(); | |
47 | |||
48 | // // wait for the worker | ||
49 | // { | ||
50 | // std::unique_lock lk(_workerMutex); | ||
51 | // _workerConditionVariable.wait(lk, [&, this] { return _state == State::Shutdown; }); | ||
52 | // } | ||
53 | 688 | _worker.join(); | |
54 | } | ||
55 | 12784 | } | |
56 | |||
57 | ✗ | void NAV::Node::guiConfig() {} | |
58 | |||
59 | ✗ | json NAV::Node::save() const { return {}; } | |
60 | |||
61 | 53 | void NAV::Node::restore(const json& /*j*/) {} | |
62 | |||
63 | 305 | void NAV::Node::restoreAtferLink(const json& /*j*/) {} | |
64 | |||
65 | 160 | bool NAV::Node::initialize() | |
66 | { | ||
67 | 160 | return true; | |
68 | } | ||
69 | |||
70 | 94 | void NAV::Node::deinitialize() {} | |
71 | |||
72 | 324 | void NAV::Node::flush() {} | |
73 | |||
74 | 329 | bool NAV::Node::resetNode() | |
75 | { | ||
76 | LOG_TRACE("{}: called", nameId()); | ||
77 | |||
78 | 329 | return initialize(); | |
79 | } | ||
80 | |||
81 | 532 | bool NAV::Node::onCreateLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) | |
82 | { | ||
83 | 532 | return true; | |
84 | } | ||
85 | |||
86 | 537 | void NAV::Node::onDeleteLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {} | |
87 | |||
88 | 444 | void NAV::Node::afterCreateLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {} | |
89 | |||
90 | 511 | void NAV::Node::afterDeleteLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {} | |
91 | |||
92 | ✗ | void NAV::Node::notifyOutputValueChanged(size_t pinIdx, const InsTime& insTime, const std::scoped_lock<std::mutex>& /* guard */) | |
93 | { | ||
94 | ✗ | if (callbacksEnabled && isInitialized()) | |
95 | { | ||
96 | ✗ | auto& outputPin = outputPins.at(pinIdx); | |
97 | |||
98 | ✗ | if (!outputPin.isPinLinked()) { return; } | |
99 | |||
100 | ✗ | for (auto& link : outputPin.links) | |
101 | { | ||
102 | ✗ | auto* targetPin = link.getConnectedPin(); | |
103 | ✗ | if (link.connectedNode->isInitialized() && !targetPin->queueBlocked) | |
104 | { | ||
105 | ✗ | outputPin.dataAccessCounter++; | |
106 | ✗ | link.dataChangeNotification = true; | |
107 | LOG_DATA("{}: Increasing data access counter on output pin '{}'. Value now {}.", nameId(), outputPin.name, outputPin.dataAccessCounter); | ||
108 | |||
109 | ✗ | if (nm::showFlowWhenNotifyingValueChange) | |
110 | { | ||
111 | ✗ | FlowAnimation::Add(link.linkId); | |
112 | } | ||
113 | |||
114 | ✗ | auto data = std::make_shared<NodeData>(); | |
115 | ✗ | data->insTime = insTime; | |
116 | |||
117 | ✗ | targetPin->queue.push_back(data); | |
118 | ✗ | } | |
119 | } | ||
120 | ✗ | for (const auto& link : outputPin.links) | |
121 | { | ||
122 | ✗ | auto* targetPin = link.getConnectedPin(); | |
123 | ✗ | if (link.connectedNode->isInitialized() && !targetPin->queueBlocked) | |
124 | { | ||
125 | LOG_DATA("{}: Waking up worker of node '{}'. New data on pin '{}'", nameId(), link.connectedNode->nameId(), targetPin->name); | ||
126 | ✗ | link.connectedNode->wakeWorker(); | |
127 | } | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | 145 | std::scoped_lock<std::mutex> NAV::Node::requestOutputValueLock(size_t pinIdx) | |
133 | { | ||
134 | 145 | auto& outputPin = outputPins.at(pinIdx); | |
135 | { | ||
136 |
1/2✓ Branch 1 taken 145 times.
✗ Branch 2 not taken.
|
145 | std::unique_lock<std::mutex> lk(outputPin.dataAccessMutex); |
137 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 145 times.
|
145 | if (outputPin.dataAccessCounter > 0) |
138 | { | ||
139 | LOG_DATA("{}: Requesting lock on output pin '{}', {} threads accessing still.", nameId(), outputPin.name, outputPin.dataAccessCounter); | ||
140 | ✗ | outputPin.dataAccessConditionVariable.wait(lk, [&outputPin]() { return outputPin.dataAccessCounter == 0; }); | |
141 | LOG_DATA("{}: Lock on output pin '{}' acquired.", nameId(), outputPin.name); | ||
142 | } | ||
143 | 145 | } | |
144 | 145 | return std::scoped_lock(outputPin.dataAccessMutex); | |
145 | } | ||
146 | |||
147 | ✗ | void NAV::Node::releaseInputValue(size_t portIndex) | |
148 | { | ||
149 | ✗ | if (OutputPin* outputPin = inputPins.at(portIndex).link.getConnectedPin()) | |
150 | { | ||
151 | ✗ | std::scoped_lock<std::mutex> lk(outputPin->dataAccessMutex); | |
152 | ✗ | if (outputPin->dataAccessCounter > 0) | |
153 | { | ||
154 | ✗ | auto outgoingLink = std::ranges::find_if(outputPin->links, [&](const OutputPin::OutgoingLink& link) { | |
155 | ✗ | return link.connectedPinId == inputPins.at(portIndex).id; | |
156 | }); | ||
157 | ✗ | if (outgoingLink != outputPin->links.end() && outgoingLink->dataChangeNotification) | |
158 | { | ||
159 | ✗ | outgoingLink->dataChangeNotification = false; | |
160 | ✗ | outputPin->dataAccessCounter--; | |
161 | |||
162 | ✗ | if (outputPin->dataAccessCounter == 0) | |
163 | { | ||
164 | LOG_DATA("{}: Notifying node '{}' connected to pin {} that all data is read.", nameId(), outputPin->parentNode->nameId(), outputPin->name); | ||
165 | ✗ | outputPin->dataAccessConditionVariable.notify_all(); | |
166 | } | ||
167 | } | ||
168 | } | ||
169 | ✗ | } | |
170 | ✗ | } | |
171 | |||
172 | 365355 | void NAV::Node::invokeCallbacks(size_t portIndex, const std::shared_ptr<const NAV::NodeData>& data) | |
173 | { | ||
174 |
2/2✓ Branch 0 taken 365340 times.
✓ Branch 1 taken 15 times.
|
365355 | if (callbacksEnabled) |
175 | { | ||
176 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 365244 times.
|
365340 | if (data == nullptr) |
177 | { | ||
178 | ✗ | LOG_DEBUG("{}: Tried to invokeCallbacks on pin {} with a nullptr, which is not allowed!!!", nameId(), portIndex); | |
179 | ✗ | return; | |
180 | } | ||
181 |
2/2✓ Branch 2 taken 49 times.
✓ Branch 3 taken 365058 times.
|
365244 | if (data->insTime.empty()) |
182 | { | ||
183 | LOG_DATA("{}: Tried to invokeCallbacks on pin {} without a InsTime. The time is mandatory though!!! ", nameId(), portIndex); | ||
184 | 49 | return; | |
185 | } | ||
186 | |||
187 |
3/4✓ Branch 1 taken 365134 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 543087 times.
✓ Branch 9 taken 365317 times.
|
908470 | for (const auto& link : outputPins.at(portIndex).links) |
188 | { | ||
189 |
1/2✓ Branch 1 taken 543416 times.
✗ Branch 2 not taken.
|
543031 | auto* targetPin = link.getConnectedPin(); |
190 |
7/8✓ Branch 1 taken 543138 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 494691 times.
✓ Branch 4 taken 48447 times.
✓ Branch 5 taken 467123 times.
✓ Branch 6 taken 27568 times.
✓ Branch 7 taken 467132 times.
✓ Branch 8 taken 76006 times.
|
543416 | if (link.connectedNode->isInitialized() && !targetPin->queueBlocked) |
191 | { | ||
192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 467132 times.
|
467132 | if (NodeManager::showFlowWhenNotifyingValueChange) |
193 | { | ||
194 | ✗ | FlowAnimation::Add(link.linkId); | |
195 | } | ||
196 | |||
197 |
1/2✓ Branch 1 taken 466915 times.
✗ Branch 2 not taken.
|
467132 | targetPin->queue.push_back(data); |
198 | LOG_DATA("{}: Waking up worker of node {}. New data on pin '{}'", nameId(), size_t(link.connectedNode->id), targetPin->name); | ||
199 |
1/2✓ Branch 1 taken 467406 times.
✗ Branch 2 not taken.
|
466915 | link.connectedNode->wakeWorker(); |
200 | } | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | |||
205 | ✗ | NAV::InputPin& NAV::Node::inputPinFromId(ax::NodeEditor::PinId pinId) | |
206 | { | ||
207 | ✗ | for (auto& inputPin : inputPins) | |
208 | { | ||
209 | ✗ | if (pinId == inputPin.id) { return inputPin; } | |
210 | } | ||
211 | |||
212 | ✗ | throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str()); | |
213 | } | ||
214 | |||
215 | ✗ | NAV::OutputPin& NAV::Node::outputPinFromId(ax::NodeEditor::PinId pinId) | |
216 | { | ||
217 | ✗ | for (auto& outputPin : outputPins) | |
218 | { | ||
219 | ✗ | if (pinId == outputPin.id) { return outputPin; } | |
220 | } | ||
221 | |||
222 | ✗ | throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str()); | |
223 | } | ||
224 | |||
225 | 75 | size_t NAV::Node::inputPinIndexFromId(ax::NodeEditor::PinId pinId) const | |
226 | { | ||
227 |
1/2✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
|
154 | for (size_t i = 0; i < inputPins.size(); i++) |
228 | { | ||
229 |
2/2✓ Branch 2 taken 75 times.
✓ Branch 3 taken 79 times.
|
154 | if (pinId == inputPins.at(i).id) { return i; } |
230 | } | ||
231 | |||
232 | ✗ | throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str()); | |
233 | } | ||
234 | |||
235 | ✗ | size_t NAV::Node::outputPinIndexFromId(ax::NodeEditor::PinId pinId) const | |
236 | { | ||
237 | ✗ | for (size_t i = 0; i < outputPins.size(); i++) | |
238 | { | ||
239 | ✗ | if (pinId == outputPins.at(i).id) { return i; } | |
240 | } | ||
241 | |||
242 | ✗ | throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str()); | |
243 | } | ||
244 | |||
245 | 99229 | std::string NAV::Node::nameId() const | |
246 | { | ||
247 |
5/10✓ Branch 1 taken 99223 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 99196 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 99183 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 99213 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 99177 times.
✗ Branch 14 not taken.
|
595195 | return fmt::format("{} ({})", str::replaceAll_copy(name, "\n", ""), size_t(id)); |
248 | } | ||
249 | |||
250 | ✗ | const ImVec2& NAV::Node::getSize() const | |
251 | { | ||
252 | ✗ | return _size; | |
253 | } | ||
254 | |||
255 | 672 | std::string NAV::Node::toString(State state) | |
256 | { | ||
257 |
2/10✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 339 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 340 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
672 | switch (state) |
258 | { | ||
259 | ✗ | case State::Disabled: | |
260 | ✗ | return "Disabled"; | |
261 | ✗ | case State::Deinitialized: | |
262 | ✗ | return "Deinitialized"; | |
263 | 339 | case State::DoInitialize: | |
264 |
1/2✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
|
681 | return "DoInitialize"; |
265 | ✗ | case State::Initializing: | |
266 | ✗ | return "Initializing"; | |
267 | ✗ | case State::Initialized: | |
268 | ✗ | return "Initialized"; | |
269 | 340 | case State::DoDeinitialize: | |
270 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
680 | return "DoDeinitialize"; |
271 | ✗ | case State::Deinitializing: | |
272 | ✗ | return "Deinitializing"; | |
273 | ✗ | case State::DoShutdown: | |
274 | ✗ | return "DoShutdown"; | |
275 | ✗ | case State::Shutdown: | |
276 | ✗ | return "Shutdown"; | |
277 | } | ||
278 | ✗ | return ""; | |
279 | } | ||
280 | |||
281 | ✗ | NAV::Node::State NAV::Node::getState() const | |
282 | { | ||
283 | ✗ | std::scoped_lock lk(_stateMutex); | |
284 | ✗ | return _state; | |
285 | ✗ | } | |
286 | |||
287 | ✗ | NAV::Node::Mode NAV::Node::getMode() const | |
288 | { | ||
289 | ✗ | return _mode; | |
290 | } | ||
291 | |||
292 | 507 | bool NAV::Node::doInitialize(bool wait) | |
293 | { | ||
294 |
1/2✓ Branch 1 taken 507 times.
✗ Branch 2 not taken.
|
507 | std::unique_lock<std::mutex> lk(_stateMutex); |
295 | LOG_TRACE("{}: Current state = {}", nameId(), toString(_state)); | ||
296 | |||
297 |
2/6✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 165 times.
✓ Branch 4 taken 342 times.
✗ Branch 5 not taken.
|
507 | switch (_state) |
298 | { | ||
299 | ✗ | case State::Initialized: | |
300 | ✗ | lk.unlock(); | |
301 | ✗ | return true; | |
302 | ✗ | case State::Disabled: | |
303 | case State::DoShutdown: | ||
304 | case State::Shutdown: | ||
305 | ✗ | lk.unlock(); | |
306 | ✗ | return false; | |
307 | ✗ | case State::DoDeinitialize: | |
308 | case State::Deinitializing: | ||
309 | ✗ | if (_reinitialize) | |
310 | { | ||
311 | ✗ | lk.unlock(); | |
312 | ✗ | break; | |
313 | } | ||
314 | ✗ | lk.unlock(); | |
315 | ✗ | return false; | |
316 | 165 | case State::DoInitialize: | |
317 | case State::Initializing: | ||
318 |
1/2✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
|
165 | lk.unlock(); |
319 | 165 | break; | |
320 | 342 | case State::Deinitialized: | |
321 | { | ||
322 | 342 | _state = State::DoInitialize; | |
323 |
1/2✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
|
342 | lk.unlock(); |
324 |
1/2✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
|
342 | wakeWorker(); |
325 | 342 | break; | |
326 | } | ||
327 | } | ||
328 | |||
329 |
2/2✓ Branch 0 taken 165 times.
✓ Branch 1 taken 342 times.
|
507 | if (wait) |
330 | { | ||
331 |
1/2✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
|
165 | std::unique_lock lk(_workerMutex); |
332 |
1/2✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
|
165 | _workerConditionVariable.wait(lk, [&, this] { |
333 |
1/2✓ Branch 1 taken 356 times.
✗ Branch 2 not taken.
|
356 | std::scoped_lock lks(_stateMutex); |
334 |
4/4✓ Branch 0 taken 192 times.
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 191 times.
|
712 | return _state == State::Initialized || _state == State::Deinitialized; |
335 | 356 | }); | |
336 |
1/2✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
|
165 | std::scoped_lock lks(_stateMutex); |
337 | 165 | return _state == State::Initialized; | |
338 | 165 | } | |
339 | 342 | return true; | |
340 | 507 | } | |
341 | |||
342 | ✗ | bool NAV::Node::doReinitialize(bool wait) | |
343 | { | ||
344 | ✗ | std::unique_lock<std::mutex> lk(_stateMutex); | |
345 | LOG_TRACE("{}: Current state = {}", nameId(), toString(_state)); | ||
346 | |||
347 | ✗ | switch (_state) | |
348 | { | ||
349 | ✗ | case State::Disabled: | |
350 | case State::DoShutdown: | ||
351 | case State::Shutdown: | ||
352 | ✗ | lk.unlock(); | |
353 | ✗ | return false; | |
354 | ✗ | case State::DoDeinitialize: | |
355 | case State::Deinitializing: | ||
356 | ✗ | _reinitialize = true; | |
357 | ✗ | lk.unlock(); | |
358 | ✗ | break; | |
359 | ✗ | case State::DoInitialize: | |
360 | case State::Initializing: | ||
361 | ✗ | lk.unlock(); | |
362 | ✗ | break; | |
363 | ✗ | case State::Deinitialized: | |
364 | ✗ | lk.unlock(); | |
365 | ✗ | return doInitialize(wait); | |
366 | ✗ | case State::Initialized: | |
367 | ✗ | _state = State::DoDeinitialize; | |
368 | ✗ | _reinitialize = true; | |
369 | ✗ | lk.unlock(); | |
370 | ✗ | wakeWorker(); | |
371 | ✗ | break; | |
372 | } | ||
373 | |||
374 | ✗ | if (wait) | |
375 | { | ||
376 | ✗ | std::unique_lock lk(_workerMutex); | |
377 | ✗ | _workerConditionVariable.wait(lk, [&, this] { | |
378 | ✗ | std::scoped_lock lks(_stateMutex); | |
379 | ✗ | return _state == State::Initialized || _state == State::Deinitialized; | |
380 | ✗ | }); | |
381 | ✗ | std::scoped_lock lks(_stateMutex); | |
382 | ✗ | return _state == State::Initialized; | |
383 | ✗ | } | |
384 | ✗ | return true; | |
385 | ✗ | } | |
386 | |||
387 | 356 | bool NAV::Node::doDeinitialize(bool wait) | |
388 | { | ||
389 |
1/2✓ Branch 1 taken 356 times.
✗ Branch 2 not taken.
|
356 | std::unique_lock<std::mutex> lk(_stateMutex); |
390 | LOG_TRACE("{}: Current state = {}", nameId(), toString(_state)); | ||
391 | |||
392 |
3/5✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 340 times.
✗ Branch 4 not taken.
|
356 | switch (_state) |
393 | { | ||
394 | 10 | case State::Deinitialized: | |
395 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | lk.unlock(); |
396 | 10 | return true; | |
397 | 6 | case State::Disabled: | |
398 | case State::DoShutdown: | ||
399 | case State::Shutdown: | ||
400 | case State::DoInitialize: | ||
401 | case State::Initializing: | ||
402 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | lk.unlock(); |
403 | 6 | return false; | |
404 | ✗ | case State::DoDeinitialize: | |
405 | case State::Deinitializing: | ||
406 | ✗ | lk.unlock(); | |
407 | ✗ | break; | |
408 | 340 | case State::Initialized: | |
409 | { | ||
410 | 340 | _state = State::DoDeinitialize; | |
411 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
340 | lk.unlock(); |
412 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
340 | wakeWorker(); |
413 | 340 | break; | |
414 | } | ||
415 | } | ||
416 | |||
417 |
2/2✓ Branch 0 taken 338 times.
✓ Branch 1 taken 2 times.
|
340 | if (wait) |
418 | { | ||
419 |
1/2✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
|
338 | std::unique_lock lk(_workerMutex); |
420 |
1/2✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
|
338 | _workerConditionVariable.wait(lk, [&, this] { |
421 |
1/2✓ Branch 1 taken 676 times.
✗ Branch 2 not taken.
|
676 | std::scoped_lock lks(_stateMutex); |
422 | 676 | return _state == State::Deinitialized; | |
423 | 676 | }); | |
424 | 338 | } | |
425 | 340 | return true; | |
426 | 356 | } | |
427 | |||
428 | ✗ | bool NAV::Node::doDisable(bool wait) | |
429 | { | ||
430 | ✗ | std::unique_lock<std::mutex> lk(_stateMutex); | |
431 | LOG_TRACE("{}: Current state = {}", nameId(), toString(_state)); | ||
432 | |||
433 | ✗ | switch (_state) | |
434 | { | ||
435 | ✗ | case State::Disabled: | |
436 | ✗ | lk.unlock(); | |
437 | ✗ | return true; | |
438 | ✗ | case State::DoShutdown: | |
439 | case State::Shutdown: | ||
440 | case State::Initializing: | ||
441 | ✗ | lk.unlock(); | |
442 | ✗ | return false; | |
443 | ✗ | case State::Initialized: | |
444 | case State::DoDeinitialize: | ||
445 | case State::Deinitializing: | ||
446 | ✗ | _disable = true; | |
447 | ✗ | lk.unlock(); | |
448 | ✗ | doDeinitialize(); | |
449 | ✗ | break; | |
450 | ✗ | case State::DoInitialize: | |
451 | case State::Deinitialized: | ||
452 | { | ||
453 | ✗ | _state = State::Disabled; | |
454 | ✗ | lk.unlock(); | |
455 | ✗ | break; | |
456 | } | ||
457 | } | ||
458 | |||
459 | ✗ | if (wait) | |
460 | { | ||
461 | ✗ | std::unique_lock lk(_workerMutex); | |
462 | ✗ | _workerConditionVariable.wait(lk, [&, this] { | |
463 | ✗ | std::scoped_lock lks(_stateMutex); | |
464 | ✗ | return _state == State::Deinitialized; | |
465 | ✗ | }); | |
466 | ✗ | } | |
467 | ✗ | return true; | |
468 | ✗ | } | |
469 | |||
470 | ✗ | bool NAV::Node::doEnable() | |
471 | { | ||
472 | ✗ | std::scoped_lock lk(_stateMutex); | |
473 | LOG_TRACE("{}: Current state = {}", nameId(), toString(_state)); | ||
474 | |||
475 | ✗ | if (_state == State::Disabled) | |
476 | { | ||
477 | ✗ | _state = State::Deinitialized; | |
478 | } | ||
479 | ✗ | return true; | |
480 | ✗ | } | |
481 | |||
482 | 468780 | void NAV::Node::wakeWorker() | |
483 | { | ||
484 | { | ||
485 |
1/2✓ Branch 1 taken 468872 times.
✗ Branch 2 not taken.
|
468780 | std::scoped_lock lk(_workerMutex); |
486 | 468872 | _workerWakeup = true; | |
487 | 468872 | } | |
488 | 468880 | _workerConditionVariable.notify_all(); | |
489 | 469312 | } | |
490 | |||
491 | 363504 | bool NAV::Node::isDisabled() const | |
492 | { | ||
493 |
1/2✓ Branch 1 taken 363534 times.
✗ Branch 2 not taken.
|
363504 | std::scoped_lock lk(_stateMutex); |
494 | 363529 | return _state == State::Disabled; | |
495 | 363534 | } | |
496 | 1677275 | bool NAV::Node::isInitialized() const | |
497 | { | ||
498 |
1/2✓ Branch 1 taken 1675088 times.
✗ Branch 2 not taken.
|
1677275 | std::scoped_lock lk(_stateMutex); |
499 | 1674976 | return _state == State::Initialized; | |
500 | 1675088 | } | |
501 | 272463 | bool NAV::Node::isTransient() const | |
502 | { | ||
503 |
1/2✓ Branch 1 taken 272461 times.
✗ Branch 2 not taken.
|
272463 | std::scoped_lock lk(_stateMutex); |
504 |
1/3✓ Branch 0 taken 272462 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
272461 | switch (_state) |
505 | { | ||
506 | 272462 | case State::Disabled: | |
507 | case State::Initialized: | ||
508 | case State::Deinitialized: | ||
509 | 272462 | return false; | |
510 | ✗ | case State::DoShutdown: | |
511 | case State::Shutdown: | ||
512 | case State::Initializing: | ||
513 | case State::DoDeinitialize: | ||
514 | case State::Deinitializing: | ||
515 | case State::DoInitialize: | ||
516 | ✗ | return true; | |
517 | } | ||
518 | |||
519 | ✗ | return true; | |
520 | 272461 | } | |
521 | 3 | bool NAV::Node::isOnlyRealtime() const | |
522 | { | ||
523 | 3 | return _onlyRealTime; | |
524 | } | ||
525 | |||
526 | 346 | void NAV::Node::workerThread(Node* node) | |
527 | { | ||
528 | LOG_TRACE("{}: Worker thread started.", node->nameId()); | ||
529 | |||
530 |
1/2✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
|
346 | std::unique_lock<std::mutex> lk(node->_stateMutex); |
531 |
4/6✓ Branch 1 taken 273474 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 273475 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 273485 times.
✗ Branch 6 not taken.
|
546953 | while ([]() { return true; }() && node->_state != State::Shutdown) |
532 | { | ||
533 |
3/4✓ Branch 1 taken 1028 times.
✓ Branch 2 taken 272464 times.
✓ Branch 4 taken 1028 times.
✗ Branch 5 not taken.
|
273485 | if (lk.owns_lock()) { lk.unlock(); } |
534 | |||
535 |
1/2✓ Branch 1 taken 273462 times.
✗ Branch 2 not taken.
|
273492 | if (std::unique_lock<std::mutex> lock(node->_stateMutex); |
536 |
2/2✓ Branch 0 taken 344 times.
✓ Branch 1 taken 273118 times.
|
273462 | node->_state == State::DoShutdown) |
537 | { | ||
538 | LOG_TRACE("{}: Worker doing shutdown...", node->nameId()); | ||
539 | 344 | node->_state = State::Shutdown; | |
540 |
1/2✓ Branch 1 taken 344 times.
✗ Branch 2 not taken.
|
344 | lock.unlock(); |
541 | 344 | node->_workerConditionVariable.notify_all(); | |
542 | 344 | break; | |
543 | 273462 | } | |
544 |
1/2✓ Branch 1 taken 273132 times.
✗ Branch 2 not taken.
|
273103 | if (std::unique_lock<std::mutex> lock(node->_stateMutex); |
545 |
2/2✓ Branch 0 taken 334 times.
✓ Branch 1 taken 272798 times.
|
273132 | node->_state == State::DoInitialize) |
546 | { | ||
547 | LOG_TRACE("{}: Worker doing initialization...", node->nameId()); | ||
548 |
1/2✓ Branch 1 taken 332 times.
✗ Branch 2 not taken.
|
334 | lock.unlock(); |
549 |
1/2✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
|
332 | node->workerInitializeNode(); |
550 | LOG_TRACE("{}: Worker finished initialization, notifying all waiting threads (state = {})", node->nameId(), Node::toString(node->_state)); | ||
551 | 342 | node->_workerConditionVariable.notify_all(); | |
552 | |||
553 |
1/2✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
|
342 | lk.lock(); |
554 | 342 | continue; | |
555 | 273140 | } | |
556 |
1/2✓ Branch 1 taken 272806 times.
✗ Branch 2 not taken.
|
272785 | if (std::unique_lock<std::mutex> lock(node->_stateMutex); |
557 |
2/2✓ Branch 0 taken 340 times.
✓ Branch 1 taken 272466 times.
|
272806 | node->_state == State::DoDeinitialize) |
558 | { | ||
559 | LOG_TRACE("{}: Worker doing deinitialization...", node->nameId()); | ||
560 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
340 | lock.unlock(); |
561 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
340 | node->workerDeinitializeNode(); |
562 | LOG_TRACE("{}: Worker finished deinitialization, notifying all waiting threads (state = {})", node->nameId(), Node::toString(node->_state)); | ||
563 | 340 | node->_workerConditionVariable.notify_all(); | |
564 | |||
565 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
340 | lk.lock(); |
566 | 340 | continue; | |
567 | 272806 | } | |
568 | |||
569 |
2/4✓ Branch 1 taken 272469 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 272472 times.
✗ Branch 4 not taken.
|
272469 | if (!node->isTransient()) |
570 | { | ||
571 | // Wait for data or state change | ||
572 | LOG_DATA("{}: Worker going to sleep", node->nameId()); | ||
573 | 272472 | bool timeout = false; | |
574 | { | ||
575 |
1/2✓ Branch 1 taken 272468 times.
✗ Branch 2 not taken.
|
272472 | std::unique_lock lk(node->_workerMutex); |
576 |
1/2✓ Branch 1 taken 272410 times.
✗ Branch 2 not taken.
|
813055 | timeout = !node->_workerConditionVariable.wait_for(lk, node->_workerTimeout, [node] { return node->_workerWakeup; }); |
577 | 272410 | node->_workerWakeup = false; | |
578 | 272410 | } | |
579 | LOG_DATA("{}: Worker woke up", node->nameId()); | ||
580 | |||
581 |
8/10✓ Branch 1 taken 271881 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 270566 times.
✓ Branch 4 taken 1315 times.
✓ Branch 5 taken 264 times.
✓ Branch 6 taken 270302 times.
✓ Branch 8 taken 551 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 271048 times.
✓ Branch 11 taken 833 times.
|
271889 | if (node->isInitialized() && (node->callbacksEnabled || node->_mode == Node::Mode::REAL_TIME)) |
582 | { | ||
583 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 271047 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
271048 | if (timeout && node->callbacksEnabled) // Timeout reached |
584 | { | ||
585 | ✗ | node->workerTimeoutHandler(); | |
586 | } | ||
587 | |||
588 | // Check input pin for data and trigger callbacks | ||
589 |
2/4✓ Branch 1 taken 270260 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 270534 times.
✗ Branch 4 not taken.
|
271048 | if (std::ranges::any_of(node->inputPins, [](const InputPin& inputPin) { |
590 | 269904 | return inputPin.isPinLinked(); | |
591 | })) | ||
592 | { | ||
593 |
2/4✓ Branch 1 taken 737442 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 737460 times.
✗ Branch 4 not taken.
|
737745 | while (node->isInitialized()) |
594 | { | ||
595 | // -------------------------- Data processing on input non-flow pins ----------------------------- | ||
596 | 737460 | bool notifyTriggered = false; | |
597 |
2/2✓ Branch 1 taken 2121677 times.
✓ Branch 2 taken 738376 times.
|
2860639 | for (size_t i = 0; i < node->inputPins.size(); i++) |
598 | { | ||
599 | 2121677 | auto& inputPin = node->inputPins[i]; | |
600 |
4/6✓ Branch 1 taken 817 times.
✓ Branch 2 taken 2122362 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 817 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2123179 times.
|
2122572 | if (inputPin.type != Pin::Type::Flow && !inputPin.queue.empty()) |
601 | { | ||
602 | ✗ | if (auto callback = std::get<InputPin::DataChangedNotifyFunc>(inputPin.callback)) | |
603 | { | ||
604 | LOG_DATA("{}: Invoking notify callback on input pin '{}'", node->nameId(), inputPin.name); | ||
605 | ✗ | InsTime insTime = inputPin.queue.extract_front()->insTime; | |
606 | #ifdef TESTING | ||
607 | ✗ | for (const auto& watcherCallback : inputPin.watcherCallbacks) | |
608 | { | ||
609 | ✗ | if (auto watcherCall = std::get<InputPin::DataChangedWatcherNotifyFunc>(watcherCallback)) | |
610 | { | ||
611 | ✗ | std::invoke(watcherCall, node, insTime, i); | |
612 | ✗ | } | |
613 | } | ||
614 | #endif | ||
615 | ✗ | std::invoke(callback, node, insTime, i); | |
616 | ✗ | notifyTriggered = true; | |
617 | } | ||
618 | } | ||
619 | } | ||
620 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 738376 times.
|
738376 | if (notifyTriggered) { continue; } |
621 | |||
622 | // ------------------------------ Process data on input flow pins -------------------------------- | ||
623 |
6/6✓ Branch 0 taken 263 times.
✓ Branch 1 taken 738113 times.
✓ Branch 3 taken 234 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 738363 times.
✓ Branch 6 taken 13 times.
|
738376 | if (node->callbacksEnabled || node->_mode == Node::Mode::REAL_TIME) |
624 | { | ||
625 | LOG_DATA("{}: Checking for firable input pins", node->nameId()); | ||
626 | |||
627 |
2/2✓ Branch 1 taken 736416 times.
✓ Branch 2 taken 242 times.
|
738363 | if (node->_mode == Mode::POST_PROCESSING) |
628 | { | ||
629 | // Check if all input flow pins have data | ||
630 | 736416 | bool allInputPinsHaveData = !node->inputPins.empty(); | |
631 |
2/2✓ Branch 5 taken 2028925 times.
✓ Branch 6 taken 467538 times.
|
2497945 | for (const auto& inputPin : node->inputPins) |
632 | { | ||
633 |
9/10✓ Branch 1 taken 2030262 times.
✓ Branch 2 taken 2212 times.
✓ Branch 3 taken 2030892 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1953466 times.
✓ Branch 6 taken 77426 times.
✓ Branch 8 taken 507307 times.
✓ Branch 9 taken 1446234 times.
✓ Branch 10 taken 507307 times.
✓ Branch 11 taken 1525242 times.
|
2030361 | if (inputPin.type == Pin::Type::Flow && inputPin.neededForTemporalQueueCheck && !inputPin.queueBlocked && inputPin.queue.empty()) |
634 | { | ||
635 |
1/2✓ Branch 1 taken 507294 times.
✗ Branch 2 not taken.
|
507307 | if (auto* connectedPin = inputPin.link.getConnectedPin(); |
636 |
6/6✓ Branch 0 taken 506965 times.
✓ Branch 1 taken 329 times.
✓ Branch 3 taken 270823 times.
✓ Branch 4 taken 236119 times.
✓ Branch 5 taken 270825 times.
✓ Branch 6 taken 236446 times.
|
507294 | connectedPin && !connectedPin->noMoreDataAvailable) |
637 | { | ||
638 | 270825 | allInputPinsHaveData = false; | |
639 | 270825 | break; | |
640 | } | ||
641 | } | ||
642 | } | ||
643 |
2/2✓ Branch 0 taken 270816 times.
✓ Branch 1 taken 467547 times.
|
738363 | if (!allInputPinsHaveData) |
644 | { | ||
645 | LOG_DATA("{}: Not all pins have data for temporal sorting", node->nameId()); | ||
646 | 271251 | break; | |
647 | } | ||
648 | LOG_DATA("{}: All pins have data for temporal sorting", node->nameId()); | ||
649 | } | ||
650 | |||
651 | // Find pin with the earliest data | ||
652 | 467789 | InsTime earliestTime; | |
653 | 467789 | size_t earliestInputPinIdx = 0; | |
654 | 467789 | int earliestInputPinPriority = -1000; | |
655 |
2/2✓ Branch 1 taken 1371370 times.
✓ Branch 2 taken 467710 times.
|
1839547 | for (size_t i = 0; i < node->inputPins.size(); i++) |
656 | { | ||
657 | 1371370 | auto& inputPin = node->inputPins[i]; | |
658 |
2/2✓ Branch 2 taken 1148206 times.
✓ Branch 3 taken 223959 times.
|
2744928 | if (inputPin.type == Pin::Type::Flow && !inputPin.queue.empty() |
659 |
6/6✓ Branch 0 taken 1372233 times.
✓ Branch 1 taken 435 times.
✓ Branch 3 taken 681309 times.
✓ Branch 4 taken 466580 times.
✓ Branch 5 taken 678769 times.
✓ Branch 6 taken 693735 times.
|
3426363 | && (earliestTime.empty() |
660 |
2/2✓ Branch 3 taken 469262 times.
✓ Branch 4 taken 211610 times.
|
681309 | || inputPin.queue.front()->insTime < earliestTime |
661 |
4/4✓ Branch 3 taken 392570 times.
✓ Branch 4 taken 77350 times.
✓ Branch 5 taken 526 times.
✓ Branch 6 taken 392044 times.
|
469262 | || (inputPin.queue.front()->insTime == earliestTime && inputPin.priority > earliestInputPinPriority))) |
662 | { | ||
663 | 678769 | earliestTime = inputPin.queue.front()->insTime; | |
664 | 678023 | earliestInputPinIdx = i; | |
665 | 678023 | earliestInputPinPriority = inputPin.priority; | |
666 | } | ||
667 | } | ||
668 |
2/2✓ Branch 0 taken 437 times.
✓ Branch 1 taken 467273 times.
|
467710 | if (earliestInputPinPriority == -1000) { break; } |
669 | |||
670 | 467273 | auto& inputPin = node->inputPins[earliestInputPinIdx]; | |
671 |
5/8✓ Branch 0 taken 467262 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 467306 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 467307 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 467309 times.
✗ Branch 8 not taken.
|
467263 | if (inputPin.firable && inputPin.firable(node, inputPin)) |
672 | { | ||
673 |
2/4✓ Branch 1 taken 467174 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 467192 times.
✗ Branch 4 not taken.
|
467309 | if (auto callback = std::get<InputPin::FlowFirableCallbackFunc>(inputPin.callback)) |
674 | { | ||
675 | LOG_DATA("{}: Invoking callback on input pin '{}'", node->nameId(), inputPin.name); | ||
676 | #ifdef TESTING | ||
677 |
2/2✓ Branch 5 taken 63639 times.
✓ Branch 6 taken 467125 times.
|
530834 | for (const auto& watcherCallback : inputPin.watcherCallbacks) |
678 | { | ||
679 |
3/6✓ Branch 1 taken 63640 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63642 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 63642 times.
✗ Branch 8 not taken.
|
63639 | if (auto watcherCall = std::get<InputPin::FlowFirableWatcherCallbackFunc>(watcherCallback)) |
680 | { | ||
681 |
1/2✓ Branch 1 taken 63642 times.
✗ Branch 2 not taken.
|
63642 | std::invoke(watcherCall, node, inputPin.queue, earliestInputPinIdx); |
682 | 63642 | } | |
683 | } | ||
684 | #endif | ||
685 |
1/2✓ Branch 1 taken 467282 times.
✗ Branch 2 not taken.
|
467125 | std::invoke(callback, node, inputPin.queue, earliestInputPinIdx); |
686 | } | ||
687 | } | ||
688 | ✗ | else if (inputPin.dropQueueIfNotFirable) | |
689 | { | ||
690 | LOG_DATA("{}: Dropping message on input pin '{}'", node->nameId(), inputPin.name); | ||
691 | ✗ | inputPin.queue.pop_front(); | |
692 | } | ||
693 | else | ||
694 | { | ||
695 | LOG_DATA("{}: Skipping message on input pin '{}'", node->nameId(), inputPin.name); | ||
696 | ✗ | break; // Do not drop an item, but put the worker to sleep | |
697 | } | ||
698 | } | ||
699 | else | ||
700 | { | ||
701 | 13 | break; | |
702 | } | ||
703 | } | ||
704 | } | ||
705 | |||
706 | // Post-processing (FileReader/Simulator) | ||
707 |
2/2✓ Branch 1 taken 120 times.
✓ Branch 2 taken 271283 times.
|
270972 | if (!node->pollEvents.empty()) |
708 | { | ||
709 | 120 | std::multimap<InsTime, std::pair<OutputPin*, size_t>>::iterator it; | |
710 |
7/10✓ Branch 3 taken 120789 times.
✓ Branch 4 taken 10 times.
✓ Branch 6 taken 120792 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 120792 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 120792 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 120789 times.
✓ Branch 13 taken 13 times.
|
120808 | while (it = node->pollEvents.begin(), it != node->pollEvents.end() && node->isInitialized() && node->callbacksEnabled) |
711 | { | ||
712 | 120789 | OutputPin* outputPin = it->second.first; | |
713 | 120785 | size_t outputPinIdx = it->second.second; | |
714 | 120790 | Node* node = outputPin->parentNode; | |
715 | |||
716 |
2/2✓ Branch 1 taken 52994 times.
✓ Branch 2 taken 67799 times.
|
120790 | if (std::holds_alternative<OutputPin::PollDataFunc>(outputPin->data)) |
717 | { | ||
718 | 52994 | auto* callback = std::get_if<OutputPin::PollDataFunc>(&outputPin->data); | |
719 |
2/4✓ Branch 0 taken 52987 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52989 times.
✗ Branch 3 not taken.
|
52987 | if (callback != nullptr && *callback != nullptr) |
720 | { | ||
721 | LOG_DATA("{}: Polling data from output pin '{}'", node->nameId(), str::replaceAll_copy(outputPin->name, "\n", "")); | ||
722 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 52989 times.
✓ Branch 3 taken 52994 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 110 times.
✓ Branch 8 taken 52889 times.
|
52989 | if ((node->**callback)() == nullptr) |
723 | { | ||
724 |
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 |
725 | 110 | break; | |
726 | } | ||
727 | } | ||
728 | } | ||
729 |
1/2✓ Branch 1 taken 67800 times.
✗ Branch 2 not taken.
|
67799 | else if (std::holds_alternative<OutputPin::PeekPollDataFunc>(outputPin->data)) |
730 | { | ||
731 | 67800 | auto* callback = std::get_if<OutputPin::PeekPollDataFunc>(&outputPin->data); | |
732 |
3/4✓ Branch 0 taken 67800 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67798 times.
✓ Branch 3 taken 2 times.
|
67798 | if (callback != nullptr && *callback != nullptr) |
733 | { | ||
734 |
1/2✓ Branch 2 taken 67798 times.
✗ Branch 3 not taken.
|
67798 | if (!it->first.empty()) |
735 | { | ||
736 | LOG_DATA("{}: Polling data from output pin '{}'", node->nameId(), str::replaceAll_copy(outputPin->name, "\n", "")); | ||
737 | // Trigger the already peeked observation and invoke it's callbacks (peek = false) | ||
738 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 67798 times.
✓ Branch 3 taken 67801 times.
✗ Branch 4 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 67800 times.
|
67798 | if ((node->**callback)(outputPinIdx, false) == nullptr) |
739 | { | ||
740 | ✗ | LOG_ERROR("{}: {} could not poll its observation despite being able to peek it.", node->nameId(), outputPin->name); | |
741 | } | ||
742 | } | ||
743 | |||
744 | // Check if data available (peek = true) | ||
745 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 67800 times.
✓ Branch 3 taken 67804 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 67779 times.
✓ Branch 7 taken 20 times.
|
67800 | if (auto obs = (node->**callback)(outputPinIdx, true)) |
746 | { | ||
747 | // Check if data has a time | ||
748 |
1/2✓ Branch 2 taken 67776 times.
✗ Branch 3 not taken.
|
67779 | if (!obs->insTime.empty()) |
749 | { | ||
750 |
1/2✓ Branch 4 taken 67779 times.
✗ Branch 5 not taken.
|
67776 | node->pollEvents.insert(std::make_pair(obs->insTime, std::make_pair(outputPin, outputPinIdx))); |
751 | } | ||
752 | else // If no time, call the object and remove it | ||
753 | { | ||
754 | ✗ | (node->**callback)(outputPinIdx, false); | |
755 | ✗ | continue; // Do not erase the iterator, because this pin needs to be called again | |
756 | } | ||
757 | } | ||
758 | else // nullptr -> no more data incoming on this pin | ||
759 | { | ||
760 | LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin->name); | ||
761 | 20 | outputPin->noMoreDataAvailable = true; | |
762 |
2/2✓ Branch 5 taken 27 times.
✓ Branch 6 taken 20 times.
|
47 | for (auto& link : outputPin->links) |
763 | { | ||
764 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | link.connectedNode->wakeWorker(); |
765 | } | ||
766 | 67799 | } | |
767 | 67802 | } | |
768 | else | ||
769 | { | ||
770 | ✗ | LOG_ERROR("{} - {}: Callback is not valid anymore", node->nameId(), size_t(outputPin->id)); | |
771 | } | ||
772 |
1/2✓ Branch 1 taken 67802 times.
✗ Branch 2 not taken.
|
67802 | node->pollEvents.erase(it); |
773 | } | ||
774 | } | ||
775 | |||
776 |
1/2✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
|
123 | if (node->pollEvents.empty()) |
777 | { | ||
778 | LOG_TRACE("{}: Finished polling all pins.", node->nameId()); | ||
779 | |||
780 | 120 | node->callbacksEnabled = false; | |
781 |
2/2✓ Branch 5 taken 136 times.
✓ Branch 6 taken 120 times.
|
256 | for (auto& outputPin : node->outputPins) |
782 | { | ||
783 |
2/2✓ Branch 1 taken 110 times.
✓ Branch 2 taken 26 times.
|
136 | if (!outputPin.noMoreDataAvailable) |
784 | { | ||
785 | LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin.name); | ||
786 | 110 | outputPin.noMoreDataAvailable = true; | |
787 |
2/2✓ Branch 5 taken 112 times.
✓ Branch 6 taken 110 times.
|
222 | for (auto& link : outputPin.links) |
788 | { | ||
789 |
1/2✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
112 | link.connectedNode->wakeWorker(); |
790 | } | ||
791 | } | ||
792 | } | ||
793 | 120 | node->_mode = Node::Mode::REAL_TIME; | |
794 |
1/2✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
|
120 | FlowExecutor::deregisterNode(node); |
795 | } | ||
796 | } | ||
797 | } | ||
798 | |||
799 | // Check if node finished | ||
800 |
2/2✓ Branch 1 taken 271024 times.
✓ Branch 2 taken 1393 times.
|
272236 | if (node->_mode == Mode::POST_PROCESSING) |
801 | { | ||
802 |
3/4✓ Branch 1 taken 271063 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 220 times.
✓ Branch 4 taken 270843 times.
|
271024 | if (std::ranges::all_of(node->inputPins, [](const InputPin& inputPin) { |
803 |
6/8✓ Branch 2 taken 361516 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 361452 times.
✓ Branch 5 taken 64 times.
✓ Branch 7 taken 361465 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 271089 times.
✓ Branch 10 taken 90376 times.
|
1084589 | return inputPin.type != Pin::Type::Flow || !inputPin.isPinLinked() || inputPin.link.connectedNode->isDisabled() |
804 |
3/4✓ Branch 1 taken 271101 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 271095 times.
✓ Branch 5 taken 9 times.
|
271089 | || !inputPin.link.getConnectedPin()->blocksConnectedNodeFromFinishing |
805 |
7/8✓ Branch 0 taken 361509 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 153641 times.
✓ Branch 4 taken 117447 times.
✓ Branch 6 taken 153663 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 259 times.
✓ Branch 10 taken 153404 times.
|
1084628 | || (inputPin.queue.empty() && inputPin.link.getConnectedPin()->noMoreDataAvailable); |
806 | })) | ||
807 | { | ||
808 | LOG_TRACE("{}: Node finished", node->nameId()); | ||
809 | 220 | node->callbacksEnabled = false; | |
810 |
2/2✓ Branch 5 taken 130 times.
✓ Branch 6 taken 220 times.
|
350 | for (auto& outputPin : node->outputPins) |
811 | { | ||
812 | LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin.name); | ||
813 | 130 | outputPin.noMoreDataAvailable = true; | |
814 |
2/2✓ Branch 5 taken 127 times.
✓ Branch 6 taken 130 times.
|
257 | for (auto& link : outputPin.links) |
815 | { | ||
816 |
1/2✓ Branch 1 taken 127 times.
✗ Branch 2 not taken.
|
127 | link.connectedNode->wakeWorker(); |
817 | } | ||
818 | } | ||
819 | 220 | node->_mode = Node::Mode::REAL_TIME; | |
820 |
1/2✓ Branch 1 taken 218 times.
✗ Branch 2 not taken.
|
219 | FlowExecutor::deregisterNode(node); |
821 | } | ||
822 | } | ||
823 | } | ||
824 | } | ||
825 | |||
826 | LOG_TRACE("{}: Worker thread ended.", node->nameId()); | ||
827 | 331 | } | |
828 | |||
829 | 331 | bool NAV::Node::workerInitializeNode() | |
830 | { | ||
831 | LOG_TRACE("{}: called", nameId()); | ||
832 | { | ||
833 |
1/2✓ Branch 1 taken 333 times.
✗ Branch 2 not taken.
|
331 | std::scoped_lock lk(_stateMutex); |
834 |
6/14✓ Branch 0 taken 333 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 339 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 341 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 341 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 339 times.
✓ Branch 14 taken 2 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
|
675 | 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()); |
835 | 342 | _state = Node::State::Initializing; | |
836 | 342 | } | |
837 | 340 | _mode = Node::Mode::REAL_TIME; | |
838 | |||
839 |
3/6✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 342 times.
✗ Branch 9 not taken.
|
339 | LOG_DEBUG("{}: Initializing Node", nameId()); |
840 | |||
841 | // Initialize Nodes connected to the input pins | ||
842 |
2/2✓ Branch 5 taken 270 times.
✓ Branch 6 taken 342 times.
|
612 | for (const auto& inputPin : inputPins) |
843 | { | ||
844 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 260 times.
|
269 | if (inputPin.type != Pin::Type::Flow) |
845 | { | ||
846 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (Node* connectedNode = inputPin.link.connectedNode) |
847 | { | ||
848 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
|
10 | if (!connectedNode->isInitialized()) |
849 | { | ||
850 |
5/10✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 10 times.
✗ Branch 15 not taken.
|
10 | LOG_DEBUG("{}: Initializing connected Node '{}' on input Pin {}", nameId(), connectedNode->nameId(), size_t(inputPin.id)); |
851 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
|
10 | if (!connectedNode->doInitialize(true)) |
852 | { | ||
853 | ✗ | LOG_ERROR("{}: Could not initialize connected node {}", nameId(), connectedNode->nameId()); | |
854 | ✗ | std::scoped_lock lk(_stateMutex); | |
855 | ✗ | if (_state == State::Initializing) | |
856 | { | ||
857 | ✗ | _state = Node::State::Deinitialized; | |
858 | } | ||
859 | ✗ | return false; | |
860 | ✗ | } | |
861 | } | ||
862 | } | ||
863 | } | ||
864 | } | ||
865 | |||
866 | 342 | _reinitialize = false; | |
867 | |||
868 | // Initialize the node itself | ||
869 | LOG_TRACE("{}: calling initialize()", nameId()); | ||
870 | 342 | bool initSucceeded = false; | |
871 | { | ||
872 |
1/2✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
|
342 | std::scoped_lock<std::mutex> guard(_configWindowMutex); |
873 |
1/2✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
|
342 | initSucceeded = initialize(); |
874 | 342 | } | |
875 |
2/2✓ Branch 0 taken 340 times.
✓ Branch 1 taken 2 times.
|
342 | if (initSucceeded) |
876 | { | ||
877 | LOG_TRACE("{}: initialize() was successful", nameId()); | ||
878 | |||
879 |
2/2✓ Branch 4 taken 270 times.
✓ Branch 5 taken 340 times.
|
610 | for (auto& inputPin : inputPins) |
880 | { | ||
881 | 270 | inputPin.queue.clear(); | |
882 | 270 | inputPin.queueBlocked = false; | |
883 | } | ||
884 | |||
885 | 340 | pollEvents.clear(); | |
886 | LOG_TRACE("{}: calling resetNode()", nameId()); | ||
887 | { | ||
888 |
1/2✓ Branch 1 taken 341 times.
✗ Branch 2 not taken.
|
341 | std::scoped_lock<std::mutex> guard(_configWindowMutex); |
889 |
1/2✓ Branch 1 taken 341 times.
✗ Branch 2 not taken.
|
341 | resetNode(); |
890 | 341 | } | |
891 | LOG_TRACE("{}: resetNode() was successful", nameId()); | ||
892 |
2/2✓ Branch 5 taken 266 times.
✓ Branch 6 taken 341 times.
|
607 | for (auto& outputPin : outputPins) |
893 | { | ||
894 | 266 | outputPin.noMoreDataAvailable = true; | |
895 |
2/2✓ Branch 5 taken 266 times.
✓ Branch 6 taken 266 times.
|
532 | for (auto& link : outputPin.links) |
896 | { | ||
897 | LOG_TRACE("{}: Waking connected node '{}'", nameId(), link.connectedNode->nameId()); | ||
898 |
1/2✓ Branch 1 taken 266 times.
✗ Branch 2 not taken.
|
266 | link.connectedNode->wakeWorker(); |
899 | } | ||
900 | } | ||
901 | |||
902 |
1/2✓ Branch 1 taken 341 times.
✗ Branch 2 not taken.
|
341 | std::scoped_lock lk(_stateMutex); |
903 |
1/2✓ Branch 0 taken 341 times.
✗ Branch 1 not taken.
|
341 | if (_state == State::Initializing) |
904 | { | ||
905 | 341 | _state = Node::State::Initialized; | |
906 | } | ||
907 | 341 | return true; | |
908 | 341 | } | |
909 | |||
910 | LOG_TRACE("{}: initialize() failed", nameId()); | ||
911 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | std::scoped_lock lk(_stateMutex); |
912 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (_state == State::Initializing) |
913 | { | ||
914 | 1 | _state = Node::State::Deinitialized; | |
915 | } | ||
916 | 1 | return false; | |
917 | 1 | } | |
918 | |||
919 | 340 | bool NAV::Node::workerDeinitializeNode() | |
920 | { | ||
921 | LOG_TRACE("{}: called", nameId()); | ||
922 | { | ||
923 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
340 | std::scoped_lock lk(_stateMutex); |
924 |
5/14✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 340 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 340 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 340 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 340 times.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
|
680 | 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()); |
925 | { | ||
926 | 340 | _state = Node::State::Deinitializing; | |
927 | } | ||
928 | 340 | } | |
929 |
3/6✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 340 times.
✗ Branch 9 not taken.
|
340 | LOG_DEBUG("{}: Deinitializing Node", nameId()); |
930 | |||
931 | 340 | callbacksEnabled = false; | |
932 | |||
933 | // Re-/Deinitialize Nodes connected to the output pins | ||
934 |
2/2✓ Branch 5 taken 266 times.
✓ Branch 6 taken 340 times.
|
606 | for (const auto& outputPin : outputPins) |
935 | { | ||
936 |
2/2✓ Branch 1 taken 49 times.
✓ Branch 2 taken 217 times.
|
266 | if (outputPin.type != Pin::Type::Flow) |
937 | { | ||
938 |
2/2✓ Branch 5 taken 4 times.
✓ Branch 6 taken 49 times.
|
53 | for (const auto& link : outputPin.links) |
939 | { | ||
940 |
3/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
|
4 | if (link.connectedNode->isInitialized()) |
941 | { | ||
942 |
6/12✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
|
2 | LOG_DEBUG("{}: {} connected Node '{}' on output Pin {}", nameId(), |
943 | _reinitialize ? "Reinitializing" : "Deinitializing", link.connectedNode->nameId(), size_t(outputPin.id)); | ||
944 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
2 | if (_reinitialize) { link.connectedNode->doReinitialize(); } |
945 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | else { link.connectedNode->doDeinitialize(); } |
946 | } | ||
947 | } | ||
948 | } | ||
949 | } | ||
950 | |||
951 | // Deinitialize the node itself | ||
952 | { | ||
953 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
340 | std::scoped_lock<std::mutex> guard(_configWindowMutex); |
954 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
340 | deinitialize(); |
955 | 340 | } | |
956 | |||
957 |
1/2✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
|
340 | std::scoped_lock lk(_stateMutex); |
958 |
1/2✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
|
340 | if (_state == State::Deinitializing) |
959 | { | ||
960 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 340 times.
|
340 | if (_disable) |
961 | { | ||
962 | ✗ | _state = State::Disabled; | |
963 | } | ||
964 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 340 times.
|
340 | else if (_reinitialize) |
965 | { | ||
966 | ✗ | _state = State::DoInitialize; | |
967 | } | ||
968 | else | ||
969 | { | ||
970 | 340 | _state = State::Deinitialized; | |
971 | } | ||
972 | } | ||
973 | |||
974 | 340 | return true; | |
975 | 340 | } | |
976 | |||
977 | ✗ | void NAV::Node::workerTimeoutHandler() | |
978 | { | ||
979 | LOG_TRACE("{}: called", nameId()); | ||
980 | ✗ | } | |
981 | |||
982 | ✗ | void NAV::to_json(json& j, const Node& node) | |
983 | { | ||
984 | ✗ | ImVec2 realSize = ed::GetNodeSize(node.id); | |
985 | ✗ | realSize.x -= 16; | |
986 | ✗ | realSize.y -= 38.0F; | |
987 | ✗ | j = json{ | |
988 | ✗ | { "id", size_t(node.id) }, | |
989 | ✗ | { "type", node.type() }, | |
990 | ✗ | { "kind", std::string(node.kind) }, | |
991 | ✗ | { "name", node.name }, | |
992 | ✗ | { "size", node._size.x == 0 && node._size.y == 0 ? node._size : realSize }, | |
993 | ✗ | { "pos", ed::GetNodePosition(node.id) }, | |
994 | ✗ | { "enabled", !node.isDisabled() }, | |
995 | ✗ | { "inputPins", node.inputPins }, | |
996 | ✗ | { "outputPins", node.outputPins }, | |
997 | ✗ | }; | |
998 | ✗ | } | |
999 | 692 | void NAV::from_json(const json& j, Node& node) | |
1000 | { | ||
1001 |
3/6✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 692 times.
✗ Branch 8 not taken.
|
692 | node.id = j.at("id").get<size_t>(); |
1002 |
1/2✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
|
692 | if (j.contains("kind")) |
1003 | { | ||
1004 |
3/6✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 692 times.
✗ Branch 8 not taken.
|
692 | node.kind = Node::Kind(j.at("kind").get<std::string>()); |
1005 | } | ||
1006 |
1/2✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
|
692 | if (j.contains("name")) |
1007 | { | ||
1008 | 692 | j.at("name").get_to(node.name); | |
1009 | } | ||
1010 |
1/2✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
|
692 | if (j.contains("size")) |
1011 | { | ||
1012 | 692 | j.at("size").get_to(node._size); | |
1013 |
6/8✓ Branch 1 taken 6 times.
✓ Branch 2 taken 686 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 686 times.
|
692 | if (node.kind == Node::Kind::GroupBox && gui::NodeEditorApplication::isUsingBigDefaultFont()) |
1014 | { | ||
1015 | 6 | node._size.y -= 20; | |
1016 | } | ||
1017 | } | ||
1018 |
1/2✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
|
692 | if (j.contains("enabled")) |
1019 | { | ||
1020 | 692 | bool enabled = j.at("enabled").get<bool>(); | |
1021 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 690 times.
|
692 | if (!enabled) |
1022 | { | ||
1023 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | std::scoped_lock lk(node._stateMutex); |
1024 | 2 | node._state = Node::State::Disabled; | |
1025 | 2 | } | |
1026 | } | ||
1027 | |||
1028 |
1/2✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
|
692 | if (j.contains("inputPins")) |
1029 | { | ||
1030 |
2/4✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
|
692 | auto inputPins = j.at("inputPins").get<std::vector<InputPin>>(); |
1031 |
2/2✓ Branch 1 taken 524 times.
✓ Branch 2 taken 646 times.
|
1170 | for (size_t i = 0; i < inputPins.size(); ++i) |
1032 | { | ||
1033 |
2/2✓ Branch 1 taken 46 times.
✓ Branch 2 taken 478 times.
|
524 | if (node.inputPins.size() <= i) |
1034 | { | ||
1035 | 46 | break; | |
1036 | } | ||
1037 |
4/8✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 478 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 478 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 478 times.
✗ Branch 11 not taken.
|
478 | j.at("inputPins").at(i).get_to(node.inputPins.at(i)); |
1038 | } | ||
1039 | 692 | } | |
1040 | |||
1041 |
1/2✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
|
692 | if (j.contains("outputPins")) |
1042 | { | ||
1043 |
2/4✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
|
692 | auto outputPins = j.at("outputPins").get<std::vector<OutputPin>>(); |
1044 |
2/2✓ Branch 1 taken 533 times.
✓ Branch 2 taken 690 times.
|
1223 | for (size_t i = 0; i < outputPins.size(); ++i) |
1045 | { | ||
1046 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 531 times.
|
533 | if (node.outputPins.size() <= i) |
1047 | { | ||
1048 | 2 | break; | |
1049 | } | ||
1050 |
4/8✓ Branch 1 taken 531 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 531 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 531 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 531 times.
✗ Branch 11 not taken.
|
531 | j.at("outputPins").at(i).get_to(node.outputPins.at(i)); |
1051 | } | ||
1052 | 692 | } | |
1053 | 692 | } | |
1054 |