From beba50bd61d32ea68acffca67a48bd7e81e6e097 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Tue, 29 Nov 2022 16:59:24 -0500 Subject: cmStrCat(): optimize when first argument is an rvalue string --- Source/cmStringAlgorithms.cxx | 18 ++++++++++---- Source/cmStringAlgorithms.h | 43 +++++++++++++++++++++++++++------ 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 views) +std::string cmCatViews(cm::optional&& first, + std::initializer_list 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 #include +#include #include #include "cmRange.h" @@ -146,7 +147,8 @@ std::vector cmExpandedLists(InputIt first, InputIt last) } /** Concatenate string pieces into a single string. */ -std::string cmCatViews(std::initializer_list views); +std::string cmCatViews(cm::optional&& first, + std::initializer_list views); /** Utility class for cmStrCat. */ class cmAlphaNum @@ -189,13 +191,38 @@ private: char Digits_[32]; }; +template +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(args).View()... }); + } +}; + +template +class cmStrCatHelper +{ +public: + static std::string Compute(std::string&& a, cmAlphaNum const& b, + AV const&... args) + { + return cmCatViews( + std::move(a), + { b.View(), static_cast(args).View()... }); + } +}; + /** Concatenate string pieces and numbers into a single string. */ -template -inline std::string cmStrCat(cmAlphaNum const& a, cmAlphaNum const& b, - AV const&... args) +template +inline std::string cmStrCat(A&& a, B&& b, AV&&... args) { - return cmCatViews( - { a.View(), b.View(), static_cast(args).View()... }); + return cmStrCatHelper::Compute( + std::forward(a), std::forward(b), std::forward(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 #include #include +#include +#include #include #include @@ -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 -- cgit v0.12