diff --git a/source/mijin/util/string.hpp b/source/mijin/util/string.hpp index 4a8b1eb..f3a1532 100644 --- a/source/mijin/util/string.hpp +++ b/source/mijin/util/string.hpp @@ -72,10 +72,12 @@ template namespace detail { -template -std::vector> splitImpl(std::basic_string_view stringView, - std::basic_string_view separator, - const SplitOptions& options) +template +void splitImpl(std::basic_string_view stringView, + std::basic_string_view separator, + const SplitOptions& options, + TOutIterator outIterator, + std::size_t& numEmitted) { using sv_t = std::basic_string_view; @@ -84,14 +86,20 @@ std::vector> splitImpl(std::basic_string_ if (separator.empty()) { - return {}; + return; } - std::vector result; + auto emit = [&](std::string_view result) + { + *outIterator = result; + ++outIterator; + ++numEmitted; + }; + if (options.limitParts <= 1) { - result.push_back(stringView); - return result; + emit(stringView); + return; } auto start = stringView.begin(); auto pos = start; @@ -108,10 +116,10 @@ std::vector> splitImpl(std::basic_string_ { if (!options.ignoreEmpty || pos != start) { - result.emplace_back(start, pos); + emit(std::string_view(start, pos)); } start = pos = (pos + separator.size()); - if (result.size() == options.limitParts - 1) + if (numEmitted == options.limitParts - 1) { if (options.ignoreEmpty) { @@ -120,14 +128,14 @@ std::vector> splitImpl(std::basic_string_ pos += separator.size(); } } - result.emplace_back(pos, end); - return result; + emit(std::string_view(pos, end)); + return; } if (!options.ignoreEmpty && pos == end) { // skipped a separator at the very end, add an empty entry - result.emplace_back(""); - return result; + emit(""); + return; } } else @@ -138,9 +146,37 @@ std::vector> splitImpl(std::basic_string_ if (start != end) { - result.emplace_back(start, end); + emit(std::string_view(start, end)); } +} +template +std::vector> splitImpl(std::basic_string_view stringView, + std::basic_string_view separator, + const SplitOptions& options) +{ + std::vector> result; + std::size_t numEmitted = 0; + splitImpl(stringView, separator, options, std::back_inserter(result), numEmitted); + return result; +} + + +template +std::array, count> splitFixedImpl(std::basic_string_view stringView, + std::basic_string_view separator, + SplitOptions options, + std::size_t* outNumResults) +{ + options.limitParts = count; + + std::array, count> result; + std::size_t numEmitted = 0; + splitImpl(stringView, separator, options, result.begin(), numEmitted); + if (outNumResults != nullptr) + { + *outNumResults = numEmitted; + } return result; } @@ -201,6 +237,13 @@ template std::basic_string_view(std::forward(separator)), options); } +template +[[nodiscard]] auto splitFixed(TLeft&& stringView, TRight&& separator, SplitOptions options = {}, std::size_t* outNumResults = nullptr) +{ + return detail::splitFixedImpl(std::basic_string_view(std::forward(stringView)), + std::basic_string_view(std::forward(separator)), options, outNumResults); +} + template [[nodiscard]] auto trimPrefix(TString&& string, TChars&& chars)