diff --git a/include/boost/utility/string_ref.hpp b/include/boost/utility/string_ref.hpp index 657e9b6..6d5cace 100644 --- a/include/boost/utility/string_ref.hpp +++ b/include/boost/utility/string_ref.hpp @@ -1,11 +1,11 @@ -/* +/* Copyright (c) Marshall Clow 2012-2012. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) For more information, see http://www.boost.org - + Based on the StringRef implementation in LLVM (http://llvm.org) and N3422 by Jeffrey Yasskin http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html @@ -24,7 +24,7 @@ #include namespace boost { - + namespace detail { // A helper functor because sometimes we don't have lambdas template @@ -34,10 +34,8 @@ namespace boost { bool operator () ( charT val ) const { return traits::eq ( ch_, val ); } charT ch_; }; - - template struct __identity { typedef T type; }; } - + template class basic_string_ref; typedef basic_string_ref > string_ref; typedef basic_string_ref > wstring_ref; @@ -49,7 +47,7 @@ namespace boost { #ifndef BOOST_NO_CXX11_CHAR32_T typedef basic_string_ref > u32string_ref; #endif - + template class basic_string_ref { public: @@ -65,7 +63,7 @@ namespace boost { typedef std::size_t size_type; typedef ptrdiff_t difference_type; static BOOST_CONSTEXPR_OR_CONST size_type npos = size_type(-1); - + // construct/copy BOOST_CONSTEXPR basic_string_ref () : ptr_(NULL), len_(0) {} @@ -78,7 +76,7 @@ namespace boost { len_ = rhs.len_; return *this; } - + basic_string_ref(const charT* str) : ptr_(str), len_(traits::length(str)) {} @@ -95,7 +93,7 @@ namespace boost { return std::basic_string ( ptr_, len_ ); } #endif - + std::basic_string to_string () const { return std::basic_string ( ptr_, len_ ); } @@ -109,13 +107,13 @@ namespace boost { const_reverse_iterator crbegin() const { return const_reverse_iterator (end()); } const_reverse_iterator rend() const { return const_reverse_iterator (begin()); } const_reverse_iterator crend() const { return const_reverse_iterator (begin()); } - + // capacity BOOST_CONSTEXPR size_type size() const { return len_; } BOOST_CONSTEXPR size_type length() const { return len_; } BOOST_CONSTEXPR size_type max_size() const { return len_; } BOOST_CONSTEXPR bool empty() const { return len_ == 0; } - + // element access BOOST_CONSTEXPR const charT& operator[](size_type pos) const { return ptr_[pos]; } @@ -124,11 +122,11 @@ namespace boost { throw std::out_of_range ( "boost::string_ref::at" ); return ptr_[pos]; } - + BOOST_CONSTEXPR const charT& front() const { return ptr_[0]; } BOOST_CONSTEXPR const charT& back() const { return ptr_[len_-1]; } BOOST_CONSTEXPR const charT* data() const { return ptr_; } - + // modifiers void clear() { len_ = 0; } void remove_prefix(size_type n) { @@ -137,14 +135,14 @@ namespace boost { ptr_ += n; len_ -= n; } - + void remove_suffix(size_type n) { if ( n > len_ ) n = len_; len_ -= n; } - - + + // basic_string_ref string operations BOOST_CONSTEXPR basic_string_ref substr(size_type pos, size_type n=npos) const { @@ -159,78 +157,78 @@ namespace boost { basic_string_ref ( data() + pos, n == npos || pos + n > size() ? size() - pos : n ); #endif } - + int compare(basic_string_ref x) const { const int cmp = traits::compare ( ptr_, x.ptr_, (std::min)(len_, x.len_)); return cmp != 0 ? cmp : ( len_ == x.len_ ? 0 : len_ < x.len_ ? -1 : 1 ); } - + 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() && 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; } size_type find(basic_string_ref s) const { - const_iterator iter = std::search ( this->cbegin (), this->cend (), + const_iterator iter = std::search ( this->cbegin (), this->cend (), s.cbegin (), s.cend (), traits::eq ); return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); } - + size_type find(charT c) const { - const_iterator iter = std::find_if ( this->cbegin (), this->cend (), + const_iterator iter = std::find_if ( this->cbegin (), this->cend (), detail::string_ref_traits_eq ( c )); return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); } - + size_type rfind(basic_string_ref s) const { - const_reverse_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 ); } size_type rfind(charT c) const { - const_reverse_iterator iter = std::find_if ( this->crbegin (), this->crend (), + const_reverse_iterator iter = std::find_if ( this->crbegin (), this->crend (), detail::string_ref_traits_eq ( c )); return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), 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 + 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 + 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 { - const_iterator iter = find_not_of ( this->cbegin (), this->cend (), s ); + 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 { for ( const_iterator iter = this->cbegin (); iter != this->cend (); ++iter ) if ( !traits::eq ( c, *iter )) return std::distance ( this->cbegin (), iter ); return npos; } - + size_type find_last_not_of(basic_string_ref s) const { - const_reverse_iterator iter = find_not_of ( this->crbegin (), this->crend (), s ); + 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 { for ( const_reverse_iterator iter = this->crbegin (); iter != this->crend (); ++iter ) if ( !traits::eq ( c, *iter )) @@ -243,55 +241,75 @@ namespace boost { 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; - } - - - + for ( ; first != last ; ++first ) + if ( 0 == traits::find ( s.ptr_, s.len_, *first )) + return first; + return last; + } + + + const charT *ptr_; std::size_t len_; }; - -// Comparison operators (3 for each operation) + +// Comparison operators // Equality template bool operator==(basic_string_ref x, basic_string_ref y) { if ( x.size () != y.size ()) return false; return x.compare(y) == 0; } - template - bool operator==(basic_string_ref x, typename detail::__identity >::type y) { - if ( x.size () != y.size ()) return false; - return x.compare(y) == 0; + + template + bool operator==(basic_string_ref x, const std::basic_string & y) { + return x == basic_string_ref(y); } - template - bool operator==(typename detail::__identity >::type x, basic_string_ref y) { - if ( x.size () != y.size ()) return false; - return x.compare(y) == 0; + + template + bool operator==(const std::basic_string & x, basic_string_ref y) { + return basic_string_ref(x) == y; } - + + template + bool operator==(basic_string_ref x, const charT * y) { + return x == basic_string_ref(y); + } + + template + bool operator==(const charT * x, basic_string_ref y) { + return basic_string_ref(x) == y; + } + // Inequality template bool operator!=(basic_string_ref x, basic_string_ref y) { if ( x.size () != y.size ()) return true; return x.compare(y) != 0; } - template - bool operator!=(basic_string_ref x, typename detail::__identity >::type y) { - if ( x.size () != y.size ()) return true; - return x.compare(y) != 0; + + template + bool operator!=(basic_string_ref x, const std::basic_string & y) { + return x != basic_string_ref(y); } + + template + bool operator!=(const std::basic_string & x, basic_string_ref y) { + return basic_string_ref(x) != y; + } + template - bool operator!=(typename detail::__identity >::type x, basic_string_ref y) { - if ( x.size () != y.size ()) return true; - return x.compare(y) != 0; + bool operator!=(basic_string_ref x, const charT * y) { + return x != basic_string_ref(y); + } + + template + bool operator!=(const charT * x, basic_string_ref y) { + return basic_string_ref(x) != y; } // Less than @@ -299,13 +317,25 @@ namespace boost { bool operator<(basic_string_ref x, basic_string_ref y) { return x.compare(y) < 0; } - template - bool operator<(basic_string_ref x, typename detail::__identity >::type y) { - return x.compare(y) < 0; + + template + bool operator<(basic_string_ref x, const std::basic_string & y) { + return x < basic_string_ref(y); } + + template + bool operator<(const std::basic_string & x, basic_string_ref y) { + return basic_string_ref(x) < y; + } + template - bool operator<(typename detail::__identity >::type x, basic_string_ref y) { - return x.compare(y) < 0; + bool operator<(basic_string_ref x, const charT * y) { + return x < basic_string_ref(y); + } + + template + bool operator<(const charT * x, basic_string_ref y) { + return basic_string_ref(x) < y; } // Greater than @@ -313,13 +343,25 @@ namespace boost { bool operator>(basic_string_ref x, basic_string_ref y) { return x.compare(y) > 0; } - template - bool operator>(basic_string_ref x, typename detail::__identity >::type y) { - return x.compare(y) > 0; + + template + bool operator>(basic_string_ref x, const std::basic_string & y) { + return x > basic_string_ref(y); } + + template + bool operator>(const std::basic_string & x, basic_string_ref y) { + return basic_string_ref(x) > y; + } + template - bool operator>(typename detail::__identity >::type x, basic_string_ref y) { - return x.compare(y) > 0; + bool operator>(basic_string_ref x, const charT * y) { + return x > basic_string_ref(y); + } + + template + bool operator>(const charT * x, basic_string_ref y) { + return basic_string_ref(x) > y; } // Less than or equal to @@ -327,13 +369,25 @@ namespace boost { bool operator<=(basic_string_ref x, basic_string_ref y) { return x.compare(y) <= 0; } - template - bool operator<=(basic_string_ref x, typename detail::__identity >::type y) { - return x.compare(y) <= 0; + + template + bool operator<=(basic_string_ref x, const std::basic_string & y) { + return x <= basic_string_ref(y); } + + template + bool operator<=(const std::basic_string & x, basic_string_ref y) { + return basic_string_ref(x) <= y; + } + template - bool operator<=(typename detail::__identity >::type x, basic_string_ref y) { - return x.compare(y) <= 0; + bool operator<=(basic_string_ref x, const charT * y) { + return x <= basic_string_ref(y); + } + + template + bool operator<=(const charT * x, basic_string_ref y) { + return basic_string_ref(x) <= y; } // Greater than or equal to @@ -341,17 +395,27 @@ namespace boost { bool operator>=(basic_string_ref x, basic_string_ref y) { return x.compare(y) >= 0; } - template - bool operator>=(basic_string_ref x, typename detail::__identity >::type y) { - return x.compare(y) >= 0; - } - template - bool operator>=(typename detail::__identity >::type x, basic_string_ref y) { - return x.compare(y) >= 0; + + template + bool operator>=(basic_string_ref x, const std::basic_string & y) { + return x >= basic_string_ref(y); } + template + bool operator>=(const std::basic_string & x, basic_string_ref y) { + return basic_string_ref(x) >= y; + } + + template + bool operator>=(basic_string_ref x, const charT * y) { + return x >= basic_string_ref(y); + } + + template + bool operator>=(const charT * x, basic_string_ref y) { + return basic_string_ref(x) >= y; + } - // Inserter template std::basic_ostream& @@ -365,7 +429,7 @@ namespace boost { #endif return os; } - + #if 0 // numeric conversions // @@ -375,63 +439,63 @@ namespace boost { int stoi (string_ref str, size_t* idx=0, int base=10) { return std::stoi ( std::string(str), idx, base ); } - + long stol (string_ref str, size_t* idx=0, int base=10) { return std::stol ( std::string(str), idx, base ); } - + unsigned long stoul (string_ref str, size_t* idx=0, int base=10) { return std::stoul ( std::string(str), idx, base ); } - + long long stoll (string_ref str, size_t* idx=0, int base=10) { return std::stoll ( std::string(str), idx, base ); } - + unsigned long long stoull (string_ref str, size_t* idx=0, int base=10) { return std::stoull ( std::string(str), idx, base ); } - + float stof (string_ref str, size_t* idx=0) { return std::stof ( std::string(str), idx ); } - + double stod (string_ref str, size_t* idx=0) { return std::stod ( std::string(str), idx ); } - + long double stold (string_ref str, size_t* idx=0) { return std::stold ( std::string(str), idx ); } - + int stoi (wstring_ref str, size_t* idx=0, int base=10) { return std::stoi ( std::wstring(str), idx, base ); } - + long stol (wstring_ref str, size_t* idx=0, int base=10) { return std::stol ( std::wstring(str), idx, base ); } - + unsigned long stoul (wstring_ref str, size_t* idx=0, int base=10) { return std::stoul ( std::wstring(str), idx, base ); } - + long long stoll (wstring_ref str, size_t* idx=0, int base=10) { return std::stoll ( std::wstring(str), idx, base ); } - + unsigned long long stoull (wstring_ref str, size_t* idx=0, int base=10) { return std::stoull ( std::wstring(str), idx, base ); } - + float stof (wstring_ref str, size_t* idx=0) { return std::stof ( std::wstring(str), idx ); } - + double stod (wstring_ref str, size_t* idx=0) { return std::stod ( std::wstring(str), idx ); } - + long double stold (wstring_ref str, size_t* idx=0) { return std::stold ( std::wstring(str), idx ); } diff --git a/test/string_ref_test1.cpp b/test/string_ref_test1.cpp index 7524536..f1d4df2 100644 --- a/test/string_ref_test1.cpp +++ b/test/string_ref_test1.cpp @@ -1,4 +1,4 @@ -/* +/* Copyright (c) Marshall Clow 2012-2012. Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -33,30 +33,30 @@ void null_tests ( const char *p ) { string_ref sr3 ( p, 0 ); string_ref sr4 ( p ); sr4.clear (); - + BOOST_CHECK ( sr1 == sr2 ); BOOST_CHECK ( sr1 == sr3 ); BOOST_CHECK ( sr2 == sr3 ); - BOOST_CHECK ( sr1 == sr4 ); + BOOST_CHECK ( sr1 == sr4 ); } // 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 ); - + // Substrings at the end for ( 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 ) 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 ) - interop ( str.substr ( i, j ), ref.substr ( i, j )); + interop ( str.substr ( i, j ), ref.substr ( i, j )); } // make sure that removing prefixes and suffixes work just like strings @@ -64,20 +64,20 @@ 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; + 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; + ref = str; while ( ref.size () >= i ) { interop ( work, ref ); work.erase ( work.size () - i, i ); @@ -93,7 +93,7 @@ const char *test_strings [] = { "0123456789", NULL }; - + BOOST_AUTO_TEST_CASE( test_main ) { const char **p = &test_strings[0]; @@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE( test_main ) test_substr ( *p ); test_remove ( *p ); null_tests ( *p ); - + p++; } } diff --git a/test/string_ref_test2.cpp b/test/string_ref_test2.cpp index c4885a4..89e1cfc 100644 --- a/test/string_ref_test2.cpp +++ b/test/string_ref_test2.cpp @@ -1,4 +1,4 @@ -/* +/* Copyright (c) Marshall Clow 2012-2012. Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -46,7 +46,7 @@ void ends_with ( const char *arg ) { 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 ); @@ -85,9 +85,9 @@ void reverse ( const char *arg ) { // This helper function eliminates signed vs. unsigned warnings string_ref::size_type ptr_diff ( const char *res, const char *base ) { - BOOST_CHECK ( res >= base ); - return static_cast ( res - base ); - } + BOOST_CHECK ( res >= base ); + return static_cast ( res - base ); + } void find ( const char *arg ) { string_ref sr1; @@ -102,7 +102,7 @@ void find ( const char *arg ) { BOOST_CHECK ( pos != string_ref::npos && ( pos <= ptr_diff ( p, arg ))); ++p; } - + // Look for each character in the string (searching from the end) p = arg; sr1 = arg; @@ -115,13 +115,13 @@ void find ( const char *arg ) { // Look for pairs on characters (searching from the start) sr1 = arg; p = arg; - while ( *p && *(p+1)) { - string_ref sr3 ( p, 2 ); - string_ref::size_type pos = sr1.find ( sr3 ); - BOOST_CHECK ( pos != string_ref::npos && pos <= static_cast( p - arg )); - p++; - } - + while ( *p && *(p+1)) { + string_ref sr3 ( p, 2 ); + string_ref::size_type pos = sr1.find ( sr3 ); + BOOST_CHECK ( pos != string_ref::npos && pos <= static_cast( p - arg )); + p++; + } + sr1 = arg; p = arg; // for all possible chars, see if we find them in the right place. @@ -166,7 +166,7 @@ void find ( const char *arg ) { sr1.remove_suffix (1); --p; } - + // Find everything at the start sr1 = arg; p = arg; @@ -187,7 +187,7 @@ 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; @@ -212,7 +212,7 @@ void find ( const char *arg ) { BOOST_CHECK ( pos2 != pos1 ); ++p; } - + // Basic sanity checking for "find_last_of / find_last_not_of" sr1 = arg; sr2 = arg; @@ -234,7 +234,7 @@ void find ( const char *arg ) { BOOST_CHECK ( sr1[i] == *p ); BOOST_CHECK ( sr1 [ pos2 ] != *p ); } - + BOOST_CHECK ( pos2 != pos1 ); ++p; } @@ -244,50 +244,51 @@ void find ( const char *arg ) { void to_string ( const char *arg ) { string_ref sr1; - std::string str1; - std::string str2; + std::string str1; + std::string str2; - str1.assign ( arg ); - sr1 = arg; + str1.assign ( arg ); + sr1 = arg; // str2 = sr1.to_string > (); - str2 = sr1.to_string (); - BOOST_CHECK ( str1 == str2 ); + str2 = sr1.to_string (); + BOOST_CHECK ( str1 == str2 ); #ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS - std::string str3 = static_cast ( sr1 ); - BOOST_CHECK ( str1 == str3 ); + std::string str3 = static_cast ( sr1 ); + BOOST_CHECK ( str1 == str3 ); #endif } void compare ( const char *arg ) { string_ref sr1; - std::string str1; - std::string str2 = str1; + std::string str1; + std::string str2 = str1; - str1.assign ( arg ); - sr1 = arg; - BOOST_CHECK ( sr1 == str1); // compare string and string_ref - BOOST_CHECK ( str1 == sr1 ); // compare string_ref and string - BOOST_CHECK ( sr1 == arg ); // compare string_ref and pointer - BOOST_CHECK ( arg == sr1 ); // compare pointer and string_ref + str1.assign ( arg ); + sr1 = arg; + BOOST_CHECK ( sr1 == sr1); // compare string_ref and string_ref + BOOST_CHECK ( sr1 == str1); // compare string and string_ref + BOOST_CHECK ( str1 == sr1 ); // compare string_ref and string + BOOST_CHECK ( sr1 == arg ); // compare string_ref and pointer + BOOST_CHECK ( arg == sr1 ); // compare pointer and string_ref - if ( sr1.size () > 0 ) { - (*str1.rbegin())++; - BOOST_CHECK ( sr1 != str1 ); - BOOST_CHECK ( str1 != sr1 ); - BOOST_CHECK ( sr1 < str1 ); - BOOST_CHECK ( sr1 <= str1 ); - BOOST_CHECK ( str1 > sr1 ); - BOOST_CHECK ( str1 >= sr1 ); + if ( sr1.size () > 0 ) { + (*str1.rbegin())++; + BOOST_CHECK ( sr1 != str1 ); + BOOST_CHECK ( str1 != sr1 ); + BOOST_CHECK ( sr1 < str1 ); + BOOST_CHECK ( sr1 <= str1 ); + BOOST_CHECK ( str1 > sr1 ); + BOOST_CHECK ( str1 >= sr1 ); - (*str1.rbegin()) -= 2; - BOOST_CHECK ( sr1 != str1 ); - BOOST_CHECK ( str1 != sr1 ); - BOOST_CHECK ( sr1 > str1 ); - BOOST_CHECK ( sr1 >= str1 ); - BOOST_CHECK ( str1 < sr1 ); - BOOST_CHECK ( str1 <= sr1 ); - } + (*str1.rbegin()) -= 2; + BOOST_CHECK ( sr1 != str1 ); + BOOST_CHECK ( str1 != sr1 ); + BOOST_CHECK ( sr1 > str1 ); + BOOST_CHECK ( sr1 >= str1 ); + BOOST_CHECK ( str1 < sr1 ); + BOOST_CHECK ( str1 <= sr1 ); + } } const char *test_strings [] = { @@ -299,19 +300,19 @@ const char *test_strings [] = { "abc\0asdfadsfasf", NULL }; - + BOOST_AUTO_TEST_CASE( test_main ) { const char **p = &test_strings[0]; - + while ( *p != NULL ) { starts_with ( *p ); ends_with ( *p ); reverse ( *p ); find ( *p ); to_string ( *p ); - compare ( *p ); - + compare ( *p ); + p++; } }