diff --git a/doc/container.qbk b/doc/container.qbk
index 51ac0c1..f1664ee 100644
--- a/doc/container.qbk
+++ b/doc/container.qbk
@@ -1461,7 +1461,7 @@ use [*Boost.Container]? There are several reasons for that:
* Implemented overaligned allocation support for `adaptive_pool`and `node_allocator`
* Updated `basic_string` to the latest standard API:
* Added missing `string_view` members and updated `operator[]` to be able to return the terminating null.
- * Added C++23 `contains` overloads
+ * Added C++20 `starts_with` and C++23 `contains` overloads.
* Fixed bugs/issues:
* [@https://github.com/boostorg/container/issues/323 GitHub #323: ['"flat_tree::try_emplace UB"]].
* [@https://github.com/boostorg/container/issues/328 GitHub #328: ['"boost::container::deque stores a redundant copy of the allocator, increasing size"]].
diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp
index a8d0e89..fc88a54 100644
--- a/include/boost/container/string.hpp
+++ b/include/boost/container/string.hpp
@@ -2981,6 +2981,38 @@ class basic_string
bool contains(const CharT* s) const BOOST_NOEXCEPT
{ return this->find(s) != npos; }
+ //! Effects: Checks if the string begins with the given prefix
+ //!
+ //! Throws: Nothing
+ //!
+ //! Returns: true if the string begins with the provided prefix, false otherwise.
+ template class BasicStringView>
+ BOOST_CONTAINER_NODISCARD inline
+ bool starts_with(BasicStringView sv) const BOOST_NOEXCEPT
+ { return this->size() >= sv.size() && Traits::compare(this->data(), sv.data(), sv.size()) == 0; }
+
+ //! Effects: Checks if the string begins with the given prefix
+ //!
+ //! Throws: Nothing
+ //!
+ //! Returns: true if the string begins with the provided prefix, false otherwise.
+ BOOST_CONTAINER_NODISCARD inline
+ bool starts_with(CharT c) const BOOST_NOEXCEPT
+ { return !empty() && Traits::eq(front(), c); }
+
+ //! Effects: Checks if the string begins with the given prefix
+ //!
+ //! Throws: Nothing
+ //!
+ //! Returns: true if the string begins with the provided prefix, false otherwise.
+ BOOST_CONTAINER_NODISCARD inline
+ bool starts_with(const CharT* s) const BOOST_NOEXCEPT
+ {
+ const size_type s_sz = Traits::length(s);
+ const size_type t_sz = this->size();
+ return t_sz >= s_sz && Traits::compare(this->data(), s, s_sz) == 0;
+ }
+
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
private:
void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_ /*steal_resources*/)
diff --git a/test/string_test.cpp b/test/string_test.cpp
index ec30592..167ed7d 100644
--- a/test/string_test.cpp
+++ b/test/string_test.cpp
@@ -1481,13 +1481,7 @@ void test_compare()
// Helper functions for starts_with/ends_with/contains since boost::container::string
// might not have these methods in older versions
namespace test_helpers {
- bool starts_with(const string& s, const char* prefix) {
- string::size_type len = std::strlen(prefix);
- return s.size() >= len && s.compare(0, len, prefix) == 0;
- }
- bool starts_with(const string& s, char c) {
- return !s.empty() && s[0] == c;
- }
+
bool ends_with(const string& s, const char* suffix) {
string::size_type len = std::strlen(suffix);
return s.size() >= len && s.compare(s.size() - len, len, suffix) == 0;
@@ -1495,27 +1489,20 @@ namespace test_helpers {
bool ends_with(const string& s, char c) {
return !s.empty() && s[s.size() - 1] == c;
}
- bool contains(const string& s, const char* substr) {
- return s.find(substr) != string::npos;
- }
- bool contains(const string& s, char c) {
- return s.find(c) != string::npos;
- }
}
void test_starts_with()
{
string s("Hello, World!");
- using test_helpers::starts_with;
- BOOST_TEST(starts_with(s, "Hello"));
- BOOST_TEST(starts_with(s, "H"));
- BOOST_TEST(starts_with(s, ""));
- BOOST_TEST(starts_with(s, 'H'));
+ BOOST_TEST(s.starts_with("Hello"));
+ BOOST_TEST(s.starts_with("H"));
+ BOOST_TEST(s.starts_with(""));
+ BOOST_TEST(s.starts_with('H'));
- BOOST_TEST(!starts_with(s, "World"));
- BOOST_TEST(!starts_with(s, "hello")); // case-sensitive
- BOOST_TEST(!starts_with(s, 'W'));
+ BOOST_TEST(!s.starts_with("World"));
+ BOOST_TEST(!s.starts_with("hello")); // case-sensitive
+ BOOST_TEST(!s.starts_with('W'));
}
void test_ends_with()