From 38928ee3ee40179ec4ad295c72cf5aaa213f617e Mon Sep 17 00:00:00 2001 From: Oleksandr Koval Date: Thu, 3 Sep 2020 23:25:37 +0300 Subject: 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(). --- Source/cmStringAlgorithms.cxx | 50 +++++++++++++++++++++++++++++++++++++++++++ Source/cmStringAlgorithms.h | 11 ++++++++++ Source/cmStringCommand.cxx | 12 +++++++---- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx index 71d28a4..e0af281 100644 --- a/Source/cmStringAlgorithms.cxx +++ b/Source/cmStringAlgorithms.cxx @@ -7,6 +7,7 @@ #include // IWYU pragma: keep #include #include +#include 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 +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 +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 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 4b0090b..c82a949 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 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 cmTokenize(cm::string_view str, cm::string_view sep); diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 653b383..4000a7d 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -11,6 +11,7 @@ #include #include +#include #include #include "cmsys/RegularExpression.hxx" @@ -534,11 +535,14 @@ bool HandleAppendCommand(std::vector 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; } -- cgit v0.12