فهرست منبع

cmStrCat(): optimize when first argument is an rvalue string

Kyle Edwards 2 سال پیش
والد
کامیت
beba50bd61
3فایلهای تغییر یافته به همراه63 افزوده شده و 12 حذف شده
  1. 13 5
      Source/cmStringAlgorithms.cxx
  2. 36 7
      Source/cmStringAlgorithms.h
  3. 14 0
      Tests/CMakeLib/testStringAlgorithms.cxx

+ 13 - 5
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);
   }

+ 36 - 7
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.  */

+ 14 - 0
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