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
{
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)
template<typename TChar, typename TTraits, typename TOutIterator>
void splitImpl(std::basic_string_view<TChar, TTraits> stringView,
std::basic_string_view<TChar, TTraits> separator,
const SplitOptions& options,
TOutIterator outIterator,
std::size_t& numEmitted)
{
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())
{
return {};
return;
}
std::vector<sv_t> 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<std::basic_string_view<TChar, TTraits>> 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<std::basic_string_view<TChar, TTraits>> 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<std::basic_string_view<TChar, TTraits>> splitImpl(std::basic_string_
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;
}
@ -201,6 +237,13 @@ template<typename TLeft, typename TRight>
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>
[[nodiscard]]
auto trimPrefix(TString&& string, TChars&& chars)