mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
AK: Add String{View,}::find(StringView)
I personally mistook `find_first_of(StringView)` to be analogous to this so let's add a `find()` method that actually searches the string.
This commit is contained in:
parent
4fa8435310
commit
39442e6d4f
Notes:
sideshowbarker
2024-07-18 23:53:03 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/39442e6d4f0 Pull-request: https://github.com/SerenityOS/serenity/pull/4929 Issue: https://github.com/SerenityOS/serenity/issues/4926
8 changed files with 70 additions and 11 deletions
33
AK/MemMem.h
33
AK/MemMem.h
|
@ -120,28 +120,39 @@ static inline Optional<size_t> memmem(const HaystackIterT& haystack_begin, const
|
|||
return {};
|
||||
}
|
||||
|
||||
static inline const void* memmem(const void* haystack, size_t haystack_length, const void* needle, size_t needle_length)
|
||||
static inline Optional<size_t> memmem_optional(const void* haystack, size_t haystack_length, const void* needle, size_t needle_length)
|
||||
{
|
||||
if (needle_length == 0)
|
||||
return haystack;
|
||||
return 0;
|
||||
|
||||
if (haystack_length < needle_length)
|
||||
return nullptr;
|
||||
return {};
|
||||
|
||||
if (haystack_length == needle_length)
|
||||
return __builtin_memcmp(haystack, needle, haystack_length) == 0 ? haystack : nullptr;
|
||||
if (haystack_length == needle_length) {
|
||||
if (__builtin_memcmp(haystack, needle, haystack_length) == 0)
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (needle_length < 32)
|
||||
return bitap_bitwise(haystack, haystack_length, needle, needle_length);
|
||||
if (needle_length < 32) {
|
||||
auto ptr = bitap_bitwise(haystack, haystack_length, needle, needle_length);
|
||||
if (ptr)
|
||||
return static_cast<size_t>((FlatPtr)ptr - (FlatPtr)haystack);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Fallback to KMP.
|
||||
Array<Span<const u8>, 1> spans { Span<const u8> { (const u8*)haystack, haystack_length } };
|
||||
auto result = memmem(spans.begin(), spans.end(), { (const u8*)needle, needle_length });
|
||||
return memmem(spans.begin(), spans.end(), { (const u8*)needle, needle_length });
|
||||
}
|
||||
|
||||
if (result.has_value())
|
||||
return (const u8*)haystack + result.value();
|
||||
static inline const void* memmem(const void* haystack, size_t haystack_length, const void* needle, size_t needle_length)
|
||||
{
|
||||
auto offset = memmem_optional(haystack, haystack_length, needle, needle_length);
|
||||
if (offset.has_value())
|
||||
return ((const u8*)haystack) + offset.value();
|
||||
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -469,4 +469,14 @@ String String::vformatted(StringView fmtstr, TypeErasedFormatParams params)
|
|||
return builder.to_string();
|
||||
}
|
||||
|
||||
Optional<size_t> String::find(char c) const
|
||||
{
|
||||
return find(StringView { &c, 1 });
|
||||
}
|
||||
|
||||
Optional<size_t> String::find(const StringView& view) const
|
||||
{
|
||||
return StringUtils::find(*this, view);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -138,6 +138,10 @@ public:
|
|||
|
||||
Vector<String> split_limit(char separator, size_t limit, bool keep_empty = false) const;
|
||||
Vector<String> split(char separator, bool keep_empty = false) const;
|
||||
|
||||
Optional<size_t> find(char) const;
|
||||
Optional<size_t> find(const StringView&) const;
|
||||
|
||||
String substring(size_t start) const;
|
||||
String substring(size_t start, size_t length) const;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/MemMem.h>
|
||||
#include <AK/Memory.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
|
@ -342,6 +343,13 @@ StringView trim_whitespace(const StringView& str, TrimMode mode)
|
|||
|
||||
return str.substring_view(substring_start, substring_length);
|
||||
}
|
||||
|
||||
Optional<size_t> find(const StringView& haystack, const StringView& needle)
|
||||
{
|
||||
return AK::memmem_optional(
|
||||
haystack.characters_without_null_termination(), haystack.length(),
|
||||
needle.characters_without_null_termination(), needle.length());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ bool starts_with(const StringView&, const StringView&, CaseSensitivity);
|
|||
bool contains(const StringView&, const StringView&, CaseSensitivity);
|
||||
bool is_whitespace(const StringView&);
|
||||
StringView trim_whitespace(const StringView&, TrimMode mode);
|
||||
Optional<size_t> find(const StringView& haystack, const StringView& needle);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -310,6 +310,16 @@ Optional<size_t> StringView::find_last_of(const StringView& view) const
|
|||
return {};
|
||||
}
|
||||
|
||||
Optional<size_t> StringView::find(char c) const
|
||||
{
|
||||
return find(StringView { &c, 1 });
|
||||
}
|
||||
|
||||
Optional<size_t> StringView::find(const StringView& view) const
|
||||
{
|
||||
return StringUtils::find(*this, view);
|
||||
}
|
||||
|
||||
String StringView::to_string() const { return String { *this }; }
|
||||
|
||||
}
|
||||
|
|
|
@ -100,6 +100,9 @@ public:
|
|||
Optional<size_t> find_last_of(char) const;
|
||||
Optional<size_t> find_last_of(const StringView&) const;
|
||||
|
||||
Optional<size_t> find(const StringView&) const;
|
||||
Optional<size_t> find(char c) const;
|
||||
|
||||
StringView substring_view(size_t start, size_t length) const;
|
||||
StringView substring_view(size_t start) const;
|
||||
Vector<StringView> split_view(char, bool keep_empty = false) const;
|
||||
|
|
|
@ -298,4 +298,16 @@ TEST_CASE(is_whitespace)
|
|||
EXPECT(!AK::StringUtils::is_whitespace("a\t"));
|
||||
}
|
||||
|
||||
TEST_CASE(find)
|
||||
{
|
||||
String test_string = "1234567";
|
||||
EXPECT_EQ(AK::StringUtils::find(test_string, "1").value_or(1), 0u);
|
||||
EXPECT_EQ(AK::StringUtils::find(test_string, "2").value_or(2), 1u);
|
||||
EXPECT_EQ(AK::StringUtils::find(test_string, "3").value_or(3), 2u);
|
||||
EXPECT_EQ(AK::StringUtils::find(test_string, "4").value_or(4), 3u);
|
||||
EXPECT_EQ(AK::StringUtils::find(test_string, "5").value_or(5), 4u);
|
||||
EXPECT_EQ(AK::StringUtils::find(test_string, "34").value_or(3), 2u);
|
||||
EXPECT_EQ(AK::StringUtils::find(test_string, "78").has_value(), false);
|
||||
}
|
||||
|
||||
TEST_MAIN(StringUtils)
|
||||
|
|
Loading…
Reference in a new issue