1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 07:27:45 +00:00

AK: Allow propagating errors from StringView::for_each_split_view()

This commit is contained in:
MacDue 2023-02-04 17:54:55 +00:00 committed by Andreas Kling
parent b16ec1880c
commit d81a72ed78

View file

@ -164,23 +164,26 @@ public:
return substring_view(0, needle_begin.release_value()); return substring_view(0, needle_begin.release_value());
} }
template<VoidFunction<StringView> Callback> template<typename Callback>
void for_each_split_view(char separator, SplitBehavior split_behavior, Callback callback) const auto for_each_split_view(char separator, SplitBehavior split_behavior, Callback callback) const
{ {
StringView seperator_view { &separator, 1 }; StringView seperator_view { &separator, 1 };
for_each_split_view(seperator_view, split_behavior, callback); return for_each_split_view(seperator_view, split_behavior, callback);
} }
template<VoidFunction<StringView> Callback> template<typename Callback>
void for_each_split_view(StringView separator, SplitBehavior split_behavior, Callback callback) const auto for_each_split_view(StringView separator, SplitBehavior split_behavior, Callback callback) const
{ {
VERIFY(!separator.is_empty()); VERIFY(!separator.is_empty());
// FIXME: This can't go in the template header since declval won't allow the incomplete StringView type.
using CallbackReturn = decltype(declval<Callback>()(StringView {}));
constexpr auto ReturnsErrorOr = IsSpecializationOf<CallbackReturn, ErrorOr>;
using ReturnType = Conditional<ReturnsErrorOr, ErrorOr<void>, void>;
return [&]() -> ReturnType {
if (is_empty()) if (is_empty())
return; return ReturnType();
StringView view { *this }; StringView view { *this };
auto maybe_separator_index = find(separator); auto maybe_separator_index = find(separator);
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty); bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator); bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
@ -188,18 +191,28 @@ public:
auto separator_index = maybe_separator_index.value(); auto separator_index = maybe_separator_index.value();
auto part_with_separator = view.substring_view(0, separator_index + separator.length()); auto part_with_separator = view.substring_view(0, separator_index + separator.length());
if (keep_empty || separator_index > 0) { if (keep_empty || separator_index > 0) {
if (keep_separator) auto part = part_with_separator;
callback(part_with_separator); if (!keep_separator)
part = part_with_separator.substring_view(0, separator_index);
if constexpr (ReturnsErrorOr)
TRY(callback(part));
else else
callback(part_with_separator.substring_view(0, separator_index)); callback(part);
} }
view = view.substring_view_starting_after_substring(part_with_separator); view = view.substring_view_starting_after_substring(part_with_separator);
maybe_separator_index = view.find(separator); maybe_separator_index = view.find(separator);
} }
if (keep_empty || !view.is_empty()) if (keep_empty || !view.is_empty()) {
if constexpr (ReturnsErrorOr)
TRY(callback(view));
else
callback(view); callback(view);
} }
return ReturnType();
}();
}
// 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