From beb090b83f699f6a709ff5803d14e4bf1c6da412 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 28 Oct 2024 18:25:39 -0700 Subject: [PATCH] Add ctl string find_first_of and find_last_of --- ctl/string.cc | 62 ++++++++++++++++++++++++++++++++++++ ctl/string.h | 4 +++ ctl/string_view.cc | 62 ++++++++++++++++++++++++++++++++++++ ctl/string_view.h | 4 +++ test/ctl/string_test.cc | 56 ++++++++++++++++++++++++++++++++ test/ctl/string_view_test.cc | 56 ++++++++++++++++++++++++++++++++ 6 files changed, 244 insertions(+) diff --git a/ctl/string.cc b/ctl/string.cc index 0e7361282..5e14220de 100644 --- a/ctl/string.cc +++ b/ctl/string.cc @@ -389,4 +389,66 @@ string::append(const ctl::string_view& s, size_t pos, size_t count) noexcept append(s.substr(pos, count)); } +size_t +string::find_last_of(char c, size_t pos) const noexcept +{ + const char* b = data(); + size_t n = size(); + if (pos > n) + pos = n; + const char* p = (const char*)memrchr(b, c, pos); + return p ? p - b : npos; +} + +size_t +string::find_last_of(ctl::string_view set, size_t pos) const noexcept +{ + if (empty() || set.empty()) + return npos; + bool lut[256] = {}; + for (char c : set) + lut[c & 255] = true; + const char* b = data(); + size_t last = size() - 1; + if (pos > last) + pos = last; + for (;;) { + if (lut[b[pos] & 255]) + return pos; + if (!pos) + return npos; + --pos; + } +} + +size_t +string::find_first_of(char c, size_t pos) const noexcept +{ + size_t n = size(); + if (pos >= n) + return npos; + const char* b = data(); + const char* p = (const char*)memchr(b + pos, c, n - pos); + return p ? p - b : npos; +} + +size_t +string::find_first_of(ctl::string_view set, size_t pos) const noexcept +{ + if (set.empty()) + return npos; + bool lut[256] = {}; + for (char c : set) + lut[c & 255] = true; + const char* b = data(); + size_t n = size(); + for (;;) { + if (pos >= n) + return npos; + if (lut[b[pos] & 255]) + return pos; + ++pos; + } +} + } // namespace ctl diff --git a/ctl/string.h b/ctl/string.h index b88c903cb..e6e736eec 100644 --- a/ctl/string.h +++ b/ctl/string.h @@ -137,6 +137,10 @@ class string bool starts_with(ctl::string_view) const noexcept; size_t find(char, size_t = 0) const noexcept; size_t find(ctl::string_view, size_t = 0) const noexcept; + size_t find_first_of(char, size_t = 0) const noexcept; + size_t find_first_of(ctl::string_view, size_t = 0) const noexcept; + size_t find_last_of(char, size_t = npos) const noexcept; + size_t find_last_of(ctl::string_view, size_t = npos) const noexcept; void swap(string& s) noexcept { diff --git a/ctl/string_view.cc b/ctl/string_view.cc index 951f707a9..3dbadbe21 100644 --- a/ctl/string_view.cc +++ b/ctl/string_view.cc @@ -108,4 +108,66 @@ string_view::starts_with(const string_view s) const noexcept return !memcmp(p, s.p, s.n); } +size_t +string_view::find_last_of(char c, size_t pos) const noexcept +{ + const char* b = data(); + size_t n = size(); + if (pos > n) + pos = n; + const char* p = (const char*)memrchr(b, c, pos); + return p ? p - b : npos; +} + +size_t +string_view::find_last_of(ctl::string_view set, size_t pos) const noexcept +{ + if (empty() || set.empty()) + return npos; + bool lut[256] = {}; + for (char c : set) + lut[c & 255] = true; + const char* b = data(); + size_t last = size() - 1; + if (pos > last) + pos = last; + for (;;) { + if (lut[b[pos] & 255]) + return pos; + if (!pos) + return npos; + --pos; + } +} + +size_t +string_view::find_first_of(char c, size_t pos) const noexcept +{ + size_t n = size(); + if (pos >= n) + return npos; + const char* b = data(); + const char* p = (const char*)memchr(b + pos, c, n - pos); + return p ? p - b : npos; +} + +size_t +string_view::find_first_of(ctl::string_view set, size_t pos) const noexcept +{ + if (set.empty()) + return npos; + bool lut[256] = {}; + for (char c : set) + lut[c & 255] = true; + const char* b = data(); + size_t n = size(); + for (;;) { + if (pos >= n) + return npos; + if (lut[b[pos] & 255]) + return pos; + ++pos; + } +} + } // namespace ctl diff --git a/ctl/string_view.h b/ctl/string_view.h index 4b237f9d5..9c5949f02 100644 --- a/ctl/string_view.h +++ b/ctl/string_view.h @@ -45,6 +45,10 @@ struct string_view string_view substr(size_t = 0, size_t = npos) const noexcept; size_t find(char, size_t = 0) const noexcept; size_t find(string_view, size_t = 0) const noexcept; + size_t find_first_of(char, size_t = 0) const noexcept; + size_t find_first_of(ctl::string_view, size_t = 0) const noexcept; + size_t find_last_of(char, size_t = npos) const noexcept; + size_t find_last_of(ctl::string_view, size_t = npos) const noexcept; constexpr string_view& operator=(const string_view s) noexcept { diff --git a/test/ctl/string_test.cc b/test/ctl/string_test.cc index 828e7eacc..6319a82da 100644 --- a/test/ctl/string_test.cc +++ b/test/ctl/string_test.cc @@ -412,5 +412,61 @@ main() return 107; } + { + String s = "ee"; + if (s.find_last_of('E') != String::npos) + return 108; + if (s.find_last_of('e') != 1) + return 109; + } + + { + String e = ""; + String s = "ee"; + if (e.find_last_of("") != String::npos) + return 110; + if (s.find_last_of("") != String::npos) + return 111; + if (s.find_last_of("AE") != String::npos) + return 112; + if (s.find_last_of("ae") != 1) + return 113; + if (s.find_last_of("ae", 1) != 1) + return 114; + if (s.find_last_of("ae", 0) != 0) + return 115; + if (s.find_last_of("ae", 10) != 1) + return 116; + } + + { + String s = "ee"; + if (s.find_first_of('E') != String::npos) + return 117; + if (s.find_first_of('e') != 0) + return 118; + if (s.find_first_of('e', 1) != 1) + return 119; + } + + { + String e = ""; + String s = "ee"; + if (e.find_first_of("") != String::npos) + return 120; + if (s.find_first_of("") != String::npos) + return 121; + if (s.find_first_of("AE") != String::npos) + return 122; + if (s.find_first_of("ae") != 0) + return 123; + if (s.find_first_of("ae", 1) != 1) + return 124; + if (s.find_first_of("ae", 0) != 0) + return 125; + if (s.find_first_of("ae", 10) != String::npos) + return 126; + } + CheckForMemoryLeaks(); } diff --git a/test/ctl/string_view_test.cc b/test/ctl/string_view_test.cc index 43e526728..a371fdfb5 100644 --- a/test/ctl/string_view_test.cc +++ b/test/ctl/string_view_test.cc @@ -182,5 +182,61 @@ main(int argc, char* argv[]) return 2; } + { + ctl::string_view s = "ee"; + if (s.find_last_of('E') != ctl::string_view::npos) + return 108; + if (s.find_last_of('e') != 1) + return 109; + } + + { + ctl::string_view e = ""; + ctl::string_view s = "ee"; + if (e.find_last_of("") != ctl::string_view::npos) + return 110; + if (s.find_last_of("") != ctl::string_view::npos) + return 111; + if (s.find_last_of("AE") != ctl::string_view::npos) + return 112; + if (s.find_last_of("ae") != 1) + return 113; + if (s.find_last_of("ae", 1) != 1) + return 114; + if (s.find_last_of("ae", 0) != 0) + return 115; + if (s.find_last_of("ae", 10) != 1) + return 116; + } + + { + ctl::string_view s = "ee"; + if (s.find_first_of('E') != ctl::string_view::npos) + return 117; + if (s.find_first_of('e') != 0) + return 118; + if (s.find_first_of('e', 1) != 1) + return 119; + } + + { + ctl::string_view e = ""; + ctl::string_view s = "ee"; + if (e.find_first_of("") != ctl::string_view::npos) + return 120; + if (s.find_first_of("") != ctl::string_view::npos) + return 121; + if (s.find_first_of("AE") != ctl::string_view::npos) + return 122; + if (s.find_first_of("ae") != 0) + return 123; + if (s.find_first_of("ae", 1) != 1) + return 124; + if (s.find_first_of("ae", 0) != 0) + return 125; + if (s.find_first_of("ae", 10) != ctl::string_view::npos) + return 126; + } + CheckForMemoryLeaks(); }