Added splitFixed() function to avoid heap-allocation when the number of (expected) splits is known at compile-time.

This commit is contained in:
Patrick 2024-09-17 09:49:36 +02:00
parent 8e117e0f47
commit aff59724fc

View File

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