summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2022-11-29 21:59:24 (GMT)
committerKyle Edwards <kyle.edwards@kitware.com>2022-11-30 05:05:09 (GMT)
commitbeba50bd61d32ea68acffca67a48bd7e81e6e097 (patch)
tree7df1a3f4f832cdafb37cc38850a6699edec6f5d4
parentd6f2a7ab4b6cbb6648928c5da6cd0bf845025126 (diff)
downloadCMake-beba50bd61d32ea68acffca67a48bd7e81e6e097.zip
CMake-beba50bd61d32ea68acffca67a48bd7e81e6e097.tar.gz
CMake-beba50bd61d32ea68acffca67a48bd7e81e6e097.tar.bz2
cmStrCat(): optimize when first argument is an rvalue string
-rw-r--r--Source/cmStringAlgorithms.cxx18
-rw-r--r--Source/cmStringAlgorithms.h43
-rw-r--r--Tests/CMakeLib/testStringAlgorithms.cxx14
3 files changed, 63 insertions, 12 deletions
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
index f73c854..e559cfa 100644
--- a/Source/cmStringAlgorithms.cxx
+++ b/Source/cmStringAlgorithms.cxx
@@ -203,15 +203,23 @@ cmAlphaNum::cmAlphaNum(double val)
MakeDigits(this->View_, this->Digits_, "%g", val);
}
-std::string cmCatViews(std::initializer_list<cm::string_view> views)
+std::string cmCatViews(cm::optional<std::string>&& first,
+ std::initializer_list<cm::string_view> views)
{
- std::size_t total_size = 0;
+ std::size_t totalSize = 0;
for (cm::string_view const& view : views) {
- total_size += view.size();
+ totalSize += view.size();
}
- std::string result(total_size, '\0');
- std::string::iterator sit = result.begin();
+ std::string result;
+ std::string::size_type initialLen = 0;
+ if (first) {
+ totalSize += first->length();
+ initialLen = first->length();
+ result = std::move(*first);
+ }
+ result.resize(totalSize);
+ std::string::iterator sit = result.begin() + initialLen;
for (cm::string_view const& view : views) {
sit = std::copy_n(view.data(), view.size(), sit);
}
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index 83938bc..bff2eda 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -12,6 +12,7 @@
#include <utility>
#include <vector>
+#include <cm/optional>
#include <cm/string_view>
#include "cmRange.h"
@@ -146,7 +147,8 @@ std::vector<std::string> cmExpandedLists(InputIt first, InputIt last)
}
/** Concatenate string pieces into a single string. */
-std::string cmCatViews(std::initializer_list<cm::string_view> views);
+std::string cmCatViews(cm::optional<std::string>&& first,
+ std::initializer_list<cm::string_view> views);
/** Utility class for cmStrCat. */
class cmAlphaNum
@@ -189,13 +191,38 @@ private:
char Digits_[32];
};
+template <typename A, typename B, typename... AV>
+class cmStrCatHelper
+{
+public:
+ static std::string Compute(cmAlphaNum const& a, cmAlphaNum const& b,
+ AV const&... args)
+ {
+ return cmCatViews(
+ cm::nullopt,
+ { a.View(), b.View(), static_cast<cmAlphaNum const&>(args).View()... });
+ }
+};
+
+template <typename B, typename... AV>
+class cmStrCatHelper<std::string, B, AV...>
+{
+public:
+ static std::string Compute(std::string&& a, cmAlphaNum const& b,
+ AV const&... args)
+ {
+ return cmCatViews(
+ std::move(a),
+ { b.View(), static_cast<cmAlphaNum const&>(args).View()... });
+ }
+};
+
/** Concatenate string pieces and numbers into a single string. */
-template <typename... AV>
-inline std::string cmStrCat(cmAlphaNum const& a, cmAlphaNum const& b,
- AV const&... args)
+template <typename A, typename B, typename... AV>
+inline std::string cmStrCat(A&& a, B&& b, AV&&... args)
{
- return cmCatViews(
- { a.View(), b.View(), static_cast<cmAlphaNum const&>(args).View()... });
+ return cmStrCatHelper<A, B, AV...>::Compute(
+ std::forward<A>(a), std::forward<B>(b), std::forward<AV>(args)...);
}
/** Joins wrapped elements of a range with separator into a single string. */
@@ -207,7 +234,9 @@ std::string cmWrap(cm::string_view prefix, Range const& rng,
return std::string();
}
return cmCatViews(
- { prefix, cmJoin(rng, cmCatViews({ suffix, sep, prefix })), suffix });
+ cm::nullopt,
+ { prefix, cmJoin(rng, cmCatViews(cm::nullopt, { suffix, sep, prefix })),
+ suffix });
}
/** Joins wrapped elements of a range with separator into a single string. */
diff --git a/Tests/CMakeLib/testStringAlgorithms.cxx b/Tests/CMakeLib/testStringAlgorithms.cxx
index 1e6b611..f73e62a 100644
--- a/Tests/CMakeLib/testStringAlgorithms.cxx
+++ b/Tests/CMakeLib/testStringAlgorithms.cxx
@@ -6,6 +6,8 @@
#include <iostream>
#include <sstream>
#include <string>
+#include <type_traits>
+#include <utility>
#include <vector>
#include <cm/string_view>
@@ -144,6 +146,18 @@ int testStringAlgorithms(int /*unused*/, char* /*unused*/ [])
d -= val;
assert_ok((d < div) && (d > -div), "cmStrCat double");
}
+ {
+ std::string val;
+ std::string expect;
+ val.reserve(120 * cmStrLen("cmStrCat move"));
+ auto data = val.data();
+ for (int i = 0; i < 100; i++) {
+ val = cmStrCat(std::move(val), "cmStrCat move");
+ expect += "cmStrCat move";
+ }
+ assert_ok((val.data() == data), "cmStrCat move");
+ assert_string(val, expect, "cmStrCat move");
+ }
// ----------------------------------------------------------------------
// Test cmWrap