From 142e0990017a7f836ded172a253a2bfe5bb1311e Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Sun, 9 Jan 2022 02:26:45 -0800 Subject: [PATCH] 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 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. --- AK/StringView.cpp | 21 ++------------------- AK/StringView.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/AK/StringView.cpp b/AK/StringView.cpp index a83e65e2296..4a569bbcb85 100644 --- a/AK/StringView.cpp +++ b/AK/StringView.cpp @@ -42,27 +42,10 @@ Vector StringView::split_view(const char separator, bool keep_empty) Vector StringView::split_view(StringView separator, bool keep_empty) const { - VERIFY(!separator.is_empty()); - - if (is_empty()) - return {}; - - StringView view { *this }; - Vector parts; - - 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()) + for_each_split_view(separator, keep_empty, [&](StringView view) { parts.append(view); - + }); return parts; } diff --git a/AK/StringView.h b/AK/StringView.h index 86f5747096e..a63f0590b52 100644 --- a/AK/StringView.h +++ b/AK/StringView.h @@ -120,6 +120,36 @@ public: [[nodiscard]] Vector split_view_if(Function const& predicate, bool keep_empty = false) const; + template 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 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 // 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