Skip to content

Commit 66665f2

Browse files
drslebedevRalphSteinhagen
authored andcommitted
fix(core): make merge tag propagation use last value
Overwrite existing keys when merging forwarded tags so MergeTagPropagation matches the documented last-key-wins behavior. Add a regression test with overlapping keys across multiple input ports. Signed-off-by: drslebedev <dr.s.lebedev@gmail.com>
1 parent c6c1bdc commit 66665f2

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

core/include/gnuradio-4.0/Block.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,7 +1145,9 @@ class Block : public lifecycle::StateMachine<Derived>, public BlockBase {
11451145
}
11461146
for (const auto& [relIndex, tagMapRef] : in.tags(tagWindow)) {
11471147
auto filtered = filterAndSubstitute(tagMapRef.get());
1148-
merged.merge(std::move(filtered));
1148+
for (auto& [key, value] : filtered) {
1149+
merged.insert_or_assign(key, std::move(value));
1150+
}
11491151
}
11501152
},
11511153
inputSpans);
@@ -2027,8 +2029,8 @@ class Block : public lifecycle::StateMachine<Derived>, public BlockBase {
20272029
work::Status userReturnStatus = dispatchProcessing(inputSpans, outputSpans, processedIn, processedOut);
20282030

20292031
if constexpr (HasProcessOneFunction<Derived> && !HasProcessBulkFunction<Derived>) {
2030-
_inputTagPresent = false;
2031-
_outputTagPending = false;
2032+
_inputTagPresent = false;
2033+
_outputTagPending = false;
20322034
_pendingOutputTag.clear();
20332035
_inProcessOneDispatch = false;
20342036
}

core/test/qa_Tags.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,33 @@ const boost::ut::suite<"CustomForwardTests"> _CustomForwardTests = [] {
970970
expect(foundMerged) << "merged tag must contain both sample_rate and signal_name";
971971
};
972972

973+
"MergeTagPropagation overlapping keys use last value"_test = [] {
974+
Graph testGraph;
975+
auto& src0 = testGraph.emplaceBlock<TagSource<float, ProcessFunction::USE_PROCESS_BULK>>({{"n_samples_max", gr::Size_t(10)}, {"verbose_console", false}});
976+
auto& src1 = testGraph.emplaceBlock<TagSource<float, ProcessFunction::USE_PROCESS_BULK>>({{"n_samples_max", gr::Size_t(10)}, {"verbose_console", false}});
977+
src0._tags = {{0, {{tag::SIGNAL_NAME.shortKey(), "first"}}}, {0, {{tag::SIGNAL_NAME.shortKey(), "second"}}}};
978+
src1._tags = {{0, {{tag::SIGNAL_NAME.shortKey(), "third"}}}, {0, {{tag::SIGNAL_NAME.shortKey(), "fourth"}}}};
979+
auto& merge = testGraph.emplaceBlock<MergePropTwoInput<float>>();
980+
auto& sink = testGraph.emplaceBlock<TagSink<float, ProcessFunction::USE_PROCESS_BULK>>({{"verbose_console", false}});
981+
982+
expect(testGraph.connect<"out", "in0">(src0, merge).has_value());
983+
expect(testGraph.connect<"out", "in1">(src1, merge).has_value());
984+
expect(testGraph.connect<"out", "in">(merge, sink).has_value());
985+
986+
scheduler::Simple<> sched;
987+
expect(sched.exchange(std::move(testGraph)).has_value());
988+
expect(sched.runAndWait().has_value());
989+
990+
const auto signalNameKey = tag::SIGNAL_NAME.shortKey();
991+
const auto found = std::ranges::find_if(sink._tags, [&signalNameKey](const gr::Tag& tag) { return tag.map.contains(signalNameKey); });
992+
993+
expect(found != sink._tags.end());
994+
if (found != sink._tags.end()) {
995+
expect(eq(found->index, 0UZ));
996+
expect(eq(found->map.at(signalNameKey).value_or(std::string{}), std::string{"fourth"})) << "last overlapping key wins";
997+
}
998+
};
999+
9731000
"MergeTagPropagation with multi-input deduplicates and merges"_test = [] {
9741001
// fan-out: same source → both inputs of merge block
9751002
// identical tags from fan-out should be deduped, then merged into one output tag

0 commit comments

Comments
 (0)