Skip to content

Commit

Permalink
AK: Add SplitBehavior::KeepTrailingSeparator with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
demostanis authored and linusg committed Oct 24, 2022
1 parent 3e8b5ac commit 7c33f8f
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 6 deletions.
6 changes: 4 additions & 2 deletions AK/String.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,13 @@ Vector<String> String::split_limit(char separator, size_t limit, SplitBehavior s
Vector<String> v;
size_t substart = 0;
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
for (size_t i = 0; i < length() && (v.size() + 1) != limit; ++i) {
char ch = characters()[i];
if (ch == separator) {
size_t sublen = i - substart;
if (sublen != 0 || keep_empty)
v.append(substring(substart, sublen));
v.append(substring(substart, keep_separator ? sublen + 1 : sublen));
substart = i + 1;
}
}
Expand All @@ -133,12 +134,13 @@ Vector<StringView> String::split_view(Function<bool(char)> separator, SplitBehav
Vector<StringView> v;
size_t substart = 0;
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
for (size_t i = 0; i < length(); ++i) {
char ch = characters()[i];
if (separator(ch)) {
size_t sublen = i - substart;
if (sublen != 0 || keep_empty)
v.append(substring_view(substart, sublen));
v.append(substring_view(substart, keep_separator ? sublen + 1 : sublen));
substart = i + 1;
}
}
Expand Down
9 changes: 8 additions & 1 deletion AK/StringUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,17 @@ enum class TrimWhitespace {
};

enum class SplitBehavior : unsigned {
// Neither keep empty substrings nor keep the trailing separator.
// This is the default behavior if unspecified.
Nothing = 0,

// If two separators follow each other without any characters
// in between, keep a "" in the resulting vector.
// in between, keep a "" in the resulting vector. (or only the
// separator if KeepTrailingSeparator is used)
KeepEmpty = 1,

// Do not strip off the separator at the end of the string.
KeepTrailingSeparator = 2,
};
AK_ENUM_BITWISE_OPERATORS(SplitBehavior);

Expand Down
3 changes: 2 additions & 1 deletion AK/StringView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,13 @@ Vector<StringView> StringView::split_view_if(Function<bool(char)> const& predica
Vector<StringView> v;
size_t substart = 0;
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
for (size_t i = 0; i < length(); ++i) {
char ch = characters_without_null_termination()[i];
if (predicate(ch)) {
size_t sublen = i - substart;
if (sublen != 0 || keep_empty)
v.append(substring_view(substart, sublen));
v.append(substring_view(substart, keep_separator ? sublen + 1 : sublen));
substart = i + 1;
}
}
Expand Down
9 changes: 7 additions & 2 deletions AK/StringView.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,16 @@ class StringView {

auto maybe_separator_index = find(separator);
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
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));
if (keep_empty || separator_index > 0) {
if (keep_separator)
callback(part_with_separator);
else
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);
}
Expand Down
5 changes: 5 additions & 0 deletions Tests/AK/TestStringView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ TEST_CASE(split_view)
EXPECT_EQ(test_string_view.split_view_if(predicate, SplitBehavior::KeepEmpty), Vector({ "a"sv, ""sv, "b"sv, "c"sv, "d"sv }));
EXPECT_EQ(test_string_view.split_view_if(predicate), Vector({ "a"sv, "b"sv, "c"sv, "d"sv }));
EXPECT_EQ(test_string_view.split_view_if(predicate, SplitBehavior::KeepEmpty), Vector({ "a"sv, ""sv, "b"sv, "c"sv, "d"sv }));

test_string_view = "a,,,b"sv;
EXPECT_EQ(test_string_view.split_view(","sv, SplitBehavior::KeepEmpty), Vector({ "a"sv, ""sv, ""sv, "b"sv }));
EXPECT_EQ(test_string_view.split_view(","sv, SplitBehavior::KeepTrailingSeparator), Vector({ "a,"sv, "b"sv }));
EXPECT_EQ(test_string_view.split_view(","sv, SplitBehavior::KeepTrailingSeparator | SplitBehavior::KeepEmpty), Vector({ "a,"sv, ","sv, ","sv, "b"sv }));
}

TEST_CASE(constexpr_stuff)
Expand Down

0 comments on commit 7c33f8f

Please sign in to comment.