AK: Implement StringView::for_each_split_view

StringView::for_each_split_view allows you to process the splits in a
StringView without needing to allocate a Vector<StringView> to store
each of the parts.

Since we migrated the implementation from the normal split_view path, we
can also re-implement split_view in terms of for_each_split_view.
This commit is contained in:
Brian Gianforcaro 2022-01-09 02:26:45 -08:00 committed by Andreas Kling
parent cd42f64bc7
commit 142e099001
Notes: sideshowbarker 2024-07-17 21:07:24 +09:00
2 changed files with 32 additions and 19 deletions

View File

@ -42,27 +42,10 @@ Vector<StringView> StringView::split_view(const char separator, bool keep_empty)
Vector<StringView> StringView::split_view(StringView separator, bool keep_empty) const Vector<StringView> StringView::split_view(StringView separator, bool keep_empty) const
{ {
VERIFY(!separator.is_empty());
if (is_empty())
return {};
StringView view { *this };
Vector<StringView> parts; Vector<StringView> parts;
for_each_split_view(separator, keep_empty, [&](StringView view) {
auto maybe_separator_index = find(separator);
while (maybe_separator_index.has_value()) {
auto separator_index = maybe_separator_index.value();
auto part_with_separator = view.substring_view(0, separator_index + separator.length());
if (keep_empty || separator_index > 0)
parts.append(part_with_separator.substring_view(0, separator_index));
view = view.substring_view_starting_after_substring(part_with_separator);
maybe_separator_index = view.find(separator);
}
if (keep_empty || !view.is_empty())
parts.append(view); parts.append(view);
});
return parts; return parts;
} }

View File

@ -120,6 +120,36 @@ public:
[[nodiscard]] Vector<StringView> split_view_if(Function<bool(char)> const& predicate, bool keep_empty = false) const; [[nodiscard]] Vector<StringView> split_view_if(Function<bool(char)> const& predicate, bool keep_empty = false) const;
template<VoidFunction<StringView> Callback>
void for_each_split_view(char separator, bool keep_empty, Callback callback) const
{
StringView seperator_view { &separator, 1 };
for_each_split_view(seperator_view, keep_empty, callback);
}
template<VoidFunction<StringView> Callback>
void for_each_split_view(StringView separator, bool keep_empty, Callback callback) const
{
VERIFY(!separator.is_empty());
if (is_empty())
return;
StringView view { *this };
auto maybe_separator_index = find(separator);
while (maybe_separator_index.has_value()) {
auto separator_index = maybe_separator_index.value();
auto part_with_separator = view.substring_view(0, separator_index + separator.length());
if (keep_empty || separator_index > 0)
callback(part_with_separator.substring_view(0, separator_index));
view = view.substring_view_starting_after_substring(part_with_separator);
maybe_separator_index = view.find(separator);
}
if (keep_empty || !view.is_empty())
callback(view);
}
// Create a Vector of StringViews split by line endings. As of CommonMark // Create a Vector of StringViews split by line endings. As of CommonMark
// 0.29, the spec defines a line ending as "a newline (U+000A), a carriage // 0.29, the spec defines a line ending as "a newline (U+000A), a carriage
// return (U+000D) not followed by a newline, or a carriage return and a // return (U+000D) not followed by a newline, or a carriage return and a