Skip to content

Commit

Permalink
Merge 'sstring: add more accessors' from Kefu Chai
Browse files Browse the repository at this point in the history
in this series, more accessors are added to `seastar::sstring`. the goal is to make sstring more standard compliant, so that it can be used in lieu of `std::string` when appropriate.

Closes #1755

* https://github.com/scylladb/seastar:
  sstring: add sstring::contains()
  sstring: add sstring::ends_with()
  sstring: add sstring::starts_with()
  sstring: add sstring::front()
  sstring: add sstring::find() overloads
  • Loading branch information
xemul committed Jul 26, 2023
2 parents c204fe7 + 3ea436e commit ba1e39d
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 6 deletions.
86 changes: 80 additions & 6 deletions include/seastar/core/sstring.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<class StringViewLike,
std::enable_if_t<std::is_convertible_v<StringViewLike,
std::basic_string_view<char_type, traits_type>>,
int> = 0>
size_t find(const StringViewLike& sv_like, size_type pos = 0) const noexcept {
std::basic_string_view<char_type, traits_type> 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
Expand Down Expand Up @@ -446,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.
Expand Down Expand Up @@ -558,6 +596,42 @@ public:
}
}

constexpr bool starts_with(std::basic_string_view<char_type, traits_type> 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<char_type, traits_type>(s));
}

constexpr bool ends_with(std::basic_string_view<char_type, traits_type> 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<char_type, traits_type>(s));
}

constexpr bool contains(std::basic_string_view<char_type, traits_type> 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;
Expand Down
53 changes: 53 additions & 0 deletions tests/unit/sstring_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <seastar/core/sstring.hh>
#include <list>

using namespace std::literals;
using namespace seastar;

BOOST_AUTO_TEST_CASE(test_make_sstring) {
Expand All @@ -51,6 +52,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);
Expand Down Expand Up @@ -99,6 +106,52 @@ 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_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_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");
Expand Down

0 comments on commit ba1e39d

Please sign in to comment.