Bladeren bron

AK: Make String::count not use strstr and take a StringView

This was needlessly copying StringView arguments, and was also using
strstr internally, which meant it was doing a bunch of unnecessary
strlen calls on it. This also moves the implementation to StringUtils
to allow API consistency between String and StringView.
Idan Horowitz 3 jaren geleden
bovenliggende
commit
6d2b003b6e
5 gewijzigde bestanden met toevoegingen van 19 en 17 verwijderingen
  1. 0 16
      AK/String.cpp
  2. 1 1
      AK/String.h
  3. 14 0
      AK/StringUtils.cpp
  4. 2 0
      AK/StringUtils.h
  5. 2 0
      AK/StringView.h

+ 0 - 16
AK/String.cpp

@@ -382,22 +382,6 @@ int String::replace(const String& needle, const String& replacement, bool all_oc
     return positions.size();
 }
 
-size_t String::count(const String& needle) const
-{
-    size_t count = 0;
-    size_t start = 0, pos;
-    for (;;) {
-        const char* ptr = strstr(characters() + start, needle.characters());
-        if (!ptr)
-            break;
-
-        pos = ptr - characters();
-        count++;
-        start = pos + 1;
-    }
-    return count;
-}
-
 String String::reverse() const
 {
     StringBuilder reversed_string(length());

+ 1 - 1
AK/String.h

@@ -286,7 +286,7 @@ public:
     }
 
     int replace(const String& needle, const String& replacement, bool all_occurrences = false);
-    [[nodiscard]] size_t count(const String& needle) const;
+    [[nodiscard]] size_t count(StringView const& needle) const { return StringUtils::count(*this, needle); }
     [[nodiscard]] String reverse() const;
 
     template<typename... Ts>

+ 14 - 0
AK/StringUtils.cpp

@@ -427,6 +427,20 @@ String to_titlecase(StringView const& str)
     return builder.to_string();
 }
 
+// TODO: Benchmark against KMP (AK/MemMem.h) and switch over if it's faster for short strings too
+size_t count(StringView const& str, StringView const& needle)
+{
+    if (needle.is_empty())
+        return str.length();
+
+    size_t count = 0;
+    for (size_t i = 0; i < str.length() - needle.length() + 1; ++i) {
+        if (str.substring_view(i).starts_with(needle))
+            count++;
+    }
+    return count;
+}
+
 }
 
 }

+ 2 - 0
AK/StringUtils.h

@@ -71,6 +71,8 @@ Optional<size_t> find_any_of(StringView const& haystack, StringView const& needl
 String to_snakecase(const StringView&);
 String to_titlecase(StringView const&);
 
+size_t count(StringView const&, StringView const& needle);
+
 }
 
 }

+ 2 - 0
AK/StringView.h

@@ -220,6 +220,8 @@ public:
 
     [[nodiscard]] bool is_whitespace() const { return StringUtils::is_whitespace(*this); }
 
+    [[nodiscard]] size_t count(StringView const& needle) const { return StringUtils::count(*this, needle); }
+
     template<typename... Ts>
     [[nodiscard]] ALWAYS_INLINE constexpr bool is_one_of(Ts&&... strings) const
     {