Browse Source

cmStringAlgorithms: Move generic strings join function to public API

Move `cmJoinImpl` from `cmStringAlgorithms.cxx` to the
`cmStringAlgorithms.h` as `cmJoinStrings`.  Two existing overloads are
not suitable for reverse iterators due to the hardcoded type of the
first parameter.

The signature is similar to the generic (template) `cmJoin`.  With
`enable_if` "magic", `cmJoinString` could be renamed to `cmJoin` in the
future.

Also, replace `getJoinedLength` with `std::accumulate`.
Alex Turbov 1 year ago
parent
commit
2e16b58b7c
2 changed files with 36 additions and 40 deletions
  1. 2 40
      Source/cmStringAlgorithms.cxx
  2. 34 0
      Source/cmStringAlgorithms.h

+ 2 - 40
Source/cmStringAlgorithms.cxx

@@ -7,7 +7,6 @@
 #include <cstddef> // IWYU pragma: keep
 #include <cstdio>
 #include <cstdlib>
-#include <iterator>
 
 std::string cmTrimWhitespace(cm::string_view str)
 {
@@ -239,51 +238,14 @@ bool cmStrToULongLong(std::string const& str, unsigned long long* value)
   return cmStrToULongLong(str.c_str(), value);
 }
 
-template <typename Range>
-std::size_t getJoinedLength(Range const& rng, cm::string_view separator)
-{
-  std::size_t rangeLength{};
-  for (auto const& item : rng) {
-    rangeLength += item.size();
-  }
-
-  auto const separatorsLength = (rng.size() - 1) * separator.size();
-
-  return rangeLength + separatorsLength;
-}
-
-template <typename Range>
-std::string cmJoinImpl(Range const& rng, cm::string_view separator,
-                       cm::string_view initial)
-{
-  if (rng.empty()) {
-    return { std::begin(initial), std::end(initial) };
-  }
-
-  std::string result;
-  result.reserve(initial.size() + getJoinedLength(rng, separator));
-  result.append(std::begin(initial), std::end(initial));
-
-  auto begin = std::begin(rng);
-  auto end = std::end(rng);
-  result += *begin;
-
-  for (++begin; begin != end; ++begin) {
-    result.append(std::begin(separator), std::end(separator));
-    result += *begin;
-  }
-
-  return result;
-}
-
 std::string cmJoin(std::vector<std::string> const& rng,
                    cm::string_view separator, cm::string_view initial)
 {
-  return cmJoinImpl(rng, separator, initial);
+  return cmJoinStrings(rng, separator, initial);
 }
 
 std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
                    cm::string_view initial)
 {
-  return cmJoinImpl(rng, separator, initial);
+  return cmJoinStrings(rng, separator, initial);
 }

+ 34 - 0
Source/cmStringAlgorithms.h

@@ -7,6 +7,8 @@
 #include <cctype>
 #include <cstring>
 #include <initializer_list>
+#include <iterator>
+#include <numeric>
 #include <sstream>
 #include <string>
 #include <utility>
@@ -77,6 +79,38 @@ std::string cmJoin(Range const& rng, cm::string_view separator)
   return os.str();
 }
 
+/** Generic function to join strings range with separator
+ *  and initial leading string into a single string.
+ */
+template <typename Range>
+std::string cmJoinStrings(Range const& rng, cm::string_view separator,
+                          cm::string_view initial)
+{
+  if (rng.empty()) {
+    return { std::begin(initial), std::end(initial) };
+  }
+
+  std::string result;
+  result.reserve(
+    std::accumulate(std::begin(rng), std::end(rng),
+                    initial.size() + (rng.size() - 1) * separator.size(),
+                    [](std::size_t sum, const std::string& item) {
+                      return sum + item.size();
+                    }));
+  result.append(std::begin(initial), std::end(initial));
+
+  auto begin = std::begin(rng);
+  auto end = std::end(rng);
+  result += *begin;
+
+  for (++begin; begin != end; ++begin) {
+    result.append(std::begin(separator), std::end(separator));
+    result += *begin;
+  }
+
+  return result;
+}
+
 /**
  * Faster overloads for std::string ranges.
  * If @a initial is provided, it prepends the resulted string without