Ver código fonte

AK: Implement String::find_any_of() and StringView::find_any_of()

This implements StringUtils::find_any_of() and uses it in
String::find_any_of() and StringView::find_any_of(). All uses of
find_{first,last}_of have been replaced with find_any_of(), find() or
find_last(). find_{first,last}_of have subsequently been removed.
Max Wipfli 4 anos atrás
pai
commit
9cc35d1ba3

+ 2 - 0
AK/String.h

@@ -147,6 +147,8 @@ public:
     [[nodiscard]] Optional<size_t> find_last(char needle) const { return StringUtils::find_last(*this, needle); }
     // FIXME: Implement find_last(StringView const&) for API symmetry.
     [[nodiscard]] Vector<size_t> find_all(StringView const& needle) const { return StringUtils::find_all(*this, needle); }
+    using SearchDirection = StringUtils::SearchDirection;
+    [[nodiscard]] Optional<size_t> find_any_of(StringView const& needles, SearchDirection direction) const { return StringUtils::find_any_of(*this, needles, direction); }
 
     [[nodiscard]] String substring(size_t start, size_t length) const;
     [[nodiscard]] String substring(size_t start) const;

+ 18 - 0
AK/StringUtils.cpp

@@ -378,6 +378,24 @@ Vector<size_t> find_all(StringView const& haystack, StringView const& needle)
     return positions;
 }
 
+Optional<size_t> find_any_of(StringView const& haystack, StringView const& needles, SearchDirection direction)
+{
+    if (haystack.is_empty() || needles.is_empty())
+        return {};
+    if (direction == SearchDirection::Forward) {
+        for (size_t i = 0; i < haystack.length(); ++i) {
+            if (needles.contains(haystack[i]))
+                return i;
+        }
+    } else if (direction == SearchDirection::Backward) {
+        for (size_t i = haystack.length(); i > 0; --i) {
+            if (needles.contains(haystack[i - 1]))
+                return i - 1;
+        }
+    }
+    return {};
+}
+
 String to_snakecase(const StringView& str)
 {
     auto should_insert_underscore = [&](auto i, auto current_char) {

+ 5 - 0
AK/StringUtils.h

@@ -62,6 +62,11 @@ Optional<size_t> find(StringView const& haystack, char needle, size_t start = 0)
 Optional<size_t> find(StringView const& haystack, StringView const& needle, size_t start = 0);
 Optional<size_t> find_last(StringView const& haystack, char needle);
 Vector<size_t> find_all(StringView const& haystack, StringView const& needle);
+enum class SearchDirection {
+    Forward,
+    Backward
+};
+Optional<size_t> find_any_of(StringView const& haystack, StringView const& needles, SearchDirection);
 
 String to_snakecase(const StringView&);
 

+ 0 - 27
AK/StringView.cpp

@@ -238,33 +238,6 @@ bool StringView::operator==(const String& string) const
     return !__builtin_memcmp(m_characters, string.characters(), m_length);
 }
 
-Optional<size_t> StringView::find_first_of(const StringView& view) const
-{
-    if (const auto location = AK::find_if(begin(), end(),
-            [&](const auto c) {
-                return any_of(view.begin(), view.end(),
-                    [&](const auto view_char) {
-                        return c == view_char;
-                    });
-            });
-        location != end()) {
-        return location.index();
-    }
-    return {};
-}
-
-Optional<size_t> StringView::find_last_of(const StringView& view) const
-{
-    for (size_t pos = m_length; pos != 0; --pos) {
-        char c = m_characters[pos - 1];
-        for (char view_char : view) {
-            if (c == view_char)
-                return pos - 1;
-        }
-    }
-    return {};
-}
-
 String StringView::to_string() const { return String { *this }; }
 
 }

+ 2 - 2
AK/StringView.h

@@ -93,8 +93,8 @@ public:
 
     [[nodiscard]] Vector<size_t> find_all(StringView const& needle) const { return StringUtils::find_all(*this, needle); }
 
-    [[nodiscard]] Optional<size_t> find_first_of(StringView const&) const;
-    [[nodiscard]] Optional<size_t> find_last_of(StringView const&) const;
+    using SearchDirection = StringUtils::SearchDirection;
+    [[nodiscard]] Optional<size_t> find_any_of(StringView const& needles, SearchDirection direction = SearchDirection::Forward) { return StringUtils::find_any_of(*this, needles, direction); }
 
     [[nodiscard]] constexpr StringView substring_view(size_t start, size_t length) const
     {

+ 9 - 16
Tests/AK/TestStringView.cpp

@@ -123,26 +123,19 @@ TEST_CASE(find_last)
     EXPECT_EQ(test_string_view.find_last('/'), 0U);
 }
 
-TEST_CASE(find_first_of)
+TEST_CASE(find_any_of)
 {
     auto test_string_view = "aabbcc_xy_ccbbaa"sv;
-    EXPECT_EQ(test_string_view.find_first_of("bc"), 2U);
-    EXPECT_EQ(test_string_view.find_first_of("yx"), 7U);
-    EXPECT_EQ(test_string_view.find_first_of("defg").has_value(), false);
+    EXPECT_EQ(test_string_view.find_any_of("bc", StringView::SearchDirection::Forward), 2U);
+    EXPECT_EQ(test_string_view.find_any_of("yx", StringView::SearchDirection::Forward), 7U);
+    EXPECT_EQ(test_string_view.find_any_of("defg", StringView::SearchDirection::Forward).has_value(), false);
+    EXPECT_EQ(test_string_view.find_any_of("bc", StringView::SearchDirection::Backward), 13U);
+    EXPECT_EQ(test_string_view.find_any_of("yx", StringView::SearchDirection::Backward), 8U);
+    EXPECT_EQ(test_string_view.find_any_of("fghi", StringView::SearchDirection::Backward).has_value(), false);
 
     test_string_view = "/"sv;
-    EXPECT_EQ(test_string_view.find_first_of("/"), 0U);
-}
-
-TEST_CASE(find_last_of)
-{
-    auto test_string_view = "aabbcc_xy_ccbbaa"sv;
-    EXPECT_EQ(test_string_view.find_last_of("bc"), 13U);
-    EXPECT_EQ(test_string_view.find_last_of("yx"), 8U);
-    EXPECT_EQ(test_string_view.find_last_of("fghi").has_value(), false);
-
-    test_string_view = "/"sv;
-    EXPECT_EQ(test_string_view.find_last_of("/"), 0U);
+    EXPECT_EQ(test_string_view.find_any_of("/", StringView::SearchDirection::Forward), 0U);
+    EXPECT_EQ(test_string_view.find_any_of("/", StringView::SearchDirection::Backward), 0U);
 }
 
 TEST_CASE(split_view)

+ 1 - 1
Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp

@@ -637,7 +637,7 @@ Optional<Vector<GUI::AutocompleteProvider::Entry>> CppComprehensionEngine::try_a
     } else
         return {};
 
-    auto last_slash = partial_include.find_last_of("/");
+    auto last_slash = partial_include.find_last('/');
     auto include_dir = String::empty();
     auto partial_basename = partial_include.substring_view((last_slash.has_value() ? last_slash.value() : 0) + 1);
     if (last_slash.has_value()) {

+ 1 - 1
Userland/DevTools/Profiler/Process.cpp

@@ -74,7 +74,7 @@ void LibraryMetadata::handle_mmap(FlatPtr base, size_t size, const String& name)
     else if (!name.contains(":"))
         return;
     else
-        path = name.substring(0, name.view().find_first_of(":").value());
+        path = name.substring(0, name.view().find(':').value());
 
     String full_path;
     if (name.contains(".so"))

+ 3 - 2
Userland/Libraries/LibELF/CoreDump.h

@@ -60,9 +60,10 @@ struct [[gnu::packed]] MemoryRegionInfo {
         StringView memory_region_name { region_name };
         if (memory_region_name.contains("Loader.so"))
             return "Loader.so";
-        if (!memory_region_name.contains(":"))
+        auto maybe_colon_index = memory_region_name.find(':');
+        if (!maybe_colon_index.has_value())
             return {};
-        return memory_region_name.substring_view(0, memory_region_name.find_first_of(":").value()).to_string();
+        return memory_region_name.substring_view(0, *maybe_colon_index).to_string();
     }
 };
 

+ 1 - 1
Userland/Libraries/LibGemini/Line.cpp

@@ -73,7 +73,7 @@ Link::Link(String text, const Document& document)
     while (index < m_text.length() && (m_text[index] == ' ' || m_text[index] == '\t'))
         ++index;
     auto url_string = m_text.substring_view(index, m_text.length() - index);
-    auto space_offset = url_string.find_first_of(" \t");
+    auto space_offset = url_string.find_any_of(" \t");
     String url = url_string;
     if (space_offset.has_value()) {
         url = url_string.substring_view(0, space_offset.value());

+ 1 - 1
Userland/Libraries/LibLine/Editor.cpp

@@ -252,7 +252,7 @@ bool Editor::load_history(const String& path)
     auto data = history_file->read_all();
     auto hist = StringView { data.data(), data.size() };
     for (auto& str : hist.split_view("\n\n")) {
-        auto it = str.find_first_of("::").value_or(0);
+        auto it = str.find("::").value_or(0);
         auto time = str.substring_view(0, it).to_uint<time_t>().value_or(0);
         auto string = str.substring_view(it == 0 ? it : it + 2);
         m_history.append({ string, time });

+ 1 - 1
Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp

@@ -222,7 +222,7 @@ static StringView parse_custom_property_name(const StringView& value)
     if (!value.starts_with("var(") || !value.ends_with(")"))
         return {};
     // FIXME: Allow for fallback
-    auto first_comma_index = value.find_first_of(",");
+    auto first_comma_index = value.find(',');
     auto length = value.length();
 
     auto substring_length = first_comma_index.has_value() ? first_comma_index.value() - 4 - 1 : length - 4 - 1;