util/str: Add string concatentation methods
Change-Id: I5caf8e0731eb9ac0f18b84d25256ea0068fab03c
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/README.md b/README.md
index bc9991b..496b6b5 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@
* A [movable](src/stdplus/handle/managed.hpp) and [copyable](src/stdplus/handle/copyable.hpp) RAII helper wrapper which is used for wrapping c-native types that have custom destruction or copy reference logic.
* [Functions](src/stdplus/signal.hpp) for trivially configuring signals without having to do the normal signal set operations from libc
* [C-Style Error Handler](src/stdplus/util/cexec.hpp) that wrap c-style functions which return errnos and negative error values into functions that throw c++ exceptions.
+* [String Utilities](src/stdplus/util/string.hpp) that focus on providing helpful wrappers like efficient string append and concatenation.
## Dependencies
diff --git a/src/meson.build b/src/meson.build
index a6e82b9..aadb68d 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -31,4 +31,5 @@
install_headers(
'stdplus/util/cexec.hpp',
+ 'stdplus/util/string.hpp',
subdir: 'stdplus/util')
diff --git a/src/stdplus/util/string.hpp b/src/stdplus/util/string.hpp
new file mode 100644
index 0000000..4e37e3b
--- /dev/null
+++ b/src/stdplus/util/string.hpp
@@ -0,0 +1,57 @@
+#pragma once
+#include <cstring>
+#include <string>
+#include <string_view>
+#include <utility>
+
+namespace stdplus
+{
+namespace util
+{
+namespace detail
+{
+
+template <typename... Views>
+void strAppendViews(std::string& dst, Views... views)
+{
+ dst.reserve((dst.size() + ... + views.size()));
+ (dst.append(views), ...);
+}
+
+} // namespace detail
+
+/** @brief Appends multiple strings to the end of the destination string
+ * in the most optimal way for the given inputs.
+ *
+ * @param[in, out] dst - The string being appended to
+ * @param[in] ...strs - An arbitrary number of strings to concatenate
+ */
+template <typename... Strs>
+void strAppend(std::string& dst, const Strs&... strs)
+{
+ detail::strAppendViews(dst, std::string_view(strs)...);
+}
+
+/** @brief Concatenates multiple strings together in the most optimal
+ * way for the given inputs.
+ *
+ * @param[in] ...strs - An arbitrary number of strings to concatenate
+ * @return The concatenated result string
+ */
+template <typename... Strs>
+std::string strCat(const Strs&... strs)
+{
+ std::string ret;
+ strAppend(ret, strs...);
+ return ret;
+}
+template <typename... Strs>
+std::string strCat(std::string&& in, const Strs&... strs)
+{
+ std::string ret = std::move(in);
+ strAppend(ret, strs...);
+ return ret;
+}
+
+} // namespace util
+} // namespace stdplus
diff --git a/test/meson.build b/test/meson.build
index bcd016e..c8fddf0 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -6,6 +6,7 @@
'handle/copyable',
'handle/managed',
'util/cexec',
+ 'util/string',
]
foreach t : tests
diff --git a/test/util/string.cpp b/test/util/string.cpp
new file mode 100644
index 0000000..8ab4e81
--- /dev/null
+++ b/test/util/string.cpp
@@ -0,0 +1,39 @@
+#include <gtest/gtest.h>
+#include <stdplus/util/string.hpp>
+#include <string>
+#include <string_view>
+
+namespace stdplus
+{
+namespace util
+{
+namespace
+{
+
+using namespace std::string_literals;
+using namespace std::string_view_literals;
+
+TEST(StrCat, NoStr)
+{
+ EXPECT_EQ("", strCat());
+}
+
+TEST(StrCat, SingleStr)
+{
+ EXPECT_EQ("func", strCat("func"));
+}
+
+TEST(StrCat, Multi)
+{
+ EXPECT_EQ("func world test", strCat("func", " world"sv, " test"s));
+}
+
+TEST(StrCat, MoveStr)
+{
+ EXPECT_EQ("func", strCat("func"s));
+ EXPECT_EQ("func world", strCat("func"s, " world"));
+}
+
+} // namespace
+} // namespace util
+} // namespace stdplus