diff --git a/include/boost/utility/string_view.hpp b/include/boost/utility/string_view.hpp index 6c682b2..cf47c10 100644 --- a/include/boost/utility/string_view.hpp +++ b/include/boost/utility/string_view.hpp @@ -245,6 +245,18 @@ namespace boost { traits::compare(ptr_ + len_ - x.len_, x.ptr_, x.len_) == 0; } + BOOST_CXX14_CONSTEXPR bool contains(basic_string_view s) const BOOST_NOEXCEPT { + return find(s) != npos; + } + + BOOST_CXX14_CONSTEXPR bool contains(charT c) const BOOST_NOEXCEPT { + return find(c) != npos; + } + + BOOST_CXX14_CONSTEXPR bool contains(const charT* s) const BOOST_NOEXCEPT { + return find(s) != npos; + } + // find BOOST_CXX14_CONSTEXPR size_type find(basic_string_view s, size_type pos = 0) const BOOST_NOEXCEPT { if (pos > size()) diff --git a/test/string_ref_test1.cpp b/test/string_ref_test1.cpp index fc88905..5ab8869 100644 --- a/test/string_ref_test1.cpp +++ b/test/string_ref_test1.cpp @@ -7,6 +7,7 @@ For more information, see http://www.boost.org */ +#include #include #include #include @@ -41,30 +42,30 @@ void null_tests ( const char *p ) { // make sure that substrings work just like strings void test_substr ( const std::string &str ) { - const size_t sz = str.size (); + const std::size_t sz = str.size (); string_ref ref ( str ); // Substrings at the end - for ( size_t i = 0; i <= sz; ++ i ) + for ( std::size_t i = 0; i <= sz; ++ i ) interop ( str.substr ( i ), ref.substr ( i )); // Substrings at the beginning - for ( size_t i = 0; i <= sz; ++ i ) + for ( std::size_t i = 0; i <= sz; ++ i ) interop ( str.substr ( 0, i ), ref.substr ( 0, i )); // All possible substrings - for ( size_t i = 0; i < sz; ++i ) - for ( size_t j = i; j < sz; ++j ) + for ( std::size_t i = 0; i < sz; ++i ) + for ( std::size_t j = i; j < sz; ++j ) interop ( str.substr ( i, j ), ref.substr ( i, j )); } // make sure that removing prefixes and suffixes work just like strings void test_remove ( const std::string &str ) { - const size_t sz = str.size (); + const std::size_t sz = str.size (); std::string work; string_ref ref; - for ( size_t i = 1; i <= sz; ++i ) { + for ( std::size_t i = 1; i <= sz; ++i ) { work = str; ref = str; while ( ref.size () >= i ) { @@ -74,7 +75,7 @@ void test_remove ( const std::string &str ) { } } - for ( size_t i = 1; i < sz; ++ i ) { + for ( std::size_t i = 1; i < sz; ++ i ) { work = str; ref = str; while ( ref.size () >= i ) { diff --git a/test/string_ref_test2.cpp b/test/string_ref_test2.cpp index d733775..59c699b 100644 --- a/test/string_ref_test2.cpp +++ b/test/string_ref_test2.cpp @@ -7,8 +7,11 @@ For more information, see http://www.boost.org */ +#include #include #include // for std::strchr +#include +#include #include @@ -17,7 +20,7 @@ typedef boost::string_ref string_ref; void ends_with ( const char *arg ) { - const size_t sz = std::strlen ( arg ); + const std::size_t sz = std::strlen ( arg ); string_ref sr ( arg ); string_ref sr2 ( arg ); const char *p = arg; @@ -41,20 +44,19 @@ void ends_with ( const char *arg ) { char ch = sz == 0 ? '\0' : arg [ sz - 1 ]; sr2 = arg; if ( sz > 0 ) - BOOST_TEST ( sr2.ends_with ( ch )); + BOOST_TEST ( sr2.ends_with ( ch )); BOOST_TEST ( !sr2.ends_with ( ++ch )); BOOST_TEST ( sr2.ends_with ( string_ref ())); } void starts_with ( const char *arg ) { - const size_t sz = std::strlen ( arg ); + const std::size_t sz = std::strlen ( arg ); string_ref sr ( arg ); string_ref sr2 ( arg ); - const char *p = arg + std::strlen ( arg ) - 1; - while ( p >= arg ) { - std::string foo ( arg, p + 1 ); + std::string foo ( arg ); + while ( !foo.empty ()) { BOOST_TEST ( sr.starts_with ( foo )); - --p; + foo.erase ( foo.end () - 1 ); } while ( !sr2.empty ()) { @@ -64,8 +66,8 @@ void starts_with ( const char *arg ) { char ch = *arg; sr2 = arg; - if ( sz > 0 ) - BOOST_TEST ( sr2.starts_with ( ch )); + if ( sz > 0 ) + BOOST_TEST ( sr2.starts_with ( ch )); BOOST_TEST ( !sr2.starts_with ( ++ch )); BOOST_TEST ( sr2.starts_with ( string_ref ())); } @@ -93,7 +95,7 @@ void find ( const char *arg ) { string_ref sr2; const char *p; -// When we search for the empty string, we find it at position 0 +// When we search for the empty string, we find it at position 0 BOOST_TEST ( sr1.find (sr2) == 0 ); BOOST_TEST ( sr1.rfind(sr2) == 0 ); @@ -207,7 +209,7 @@ void find ( const char *arg ) { string_ref::size_type pos2 = sr1.find_first_not_of(*p); BOOST_TEST ( pos1 != string_ref::npos && pos1 < sr1.size () && pos1 <= ptr_diff ( p, arg )); if ( pos2 != string_ref::npos ) { - for ( size_t i = 0 ; i < pos2; ++i ) + for ( std::size_t i = 0 ; i < pos2; ++i ) BOOST_TEST ( sr1[i] == *p ); BOOST_TEST ( sr1 [ pos2 ] != *p ); } @@ -233,7 +235,7 @@ void find ( const char *arg ) { BOOST_TEST ( pos1 != string_ref::npos && pos1 < sr1.size () && pos1 >= ptr_diff ( p, arg )); BOOST_TEST ( pos2 == string_ref::npos || pos1 < sr1.size ()); if ( pos2 != string_ref::npos ) { - for ( size_t i = sr1.size () -1 ; i > pos2; --i ) + for ( std::size_t i = sr1.size () -1 ; i > pos2; --i ) BOOST_TEST ( sr1[i] == *p ); BOOST_TEST ( sr1 [ pos2 ] != *p ); } diff --git a/test/string_view_constexpr_test1.cpp b/test/string_view_constexpr_test1.cpp index d116e12..51a2652 100644 --- a/test/string_view_constexpr_test1.cpp +++ b/test/string_view_constexpr_test1.cpp @@ -30,12 +30,12 @@ struct constexpr_char_traits static constexpr bool eq(char_type c1, char_type c2) noexcept { return c1 == c2; } static constexpr bool lt(char_type c1, char_type c2) noexcept { return c1 < c2; } - static constexpr int compare(const char_type* s1, const char_type* s2, size_t n) noexcept; - static constexpr size_t length(const char_type* s) noexcept; - static constexpr const char_type* find(const char_type* s, size_t n, const char_type& a) noexcept; - static constexpr char_type* move(char_type* s1, const char_type* s2, size_t n) noexcept; - static constexpr char_type* copy(char_type* s1, const char_type* s2, size_t n) noexcept; - static constexpr char_type* assign(char_type* s, size_t n, char_type a) noexcept; + static constexpr int compare(const char_type* s1, const char_type* s2, std::size_t n) noexcept; + static constexpr std::size_t length(const char_type* s) noexcept; + static constexpr const char_type* find(const char_type* s, std::size_t n, const char_type& a) noexcept; + static constexpr char_type* move(char_type* s1, const char_type* s2, std::size_t n) noexcept; + static constexpr char_type* copy(char_type* s1, const char_type* s2, std::size_t n) noexcept; + static constexpr char_type* assign(char_type* s, std::size_t n, char_type a) noexcept; static constexpr int_type not_eof(int_type c) noexcept { return eq_int_type(c, eof()) ? ~eof() : c; } static constexpr char_type to_char_type(int_type c) noexcept { return char_type(c); } @@ -49,7 +49,7 @@ struct constexpr_char_traits // else, a negative value if, for some j in [0,n), X::lt(s1[j],s2[j]) is true and // for each i in [0,j) X::eq(s2[i],s2[i]) is true; // else a positive value. -constexpr int constexpr_char_traits::compare(const char_type* s1, const char_type* s2, size_t n) noexcept +constexpr int constexpr_char_traits::compare(const char_type* s1, const char_type* s2, std::size_t n) noexcept { for (; n != 0; --n, ++s1, ++s2) { @@ -61,10 +61,10 @@ constexpr int constexpr_char_traits::compare(const char_type* s1, const char_typ return 0; } -// yields: the smallest i such that X::eq(s[i],charT()) is true. -constexpr size_t constexpr_char_traits::length(const char_type* s) noexcept +// yields: the smallest i such that X::eq(s[i],charT()) is true. +constexpr std::size_t constexpr_char_traits::length(const char_type* s) noexcept { - size_t len = 0; + std::size_t len = 0; for (; !eq(*s, char_type(0)); ++s) ++len; return len; @@ -76,7 +76,7 @@ int main() { constexpr string_view sv1; constexpr string_view sv2{"abc", 3}; // ptr, len - constexpr string_view sv3{"def"}; // ptr + constexpr string_view sv3{"def"}; // ptr constexpr const char *s1 = ""; constexpr const char *s2 = "abc"; diff --git a/test/string_view_test1.cpp b/test/string_view_test1.cpp index c35bbfa..22912c0 100644 --- a/test/string_view_test1.cpp +++ b/test/string_view_test1.cpp @@ -7,6 +7,7 @@ For more information, see http://www.boost.org */ +#include #include #include #include @@ -42,30 +43,30 @@ void null_tests ( const char *p ) { // make sure that substrings work just like strings void test_substr ( const std::string &str ) { - const size_t sz = str.size (); + const std::size_t sz = str.size (); string_view ref ( str ); // Substrings at the end - for ( size_t i = 0; i <= sz; ++ i ) + for ( std::size_t i = 0; i <= sz; ++ i ) interop ( str.substr ( i ), ref.substr ( i )); // Substrings at the beginning - for ( size_t i = 0; i <= sz; ++ i ) + for ( std::size_t i = 0; i <= sz; ++ i ) interop ( str.substr ( 0, i ), ref.substr ( 0, i )); // All possible substrings - for ( size_t i = 0; i < sz; ++i ) - for ( size_t j = i; j < sz; ++j ) + for ( std::size_t i = 0; i < sz; ++i ) + for ( std::size_t j = i; j < sz; ++j ) interop ( str.substr ( i, j ), ref.substr ( i, j )); } // make sure that removing prefixes and suffixes work just like strings void test_remove ( const std::string &str ) { - const size_t sz = str.size (); + const std::size_t sz = str.size (); std::string work; string_view ref; - for ( size_t i = 1; i <= sz; ++i ) { + for ( std::size_t i = 1; i <= sz; ++i ) { work = str; ref = str; while ( ref.size () >= i ) { @@ -75,7 +76,7 @@ void test_remove ( const std::string &str ) { } } - for ( size_t i = 1; i < sz; ++ i ) { + for ( std::size_t i = 1; i < sz; ++ i ) { work = str; ref = str; while ( ref.size () >= i ) { diff --git a/test/string_view_test2.cpp b/test/string_view_test2.cpp index 135fd1a..6834091 100644 --- a/test/string_view_test2.cpp +++ b/test/string_view_test2.cpp @@ -8,9 +8,11 @@ */ #include // for placement new +#include #include +#include // for std::equal #include // for NULL, std::size_t, std::ptrdiff_t -#include // for std::strchr and std::strcmp +#include // for std::strlen, std::strchr and std::strcmp #include // for std::malloc and std::free #include @@ -21,7 +23,7 @@ typedef boost::string_view string_view; void ends_with ( const char *arg ) { - const size_t sz = std::strlen ( arg ); + const std::size_t sz = std::strlen ( arg ); string_view sr ( arg ); string_view sr2 ( arg ); const char *p = arg; @@ -45,20 +47,19 @@ void ends_with ( const char *arg ) { char ch = sz == 0 ? '\0' : arg [ sz - 1 ]; sr2 = arg; if ( sz > 0 ) - BOOST_TEST ( sr2.ends_with ( ch )); + BOOST_TEST ( sr2.ends_with ( ch )); BOOST_TEST ( !sr2.ends_with ( ++ch )); BOOST_TEST ( sr2.ends_with ( string_view())); } void starts_with ( const char *arg ) { - const size_t sz = std::strlen ( arg ); + const std::size_t sz = std::strlen ( arg ); string_view sr ( arg ); string_view sr2 ( arg ); - const char *p = arg + std::strlen ( arg ) - 1; - while ( p >= arg ) { - std::string foo ( arg, p + 1 ); + std::string foo ( arg ); + while ( !foo.empty ()) { BOOST_TEST ( sr.starts_with ( foo )); - --p; + foo.erase ( foo.end () - 1 ); } while ( !sr2.empty ()) { @@ -68,12 +69,40 @@ void starts_with ( const char *arg ) { char ch = *arg; sr2 = arg; - if ( sz > 0 ) - BOOST_TEST ( sr2.starts_with ( ch )); + if ( sz > 0 ) + BOOST_TEST ( sr2.starts_with ( ch )); BOOST_TEST ( !sr2.starts_with ( ++ch )); BOOST_TEST ( sr2.starts_with ( string_view ())); } +void contains ( const char *arg ) { + const std::size_t sz = std::strlen ( arg ); + string_view sr ( arg ); + string_view sr2 ( arg ); + std::string foo ( arg ); + while ( !foo.empty ()) { + BOOST_TEST ( sr.contains ( foo )); + if ( ( foo.size () & 1u ) != 0u ) + foo.erase ( foo.end () - 1 ); + else + foo.erase ( foo.begin () ); + } + + while ( !sr2.empty ()) { + BOOST_TEST ( sr.contains ( sr2 )); + if ( ( sr2.size () & 1u ) != 0u ) + sr2.remove_suffix (1); + else + sr2.remove_prefix (1); + } + + sr2 = arg; + for ( std::size_t i = 0; i < sz; ++i ) + BOOST_TEST ( sr2.contains ( arg[i] )); + BOOST_TEST ( !sr2.contains ( '\a' )); + BOOST_TEST ( sr2.contains ( string_view ())); + } + void reverse ( const char *arg ) { // Round trip string_view sr1 ( arg ); @@ -97,7 +126,7 @@ void find ( const char *arg ) { string_view sr2; const char *p; -// When we search for the empty string, we find it at position 0 +// When we search for the empty string, we find it at position 0 BOOST_TEST ( sr1.find (sr2) == 0 ); BOOST_TEST ( sr1.rfind(sr2) == 0 ); @@ -211,7 +240,7 @@ void find ( const char *arg ) { string_view::size_type pos2 = sr1.find_first_not_of(*p); BOOST_TEST ( pos1 != string_view::npos && pos1 < sr1.size () && pos1 <= ptr_diff ( p, arg )); if ( pos2 != string_view::npos ) { - for ( size_t i = 0 ; i < pos2; ++i ) + for ( string_view::size_type i = 0 ; i < pos2; ++i ) BOOST_TEST ( sr1[i] == *p ); BOOST_TEST ( sr1 [ pos2 ] != *p ); } @@ -237,7 +266,7 @@ void find ( const char *arg ) { BOOST_TEST ( pos1 != string_view::npos && pos1 < sr1.size () && pos1 >= ptr_diff ( p, arg )); BOOST_TEST ( pos2 == string_view::npos || pos1 < sr1.size ()); if ( pos2 != string_view::npos ) { - for ( size_t i = sr1.size () -1 ; i > pos2; --i ) + for ( string_view::size_type i = sr1.size () -1 ; i > pos2; --i ) BOOST_TEST ( sr1[i] == *p ); BOOST_TEST ( sr1 [ pos2 ] != *p ); } @@ -398,12 +427,13 @@ int main() while ( *p != NULL ) { starts_with ( *p ); ends_with ( *p ); + contains ( *p ); reverse ( *p ); find ( *p ); to_string ( *p ); compare ( *p ); - p++; + ++p; } return boost::report_errors();