From 416a24752dddaa88a3d33645e28a844fd19e5235 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Mon, 24 Jul 2023 11:24:50 +0800 Subject: [PATCH 1/5] sstring: add sstring::find() overloads to be compliant with the C++20 standard, which requires that a string should have following find() overloads: template constexpr size_type find(const T& t, size_type pos = 0) const noexcept // where T should be convertible to basic_string_view constexpr size_type find(const charT* s, size_type pos, size_type n) const; constexpr size_type find(const charT* s, size_type pos = 0) const; so let's provide these overloads, so that sstring can be used in lieu of std::string, when appropriate. see also https://eel.is/c++draft/basic.string#string.ops Signed-off-by: Kefu Chai --- include/seastar/core/sstring.hh | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/include/seastar/core/sstring.hh b/include/seastar/core/sstring.hh index 6b22fc189cb..dfcd8c28cb9 100644 --- a/include/seastar/core/sstring.hh +++ b/include/seastar/core/sstring.hh @@ -256,20 +256,18 @@ public: return npos; } - size_t find(const basic_sstring& s, size_t pos = 0) const noexcept { - const char_type* it = str() + pos; - const char_type* end = str() + size(); - const char_type* c_str = s.str(); - + size_t find(const char_type* c_str, size_t pos, size_t len2) const noexcept { + assert(c_str != nullptr || len2 == 0); if (pos > size()) { return npos; } - const size_t len2 = s.size(); if (len2 == 0) { return pos; } + const char_type* it = str() + pos; + const char_type* end = str() + size(); size_t len1 = end - it; if (len1 < len2) { return npos; @@ -296,6 +294,23 @@ public: } } + constexpr size_t find(const char_type* s, size_t pos = 0) const noexcept { + return find(s, pos, traits_type::length(s)); + } + + size_t find(const basic_sstring& s, size_t pos = 0) const noexcept { + return find(s.str(), pos, s.size()); + } + + template>, + int> = 0> + size_t find(const StringViewLike& sv_like, size_type pos = 0) const noexcept { + std::basic_string_view sv = sv_like; + return find(sv.data(), pos, sv.size()); + } + /** * find_last_of find the last occurrence of c in the string. * When pos is specified, the search only includes characters From e055ef28a8c8b8fb4fa80f0c046e065d4837d4a9 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Mon, 24 Jul 2023 11:32:46 +0800 Subject: [PATCH 2/5] sstring: add sstring::front() as required by the C++20 standard, std::string should provide constexpr const charT& front() const; constexpr charT& front(); so let's add them to sstring. so that sstring can be used in lieu of std::string, when appropriate. see also https://eel.is/c++draft/basic.string#string.access Signed-off-by: Kefu Chai --- include/seastar/core/sstring.hh | 23 +++++++++++++++++++++++ tests/unit/sstring_test.cc | 6 ++++++ 2 files changed, 29 insertions(+) diff --git a/include/seastar/core/sstring.hh b/include/seastar/core/sstring.hh index dfcd8c28cb9..a99c8e85281 100644 --- a/include/seastar/core/sstring.hh +++ b/include/seastar/core/sstring.hh @@ -461,6 +461,29 @@ public: replace(p, p, beg, end); } + + /** + * Returns a read/write reference to the data at the first + * element of the string. + * This function shall not be called on empty strings. + */ + reference + front() noexcept { + assert(!empty()); + return *str(); + } + + /** + * Returns a read-only (constant) reference to the data at the first + * element of the string. + * This function shall not be called on empty strings. + */ + const_reference + front() const noexcept { + assert(!empty()); + return *str(); + } + /** * Returns a read/write reference to the data at the last * element of the string. diff --git a/tests/unit/sstring_test.cc b/tests/unit/sstring_test.cc index acc009a6862..60ccb5bb26f 100644 --- a/tests/unit/sstring_test.cc +++ b/tests/unit/sstring_test.cc @@ -51,6 +51,12 @@ BOOST_AUTO_TEST_CASE(test_add_literal_to_sstring) { BOOST_REQUIRE_EQUAL("x" + sstring("y"), sstring("xy")); } +BOOST_AUTO_TEST_CASE(test_front) { + sstring s("abcde"); + BOOST_CHECK_EQUAL(s.front(), 'a'); + BOOST_CHECK_EQUAL(std::as_const(s).front(), 'a'); +} + BOOST_AUTO_TEST_CASE(test_find_sstring) { BOOST_REQUIRE_EQUAL(sstring("abcde").find('b'), 1u); BOOST_REQUIRE_EQUAL(sstring("babcde").find('b',1), 2u); From 368c7e14d6e2d1705570c09bd6a3a81a587d1345 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Mon, 24 Jul 2023 11:35:30 +0800 Subject: [PATCH 3/5] sstring: add sstring::starts_with() as required by the C++20 standard, std::string should provide constexpr bool starts_with(basic_string_view x) const noexcept; constexpr bool starts_with(charT x) const noexcept; constexpr bool starts_with(const charT* x) const; so let's add them to sstring. . so that sstring can be used in lieu of std::string, when appropriate. see also https://eel.is/c++draft/string.starts.with Signed-off-by: Kefu Chai --- include/seastar/core/sstring.hh | 12 ++++++++++++ tests/unit/sstring_test.cc | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/seastar/core/sstring.hh b/include/seastar/core/sstring.hh index a99c8e85281..3052b31b5eb 100644 --- a/include/seastar/core/sstring.hh +++ b/include/seastar/core/sstring.hh @@ -596,6 +596,18 @@ public: } } + constexpr bool starts_with(std::basic_string_view sv) const noexcept { + return size() > sv.size() && compare(0, sv.size(), sv) == 0; + } + + constexpr bool starts_with(char_type c) const noexcept { + return !empty() && traits_type::eq(front(), c); + } + + constexpr bool starts_with(const char_type* s) const noexcept { + return starts_with(std::basic_string_view(s)); + } + void swap(basic_sstring& x) noexcept { contents tmp; tmp = x.u; diff --git a/tests/unit/sstring_test.cc b/tests/unit/sstring_test.cc index 60ccb5bb26f..fb3cdeef32e 100644 --- a/tests/unit/sstring_test.cc +++ b/tests/unit/sstring_test.cc @@ -25,6 +25,7 @@ #include #include +using namespace std::literals; using namespace seastar; BOOST_AUTO_TEST_CASE(test_make_sstring) { @@ -105,6 +106,18 @@ BOOST_AUTO_TEST_CASE(test_str_not_find_sstring) { BOOST_REQUIRE_EQUAL(sstring("abc").find("abcde"), sstring::npos); } +BOOST_AUTO_TEST_CASE(test_str_starts_with) { + BOOST_CHECK(sstring("abcdefg").starts_with("ab"sv)); + BOOST_CHECK(sstring("abcde").starts_with('a')); + BOOST_CHECK(sstring("abcde").starts_with("ab")); + BOOST_CHECK(sstring("abcdefg").starts_with("")); + + BOOST_CHECK(!sstring("abcde").starts_with("cde")); + BOOST_CHECK(!sstring("abcde").starts_with('b')); + BOOST_CHECK(!sstring("abcdefg").starts_with("cde"sv)); + BOOST_CHECK(!sstring("abcdefg").starts_with("ab\0"sv)); +} + BOOST_AUTO_TEST_CASE(test_substr_sstring) { BOOST_REQUIRE_EQUAL(sstring("abcde").substr(1,2), "bc"); BOOST_REQUIRE_EQUAL(sstring("abc").substr(1,2), "bc"); From aebef640452a6f1ad2cc2c0e0c2fec7fbd4f535a Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Mon, 24 Jul 2023 11:42:15 +0800 Subject: [PATCH 4/5] sstring: add sstring::ends_with() as required by the C++20 standard, std::string should provide constexpr bool ends_with(basic_string_view x) const noexcept; constexpr bool ends_with(charT x) const noexcept; constexpr bool ends_with(const charT* x) const; so let's add them to sstring. . so that sstring can be used in lieu of std::string, when appropriate. see also https://eel.is/c++draft/string.ends.with Signed-off-by: Kefu Chai --- include/seastar/core/sstring.hh | 12 ++++++++++++ tests/unit/sstring_test.cc | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/seastar/core/sstring.hh b/include/seastar/core/sstring.hh index 3052b31b5eb..d5ba8afb07e 100644 --- a/include/seastar/core/sstring.hh +++ b/include/seastar/core/sstring.hh @@ -608,6 +608,18 @@ public: return starts_with(std::basic_string_view(s)); } + constexpr bool ends_with(std::basic_string_view sv) const noexcept { + return size() > sv.size() && compare(size() - sv.size(), npos, sv) == 0; + } + + constexpr bool ends_with(char_type c) const noexcept { + return !empty() && traits_type::eq(back(), c); + } + + constexpr bool ends_with(const char_type* s) const noexcept { + return ends_with(std::basic_string_view(s)); + } + void swap(basic_sstring& x) noexcept { contents tmp; tmp = x.u; diff --git a/tests/unit/sstring_test.cc b/tests/unit/sstring_test.cc index fb3cdeef32e..dac7bee8311 100644 --- a/tests/unit/sstring_test.cc +++ b/tests/unit/sstring_test.cc @@ -118,6 +118,18 @@ BOOST_AUTO_TEST_CASE(test_str_starts_with) { BOOST_CHECK(!sstring("abcdefg").starts_with("ab\0"sv)); } +BOOST_AUTO_TEST_CASE(test_str_ends_with) { + BOOST_CHECK(sstring("abcdefg").ends_with("efg"sv)); + BOOST_CHECK(sstring("abcde").ends_with('e')); + BOOST_CHECK(sstring("abcde").ends_with("de")); + BOOST_CHECK(sstring("abcdefg").ends_with("")); + + BOOST_CHECK(!sstring("abcde").ends_with("abc")); + BOOST_CHECK(!sstring("abcde").ends_with('b')); + BOOST_CHECK(!sstring("abcdefg").ends_with("abc"sv)); + BOOST_CHECK(!sstring("abcdefg").ends_with("efg\0"sv)); +} + BOOST_AUTO_TEST_CASE(test_substr_sstring) { BOOST_REQUIRE_EQUAL(sstring("abcde").substr(1,2), "bc"); BOOST_REQUIRE_EQUAL(sstring("abc").substr(1,2), "bc"); From 3ea436e97452796f40325c6aca077df5c09befea Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Mon, 24 Jul 2023 11:48:52 +0800 Subject: [PATCH 5/5] sstring: add sstring::contains() as required by the C++20 standard, std::string should provide constexpr bool contains(basic_string_view x) const noexcept; constexpr bool contains(charT x) const noexcept; constexpr bool contains(const charT* x) const; so let's add them to sstring. . so that sstring can be used in lieu of std::string, when appropriate. see also https://eel.is/c++draft/string.contains Signed-off-by: Kefu Chai --- include/seastar/core/sstring.hh | 12 ++++++++++++ tests/unit/sstring_test.cc | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/seastar/core/sstring.hh b/include/seastar/core/sstring.hh index d5ba8afb07e..7bb9ae68bd3 100644 --- a/include/seastar/core/sstring.hh +++ b/include/seastar/core/sstring.hh @@ -620,6 +620,18 @@ public: return ends_with(std::basic_string_view(s)); } + constexpr bool contains(std::basic_string_view sv) const noexcept { + return find(sv) != npos; + } + + constexpr bool contains(char_type c) const noexcept { + return find(c) != npos; + } + + constexpr bool contains(const char_type* s) const noexcept { + return find(s) != npos; + } + void swap(basic_sstring& x) noexcept { contents tmp; tmp = x.u; diff --git a/tests/unit/sstring_test.cc b/tests/unit/sstring_test.cc index dac7bee8311..2cc78383891 100644 --- a/tests/unit/sstring_test.cc +++ b/tests/unit/sstring_test.cc @@ -130,6 +130,28 @@ BOOST_AUTO_TEST_CASE(test_str_ends_with) { BOOST_CHECK(!sstring("abcdefg").ends_with("efg\0"sv)); } +BOOST_AUTO_TEST_CASE(test_str_contains) { + BOOST_CHECK(sstring("abcde").starts_with("ab"sv)); + BOOST_CHECK(sstring("abcde").starts_with('a')); + BOOST_CHECK(sstring("abcde").starts_with("ab")); + BOOST_CHECK(sstring("abcde").starts_with("")); + + BOOST_CHECK(sstring("abcde").contains("bc"sv)); + BOOST_CHECK(sstring("abcde").contains("bc")); + BOOST_CHECK(sstring("abcde").contains('c')); + + BOOST_CHECK(sstring("abcde").contains("de"sv)); + BOOST_CHECK(sstring("abcde").contains("de")); + + BOOST_CHECK(!sstring("abcde").contains("bad")); + BOOST_CHECK(!sstring("abcde").contains("bce")); + BOOST_CHECK(!sstring("abcde").contains("x")); + BOOST_CHECK(!sstring("abcde").contains('x')); + BOOST_CHECK(!sstring("abcde").contains("ab\0"sv)); + BOOST_CHECK(!sstring("abcde").contains("bc\0"sv)); + BOOST_CHECK(!sstring("abcde").contains("de\0"sv)); +} + BOOST_AUTO_TEST_CASE(test_substr_sstring) { BOOST_REQUIRE_EQUAL(sstring("abcde").substr(1,2), "bc"); BOOST_REQUIRE_EQUAL(sstring("abc").substr(1,2), "bc");