INSTINCT Code Coverage Report


Directory: src/
File: Nodes/Utility/Merger.cpp
Date: 2025-11-25 23:34:18
Exec Total Coverage
Lines: 57 92 62.0%
Functions: 9 10 90.0%
Branches: 58 204 28.4%

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 "Merger.hpp"
10
11 #include "internal/FlowManager.hpp"
12
13 #include "NodeRegistry.hpp"
14
15 #include "NodeData/NodeData.hpp"
16
17 116 NAV::Merger::Merger()
18
2/4
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 116 times.
✗ Branch 5 not taken.
116 : Node(typeStatic())
19 {
20 LOG_TRACE("{}: called", name);
21
22 116 _hasConfig = false;
23 116 kind = Kind::Simple;
24
25
4/8
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 116 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 116 times.
✓ Branch 9 taken 116 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
348 CreateInputPin("", Pin::Type::Flow, { NodeData::type() }, &Merger::receiveData);
26
4/8
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 116 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 116 times.
✓ Branch 9 taken 116 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
348 CreateInputPin("", Pin::Type::Flow, { NodeData::type() }, &Merger::receiveData);
27
4/8
✓ Branch 2 taken 116 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 116 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 116 times.
✓ Branch 10 taken 116 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
464 CreateOutputPin("", Pin::Type::Flow, { NodeData::type() });
28 464 }
29
30 236 NAV::Merger::~Merger()
31 {
32 LOG_TRACE("{}: called", nameId());
33 236 }
34
35 230 std::string NAV::Merger::typeStatic()
36 {
37
1/2
✓ Branch 1 taken 230 times.
✗ Branch 2 not taken.
460 return "Merger";
38 }
39
40 std::string NAV::Merger::type() const
41 {
42 return typeStatic();
43 }
44
45 114 std::string NAV::Merger::category()
46 {
47
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
228 return "Utility";
48 }
49
50 2 void NAV::Merger::setPinIdentifiers(size_t connectedPinIndex, size_t otherPinIndex, const std::vector<std::string>& dataIdentifiers)
51 {
52
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 LOG_DEBUG("{}: Setting DataIdentifier on pinIndex {}", nameId(), otherPinIndex);
53
54 2 inputPins.at(connectedPinIndex).dataIdentifier = dataIdentifiers;
55
56
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (!inputPins.at(otherPinIndex).isPinLinked())
57 {
58 2 inputPins.at(otherPinIndex).dataIdentifier = dataIdentifiers;
59
2/2
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
4 for (const auto& dataIdentifier : dataIdentifiers)
60 {
61
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 auto parentIdentifiers = NodeRegistry::GetParentNodeDataTypes(dataIdentifier);
62
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 std::erase(parentIdentifiers, NodeData::type());
63
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
2 inputPins.at(otherPinIndex).dataIdentifier.insert(inputPins.at(otherPinIndex).dataIdentifier.end(), parentIdentifiers.rbegin(), parentIdentifiers.rend());
64 2 }
65
66 // Update the dataIdentifier of the output pin to the same as input pin
67 2 outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier = dataIdentifiers;
68 }
69 else
70 {
71 std::vector<std::string> combinedIdentifiers;
72 for (const auto& dataIdentifier : inputPins.at(connectedPinIndex).dataIdentifier)
73 {
74 if (auto iter = std::find(inputPins.at(otherPinIndex).dataIdentifier.begin(), inputPins.at(otherPinIndex).dataIdentifier.end(), dataIdentifier);
75 iter != inputPins.at(otherPinIndex).dataIdentifier.end())
76 {
77 combinedIdentifiers.push_back(*iter);
78 }
79 }
80 if (!combinedIdentifiers.empty())
81 {
82 outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier = combinedIdentifiers;
83 return;
84 }
85
86 std::vector<std::string> connectedPinParents;
87 for (const auto& dataIdentifier : inputPins.at(connectedPinIndex).dataIdentifier)
88 {
89 auto parentIdentifiers = NodeRegistry::GetParentNodeDataTypes(dataIdentifier);
90 std::erase(parentIdentifiers, NodeData::type());
91 connectedPinParents.insert(connectedPinParents.begin(), parentIdentifiers.begin(), parentIdentifiers.end());
92 }
93
94 for (const auto& dataIdentifier : inputPins.at(otherPinIndex).dataIdentifier)
95 {
96 if (std::ranges::find(connectedPinParents, dataIdentifier) != connectedPinParents.end())
97 {
98 outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier = inputPins.at(otherPinIndex).dataIdentifier;
99 }
100 else
101 {
102 outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier = inputPins.at(connectedPinIndex).dataIdentifier;
103 }
104 }
105 }
106 }
107
108 2 void NAV::Merger::updateOutputPin(const std::vector<std::string>& oldDataIdentifiers)
109 {
110 // Check if connected links on output port are still valid
111
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
2 for (auto& link : outputPins.at(OUTPUT_PORT_INDEX_FLOW).links)
112 {
113 if (auto* endPin = link.getConnectedPin())
114 {
115 if (outputPins.at(OUTPUT_PORT_INDEX_FLOW).canCreateLink(*endPin))
116 {
117 continue;
118 }
119
120 // If the link is not valid anymore, delete it
121 outputPins.at(OUTPUT_PORT_INDEX_FLOW).deleteLink(*endPin);
122 }
123 }
124
125 // Refresh all links connected to the output pin if the type changed
126
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier != oldDataIdentifiers)
127 {
128
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
2 for (auto& link : outputPins.at(OUTPUT_PORT_INDEX_FLOW).links)
129 {
130 if (auto* connectedPin = link.getConnectedPin())
131 {
132 outputPins.at(OUTPUT_PORT_INDEX_FLOW).recreateLink(*connectedPin);
133 }
134 }
135 }
136 2 }
137
138 4 bool NAV::Merger::onCreateLink(OutputPin& startPin, InputPin& endPin)
139 {
140 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
141
142
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
4 if (endPin.parentNode->id != id) // Link on Output Port
143 {
144
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 if (!inputPins.at(INPUT_PORT_INDEX_FLOW_FIRST).isPinLinked()
145
2/10
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
2 && !inputPins.at(INPUT_PORT_INDEX_FLOW_SECOND).isPinLinked())
146 {
147 outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier = endPin.dataIdentifier;
148 }
149 2 return true;
150 }
151
152
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 size_t connectedPinIndex = inputPinIndexFromId(endPin.id);
153
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 size_t otherPinIndex = connectedPinIndex == INPUT_PORT_INDEX_FLOW_FIRST ? INPUT_PORT_INDEX_FLOW_SECOND : INPUT_PORT_INDEX_FLOW_FIRST;
154
155
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 auto outputPinIdentifier = outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier;
156
157
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 setPinIdentifiers(connectedPinIndex, otherPinIndex, startPin.dataIdentifier);
158
159
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 updateOutputPin(outputPinIdentifier);
160
161 2 return true;
162 2 }
163
164 4 void NAV::Merger::afterDeleteLink([[maybe_unused]] OutputPin& startPin, InputPin& endPin)
165 {
166 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
167
168
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (endPin.parentNode->id != id) // Link on Output Pin
169 {
170 2 return;
171 }
172
173 // Link on Input Pin
174
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 for (size_t pinIdx = 0; pinIdx < inputPins.size(); pinIdx++)
175 {
176 4 auto& pin = inputPins[pinIdx];
177
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (endPin.id != pin.id) // The other pin (which is not deleted)
178 {
179
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (pin.isPinLinked())
180 {
181 size_t otherPinIndex = pinIdx == INPUT_PORT_INDEX_FLOW_FIRST ? INPUT_PORT_INDEX_FLOW_SECOND : INPUT_PORT_INDEX_FLOW_FIRST;
182
183 auto* otherNodePin = pin.link.getConnectedPin();
184
185 auto outputPinIdentifier = outputPins.at(OUTPUT_PORT_INDEX_FLOW).dataIdentifier;
186
187 setPinIdentifiers(pinIdx, otherPinIndex, otherNodePin->dataIdentifier);
188
189 updateOutputPin(outputPinIdentifier);
190 }
191 else
192 {
193
2/2
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
6 for (auto& pinReset : inputPins)
194 {
195
2/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
8 pinReset.dataIdentifier = { NodeData::type() };
196 }
197 }
198 2 break;
199 }
200 }
201 4 }
202
203 202 void NAV::Merger::receiveData(InputPin::NodeDataQueue& queue, size_t /* pinIdx */)
204 {
205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 202 times.
202 if (!(NAV::Node::callbacksEnabled))
206 {
207 NAV::Node::callbacksEnabled = true;
208 }
209
210
2/4
✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 202 times.
✗ Branch 5 not taken.
202 invokeCallbacks(OUTPUT_PORT_INDEX_FLOW, queue.extract_front());
211 202 }
212