summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke <luke.wilde@live.co.uk>2020-07-18 17:59:38 +0100
committerAndreas Kling <kling@serenityos.org>2020-07-21 01:08:32 +0200
commita5ecb9bd6b287e69bcd9565c0b33410527b34b58 (patch)
tree3959002fbe0f3bd61f7a97ad9d910a4670d6bc40
parentccc929dcf90af7d2e0d6936be0f6b80d526f0ce7 (diff)
downloadserenity-a5ecb9bd6b287e69bcd9565c0b33410527b34b58.zip
AK: Add case insensitive version of starts_with
-rw-r--r--AK/FlyString.cpp5
-rw-r--r--AK/FlyString.h1
-rw-r--r--AK/String.cpp10
-rw-r--r--AK/String.h2
-rw-r--r--AK/StringUtils.cpp25
-rw-r--r--AK/StringUtils.h1
-rw-r--r--AK/StringView.cpp12
-rw-r--r--AK/StringView.h2
-rw-r--r--AK/Tests/TestString.cpp2
-rw-r--r--AK/Tests/TestStringUtils.cpp11
-rw-r--r--AK/Tests/TestStringView.cpp2
11 files changed, 53 insertions, 20 deletions
diff --git a/AK/FlyString.cpp b/AK/FlyString.cpp
index 22c00c2db0..fdf2eed56a 100644
--- a/AK/FlyString.cpp
+++ b/AK/FlyString.cpp
@@ -99,6 +99,11 @@ bool FlyString::equals_ignoring_case(const StringView& other) const
return StringUtils::equals_ignoring_case(view(), other);
}
+bool FlyString::starts_with(const StringView& str, CaseSensitivity case_sensitivity) const
+{
+ return StringUtils::starts_with(view(), str, case_sensitivity);
+}
+
bool FlyString::ends_with(const StringView& str, CaseSensitivity case_sensitivity) const
{
return StringUtils::ends_with(view(), str, case_sensitivity);
diff --git a/AK/FlyString.h b/AK/FlyString.h
index 239dafe5cf..7862f0eee0 100644
--- a/AK/FlyString.h
+++ b/AK/FlyString.h
@@ -85,6 +85,7 @@ public:
Optional<int> to_int() const;
bool equals_ignoring_case(const StringView&) const;
+ bool starts_with(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const;
bool ends_with(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const;
static void did_destroy_impl(Badge<StringImpl>, StringImpl&);
diff --git a/AK/String.cpp b/AK/String.cpp
index bcb10d2d79..0bc454af1f 100644
--- a/AK/String.cpp
+++ b/AK/String.cpp
@@ -260,15 +260,9 @@ String String::format(const char* fmt, ...)
return builder.to_string();
}
-bool String::starts_with(const StringView& str) const
+bool String::starts_with(const StringView& str, CaseSensitivity case_sensitivity) const
{
- if (str.is_empty())
- return true;
- if (is_empty())
- return false;
- if (str.length() > length())
- return false;
- return !memcmp(characters(), str.characters_without_null_termination(), str.length());
+ return StringUtils::starts_with(*this, str, case_sensitivity);
}
bool String::starts_with(char ch) const
diff --git a/AK/String.h b/AK/String.h
index ac107f1016..8362f4fefa 100644
--- a/AK/String.h
+++ b/AK/String.h
@@ -145,7 +145,7 @@ public:
ConstIterator begin() const { return characters(); }
ConstIterator end() const { return begin() + length(); }
- bool starts_with(const StringView&) const;
+ bool starts_with(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const;
bool ends_with(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const;
bool starts_with(char) const;
bool ends_with(char) const;
diff --git a/AK/StringUtils.cpp b/AK/StringUtils.cpp
index ae5f9676d5..363cd07ab5 100644
--- a/AK/StringUtils.cpp
+++ b/AK/StringUtils.cpp
@@ -202,6 +202,31 @@ bool ends_with(const StringView& str, const StringView& end, CaseSensitivity cas
return true;
}
+bool starts_with(const StringView& str, const StringView& start, CaseSensitivity case_sensitivity)
+{
+ if (start.is_empty())
+ return true;
+ if (str.is_empty())
+ return false;
+ if (start.length() > str.length())
+ return false;
+ if (str.characters_without_null_termination() == start.characters_without_null_termination())
+ return true;
+
+ if (case_sensitivity == CaseSensitivity::CaseSensitive)
+ return !memcmp(str.characters_without_null_termination(), start.characters_without_null_termination(), start.length());
+
+ auto str_chars = str.characters_without_null_termination();
+ auto start_chars = start.characters_without_null_termination();
+
+ size_t si = 0;
+ for (size_t starti = 0; starti < start.length(); ++si, ++starti) {
+ if (to_lowercase(str_chars[si]) != to_lowercase(start_chars[starti]))
+ return false;
+ }
+ return true;
+}
+
}
}
diff --git a/AK/StringUtils.h b/AK/StringUtils.h
index fb5464c59e..b2b9185166 100644
--- a/AK/StringUtils.h
+++ b/AK/StringUtils.h
@@ -44,6 +44,7 @@ Optional<unsigned> convert_to_uint(const StringView&);
Optional<unsigned> convert_to_uint_from_hex(const StringView&);
bool equals_ignoring_case(const StringView&, const StringView&);
bool ends_with(const StringView& a, const StringView& b, CaseSensitivity);
+bool starts_with(const StringView&, const StringView&, CaseSensitivity);
}
}
diff --git a/AK/StringView.cpp b/AK/StringView.cpp
index 121b7f235d..635a4be2d2 100644
--- a/AK/StringView.cpp
+++ b/AK/StringView.cpp
@@ -147,17 +147,9 @@ bool StringView::starts_with(char ch) const
return ch == characters_without_null_termination()[0];
}
-bool StringView::starts_with(const StringView& str) const
+bool StringView::starts_with(const StringView& str, CaseSensitivity case_sensitivity) const
{
- if (str.is_empty())
- return true;
- if (is_empty())
- return false;
- if (str.length() > length())
- return false;
- if (characters_without_null_termination() == str.characters_without_null_termination())
- return true;
- return !memcmp(characters_without_null_termination(), str.characters_without_null_termination(), str.length());
+ return StringUtils::starts_with(*this, str, case_sensitivity);
}
bool StringView::ends_with(char ch) const
diff --git a/AK/StringView.h b/AK/StringView.h
index 2d05bea0a7..35c99e69f5 100644
--- a/AK/StringView.h
+++ b/AK/StringView.h
@@ -72,7 +72,7 @@ public:
unsigned hash() const;
- bool starts_with(const StringView&) const;
+ bool starts_with(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const;
bool ends_with(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const;
bool starts_with(char) const;
bool ends_with(char) const;
diff --git a/AK/Tests/TestString.cpp b/AK/Tests/TestString.cpp
index b3c70e6826..55aab73259 100644
--- a/AK/Tests/TestString.cpp
+++ b/AK/Tests/TestString.cpp
@@ -87,6 +87,8 @@ TEST_CASE(starts_with)
EXPECT(!test_string.starts_with('B'));
EXPECT(test_string.starts_with("ABCDEF"));
EXPECT(!test_string.starts_with("DEF"));
+ EXPECT(test_string.starts_with("abc", CaseSensitivity::CaseInsensitive));
+ EXPECT(!test_string.starts_with("abc", CaseSensitivity::CaseSensitive));
}
TEST_CASE(ends_with)
diff --git a/AK/Tests/TestStringUtils.cpp b/AK/Tests/TestStringUtils.cpp
index ce17af6e6e..2d5ecea7e0 100644
--- a/AK/Tests/TestStringUtils.cpp
+++ b/AK/Tests/TestStringUtils.cpp
@@ -164,4 +164,15 @@ TEST_CASE(ends_with)
EXPECT(!AK::StringUtils::ends_with(test_string, "def", CaseSensitivity::CaseSensitive));
}
+TEST_CASE(starts_with)
+{
+ String test_string = "ABCDEF";
+ EXPECT(AK::StringUtils::starts_with(test_string, "ABC", CaseSensitivity::CaseSensitive));
+ EXPECT(AK::StringUtils::starts_with(test_string, "ABCDEF", CaseSensitivity::CaseSensitive));
+ EXPECT(!AK::StringUtils::starts_with(test_string, "BCDEF", CaseSensitivity::CaseSensitive));
+ EXPECT(!AK::StringUtils::starts_with(test_string, "ABCDEFG", CaseSensitivity::CaseSensitive));
+ EXPECT(AK::StringUtils::starts_with(test_string, "abc", CaseSensitivity::CaseInsensitive));
+ EXPECT(!AK::StringUtils::starts_with(test_string, "abc", CaseSensitivity::CaseSensitive));
+}
+
TEST_MAIN(StringUtils)
diff --git a/AK/Tests/TestStringView.cpp b/AK/Tests/TestStringView.cpp
index ded60c943e..021be691b2 100644
--- a/AK/Tests/TestStringView.cpp
+++ b/AK/Tests/TestStringView.cpp
@@ -68,6 +68,8 @@ TEST_CASE(starts_with)
EXPECT(test_string_view.starts_with("AB"));
EXPECT(test_string_view.starts_with("ABCDEF"));
EXPECT(!test_string_view.starts_with("DEF"));
+ EXPECT(test_string_view.starts_with("abc", CaseSensitivity::CaseInsensitive));
+ EXPECT(!test_string_view.starts_with("abc", CaseSensitivity::CaseSensitive));
}
TEST_CASE(ends_with)