From b1a1b7a1aea1a3ffc9b1fe1193610e117bcaa05c Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Thu, 12 Jan 2023 18:16:06 -0300 Subject: [PATCH] string_view interoperability fix #26 --- include/boost/static_string/config.hpp | 27 + include/boost/static_string/static_string.hpp | 491 ++++++++++++++++-- test/constexpr_tests.hpp | 2 + test/static_string.cpp | 220 +++++++- 4 files changed, 675 insertions(+), 65 deletions(-) diff --git a/include/boost/static_string/config.hpp b/include/boost/static_string/config.hpp index 02b3ad5..878edd7 100644 --- a/include/boost/static_string/config.hpp +++ b/include/boost/static_string/config.hpp @@ -147,15 +147,34 @@ #endif #ifndef BOOST_STATIC_STRING_STANDALONE +#include #include #include #include #include +#include #include +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) && \ + !defined(BOOST_STATIC_STRING_CXX17_STRING_VIEW) +#define BOOST_STATIC_STRING_CXX17_STRING_VIEW +#endif #else #include #include +#endif + +// Include std::string_view +#if defined(BOOST_STATIC_STRING_CXX17_STRING_VIEW) || __cplusplus >= 201703L #include +#elif defined(__has_include) +#if __has_include() +#include +#endif +#endif + +// Determine if the class (and not only the header) is available +#if __cpp_lib_string_view >= 201606L +#define BOOST_STATIC_STRING_HAS_STD_STRING_VIEW #endif // Compiler bug prevents constexpr from working with clang 4.x and 5.x @@ -192,6 +211,12 @@ defined(BOOST_STATIC_STRING_CPP14) #define BOOST_STATIC_STRING_GCC5_BAD_CONSTEXPR #endif +// Define the basic string_view type used by the library +// Conversions to and from other available string_view types +// are still defined. +#if !defined(BOOST_STATIC_STRING_STANDALONE) || \ + defined(BOOST_STATIC_STRING_HAS_STD_STRING_VIEW) +#define BOOST_STATIC_STRING_HAS_STRING_VIEW namespace boost { namespace static_strings { @@ -205,4 +230,6 @@ using basic_string_view = #endif } // static_strings } // boost +#endif + #endif \ No newline at end of file diff --git a/include/boost/static_string/static_string.hpp b/include/boost/static_string/static_string.hpp index 12a3ab1..e43a37b 100644 --- a/include/boost/static_string/static_string.hpp +++ b/include/boost/static_string/static_string.hpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -126,16 +127,43 @@ struct void_t_helper template using void_t = typename void_t_helper::type; +template +struct is_string_like : std::false_type {}; + +template +struct is_string_like< + T, CharT, + std::void_t< + decltype(std::declval() = std::declval().data()), + decltype(std::declval() = std::declval().size())>> + : std::true_type +{}; + // Check if a type can be used for templated // overloads string_view_type +// This will be used by overloads that accept the string_view types +// directly and other convertible types such as std::string. +// When no string_view type is available, then we check for the +// data and size member functions, and use them directly for assignments. template struct enable_if_viewable { }; template struct enable_if_viewable>::value && - !std::is_convertible::value>::type> + typename std::enable_if< +#if !defined(BOOST_STATIC_STRING_HAS_STRING_VIEW) + is_string_like::value +#elif defined(BOOST_STATIC_STRING_STANDALONE) + std::is_convertible>::value && + !std::is_convertible::value +#else + ( + std::is_convertible>::value || + std::is_convertible>::value + ) && + !std::is_convertible::value +#endif + >::type> { using type = void; }; @@ -143,6 +171,59 @@ struct enable_if_viewable using enable_if_viewable_t = typename enable_if_viewable::type; +// The common string_view type used in private operations with enable_if_viewable_t +// - T const& itself when no string_view type is available +// - basic_string_view (boost::string_view or std::string_view) when in +// standalone because core::detail::string_view is unavailable +// - core::detail::basic_string_view otherwise because it's convertible +// to and from most types, including std::string_view +// After converting a parameter to a common_string_view_type reference, we +// can use the data() and size() member functions. +#if !defined(BOOST_STATIC_STRING_HAS_STRING_VIEW) +template +using common_string_view_type = T const&; +#elif defined(BOOST_STATIC_STRING_STANDALONE) +template +using common_string_view_type = basic_string_view; +#else +template +struct common_string_view_type_impl {}; + +template +struct common_string_view_type_impl< + T, CharT, Traits, + typename std::enable_if< + is_string_like::value && + !std::is_convertible>::value && + !std::is_convertible>::value>::type> +{ + using type = T const&; +}; + +template +struct common_string_view_type_impl< + T, CharT, Traits, + typename std::enable_if< + std::is_convertible>::value && + !std::is_convertible>::value>::type> +{ + using type = basic_string_view; +}; + +template +struct common_string_view_type_impl< + T, CharT, Traits, + typename std::enable_if< + std::is_convertible>::value>::type> +{ + using type = core::basic_string_view; +}; + +template +using common_string_view_type = typename common_string_view_type_impl::type; +#endif + + // Simplified check for if a type is an iterator template struct is_iterator : std::false_type { }; @@ -879,9 +960,11 @@ class basic_static_string using const_reverse_iterator = std::reverse_iterator; +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW /// The string view type. using string_view_type = basic_string_view; +#endif //-------------------------------------------------------------------------- // @@ -1538,7 +1621,7 @@ class basic_static_string basic_static_string& assign(const T& t) { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return assign(sv.data(), sv.size()); } @@ -1590,8 +1673,12 @@ class basic_static_string size_type pos, size_type count = npos) { - const auto sv = string_view_type(t).substr(pos, count); - return assign(sv.data(), sv.size()); + detail::common_string_view_type sv = t; + if( pos > sv.size() ) + detail::throw_exception( + "pos >= t.size()"); + std::size_t rlen = (std::min)( count, sv.size() - pos ); + return assign(sv.data() + pos, rlen); } //-------------------------------------------------------------------------- @@ -1837,6 +1924,7 @@ class basic_static_string return data(); } +#ifdef BOOST_STATIC_STRING_DOCS /** Convert to a string view referring to the string. Returns a string view referring to the @@ -1851,6 +1939,28 @@ class basic_static_string { return string_view_type(data(), size()); } +#else +#ifdef BOOST_STATIC_STRING_HAS_STD_STRING_VIEW + BOOST_STATIC_STRING_CPP11_CONSTEXPR + operator std::basic_string_view() const noexcept + { + return std::basic_string_view(data(), size()); + } +#endif +#ifndef BOOST_STATIC_STRING_STANDALONE + BOOST_STATIC_STRING_CPP11_CONSTEXPR + operator ::boost::basic_string_view() const noexcept + { + return ::boost::basic_string_view(data(), size()); + } + + BOOST_STATIC_STRING_CPP11_CONSTEXPR + operator ::boost::core::basic_string_view() const noexcept + { + return ::boost::core::basic_string_view(data(), size()); + } +#endif +#endif //-------------------------------------------------------------------------- // @@ -2503,7 +2613,7 @@ class basic_static_string size_type index, const T& t) { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return insert(index, sv.data(), sv.size()); } @@ -2552,8 +2662,10 @@ class basic_static_string size_type index_str, size_type count = npos) { - const auto sv = string_view_type(t).substr(index_str, count); - return insert(index, sv.data(), sv.size()); + detail::common_string_view_type sv(t); + if ( index_str > sv.size() ) + detail::throw_exception("index_str > t.size()"); + return insert(index, sv.data() + index_str, (std::min)(sv.size() - index_str, count)); } /** Erase from the string. @@ -2912,7 +3024,7 @@ class basic_static_string basic_static_string& append(const T& t) { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return append(sv.data(), sv.size()); } @@ -2957,8 +3069,10 @@ class basic_static_string size_type pos, size_type count = npos) { - const auto sv = string_view_type(t).substr(pos, count); - return append(sv.data(), sv.size()); + detail::common_string_view_type sv = t; + if ( pos > sv.size() ) + detail::throw_exception("pos > t.size()"); + return append(sv.data() + pos, (std::min)(sv.size() - pos, count)); } /** Append to the string. @@ -3342,7 +3456,7 @@ class basic_static_string int compare(const T& t) const noexcept { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return detail::lexicographical_compare( data(), size(), sv.data(), sv.size()); } @@ -3393,7 +3507,7 @@ class basic_static_string size_type count1, const T& t) const { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return detail::lexicographical_compare( data() + pos1, capped_length(pos1, count1), sv.data(), sv.size()); } @@ -3450,9 +3564,12 @@ class basic_static_string size_type pos2, size_type count2 = npos) const { - const auto sv = string_view_type(t).substr(pos2, count2); - return compare(pos1, count1, - sv.data(), sv.size()); + detail::common_string_view_type sv = t; + if ( pos2 > sv.size()) + detail::throw_exception("pos2 > sv.size()"); + return compare( + pos1, count1, sv.data() + pos2, + (std::min)(sv.size() - pos2, count2)); } /** Return a substring. @@ -3485,6 +3602,7 @@ class basic_static_string data() + pos, capped_length(pos, count)); } +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW /** Return a string view of a substring. Returns a view of a substring. @@ -3512,6 +3630,7 @@ class basic_static_string return string_view_type( data() + pos, capped_length(pos, count)); } +#endif /** Copy a substring to another string. @@ -3771,7 +3890,7 @@ class basic_static_string size_type n1, const T& t) { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return replace(pos1, n1, sv.data(), sv.size()); } @@ -3823,8 +3942,12 @@ class basic_static_string size_type pos2, size_type n2 = npos) { - const string_view_type sv = t; - return replace(pos1, n1, sv.substr(pos2, n2)); + detail::common_string_view_type sv = t; + if ( pos2 > sv.size()) + detail::throw_exception("pos2 > t.size()"); + return replace( + pos1, n1, sv.data() + pos2, + (std::min)(sv.size() - pos2, n2)); } /** Replace a part of the string. @@ -4029,8 +4152,8 @@ class basic_static_string const_iterator i2, const T& t) { - const string_view_type sv = t; - return replace(i1, i2, sv.begin(), sv.end()); + detail::common_string_view_type sv = t; + return replace(i1, i2, sv.data(), sv.data() + sv.size()); } /** Replace a part of the string. @@ -4290,9 +4413,13 @@ class basic_static_string find( const T& t, size_type pos = 0) const +#ifdef BOOST_STATIC_STRING_DOCS noexcept(detail::is_nothrow_convertible::value) +#else + noexcept(detail::is_nothrow_convertible>::value) +#endif { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return find(sv.data(), pos, sv.size()); } @@ -4443,9 +4570,13 @@ class basic_static_string rfind( const T& t, size_type pos = npos) const +#ifdef BOOST_STATIC_STRING_DOCS noexcept(detail::is_nothrow_convertible::value) +#else + noexcept(detail::is_nothrow_convertible>::value) +#endif { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return rfind(sv.data(), pos, sv.size()); } @@ -4591,9 +4722,13 @@ class basic_static_string find_first_of( const T& t, size_type pos = 0) const +#ifdef BOOST_STATIC_STRING_DOCS noexcept(detail::is_nothrow_convertible::value) +#else + noexcept(detail::is_nothrow_convertible>::value) +#endif { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return find_first_of(sv.data(), pos, sv.size()); } @@ -4734,9 +4869,13 @@ class basic_static_string find_last_of( const T& t, size_type pos = npos) const +#ifdef BOOST_STATIC_STRING_DOCS noexcept(detail::is_nothrow_convertible::value) +#else + noexcept(detail::is_nothrow_convertible>::value) +#endif { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return find_last_of(sv.data(), pos, sv.size()); } @@ -4876,9 +5015,13 @@ class basic_static_string find_first_not_of( const T& t, size_type pos = 0) const +#ifdef BOOST_STATIC_STRING_DOCS noexcept(detail::is_nothrow_convertible::value) +#else + noexcept(detail::is_nothrow_convertible>::value) +#endif { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return find_first_not_of(sv.data(), pos, sv.size()); } @@ -5017,9 +5160,13 @@ class basic_static_string find_last_not_of( const T& t, size_type pos = npos) const +#ifdef BOOST_STATIC_STRING_DOCS noexcept(detail::is_nothrow_convertible::value) +#else + noexcept(detail::is_nothrow_convertible>::value) +#endif { - const string_view_type sv = t; + detail::common_string_view_type sv = t; return find_last_not_of(sv.data(), pos, sv.size()); } @@ -5133,15 +5280,21 @@ class basic_static_string Linear. - @param s The string view to check for. + @param t The string view to check for. */ + template +#endif + > BOOST_STATIC_STRING_CPP14_CONSTEXPR bool starts_with( - string_view_type s) const noexcept + T const& t) const noexcept { - const size_type len = s.size(); - return size() >= len && !traits_type::compare(data(), s.data(), len); + detail::common_string_view_type sv = t; + const size_type len = sv.size(); + return size() >= len && !traits_type::compare(data(), sv.data(), len); } /** Return whether the string begins with a character. @@ -5191,15 +5344,21 @@ class basic_static_string Linear. - @param s The string view to check for. + @param t The string view to check for. */ + template +#endif + > BOOST_STATIC_STRING_CPP14_CONSTEXPR bool ends_with( - string_view_type s) const noexcept + T const& t) const noexcept { - const size_type len = s.size(); - return size() >= len && !traits_type::compare(data() + (size() - len), s.data(), len); + detail::common_string_view_type sv = t; + const size_type len = sv.size(); + return size() >= len && !traits_type::compare(data() + (size() - len), sv.data(), len); } /** Return whether the string ends with a character. @@ -5456,6 +5615,42 @@ operator==( rhs, Traits::length(rhs)) == 0; } +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator==( + const T& lhs, + const basic_static_string& rhs) +{ + detail::common_string_view_type lhsv = lhs; + return detail::lexicographical_compare( + lhsv.data(), lhsv.size(), + rhs.data(), rhs.size()) == 0; +} + +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator==( + const basic_static_string& lhs, + const T& rhs) +{ + detail::common_string_view_type rhsv = rhs; + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhsv.data(), rhsv.size()) == 0; +} + template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline @@ -5482,6 +5677,42 @@ operator!=( rhs, Traits::length(rhs)) != 0; } +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator!=( + const T& lhs, + const basic_static_string& rhs) +{ + detail::common_string_view_type lhsv = lhs; + return detail::lexicographical_compare( + lhsv.data(), lhsv.size(), + rhs.data(), rhs.size()) != 0; +} + +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator!=( + const basic_static_string& lhs, + const T& rhs) +{ + detail::common_string_view_type rhsv = rhs; + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhsv.data(), rhsv.size()) != 0; +} + template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline @@ -5508,6 +5739,42 @@ operator<( rhs, Traits::length(rhs)) < 0; } +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator<( + const T& lhs, + const basic_static_string& rhs) +{ + detail::common_string_view_type lhsv = lhs; + return detail::lexicographical_compare( + lhsv.data(), lhsv.size(), + rhs.data(), rhs.size()) < 0; +} + +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator<( + const basic_static_string& lhs, + const T& rhs) +{ + detail::common_string_view_type rhsv = rhs; + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhsv.data(), rhsv.size()) < 0; +} + template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline @@ -5534,6 +5801,42 @@ operator<=( rhs, Traits::length(rhs)) <= 0; } +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator<=( + const T& lhs, + const basic_static_string& rhs) +{ + detail::common_string_view_type lhsv = lhs; + return detail::lexicographical_compare( + lhsv.data(), lhsv.size(), + rhs.data(), rhs.size()) <= 0; +} + +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator<=( + const basic_static_string& lhs, + const T& rhs) +{ + detail::common_string_view_type rhsv = rhs; + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhsv.data(), rhsv.size()) <= 0; +} + template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline @@ -5560,6 +5863,43 @@ operator>( rhs, Traits::length(rhs)) > 0; } +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator>( + const T& lhs, + const basic_static_string& rhs) +{ + detail::common_string_view_type lhsv = lhs; + return detail::lexicographical_compare( + lhsv.data(), lhsv.size(), + rhs.data(), rhs.size()) > 0; +} + +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator>( + const basic_static_string& lhs, + const T& rhs) +{ + detail::common_string_view_type rhsv = rhs; + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhsv.data(), rhsv.size()) > 0; +} + + template BOOST_STATIC_STRING_CPP14_CONSTEXPR inline @@ -5586,6 +5926,42 @@ operator>=( rhs, Traits::length(rhs)) >= 0; } +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator>=( + const T& lhs, + const basic_static_string& rhs) +{ + detail::common_string_view_type lhsv = lhs; + return detail::lexicographical_compare( + lhsv.data(), lhsv.size(), + rhs.data(), rhs.size()) >= 0; +} + +template +#endif + > +BOOST_STATIC_STRING_CPP14_CONSTEXPR +inline +bool +operator>=( + const basic_static_string& lhs, + const T& rhs) +{ + detail::common_string_view_type rhsv = rhs; + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhsv.data(), rhsv.size()) >= 0; +} + template< std::size_t N, std::size_t M, typename CharT, typename Traits> @@ -5721,7 +6097,13 @@ operator<<( std::basic_ostream& os, const basic_static_string& s) { +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW return os << basic_string_view(s.data(), s.size()); +#else + for (auto c: s) + os << c; + return os; +#endif } //------------------------------------------------------------------------------ @@ -5961,14 +6343,47 @@ struct hash< operator()( const boost::static_strings::basic_static_string& str) const noexcept { -#ifndef BOOST_STATIC_STRING_STANDALONE +#if !defined(BOOST_STATIC_STRING_STANDALONE) return boost::hash_range(str.begin(), str.end()); -#else +#elif defined(BOOST_STATIC_STRING_HAS_STRING_VIEW) using view_type = typename boost::static_strings::basic_string_view; return std::hash()(view_type(str.data(), str.size())); +#else + std::size_t seed = 0; + for (CharT const& c : str) { + mix_impl(std::integral_constant= 8>{}, seed, c); + } + return seed; #endif } + + static + void + mix_impl(std::true_type, std::size_t& seed, CharT c) + { + seed += 0x9e3779b9 + std::hash()( c ); + std::size_t const m = (std::size_t(0xe9846af) << 32) + 0x9b1a615d; + seed ^= seed >> 32; + seed *= m; + seed ^= seed >> 32; + seed *= m; + seed ^= seed >> 28; + } + + static + void + mix_impl(std::false_type, std::size_t& seed, CharT c) + { + seed += 0x9e3779b9 + std::hash()( c ); + std::size_t const m1 = 0x21f0aaad; + std::size_t const m2 = 0x735a2d97; + seed ^= seed >> 16; + seed *= m1; + seed ^= seed >> 15; + seed *= m2; + seed ^= seed >> 15; + } }; } // std diff --git a/test/constexpr_tests.hpp b/test/constexpr_tests.hpp index af6547f..9b2e83c 100644 --- a/test/constexpr_tests.hpp +++ b/test/constexpr_tests.hpp @@ -357,8 +357,10 @@ testConstantEvaluation() a.substr(0); #endif +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW // subview a.subview(0); +#endif // copy char k[20]{}; diff --git a/test/static_string.cpp b/test/static_string.cpp index cfeb2a1..f802028 100644 --- a/test/static_string.cpp +++ b/test/static_string.cpp @@ -26,7 +26,15 @@ namespace static_strings { template class basic_static_string<420, char>; +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW using string_view = basic_string_view>; +#endif + +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW +using string_like = basic_string_view>; +#else +using string_like = std::string; +#endif template bool @@ -51,13 +59,21 @@ testSV(const S& s, typename S::size_type pos, typename S::size_type n) { if (pos <= s.size()) { +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW typename S::string_view_type str = s.subview(pos, n); +#else + auto str = s.substr(pos, n); +#endif typename S::size_type rlen = (std::min)(n, s.size() - pos); return (S::traits_type::compare(s.data() + pos, str.data(), rlen) == 0); } else { +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW BOOST_TEST_THROWS((s.subview(pos, n)), std::out_of_range); +#else + BOOST_TEST_THROWS((s.substr(pos, n)), std::out_of_range); +#endif return true; } } @@ -342,11 +358,11 @@ testConstruct() } { static_string<3> s1( - string_view("123")); + string_like("123")); BOOST_TEST(s1 == "123"); BOOST_TEST(*s1.end() == 0); BOOST_TEST_THROWS( - (static_string<2>(string_view("123"))), + (static_string<2>(string_like("123"))), std::length_error); } { @@ -424,6 +440,7 @@ testAssignment() // assign(T const& t) { +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW struct T { operator string_view() const noexcept @@ -431,6 +448,21 @@ testAssignment() return "abc"; } }; +#else + struct T + { + char const* data() const noexcept + { + static char p[] = "abc"; + return p; + } + + std::size_t size() const noexcept + { + return 3; + } + }; +#endif BOOST_TEST(static_string<3>{}.assign(T{}) == "abc"); BOOST_TEST(static_string<3>{"*"}.assign(T{}) == "abc"); BOOST_TEST(static_string<3>{"***"}.assign(T{}) == "abc"); @@ -439,6 +471,7 @@ testAssignment() // assign(T const& t, size_type pos, size_type count = npos) { +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW struct T { operator string_view() const noexcept @@ -446,6 +479,23 @@ testAssignment() return "abcde"; } }; +#else + struct T + { + char const* + data() const noexcept + { + static char p[] = "abcde"; + return p; + } + + std::size_t + size() const + { + return 5; + } + }; +#endif BOOST_TEST(static_string<5>{}.assign(T{}, 0) == "abcde"); BOOST_TEST(static_string<5>{}.assign(T{}, 0, 5) == "abcde"); BOOST_TEST(static_string<5>{}.assign(T{}, 1, 3) == "bcd"); @@ -507,15 +557,14 @@ testAssignment() } { static_string<3> s1; - s1 = string_view("123"); + s1 = string_like("123"); BOOST_TEST(s1 == "123"); BOOST_TEST(*s1.end() == 0); static_string<1> s2; BOOST_TEST_THROWS( - s2 = string_view("123"), + s2 = string_like("123"), std::length_error); } - { static_string<4> s1; s1.assign(3, 'x'); @@ -603,14 +652,14 @@ testAssignment() } { static_string<5> s1; - s1.assign(string_view("123")); + s1.assign(string_like("123")); BOOST_TEST(s1 == "123"); BOOST_TEST(*s1.end() == 0); - s1.assign(string_view("12345")); + s1.assign(string_like("12345")); BOOST_TEST(s1 == "12345"); BOOST_TEST(*s1.end() == 0); BOOST_TEST_THROWS( - s1.assign(string_view("1234567")), + s1.assign(string_like("1234567")), std::length_error); } { @@ -788,11 +837,20 @@ testElements() BOOST_TEST(std::memcmp( s.c_str(), "123\0", 4) == 0); } +#ifdef BOOST_STATIC_ASSERT_HAS_STRING_VIEW { static_string<3> s("123"); string_view sv = s; BOOST_TEST(static_string<5>(sv) == "123"); } +#endif +#ifdef BOOST_STATIC_ASSERT_HAS_STD_STRING_VIEW + { + static_string<3> s("123"); + std::string_view sv = s; + BOOST_TEST(static_string<5>(sv) == "123"); + } +#endif } // done @@ -909,7 +967,7 @@ static void testInsert() { - using sv = string_view; + using sv = string_like; using S = static_string<100>; // insert(size_type index, size_type count, CharT ch) @@ -990,6 +1048,7 @@ testInsert() // insert(size_type index, T const& t) { +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW struct T { operator string_view() const noexcept @@ -997,6 +1056,23 @@ testInsert() return "b"; } }; +#else + struct T + { + char const* + data() const noexcept + { + static char p[] = "b"; + return p; + } + + std::size_t + size() const + { + return 1; + } + }; +#endif BOOST_TEST(static_string<3>{"ac"}.insert(1, T{}) == "abc"); BOOST_TEST_THROWS(static_string<4>{"abc"}.insert(4, T{}), std::out_of_range); BOOST_TEST_THROWS(static_string<3>{"abc"}.insert(1, T{}), std::length_error); @@ -1004,6 +1080,7 @@ testInsert() // insert(size_type index, T const& t, size_type index_str, size_type count = npos) { +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW struct T { operator string_view() const noexcept @@ -1011,6 +1088,23 @@ testInsert() return "abcd"; } }; +#else + struct T + { + char const* + data() const noexcept + { + static char p[] = "abcd"; + return p; + } + + std::size_t + size() const noexcept + { + return 4; + } + }; +#endif BOOST_TEST(static_string<6>{"ae"}.insert(1, T{}, 1) == "abcde"); BOOST_TEST(static_string<6>{"abe"}.insert(2, T{}, 2) == "abcde"); BOOST_TEST(static_string<4>{"ac"}.insert(1, T{}, 1, 1) == "abc"); @@ -1138,16 +1232,16 @@ testInsert() } { static_string<5> s1("123"); - s1.insert(1, string_view("UV")); + s1.insert(1, string_like("UV")); BOOST_TEST(s1 == "1UV23"); BOOST_TEST(*s1.end() == 0); static_string<4> s2("123"); BOOST_TEST_THROWS( - (s2.insert(1, string_view("UV"))), + (s2.insert(1, string_like("UV"))), std::length_error); static_string<5> s3("123"); BOOST_TEST_THROWS( - (s3.insert(5, string_view("UV"))), + (s3.insert(5, string_like("UV"))), std::out_of_range); } { @@ -1979,7 +2073,7 @@ void testAppend() { using S = static_string<400>; - using sv = string_view; + using sv = string_like; // append(size_type count, CharT ch) BOOST_TEST(static_string<1>{}.append(1, 'a') == "a"); @@ -2024,6 +2118,7 @@ testAppend() // append(T const& t) { +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW struct T { operator string_view() const noexcept @@ -2031,12 +2126,29 @@ testAppend() return "c"; } }; +#else + struct T + { + char const* + data() const noexcept + { + return "c"; + } + + std::size_t + size() const noexcept + { + return 1; + } + }; +#endif BOOST_TEST(static_string<3>{"ab"}.append(T{}) == "abc"); BOOST_TEST_THROWS(static_string<3>{"abc"}.append(T{}), std::length_error); } // append(T const& t, size_type pos, size_type count = npos) { +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW struct T { operator string_view() const noexcept @@ -2044,6 +2156,22 @@ testAppend() return "abcd"; } }; +#else + struct T + { + char const* + data() const noexcept + { + return "abcd"; + } + + std::size_t + size() const noexcept + { + return 4; + } + }; +#endif BOOST_TEST(static_string<4>{"ab"}.append(T{}, 2) == "abcd"); BOOST_TEST(static_string<3>{"a"}.append(T{}, 1, 2) == "abc"); BOOST_TEST_THROWS(static_string<4>{"abc"}.append(T{}, 5), std::out_of_range); @@ -2134,7 +2262,7 @@ testAppend() std::length_error); } { - string_view s1("XYZ"); + string_like s1("XYZ"); static_string<5> s2("12"); s2.append(s1); BOOST_TEST(s2 == "12XYZ"); @@ -2189,7 +2317,7 @@ static void testPlusEquals() { - using sv = string_view; + using sv = string_like; // operator+=(CharT ch) BOOST_TEST((static_string<3>{"ab"} += 'c') == "abc"); @@ -2245,7 +2373,7 @@ testPlusEquals() std::length_error); } { - string_view s1("34"); + string_like s1("34"); static_string<4> s2("12"); s2 += s1; BOOST_TEST(s2 == "1234"); @@ -2281,6 +2409,7 @@ testCompare() BOOST_TEST(s1.compare(0, 2, s2.data()) < 0); BOOST_TEST(s2.compare(0, 1, s1.data()) > 0); +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW BOOST_TEST(s1.compare(s2.subview()) < 0); BOOST_TEST(s2.compare(s1.subview()) > 0); @@ -2289,6 +2418,7 @@ testCompare() BOOST_TEST(s1.compare(0, 2, s2.subview(), 0, 1) < 0); BOOST_TEST(s2.compare(0, 1, s1.subview(), 0, 2) > 0); +#endif BOOST_TEST(s1 < "10"); BOOST_TEST(s2 > "1"); @@ -2297,6 +2427,14 @@ testCompare() BOOST_TEST(s1 < "20"); BOOST_TEST(s2 > "1"); BOOST_TEST(s2 > "2"); + + BOOST_TEST(s1 < string_like("10")); + BOOST_TEST(s2 > string_like("1")); + BOOST_TEST(string_like("10") > s1); + BOOST_TEST(string_like("1") < s2); + BOOST_TEST(s1 < string_like("20")); + BOOST_TEST(s2 > string_like("1")); + BOOST_TEST(s2 > string_like("2")); } { str2 s1("x"); @@ -2332,6 +2470,19 @@ testCompare() BOOST_TEST(! ("x" < s)); BOOST_TEST(! ("x" > s)); BOOST_TEST(! ("x" != s)); + + BOOST_TEST(s == string_like("x")); + BOOST_TEST(s <= string_like("x")); + BOOST_TEST(s >= string_like("x")); + BOOST_TEST(! (s < string_like("x"))); + BOOST_TEST(! (s > string_like("x"))); + BOOST_TEST(! (s != string_like("x"))); + BOOST_TEST(string_like("x") == s); + BOOST_TEST(string_like("x") <= s); + BOOST_TEST(string_like("x") >= s); + BOOST_TEST(! (string_like("x") < s)); + BOOST_TEST(! (string_like("x") > s)); + BOOST_TEST(! (string_like("x") != s)); } { str2 s("x"); @@ -2347,6 +2498,19 @@ testCompare() BOOST_TEST(! ("y" == s)); BOOST_TEST(! ("y" <= s)); BOOST_TEST(! ("y" < s)); + + BOOST_TEST(s <= string_like("y")); + BOOST_TEST(s < string_like("y")); + BOOST_TEST(s != string_like("y")); + BOOST_TEST(! (s == string_like("y"))); + BOOST_TEST(! (s >= string_like("y"))); + BOOST_TEST(! (s > "x")); + BOOST_TEST(string_like("y") >= s); + BOOST_TEST(string_like("y") > s); + BOOST_TEST(string_like("y") != s); + BOOST_TEST(! (string_like("y") == s)); + BOOST_TEST(! (string_like("y") <= s)); + BOOST_TEST(! (string_like("y") < s)); } { str1 s1("x"); @@ -3808,8 +3972,8 @@ testFind() { const char* cs1 = "12345"; const char* cs2 = "2345"; - string_view v1 = cs1; - string_view v2 = cs2; + string_like v1 = cs1; + string_like v2 = cs2; static_string<5> fs1 = cs1; static_string<4> fs2 = cs2; using S = static_string<400>; @@ -5132,8 +5296,8 @@ testFind() const char* cs3 = "12456"; const char* cs4 = "2356"; - string_view v3 = cs3; - string_view v4 = cs4; + string_like v3 = cs3; + string_like v4 = cs4; static_string<5> fs3 = cs3; static_string<4> fs4 = cs4; @@ -5918,12 +6082,12 @@ testReplace() // replace(size_type pos1, size_type n1, const T& t); { static_string<20> fs1 = "helloworld"; - BOOST_TEST(fs1.replace(0, fs1.size(), string_view(fs1)) == "helloworld"); + BOOST_TEST(fs1.replace(0, fs1.size(), string_like(fs1.data(), fs1.size())) == "helloworld"); } // replace(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos); { static_string<20> fs1 = "helloworld"; - BOOST_TEST(fs1.replace(0, fs1.size(), string_view(fs1), 0, fs1.size()) == "helloworld"); + BOOST_TEST(fs1.replace(0, fs1.size(), string_like(fs1.data(), fs1.size()), 0, fs1.size()) == "helloworld"); } // replace(size_type pos, size_type n, const charT * s); { @@ -5949,7 +6113,7 @@ testReplace() // replace(const_iterator i1, const_iterator i2, const T& t); { static_string<20> fs1 = "helloworld"; - BOOST_TEST(fs1.replace(fs1.begin(), fs1.end(), string_view(fs1)) == "helloworld"); + BOOST_TEST(fs1.replace(fs1.begin(), fs1.end(), string_like(fs1.data(), fs1.size())) == "helloworld"); } // replace(const_iterator i1, const_iterator i2, const charT* s, size_type n); { @@ -7096,21 +7260,21 @@ testStartsEnds() BOOST_TEST(S("1234567890").starts_with("1234567890")); BOOST_TEST(!S("1234567890").starts_with("234")); BOOST_TEST(!S("1234567890").starts_with("12345678900")); - BOOST_TEST(S("1234567890").starts_with(string_view("1234567890"))); + BOOST_TEST(S("1234567890").starts_with(string_like("1234567890"))); BOOST_TEST(S("1234567890").ends_with('0')); BOOST_TEST(S("1234567890").ends_with("890")); BOOST_TEST(S("1234567890").ends_with("1234567890")); BOOST_TEST(!S("1234567890").ends_with("234")); BOOST_TEST(!S("1234567890").ends_with("12345678900")); - BOOST_TEST(S("1234567890").ends_with(string_view("1234567890"))); + BOOST_TEST(S("1234567890").ends_with(string_like("1234567890"))); BOOST_TEST(!S().starts_with('0')); BOOST_TEST(!S().starts_with("0")); - BOOST_TEST(!S().starts_with(string_view("0"))); + BOOST_TEST(!S().starts_with(string_like("0"))); BOOST_TEST(!S().ends_with('0')); BOOST_TEST(!S().ends_with("0")); - BOOST_TEST(!S().ends_with(string_view("0"))); + BOOST_TEST(!S().ends_with(string_like("0"))); } void @@ -7151,7 +7315,9 @@ testStream() static_string<10> b = "abcdefghij"; a << b; static_string<10> c(std::istream_iterator{a}, std::istream_iterator{}); +#ifdef BOOST_STATIC_STRING_HAS_STRING_VIEW BOOST_TEST(a.str() == b.subview()); +#endif BOOST_TEST(b == c); }