diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2022-11-29 21:59:24 (GMT) |
---|---|---|
committer | Kyle Edwards <kyle.edwards@kitware.com> | 2022-11-30 05:05:09 (GMT) |
commit | beba50bd61d32ea68acffca67a48bd7e81e6e097 (patch) | |
tree | 7df1a3f4f832cdafb37cc38850a6699edec6f5d4 | |
parent | d6f2a7ab4b6cbb6648928c5da6cd0bf845025126 (diff) | |
download | CMake-beba50bd61d32ea68acffca67a48bd7e81e6e097.zip CMake-beba50bd61d32ea68acffca67a48bd7e81e6e097.tar.gz CMake-beba50bd61d32ea68acffca67a48bd7e81e6e097.tar.bz2 |
cmStrCat(): optimize when first argument is an rvalue string
-rw-r--r-- | Source/cmStringAlgorithms.cxx | 18 | ||||
-rw-r--r-- | Source/cmStringAlgorithms.h | 43 | ||||
-rw-r--r-- | Tests/CMakeLib/testStringAlgorithms.cxx | 14 |
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 |