summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Koval <oleksandr.koval.dev@gmail.com>2020-09-03 23:25:37 +0300
committerOleksandr Koval <oleksandr.koval.dev@gmail.com>2020-09-03 23:25:37 +0300
commit38928ee3ee40179ec4ad295c72cf5aaa213f617e (patch)
tree3201e3a0c612cbf6dab0bf9ca44e87c688ae21ec
parentca5babfd7a1da8e32f927ad086fdd91c2b09853b (diff)
downloadcmake-38928ee3ee40179ec4ad295c72cf5aaa213f617e.tar.gz
cmStringAlgorithms: Add faster cmJoin overloads for strings
cmJoin() is often used with std::string ranges. Generic implementation uses std::ostringstream which is not optimal. With strings we can avoid operator<<() and make much faster implementation. Additional 'initial' argument is useful for cmStringCommand.cxx:HandleAppendCommand().
-rw-r--r--Source/cmStringAlgorithms.cxx50
-rw-r--r--Source/cmStringAlgorithms.h11
-rw-r--r--Source/cmStringCommand.cxx12
3 files changed, 69 insertions, 4 deletions
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
index 71d28a49df..e0af28185a 100644
--- a/Source/cmStringAlgorithms.cxx
+++ b/Source/cmStringAlgorithms.cxx
@@ -7,6 +7,7 @@
#include <cstddef> // IWYU pragma: keep
#include <cstdio>
#include <cstdlib>
+#include <iterator>
std::string cmTrimWhitespace(cm::string_view str)
{
@@ -323,3 +324,52 @@ bool cmStrToULong(std::string const& str, unsigned long* value)
{
return cmStrToULong(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);
+}
+
+std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
+ cm::string_view initial)
+{
+ return cmJoinImpl(rng, separator, initial);
+}
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index 4b0090b97d..c82a9495cc 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -81,6 +81,17 @@ std::string cmJoin(Range const& rng, cm::string_view separator)
return os.str();
}
+/**
+ * Faster overloads for std::string ranges.
+ * If @a initial is provided, it prepends the resulted string without
+ * @a separator between them.
+ */
+std::string cmJoin(std::vector<std::string> const& rng,
+ cm::string_view separator, cm::string_view initial = {});
+
+std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
+ cm::string_view initial = {});
+
/** Extract tokens that are separated by any of the characters in @a sep. */
std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep);
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 653b383ccf..4000a7de08 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -11,6 +11,7 @@
#include <memory>
#include <cm/iterator>
+#include <cm/string_view>
#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
@@ -534,11 +535,14 @@ bool HandleAppendCommand(std::vector<std::string> const& args,
return true;
}
- const std::string& variable = args[1];
+ auto const& variableName = args[1];
+
+ cm::string_view oldView{ status.GetMakefile().GetSafeDefinition(
+ variableName) };
+
+ auto const newValue = cmJoin(cmMakeRange(args).advance(2), {}, oldView);
+ status.GetMakefile().AddDefinition(variableName, newValue);
- std::string value = status.GetMakefile().GetSafeDefinition(variable);
- value += cmJoin(cmMakeRange(args).advance(2), std::string());
- status.GetMakefile().AddDefinition(variable, value);
return true;
}