From a7fe472583f687dcb17699059e701cbac48fe08f Mon Sep 17 00:00:00 2001 From: Megamouse Date: Wed, 29 Jul 2026 09:25:16 +0200 Subject: [PATCH] Allow to skip empty strings in fmt::merge --- Utilities/StrUtil.h | 28 ++++- rpcs3/tests/test_fmt.cpp | 163 ++++++++++++++++++++++++++++++ rpcs3/tests/test_spu_analyser.cpp | 5 +- 3 files changed, 191 insertions(+), 5 deletions(-) diff --git a/Utilities/StrUtil.h b/Utilities/StrUtil.h index 3fcfe98a8..d1ae5154d 100644 --- a/Utilities/StrUtil.h +++ b/Utilities/StrUtil.h @@ -161,7 +161,7 @@ namespace fmt std::string_view trim_back_sv(std::string_view source, std::string_view values = " \t"); template - std::string merge(const T& source, std::string_view separator) + std::string merge(const T& source, std::string_view separator, bool is_skip_empty = false) { if (source.empty()) { @@ -180,6 +180,23 @@ namespace fmt auto it = source.begin(); auto end = source.end(); + if (is_skip_empty) + { + for (; it != end; ++it) + { + if (it->empty()) continue; + + if (!result.empty() && !separator.empty()) + { + result.append(separator); + } + + result.append(*it); + } + + return result; + } + for (--end; it != end; ++it) { result.append(*it); @@ -192,7 +209,7 @@ namespace fmt } template - std::string merge(std::initializer_list sources, std::string_view separator) + std::string merge(std::initializer_list sources, std::string_view separator, bool is_skip_empty = false) { if (!sources.size()) { @@ -213,6 +230,11 @@ namespace fmt for (const auto& v : sources) { + if (v.empty()) continue; + + std::string sub = fmt::merge(v, separator, is_skip_empty); + if (sub.empty()) continue; + if (first) { first = false; @@ -222,7 +244,7 @@ namespace fmt result.append(separator); } - result.append(fmt::merge(v, separator)); + result.append(std::move(sub)); } return result; diff --git a/rpcs3/tests/test_fmt.cpp b/rpcs3/tests/test_fmt.cpp index 069051bd1..c145b148b 100644 --- a/rpcs3/tests/test_fmt.cpp +++ b/rpcs3/tests/test_fmt.cpp @@ -571,11 +571,36 @@ namespace fmt EXPECT_EQ("a"s, fmt::merge(vec{"a"}, "-")); EXPECT_EQ("a"s, fmt::merge(vec{"a"}, " *-* ")); + EXPECT_EQ("a"s, fmt::merge(vec{"a", ""}, "")); + EXPECT_EQ("a "s, fmt::merge(vec{"a", ""}, " ")); + EXPECT_EQ("a-"s, fmt::merge(vec{"a", ""}, "-")); + EXPECT_EQ("a *-* "s, fmt::merge(vec{"a", ""}, " *-* ")); + + EXPECT_EQ("a"s, fmt::merge(vec{"a", "", ""}, "")); + EXPECT_EQ("a "s, fmt::merge(vec{"a", "", ""}, " ")); + EXPECT_EQ("a--"s, fmt::merge(vec{"a", "", ""}, "-")); + EXPECT_EQ("a *-* *-* "s, fmt::merge(vec{"a", "", ""}, " *-* ")); + + EXPECT_EQ("a"s, fmt::merge(vec{"", "a"}, "")); + EXPECT_EQ(" a"s, fmt::merge(vec{"", "a"}, " ")); + EXPECT_EQ("-a"s, fmt::merge(vec{"", "a"}, "-")); + EXPECT_EQ(" *-* a"s, fmt::merge(vec{"", "a"}, " *-* ")); + EXPECT_EQ("ab"s, fmt::merge(vec{"a", "b"}, "")); EXPECT_EQ("a b"s, fmt::merge(vec{"a", "b"}, " ")); EXPECT_EQ("a-b"s, fmt::merge(vec{"a", "b"}, "-")); EXPECT_EQ("a *-* b"s, fmt::merge(vec{"a", "b"}, " *-* ")); + EXPECT_EQ("ab"s, fmt::merge(vec{"a", "", "b"}, "")); + EXPECT_EQ("a b"s, fmt::merge(vec{"a", "", "b"}, " ")); + EXPECT_EQ("a--b"s, fmt::merge(vec{"a", "", "b"}, "-")); + EXPECT_EQ("a *-* *-* b"s, fmt::merge(vec{"a", "", "b"}, " *-* ")); + + EXPECT_EQ("ab"s, fmt::merge(vec{"a", "", "", "b"}, "")); + EXPECT_EQ("a b"s, fmt::merge(vec{"a", "", "", "b"}, " ")); + EXPECT_EQ("a---b"s, fmt::merge(vec{"a", "", "", "b"}, "-")); + EXPECT_EQ("a *-* *-* *-* b"s, fmt::merge(vec{"a", "", "", "b"}, " *-* ")); + EXPECT_EQ("abc"s, fmt::merge(vec{"a", "b", "c"}, "")); EXPECT_EQ("a b c"s, fmt::merge(vec{"a", "b", "c"}, " ")); EXPECT_EQ("a-b-c"s, fmt::merge(vec{"a", "b", "c"}, "-")); @@ -597,6 +622,16 @@ namespace fmt EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}}, "-")); EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}}, " *-* ")); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}, vec{}}, "")); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}, vec{}}, " ")); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}, vec{}}, "-")); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}, vec{}}, " *-* ")); + + EXPECT_EQ("a"s, fmt::merge(lst{vec{}, vec{"a"}}, "")); + EXPECT_EQ("a"s, fmt::merge(lst{vec{}, vec{"a"}}, " ")); + EXPECT_EQ("a"s, fmt::merge(lst{vec{}, vec{"a"}}, "-")); + EXPECT_EQ("a"s, fmt::merge(lst{vec{}, vec{"a"}}, " *-* ")); + EXPECT_EQ("ab"s, fmt::merge(lst{vec{"a", "b"}}, "")); EXPECT_EQ("a b"s, fmt::merge(lst{vec{"a", "b"}}, " ")); EXPECT_EQ("a-b"s, fmt::merge(lst{vec{"a", "b"}}, "-")); @@ -612,6 +647,11 @@ namespace fmt EXPECT_EQ("a-b"s, fmt::merge(lst{vec{"a"}, vec{"b"}}, "-")); EXPECT_EQ("a *-* b"s, fmt::merge(lst{vec{"a"}, vec{"b"}}, " *-* ")); + EXPECT_EQ("ab"s, fmt::merge(lst{vec{"a"}, vec{}, vec{"b"}}, "")); + EXPECT_EQ("a b"s, fmt::merge(lst{vec{"a"}, vec{}, vec{"b"}}, " ")); + EXPECT_EQ("a-b"s, fmt::merge(lst{vec{"a"}, vec{}, vec{"b"}}, "-")); + EXPECT_EQ("a *-* b"s, fmt::merge(lst{vec{"a"}, vec{}, vec{"b"}}, " *-* ")); + EXPECT_EQ("abc"s, fmt::merge(lst{vec{"a"}, vec{"b"}, vec{"c"}}, "")); EXPECT_EQ("a b c"s, fmt::merge(lst{vec{"a"}, vec{"b"}, vec{"c"}}, " ")); EXPECT_EQ("a-b-c"s, fmt::merge(lst{vec{"a"}, vec{"b"}, vec{"c"}}, "-")); @@ -621,6 +661,129 @@ namespace fmt EXPECT_EQ("a 1 b 2"s, fmt::merge(lst{vec{"a", "1"}, vec{"b", "2"}}, " ")); EXPECT_EQ("a-1-b-2"s, fmt::merge(lst{vec{"a", "1"}, vec{"b", "2"}}, "-")); EXPECT_EQ("a *-* 1 *-* b *-* 2"s, fmt::merge(lst{vec{"a", "1"}, vec{"b", "2"}}, " *-* ")); + + EXPECT_EQ("a1b2"s, fmt::merge(lst{vec{"a", "", "1"}, vec{"b", "2", ""}}, "")); + EXPECT_EQ("a 1 b 2 "s, fmt::merge(lst{vec{"a", "", "1"}, vec{"b", "2", ""}}, " ")); + EXPECT_EQ("a--1-b-2-"s, fmt::merge(lst{vec{"a", "", "1"}, vec{"b", "2", ""}}, "-")); + EXPECT_EQ("a *-* *-* 1 *-* b *-* 2 *-* "s, fmt::merge(lst{vec{"a", "", "1"}, vec{"b", "2", ""}}, " *-* ")); + } + + TEST(StrUtil, Merge_SkipEmpty) + { + using vec = std::vector; + using lst = std::initializer_list>; + + // Vector of strings + EXPECT_EQ(""s, fmt::merge(vec{}, "", true)); + EXPECT_EQ(""s, fmt::merge(vec{}, " ", true)); + EXPECT_EQ(""s, fmt::merge(vec{}, "-", true)); + EXPECT_EQ(""s, fmt::merge(vec{}, " *-* ", true)); + + EXPECT_EQ(""s, fmt::merge(vec{""}, "", true)); + EXPECT_EQ(""s, fmt::merge(vec{""}, " ", true)); + EXPECT_EQ(""s, fmt::merge(vec{""}, "-", true)); + EXPECT_EQ(""s, fmt::merge(vec{""}, " *-* ", true)); + + EXPECT_EQ("a"s, fmt::merge(vec{"a"}, "", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"a"}, " ", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"a"}, "-", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"a"}, " *-* ", true)); + + EXPECT_EQ("a"s, fmt::merge(vec{"a", ""}, "", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"a", ""}, " ", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"a", ""}, "-", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"a", ""}, " *-* ", true)); + + EXPECT_EQ("a"s, fmt::merge(vec{"a", "", ""}, "", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"a", "", ""}, " ", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"a", "", ""}, "-", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"a", "", ""}, " *-* ", true)); + + EXPECT_EQ("a"s, fmt::merge(vec{"", "a"}, "", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"", "a"}, " ", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"", "a"}, "-", true)); + EXPECT_EQ("a"s, fmt::merge(vec{"", "a"}, " *-* ", true)); + + EXPECT_EQ("ab"s, fmt::merge(vec{"a", "b"}, "", true)); + EXPECT_EQ("a b"s, fmt::merge(vec{"a", "b"}, " ", true)); + EXPECT_EQ("a-b"s, fmt::merge(vec{"a", "b"}, "-", true)); + EXPECT_EQ("a *-* b"s, fmt::merge(vec{"a", "b"}, " *-* ", true)); + + EXPECT_EQ("ab"s, fmt::merge(vec{"a", "", "b"}, "", true)); + EXPECT_EQ("a b"s, fmt::merge(vec{"a", "", "b"}, " ", true)); + EXPECT_EQ("a-b"s, fmt::merge(vec{"a", "", "b"}, "-", true)); + EXPECT_EQ("a *-* b"s, fmt::merge(vec{"a", "", "b"}, " *-* ", true)); + + EXPECT_EQ("ab"s, fmt::merge(vec{"a", "", "", "b"}, "", true)); + EXPECT_EQ("a b"s, fmt::merge(vec{"a", "", "", "b"}, " ", true)); + EXPECT_EQ("a-b"s, fmt::merge(vec{"a", "", "", "b"}, "-", true)); + EXPECT_EQ("a *-* b"s, fmt::merge(vec{"a", "", "", "b"}, " *-* ", true)); + + EXPECT_EQ("abc"s, fmt::merge(vec{"a", "b", "c"}, "", true)); + EXPECT_EQ("a b c"s, fmt::merge(vec{"a", "b", "c"}, " ", true)); + EXPECT_EQ("a-b-c"s, fmt::merge(vec{"a", "b", "c"}, "-", true)); + EXPECT_EQ("a *-* b *-* c"s, fmt::merge(vec{"a", "b", "c"}, " *-* ", true)); + + // Initializer list of vector of strings + EXPECT_EQ(""s, fmt::merge(lst{}, "", true)); + EXPECT_EQ(""s, fmt::merge(lst{}, " ", true)); + EXPECT_EQ(""s, fmt::merge(lst{}, "-", true)); + EXPECT_EQ(""s, fmt::merge(lst{}, " *-* ", true)); + + EXPECT_EQ(""s, fmt::merge(lst{vec{}}, "", true)); + EXPECT_EQ(""s, fmt::merge(lst{vec{}}, " ", true)); + EXPECT_EQ(""s, fmt::merge(lst{vec{}}, "-", true)); + EXPECT_EQ(""s, fmt::merge(lst{vec{}}, " *-* ", true)); + + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}}, "", true)); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}}, " ", true)); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}}, "-", true)); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}}, " *-* ", true)); + + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}, vec{}}, "", true)); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}, vec{}}, " ", true)); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}, vec{}}, "-", true)); + EXPECT_EQ("a"s, fmt::merge(lst{vec{"a"}, vec{}}, " *-* ", true)); + + EXPECT_EQ("a"s, fmt::merge(lst{vec{}, vec{"a"}}, "", true)); + EXPECT_EQ("a"s, fmt::merge(lst{vec{}, vec{"a"}}, " ", true)); + EXPECT_EQ("a"s, fmt::merge(lst{vec{}, vec{"a"}}, "-", true)); + EXPECT_EQ("a"s, fmt::merge(lst{vec{}, vec{"a"}}, " *-* ", true)); + + EXPECT_EQ("ab"s, fmt::merge(lst{vec{"a", "b"}}, "", true)); + EXPECT_EQ("a b"s, fmt::merge(lst{vec{"a", "b"}}, " ", true)); + EXPECT_EQ("a-b"s, fmt::merge(lst{vec{"a", "b"}}, "-", true)); + EXPECT_EQ("a *-* b"s, fmt::merge(lst{vec{"a", "b"}}, " *-* ", true)); + + EXPECT_EQ("abc"s, fmt::merge(lst{vec{"a", "b", "c"}}, "", true)); + EXPECT_EQ("a b c"s, fmt::merge(lst{vec{"a", "b", "c"}}, " ", true)); + EXPECT_EQ("a-b-c"s, fmt::merge(lst{vec{"a", "b", "c"}}, "-", true)); + EXPECT_EQ("a *-* b *-* c"s, fmt::merge(lst{vec{"a", "b", "c"}}, " *-* ", true)); + + EXPECT_EQ("ab"s, fmt::merge(lst{vec{"a"}, vec{"b"}}, "", true)); + EXPECT_EQ("a b"s, fmt::merge(lst{vec{"a"}, vec{"b"}}, " ", true)); + EXPECT_EQ("a-b"s, fmt::merge(lst{vec{"a"}, vec{"b"}}, "-", true)); + EXPECT_EQ("a *-* b"s, fmt::merge(lst{vec{"a"}, vec{"b"}}, " *-* ", true)); + + EXPECT_EQ("ab"s, fmt::merge(lst{vec{"a"}, vec{}, vec{"b"}}, "", true)); + EXPECT_EQ("a b"s, fmt::merge(lst{vec{"a"}, vec{}, vec{"b"}}, " ", true)); + EXPECT_EQ("a-b"s, fmt::merge(lst{vec{"a"}, vec{}, vec{"b"}}, "-", true)); + EXPECT_EQ("a *-* b"s, fmt::merge(lst{vec{"a"}, vec{}, vec{"b"}}, " *-* ", true)); + + EXPECT_EQ("abc"s, fmt::merge(lst{vec{"a"}, vec{"b"}, vec{"c"}}, "", true)); + EXPECT_EQ("a b c"s, fmt::merge(lst{vec{"a"}, vec{"b"}, vec{"c"}}, " ", true)); + EXPECT_EQ("a-b-c"s, fmt::merge(lst{vec{"a"}, vec{"b"}, vec{"c"}}, "-", true)); + EXPECT_EQ("a *-* b *-* c"s, fmt::merge(lst{vec{"a"}, vec{"b"}, vec{"c"}}, " *-* ", true)); + + EXPECT_EQ("a1b2"s, fmt::merge(lst{vec{"a", "1"}, vec{"b", "2"}}, "", true)); + EXPECT_EQ("a 1 b 2"s, fmt::merge(lst{vec{"a", "1"}, vec{"b", "2"}}, " ", true)); + EXPECT_EQ("a-1-b-2"s, fmt::merge(lst{vec{"a", "1"}, vec{"b", "2"}}, "-", true)); + EXPECT_EQ("a *-* 1 *-* b *-* 2"s, fmt::merge(lst{vec{"a", "1"}, vec{"b", "2"}}, " *-* ", true)); + + EXPECT_EQ("a1b2"s, fmt::merge(lst{vec{"a", "", "1"}, vec{"b", "2", ""}}, "", true)); + EXPECT_EQ("a 1 b 2"s, fmt::merge(lst{vec{"a", "", "1"}, vec{"b", "2", ""}}, " ", true)); + EXPECT_EQ("a-1-b-2"s, fmt::merge(lst{vec{"a", "", "1"}, vec{"b", "2", ""}}, "-", true)); + EXPECT_EQ("a *-* 1 *-* b *-* 2"s, fmt::merge(lst{vec{"a", "", "1"}, vec{"b", "2", ""}}, " *-* ", true)); } TEST(StrUtil, GetFileExtension) diff --git a/rpcs3/tests/test_spu_analyser.cpp b/rpcs3/tests/test_spu_analyser.cpp index 57881edaa..ec9272bbc 100644 --- a/rpcs3/tests/test_spu_analyser.cpp +++ b/rpcs3/tests/test_spu_analyser.cpp @@ -15,7 +15,7 @@ // Giga SPU analyser regression: a brsl whose return address is a stop-trap leaves // a dangling target edge after block cleanup, which the reg-state walk must not // dereference. The SPU program below is made-up data (not from any game). -namespace +namespace test_spu { constexpr u32 SPU_STOP = 0x00000000u; // stop 0x0 — the no-return trap word @@ -37,7 +37,6 @@ namespace { return 0x1a8u << 21; } -} TEST(SpuAnalyserGiga, ReturnToStopTrapDoesNotRangeCheckFail) { @@ -242,3 +241,5 @@ TEST(SpuAnalyserGiga, ReDecodeConstPropCompletes) g_cfg.core.spu_block_size.set(saved); } + +}