This is an automated email from the ASF dual-hosted git repository.
twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 8f04af34e fix(util): avoid the overload conflict of `StringJoin`
(#3207)
8f04af34e is described below
commit 8f04af34e804587a8f5bfe206937bb20e21d187b
Author: Twice <[email protected]>
AuthorDate: Fri Oct 3 16:12:49 2025 +0800
fix(util): avoid the overload conflict of `StringJoin` (#3207)
We added an `enable_if` to the first overload of StringJoin so that it
will not participate in the overload resolution if users want the second
overload (i.e. without the mapping function).
Test cases also added for this function.
---------
Co-authored-by: Aleks Lozovyuk <[email protected]>
---
src/common/string_util.h | 3 ++-
src/config/config.cc | 3 +--
src/search/value.h | 6 ++----
tests/cppunit/string_util_test.cc | 25 +++++++++++++++++++++++++
4 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 20eca54f3..9149b2f60 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -23,6 +23,7 @@
#include <cstdint>
#include <string>
#include <string_view>
+#include <type_traits>
#include <utility>
#include <vector>
@@ -62,7 +63,7 @@ std::vector<std::string> TokenizeRedisProtocol(const
std::string &value);
std::string EscapeString(std::string_view s);
std::string StringNext(std::string s);
-template <typename T, typename F>
+template <typename T, typename F, std::enable_if_t<std::is_invocable_v<F,
typename T::value_type>, int> = 0>
std::string StringJoin(const T &con, F &&f, std::string_view sep = ", ") {
std::string res;
bool is_first = true;
diff --git a/src/config/config.cc b/src/config/config.cc
index c3b3400f7..28584386f 100644
--- a/src/config/config.cc
+++ b/src/config/config.cc
@@ -125,8 +125,7 @@ Status SetRocksdbCompression(Server *srv, const
rocksdb::CompressionType compres
for (size_t i = compression_start_level; i < KVROCKS_MAX_LSM_LEVEL; i++) {
compression_per_level_builder.emplace_back(compression_option);
}
- const std::string compression_per_level = util::StringJoin(
- compression_per_level_builder, [](const auto &s) -> decltype(auto) {
return s; }, ":");
+ const std::string compression_per_level =
util::StringJoin(compression_per_level_builder, ":");
return srv->storage->SetOptionForAllColumnFamilies("compression_per_level",
compression_per_level);
};
diff --git a/src/search/value.h b/src/search/value.h
index 8978b22fa..78ccaff5f 100644
--- a/src/search/value.h
+++ b/src/search/value.h
@@ -77,8 +77,7 @@ struct Value : std::variant<Null, Numeric, String,
StringArray, NumericArray> {
} else if (Is<String>()) {
return Get<String>();
} else if (Is<StringArray>()) {
- return util::StringJoin(
- Get<StringArray>(), [](const auto &v) -> decltype(auto) { return v;
}, sep);
+ return util::StringJoin(Get<StringArray>(), sep);
} else if (Is<NumericArray>()) {
return util::StringJoin(
Get<NumericArray>(), [](const auto &v) -> decltype(auto) { return
std::to_string(v); }, sep);
@@ -97,8 +96,7 @@ struct Value : std::variant<Null, Numeric, String,
StringArray, NumericArray> {
} else if (Is<StringArray>()) {
auto tag = dynamic_cast<redis::TagFieldMetadata *>(meta);
char sep = tag ? tag->separator : ',';
- return util::StringJoin(
- Get<StringArray>(), [](const auto &v) -> decltype(auto) { return v;
}, std::string(1, sep));
+ return util::StringJoin(Get<StringArray>(), std::string(1, sep));
} else if (Is<NumericArray>()) {
return util::StringJoin(Get<NumericArray>(), [](const auto &v) ->
decltype(auto) { return std::to_string(v); });
}
diff --git a/tests/cppunit/string_util_test.cc
b/tests/cppunit/string_util_test.cc
index 02c131393..fe41d0697 100644
--- a/tests/cppunit/string_util_test.cc
+++ b/tests/cppunit/string_util_test.cc
@@ -23,9 +23,11 @@
#include <gtest/gtest.h>
#include <initializer_list>
+#include <list>
#include <map>
#include <string>
#include <unordered_map>
+#include <unordered_set>
TEST(StringUtil, ToLower) {
std::map<std::string, std::string> cases{
@@ -336,3 +338,26 @@ TEST(StringUtil, SplitArguments) {
ASSERT_EQ(result.Msg(), expected_error);
}
}
+
+TEST(StringUtil, StringJoin) {
+ std::vector<std::string> vec{"a", "b", "c"};
+ std::list<std::string> lst{"a", "b", "c"};
+ std::set<std::string> st{"a", "b", "c"};
+
+ auto func = [](const std::string &s) { return "[" + s + "]"; };
+
+ ASSERT_EQ(util::StringJoin(vec), "a, b, c");
+ ASSERT_EQ(util::StringJoin(vec, "; "), "a; b; c");
+ ASSERT_EQ(util::StringJoin(vec, func), "[a], [b], [c]");
+ ASSERT_EQ(util::StringJoin(vec, func, "; "), "[a]; [b]; [c]");
+
+ ASSERT_EQ(util::StringJoin(lst), "a, b, c");
+ ASSERT_EQ(util::StringJoin(lst, "; "), "a; b; c");
+ ASSERT_EQ(util::StringJoin(lst, func), "[a], [b], [c]");
+ ASSERT_EQ(util::StringJoin(lst, func, "; "), "[a]; [b]; [c]");
+
+ ASSERT_EQ(util::StringJoin(st), "a, b, c");
+ ASSERT_EQ(util::StringJoin(st, "; "), "a; b; c");
+ ASSERT_EQ(util::StringJoin(st, func), "[a], [b], [c]");
+ ASSERT_EQ(util::StringJoin(st, func, "; "), "[a]; [b]; [c]");
+}