Skip to content

Commit 20aa1ae

Browse files
committed
Implement "ends_with" and update "starts_with" to the same implementation style.
1 parent dc3a96a commit 20aa1ae

File tree

3 files changed

+52
-28
lines changed

3 files changed

+52
-28
lines changed

doc/container.qbk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1461,7 +1461,7 @@ use [*Boost.Container]? There are several reasons for that:
14611461
* Implemented overaligned allocation support for `adaptive_pool`and `node_allocator`
14621462
* Updated `basic_string` to the latest standard API:
14631463
* Added missing `string_view` members and updated `operator[]` to be able to return the terminating null.
1464-
* Added C++20 `starts_with` and C++23 `contains` overloads.
1464+
* Added C++20 `starts_with`/`ends_with` and C++23 `contains` overloads.
14651465
* Fixed bugs/issues:
14661466
* [@https://github.com/boostorg/container/issues/323 GitHub #323: ['"flat_tree::try_emplace UB"]].
14671467
* [@https://github.com/boostorg/container/issues/328 GitHub #328: ['"boost::container::deque stores a redundant copy of the allocator, increasing size"]].

include/boost/container/string.hpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2989,7 +2989,11 @@ class basic_string
29892989
template<template <class, class> class BasicStringView>
29902990
BOOST_CONTAINER_NODISCARD inline
29912991
bool starts_with(BasicStringView<CharT, Traits> sv) const BOOST_NOEXCEPT
2992-
{ return this->size() >= sv.size() && Traits::compare(this->data(), sv.data(), sv.size()) == 0; }
2992+
{
2993+
const std::size_t s_sz = sv.size();
2994+
const std::size_t t_sz = this->size();
2995+
return t_sz >= s_sz && Traits::compare(this->data(), sv.data(), s_sz) == 0;
2996+
}
29932997

29942998
//! <b>Effects</b>: Checks if the string begins with the given prefix
29952999
//!
@@ -3008,11 +3012,47 @@ class basic_string
30083012
BOOST_CONTAINER_NODISCARD inline
30093013
bool starts_with(const CharT* s) const BOOST_NOEXCEPT
30103014
{
3011-
const size_type s_sz = Traits::length(s);
3012-
const size_type t_sz = this->size();
3015+
const std::size_t s_sz = Traits::length(s);
3016+
const std::size_t t_sz = this->size();
30133017
return t_sz >= s_sz && Traits::compare(this->data(), s, s_sz) == 0;
30143018
}
30153019

3020+
//! <b>Effects</b>: Checks if the string begins with the given suffix
3021+
//!
3022+
//! <b>Throws</b>: Nothing
3023+
//!
3024+
//! <b>Returns</b>: true if the string begins with the provided suffix, false otherwise.
3025+
template<template <class, class> class BasicStringView>
3026+
BOOST_CONTAINER_NODISCARD inline
3027+
bool ends_with(BasicStringView<CharT, Traits> sv) const BOOST_NOEXCEPT
3028+
{
3029+
const std::size_t s_sz = sv.size();
3030+
const std::size_t t_sz = this->size();
3031+
return t_sz >= s_sz && Traits::compare(this->data() + std::ptrdiff_t(t_sz - s_sz), sv.data(), s_sz) == 0;
3032+
}
3033+
3034+
//! <b>Effects</b>: Checks if the string begins with the given suffix
3035+
//!
3036+
//! <b>Throws</b>: Nothing
3037+
//!
3038+
//! <b>Returns</b>: true if the string begins with the provided suffix, false otherwise.
3039+
BOOST_CONTAINER_NODISCARD inline
3040+
bool ends_with(CharT c) const BOOST_NOEXCEPT
3041+
{ return !empty() && Traits::eq(back(), c); }
3042+
3043+
//! <b>Effects</b>: Checks if the string begins with the given suffix
3044+
//!
3045+
//! <b>Throws</b>: Nothing
3046+
//!
3047+
//! <b>Returns</b>: true if the string begins with the provided suffix, false otherwise.
3048+
BOOST_CONTAINER_NODISCARD inline
3049+
bool ends_with(const CharT* s) const BOOST_NOEXCEPT
3050+
{
3051+
const std::size_t s_sz = Traits::length(s);
3052+
const std::size_t t_sz = this->size();
3053+
return t_sz >= s_sz && Traits::compare(this->data() + std::ptrdiff_t(t_sz - s_sz), s, s_sz) == 0;
3054+
}
3055+
30163056
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
30173057
private:
30183058
void priv_move_assign(BOOST_RV_REF(basic_string) x, dtl::bool_<true> /*steal_resources*/)

test/string_test.cpp

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,24 +1473,9 @@ void test_compare()
14731473
}
14741474

14751475
//==============================================================================
1476-
// SECTION 11: Operations - starts_with, ends_with, contains (helper functions)
1477-
// Note: boost::container::string may not have these methods, so we implement
1478-
// them using find/compare for testing purposes
1476+
// SECTION 11: Operations - starts_with, ends_with, contains
14791477
//==============================================================================
14801478

1481-
// Helper functions for starts_with/ends_with/contains since boost::container::string
1482-
// might not have these methods in older versions
1483-
namespace test_helpers {
1484-
1485-
bool ends_with(const string& s, const char* suffix) {
1486-
string::size_type len = std::strlen(suffix);
1487-
return s.size() >= len && s.compare(s.size() - len, len, suffix) == 0;
1488-
}
1489-
bool ends_with(const string& s, char c) {
1490-
return !s.empty() && s[s.size() - 1] == c;
1491-
}
1492-
}
1493-
14941479
void test_starts_with()
14951480
{
14961481
string s("Hello, World!");
@@ -1509,15 +1494,14 @@ void test_ends_with()
15091494
{
15101495
string s("Hello, World!");
15111496

1512-
using test_helpers::ends_with;
1513-
BOOST_TEST(ends_with(s, "World!"));
1514-
BOOST_TEST(ends_with(s, "!"));
1515-
BOOST_TEST(ends_with(s, ""));
1516-
BOOST_TEST(ends_with(s, '!'));
1497+
BOOST_TEST(s.ends_with("World!"));
1498+
BOOST_TEST(s.ends_with("!"));
1499+
BOOST_TEST(s.ends_with(""));
1500+
BOOST_TEST(s.ends_with('!'));
15171501

1518-
BOOST_TEST(!ends_with(s, "Hello"));
1519-
BOOST_TEST(!ends_with(s, "world!")); // case-sensitive
1520-
BOOST_TEST(!ends_with(s, 'H'));
1502+
BOOST_TEST(!s.ends_with("Hello"));
1503+
BOOST_TEST(!s.ends_with("world!")); // case-sensitive
1504+
BOOST_TEST(!s.ends_with('H'));
15211505
}
15221506

15231507
void test_contains()

0 commit comments

Comments
 (0)