diff --git a/include/boost/algorithm/string_ref.hpp b/include/boost/algorithm/string_ref.hpp index 0acadc1..843d160 100644 --- a/include/boost/algorithm/string_ref.hpp +++ b/include/boost/algorithm/string_ref.hpp @@ -63,7 +63,7 @@ namespace boost { typedef const_iterator iterator; typedef std::reverse_iterator const_reverse_iterator; typedef const_reverse_iterator reverse_iterator; - typedef size_t size_type; + typedef std::size_t size_type; typedef ptrdiff_t difference_type; static BOOST_CONSTEXPR_OR_CONST size_type npos = size_type(-1); @@ -162,18 +162,16 @@ namespace boost { return cmp != 0 ? cmp : ( len_ == x.len_ ? 0 : len_ < x.len_ ? -1 : 1 ); } - bool starts_with(charT c) const { return !empty() && front() == c; } + bool starts_with(charT c) const { return !empty() && traits::eq ( c, front()); } bool starts_with(basic_string_ref x) const { return len_ >= x.len_ && traits::compare ( ptr_, x.ptr_, x.len_ ) == 0; } - bool ends_with(charT c) const { return !empty() && back() == c; } + bool ends_with(charT c) const { return !empty() && traits::eq ( c, back()); } bool ends_with(basic_string_ref x) const { return len_ >= x.len_ && traits::compare ( ptr_ + len_ - x.len_, x.ptr_, x.len_ ) == 0; } - -// Have to use traits here size_type find(basic_string_ref s) const { const_iterator iter = std::search ( this->cbegin (), this->cend (), s.cbegin (), s.cend (), traits::eq ); @@ -187,7 +185,7 @@ namespace boost { } size_type rfind(basic_string_ref s) const { - const_iterator iter = std::search ( this->crbegin (), this->crend (), + const_reverse_iterator iter = std::search ( this->crbegin (), this->crend (), s.crbegin (), s.crend (), traits::eq ); return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); } @@ -198,27 +196,24 @@ namespace boost { return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); } - size_type find_first_of(basic_string_ref s) const { - const_iterator iter = std::find_first_of ( this->cbegin (), this->cend (), - s.cbegin (), s.cend (), traits::eq ); - return iter = this->cend () ? npos : std::distance ( this->cbegin (), iter ); - } - size_type find_first_of(charT c) const { return find (c); } size_type find_last_of (charT c) const { return rfind (c); } - + + size_type find_first_of(basic_string_ref s) const { + const_iterator iter = std::find_first_of + ( this->cbegin (), this->cend (), s.cbegin (), s.cend (), traits::eq ); + return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); + } size_type find_last_of(basic_string_ref s) const { - const_reverse_iterator iter = std::find_first_of ( this->crbegin (), this->crend (), - s.crbegin (), s.crend (), traits::eq ); - return iter = this->cend () ? npos : reverse_distance ( this->crbegin (), iter); + const_reverse_iterator iter = std::find_first_of + ( this->crbegin (), this->crend (), s.cbegin (), s.cend (), traits::eq ); + return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter); } size_type find_first_not_of(basic_string_ref s) const { - for ( const_reverse_iterator iter = this->cbegin (); iter != this->cend (); ++iter ) - if ( 0 == traits::find ( s->ptr_, s.len_, *iter )) - return std::distance ( this->cbegin (), iter ); - return npos; + const_iterator iter = find_not_of ( this->cbegin (), this->cend (), s ); + return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); } size_type find_first_not_of(charT c) const { @@ -229,10 +224,8 @@ namespace boost { } size_type find_last_not_of(basic_string_ref s) const { - for ( const_reverse_iterator iter = this->crbegin (); iter != this->crend (); ++iter ) - if ( 0 == traits::find ( s.ptr_, s.len_, *iter )) - return reverse_distance ( this->crbegin (), iter ); - return npos; + const_reverse_iterator iter = find_not_of ( this->crbegin (), this->crend (), s ); + return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); } size_type find_last_not_of(charT c) const { @@ -243,10 +236,21 @@ namespace boost { } private: - size_type reverse_distance ( reverse_iterator first, reverse_iterator last ) const { - return len_ - 1 + std::distance ( first, last ); + template + size_type reverse_distance ( r_iter first, r_iter last ) const { + return len_ - 1 - std::distance ( first, last ); } + template + Iterator find_not_of ( Iterator first, Iterator last, basic_string_ref s ) const { + for ( ; first != last ; ++first ) + if ( 0 == traits::find ( s.ptr_, s.len_, *first )) + return first; + return last; + } + + + const charT *ptr_; std::size_t len_; }; diff --git a/test/string_ref_test1.cpp b/test/string_ref_test1.cpp index 0d3abf5..f346a02 100644 --- a/test/string_ref_test1.cpp +++ b/test/string_ref_test1.cpp @@ -22,10 +22,12 @@ typedef boost::string_ref string_ref; void interop ( const std::string &str, string_ref ref ) { // BOOST_CHECK ( str == ref ); BOOST_CHECK ( str.size () == ref.size ()); - BOOST_CHECK ( std::equal ( str.begin (), str.end (), ref.begin ())); + BOOST_CHECK ( std::equal ( str.begin (), str.end (), ref.begin ())); + BOOST_CHECK ( std::equal ( str.rbegin (), str.rend (), ref.rbegin ())); } -void substr ( const std::string &str ) { +// make sure that substrings work just like strings +void test_substr ( const std::string &str ) { const size_t sz = str.size (); string_ref ref ( str ); @@ -43,6 +45,33 @@ void substr ( const std::string &str ) { 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 (); + std::string work; + string_ref ref; + + for ( size_t i = 1; i <= sz; ++i ) { + work = str; + ref = str; + while ( ref.size () >= i ) { + interop ( work, ref ); + work.erase ( 0, i ); + ref.remove_prefix (i); + } + } + + for ( size_t i = 1; i < sz; ++ i ) { + work = str; + ref = str; + while ( ref.size () >= i ) { + interop ( work, ref ); + work.erase ( work.size () - i, i ); + ref.remove_suffix (i); + } + } + } + const char *test_strings [] = { "", "1", @@ -57,8 +86,9 @@ int test_main( int , char* [] ) { while ( *p != NULL ) { interop ( *p, *p ); - substr ( *p ); - + test_substr ( *p ); + test_remove ( *p ); + p++; } diff --git a/test/string_ref_test2.cpp b/test/string_ref_test2.cpp index af1ba15..f461fa9 100644 --- a/test/string_ref_test2.cpp +++ b/test/string_ref_test2.cpp @@ -8,6 +8,7 @@ */ #include +#include // for std::strchr #include @@ -16,6 +17,7 @@ typedef boost::string_ref string_ref; void ends_with ( const char *arg ) { + const size_t sz = strlen ( arg ); string_ref sr ( arg ); string_ref sr2 ( arg ); const char *p = arg; @@ -36,10 +38,16 @@ void ends_with ( const char *arg ) { sr2.remove_prefix (1); } - BOOST_CHECK ( sr.ends_with ( string_ref ())); + char ch = sz == 0 ? '\0' : arg [ sz - 1 ]; + sr2 = arg; + if ( sz > 0 ) + BOOST_CHECK ( sr2.ends_with ( ch )); + BOOST_CHECK ( !sr2.ends_with ( ++ch )); + BOOST_CHECK ( sr2.ends_with ( string_ref ())); } void starts_with ( const char *arg ) { + const size_t sz = strlen ( arg ); string_ref sr ( arg ); string_ref sr2 ( arg ); const char *p = arg + std::strlen ( arg ) - 1; @@ -54,7 +62,12 @@ void starts_with ( const char *arg ) { sr2.remove_suffix (1); } - BOOST_CHECK ( sr.starts_with ( string_ref ())); + char ch = *arg; + sr2 = arg; + if ( sz > 0 ) + BOOST_CHECK ( sr2.starts_with ( ch )); + BOOST_CHECK ( !sr2.starts_with ( ++ch )); + BOOST_CHECK ( sr2.starts_with ( string_ref ())); } void reverse ( const char *arg ) { @@ -71,10 +84,56 @@ void reverse ( const char *arg ) { void find ( const char *arg ) { - string_ref sr1 ( arg ); - const char *p = arg; - + string_ref sr1; + string_ref sr2; + const char *p; + +// Look for each character in the string(searching from the start) + p = arg; + sr1 = arg; + while ( *p ) { + string_ref::size_type pos = sr1.find(*p); + BOOST_CHECK ( pos != string_ref::npos && ( pos <= p - arg )); + ++p; + } + +// Look for each character in the string (searching from the end) + p = arg; + sr1 = arg; + while ( *p ) { + string_ref::size_type pos = sr1.rfind(*p); + BOOST_CHECK ( pos != string_ref::npos && pos < sr1.size () && ( pos >= p - arg )); + ++p; + } + + sr1 = arg; + p = arg; +// for all possible chars, see if we find them in the right place. +// Note that strchr will/might do the _wrong_ thing if we search for NULL + for ( int ch = 1; ch < 256; ++ch ) { + string_ref::size_type pos = sr1.find(ch); + const char *strp = std::strchr ( arg, ch ); + BOOST_CHECK (( strp == NULL ) == ( pos == string_ref::npos )); + if ( strp != NULL ) + BOOST_CHECK (( strp - arg ) == pos ); + } + + sr1 = arg; + p = arg; +// for all possible chars, see if we find them in the right place. +// Note that strchr will/might do the _wrong_ thing if we search for NULL + for ( int ch = 1; ch < 256; ++ch ) { + string_ref::size_type pos = sr1.rfind(ch); + const char *strp = std::strrchr ( arg, ch ); + BOOST_CHECK (( strp == NULL ) == ( pos == string_ref::npos )); + if ( strp != NULL ) + BOOST_CHECK (( strp - arg ) == pos ); + } + + // Find everything at the start + p = arg; + sr1 = arg; while ( !sr1.empty ()) { string_ref::size_type pos = sr1.find(*p); BOOST_CHECK ( pos == 0 ); @@ -112,12 +171,65 @@ void find ( const char *arg ) { sr1.remove_suffix (1); --p; } + +// Basic sanity checking for "find_first_of / find_first_not_of" + sr1 = arg; + sr2 = arg; + while ( !sr1.empty() ) { + BOOST_CHECK ( sr1.find_first_of ( sr2 ) == 0 ); + BOOST_CHECK ( sr1.find_first_not_of ( sr2 ) == string_ref::npos ); + sr1.remove_prefix ( 1 ); + } + + p = arg; + sr1 = arg; + while ( *p ) { + string_ref::size_type pos1 = sr1.find_first_of(*p); + string_ref::size_type pos2 = sr1.find_first_not_of(*p); + BOOST_CHECK ( pos1 != string_ref::npos && pos1 < sr1.size () && pos1 <= ( p - arg )); + if ( pos2 != string_ref::npos ) { + for ( size_t i = 0 ; i < pos2; ++i ) + BOOST_CHECK ( sr1[i] == *p ); + BOOST_CHECK ( sr1 [ pos2 ] != *p ); + } + + BOOST_CHECK ( pos2 != pos1 ); + ++p; + } + +// Basic sanity checking for "find_last_of / find_last_not_of" + sr1 = arg; + sr2 = arg; + while ( !sr1.empty() ) { + BOOST_CHECK ( sr1.find_last_of ( sr2 ) == ( sr1.size () - 1 )); + BOOST_CHECK ( sr1.find_last_not_of ( sr2 ) == string_ref::npos ); + sr1.remove_suffix ( 1 ); + } + + p = arg; + sr1 = arg; + while ( *p ) { + string_ref::size_type pos1 = sr1.find_last_of(*p); + string_ref::size_type pos2 = sr1.find_last_not_of(*p); + BOOST_CHECK ( pos1 != string_ref::npos && pos1 < sr1.size () && pos1 >= ( p - arg )); + BOOST_CHECK ( pos2 == string_ref::npos || pos1 < sr1.size ()); + if ( pos2 != string_ref::npos ) { + for ( size_t i = sr1.size () -1 ; i > pos2; --i ) + BOOST_CHECK ( sr1[i] == *p ); + BOOST_CHECK ( sr1 [ pos2 ] != *p ); + } + + BOOST_CHECK ( pos2 != pos1 ); + ++p; + } + } const char *test_strings [] = { "", "0", "abc", + "AAA", // all the same "adsfadadiaef;alkdg;aljt;j agl;sjrl;tjs;lga;lretj;srg[w349u5209dsfadfasdfasdfadsf", "abc\0asdfadsfasf", NULL