string_view interoperability

fix #26
This commit is contained in:
alandefreitas
2023-01-12 18:16:06 -03:00
committed by Alan de Freitas
parent 269987446e
commit ac84c4f40e
4 changed files with 692 additions and 65 deletions

View File

@ -147,15 +147,51 @@
#endif
#ifndef BOOST_STATIC_STRING_STANDALONE
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/static_assert.hpp>
#include <boost/utility/string_view.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/throw_exception.hpp>
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) || \
defined(BOOST_STATIC_STRING_CXX17_STRING_VIEW)
#include <string_view>
#define BOOST_STATIC_STRING_HAS_STD_STRING_VIEW
#endif
#else
#include <cassert>
#include <stdexcept>
/*
* Replicate the logic from Boost.Config
*/
// GNU libstdc++3:
#if defined(__GLIBCPP__) || defined(__GLIBCXX__)
#if (BOOST_LIBSTDCXX_VERSION < 70100) || (__cplusplus <= 201402L)
# define BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW
#endif
// libc++:
#elif defined(_LIBCPP_VERSION)
#if (_LIBCPP_VERSION < 4000) || (__cplusplus <= 201402L)
# define BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW
#endif
// MSVC uses logic from catch all for BOOST_NO_CXX17_HDR_STRING_VIEW
// catch all:
#elif !defined(_YVALS) && !defined(_CPPLIB_VER)
#if (!defined(__has_include) || (__cplusplus < 201700))
# define BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW
#elif !__has_include(<string_view>)
# define BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW
#endif
#endif
#if !defined(BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW) || \
defined(BOOST_STATIC_STRING_CXX17_STRING_VIEW)
#include <string_view>
#define BOOST_STATIC_STRING_HAS_STD_STRING_VIEW
#endif
#endif
// Compiler bug prevents constexpr from working with clang 4.x and 5.x
@ -192,6 +228,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_ANY_STRING_VIEW
namespace boost {
namespace static_strings {
@ -205,4 +247,6 @@ using basic_string_view =
#endif
} // static_strings
} // boost
#endif
#endif

View File

@ -37,6 +37,7 @@
#include <cwchar>
#include <functional>
#include <initializer_list>
#include <limits>
#include <iosfwd>
#include <type_traits>
@ -126,16 +127,43 @@ struct void_t_helper
template<typename... Ts>
using void_t = typename void_t_helper<Ts...>::type;
template <class T, typename CharT, typename = void>
struct is_string_like : std::false_type {};
template<typename T, typename CharT>
struct is_string_like<
T, CharT,
void_t<
decltype(std::declval<CharT const*&>() = std::declval<T>().data()),
decltype(std::declval<std::size_t&>() = std::declval<T>().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<typename T, typename CharT, typename Traits, typename = void>
struct enable_if_viewable { };
template<typename T, typename CharT, typename Traits>
struct enable_if_viewable<T, CharT, Traits,
typename std::enable_if<
std::is_convertible<const T&, basic_string_view<CharT, Traits>>::value &&
!std::is_convertible<const T&, const CharT*>::value>::type>
typename std::enable_if<
#if !defined(BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW)
is_string_like<T, CharT>::value
#elif defined(BOOST_STATIC_STRING_STANDALONE)
std::is_convertible<const T&, std::basic_string_view<CharT, Traits>>::value &&
!std::is_convertible<const T&, const CharT*>::value
#else
(
std::is_convertible<const T&, basic_string_view<CharT, Traits>>::value ||
std::is_convertible<const T&, core::basic_string_view<CharT>>::value
) &&
!std::is_convertible<const T&, const CharT*>::value
#endif
>::type>
{
using type = void;
};
@ -143,6 +171,59 @@ struct enable_if_viewable<T, CharT, Traits,
template<typename T, typename CharT, typename Traits>
using enable_if_viewable_t = typename enable_if_viewable<T, CharT, Traits>::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_ANY_STRING_VIEW)
template<typename T, typename CharT, typename Traits>
using common_string_view_type = T const&;
#elif defined(BOOST_STATIC_STRING_STANDALONE)
template<typename T, typename CharT, typename Traits>
using common_string_view_type = basic_string_view<CharT, Traits>;
#else
template <class T, typename CharT, typename Traits, typename = void>
struct common_string_view_type_impl {};
template<typename T, typename CharT, typename Traits>
struct common_string_view_type_impl<
T, CharT, Traits,
typename std::enable_if<
is_string_like<T, CharT>::value &&
!std::is_convertible<const T&, basic_string_view<CharT, Traits>>::value &&
!std::is_convertible<const T&, core::basic_string_view<CharT>>::value>::type>
{
using type = T const&;
};
template<typename T, typename CharT, typename Traits>
struct common_string_view_type_impl<
T, CharT, Traits,
typename std::enable_if<
std::is_convertible<const T&, basic_string_view<CharT, Traits>>::value &&
!std::is_convertible<const T&, core::basic_string_view<CharT>>::value>::type>
{
using type = basic_string_view<CharT, Traits>;
};
template<typename T, typename CharT, typename Traits>
struct common_string_view_type_impl<
T, CharT, Traits,
typename std::enable_if<
std::is_convertible<const T&, core::basic_string_view<CharT>>::value>::type>
{
using type = core::basic_string_view<CharT>;
};
template<typename T, typename CharT, typename Traits>
using common_string_view_type = typename common_string_view_type_impl<T, CharT, Traits>::type;
#endif
// Simplified check for if a type is an iterator
template<typename T, typename = void>
struct is_iterator : std::false_type { };
@ -879,9 +960,11 @@ public:
using const_reverse_iterator =
std::reverse_iterator<const_iterator>;
#ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW
/// The string view type.
using string_view_type =
basic_string_view<value_type, traits_type>;
#endif
//--------------------------------------------------------------------------
//
@ -1538,7 +1621,7 @@ public:
basic_static_string&
assign(const T& t)
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return assign(sv.data(), sv.size());
}
@ -1590,8 +1673,12 @@ public:
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<T, CharT, Traits> sv = t;
if( pos > sv.size() )
detail::throw_exception<std::out_of_range>(
"pos >= t.size()");
std::size_t rlen = (std::min)( count, sv.size() - pos );
return assign(sv.data() + pos, rlen);
}
//--------------------------------------------------------------------------
@ -1837,6 +1924,7 @@ public:
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 @@ public:
{
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<CharT, Traits>() const noexcept
{
return std::basic_string_view<CharT, Traits>(data(), size());
}
#endif
#ifndef BOOST_STATIC_STRING_STANDALONE
BOOST_STATIC_STRING_CPP11_CONSTEXPR
operator ::boost::basic_string_view<CharT, Traits>() const noexcept
{
return ::boost::basic_string_view<CharT, Traits>(data(), size());
}
BOOST_STATIC_STRING_CPP11_CONSTEXPR
operator ::boost::core::basic_string_view<CharT>() const noexcept
{
return ::boost::core::basic_string_view<CharT>(data(), size());
}
#endif
#endif
//--------------------------------------------------------------------------
//
@ -2503,7 +2613,7 @@ public:
size_type index,
const T& t)
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return insert(index, sv.data(), sv.size());
}
@ -2552,8 +2662,10 @@ public:
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<T, CharT, Traits> sv(t);
if ( index_str > sv.size() )
detail::throw_exception<std::out_of_range>("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 @@ public:
basic_static_string&
append(const T& t)
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return append(sv.data(), sv.size());
}
@ -2957,8 +3069,10 @@ public:
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<T, CharT, Traits> sv = t;
if ( pos > sv.size() )
detail::throw_exception<std::out_of_range>("pos > t.size()");
return append(sv.data() + pos, (std::min)(sv.size() - pos, count));
}
/** Append to the string.
@ -3342,7 +3456,7 @@ public:
int
compare(const T& t) const noexcept
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return detail::lexicographical_compare<CharT, Traits>(
data(), size(), sv.data(), sv.size());
}
@ -3393,7 +3507,7 @@ public:
size_type count1,
const T& t) const
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return detail::lexicographical_compare<CharT, Traits>(
data() + pos1, capped_length(pos1, count1), sv.data(), sv.size());
}
@ -3450,9 +3564,12 @@ public:
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<T, CharT, Traits> sv = t;
if ( pos2 > sv.size())
detail::throw_exception<std::out_of_range>("pos2 > sv.size()");
return compare(
pos1, count1, sv.data() + pos2,
(std::min)(sv.size() - pos2, count2));
}
/** Return a substring.
@ -3485,6 +3602,7 @@ public:
data() + pos, capped_length(pos, count));
}
#ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW
/** Return a string view of a substring.
Returns a view of a substring.
@ -3512,6 +3630,7 @@ public:
return string_view_type(
data() + pos, capped_length(pos, count));
}
#endif
/** Copy a substring to another string.
@ -3771,7 +3890,7 @@ public:
size_type n1,
const T& t)
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return replace(pos1, n1, sv.data(), sv.size());
}
@ -3823,8 +3942,12 @@ public:
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<T, CharT, Traits> sv = t;
if ( pos2 > sv.size())
detail::throw_exception<std::out_of_range>("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 @@ public:
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<T, CharT, Traits> sv = t;
return replace(i1, i2, sv.data(), sv.data() + sv.size());
}
/** Replace a part of the string.
@ -4290,9 +4413,13 @@ public:
find(
const T& t,
size_type pos = 0) const
#ifdef BOOST_STATIC_STRING_DOCS
noexcept(detail::is_nothrow_convertible<const T&, string_view_type>::value)
#else
noexcept(detail::is_nothrow_convertible<const T&, detail::common_string_view_type<T, CharT, Traits>>::value)
#endif
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return find(sv.data(), pos, sv.size());
}
@ -4443,9 +4570,13 @@ public:
rfind(
const T& t,
size_type pos = npos) const
#ifdef BOOST_STATIC_STRING_DOCS
noexcept(detail::is_nothrow_convertible<const T&, string_view_type>::value)
#else
noexcept(detail::is_nothrow_convertible<const T&, detail::common_string_view_type<T, CharT, Traits>>::value)
#endif
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return rfind(sv.data(), pos, sv.size());
}
@ -4591,9 +4722,13 @@ public:
find_first_of(
const T& t,
size_type pos = 0) const
#ifdef BOOST_STATIC_STRING_DOCS
noexcept(detail::is_nothrow_convertible<const T&, string_view_type>::value)
#else
noexcept(detail::is_nothrow_convertible<const T&, detail::common_string_view_type<T, CharT, Traits>>::value)
#endif
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return find_first_of(sv.data(), pos, sv.size());
}
@ -4734,9 +4869,13 @@ public:
find_last_of(
const T& t,
size_type pos = npos) const
#ifdef BOOST_STATIC_STRING_DOCS
noexcept(detail::is_nothrow_convertible<const T&, string_view_type>::value)
#else
noexcept(detail::is_nothrow_convertible<const T&, detail::common_string_view_type<T, CharT, Traits>>::value)
#endif
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return find_last_of(sv.data(), pos, sv.size());
}
@ -4876,9 +5015,13 @@ public:
find_first_not_of(
const T& t,
size_type pos = 0) const
#ifdef BOOST_STATIC_STRING_DOCS
noexcept(detail::is_nothrow_convertible<const T&, string_view_type>::value)
#else
noexcept(detail::is_nothrow_convertible<const T&, detail::common_string_view_type<T, CharT, Traits>>::value)
#endif
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return find_first_not_of(sv.data(), pos, sv.size());
}
@ -5017,9 +5160,13 @@ public:
find_last_not_of(
const T& t,
size_type pos = npos) const
#ifdef BOOST_STATIC_STRING_DOCS
noexcept(detail::is_nothrow_convertible<const T&, string_view_type>::value)
#else
noexcept(detail::is_nothrow_convertible<const T&, detail::common_string_view_type<T, CharT, Traits>>::value)
#endif
{
const string_view_type sv = t;
detail::common_string_view_type<T, CharT, Traits> sv = t;
return find_last_not_of(sv.data(), pos, sv.size());
}
@ -5133,15 +5280,21 @@ public:
Linear.
@param s The string view to check for.
@param t The string view to check for.
*/
template<typename T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#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<T, CharT, Traits> 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 @@ public:
Linear.
@param s The string view to check for.
@param t The string view to check for.
*/
template<typename T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#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<T, CharT, Traits> 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<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator==(
const T& lhs,
const basic_static_string<N, CharT, Traits>& rhs)
{
detail::common_string_view_type<T, CharT, Traits> lhsv = lhs;
return detail::lexicographical_compare<CharT, Traits>(
lhsv.data(), lhsv.size(),
rhs.data(), rhs.size()) == 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator==(
const basic_static_string<N, CharT, Traits>& lhs,
const T& rhs)
{
detail::common_string_view_type<T, CharT, Traits> rhsv = rhs;
return detail::lexicographical_compare<CharT, Traits>(
lhs.data(), lhs.size(),
rhsv.data(), rhsv.size()) == 0;
}
template<std::size_t N, typename CharT, typename Traits>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
@ -5482,6 +5677,42 @@ operator!=(
rhs, Traits::length(rhs)) != 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator!=(
const T& lhs,
const basic_static_string<N, CharT, Traits>& rhs)
{
detail::common_string_view_type<T, CharT, Traits> lhsv = lhs;
return detail::lexicographical_compare<CharT, Traits>(
lhsv.data(), lhsv.size(),
rhs.data(), rhs.size()) != 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator!=(
const basic_static_string<N, CharT, Traits>& lhs,
const T& rhs)
{
detail::common_string_view_type<T, CharT, Traits> rhsv = rhs;
return detail::lexicographical_compare<CharT, Traits>(
lhs.data(), lhs.size(),
rhsv.data(), rhsv.size()) != 0;
}
template<std::size_t N, typename CharT, typename Traits>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
@ -5508,6 +5739,42 @@ operator<(
rhs, Traits::length(rhs)) < 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator<(
const T& lhs,
const basic_static_string<N, CharT, Traits>& rhs)
{
detail::common_string_view_type<T, CharT, Traits> lhsv = lhs;
return detail::lexicographical_compare<CharT, Traits>(
lhsv.data(), lhsv.size(),
rhs.data(), rhs.size()) < 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator<(
const basic_static_string<N, CharT, Traits>& lhs,
const T& rhs)
{
detail::common_string_view_type<T, CharT, Traits> rhsv = rhs;
return detail::lexicographical_compare<CharT, Traits>(
lhs.data(), lhs.size(),
rhsv.data(), rhsv.size()) < 0;
}
template<std::size_t N, typename CharT, typename Traits>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
@ -5534,6 +5801,42 @@ operator<=(
rhs, Traits::length(rhs)) <= 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator<=(
const T& lhs,
const basic_static_string<N, CharT, Traits>& rhs)
{
detail::common_string_view_type<T, CharT, Traits> lhsv = lhs;
return detail::lexicographical_compare<CharT, Traits>(
lhsv.data(), lhsv.size(),
rhs.data(), rhs.size()) <= 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator<=(
const basic_static_string<N, CharT, Traits>& lhs,
const T& rhs)
{
detail::common_string_view_type<T, CharT, Traits> rhsv = rhs;
return detail::lexicographical_compare<CharT, Traits>(
lhs.data(), lhs.size(),
rhsv.data(), rhsv.size()) <= 0;
}
template<std::size_t N, typename CharT, typename Traits>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
@ -5560,6 +5863,43 @@ operator>(
rhs, Traits::length(rhs)) > 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator>(
const T& lhs,
const basic_static_string<N, CharT, Traits>& rhs)
{
detail::common_string_view_type<T, CharT, Traits> lhsv = lhs;
return detail::lexicographical_compare<CharT, Traits>(
lhsv.data(), lhsv.size(),
rhs.data(), rhs.size()) > 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator>(
const basic_static_string<N, CharT, Traits>& lhs,
const T& rhs)
{
detail::common_string_view_type<T, CharT, Traits> rhsv = rhs;
return detail::lexicographical_compare<CharT, Traits>(
lhs.data(), lhs.size(),
rhsv.data(), rhsv.size()) > 0;
}
template<std::size_t N, typename CharT, typename Traits>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
@ -5586,6 +5926,42 @@ operator>=(
rhs, Traits::length(rhs)) >= 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator>=(
const T& lhs,
const basic_static_string<N, CharT, Traits>& rhs)
{
detail::common_string_view_type<T, CharT, Traits> lhsv = lhs;
return detail::lexicographical_compare<CharT, Traits>(
lhsv.data(), lhsv.size(),
rhs.data(), rhs.size()) >= 0;
}
template<std::size_t N, typename CharT, typename Traits, class T
#ifndef BOOST_STATIC_STRING_DOCS
, typename = detail::enable_if_viewable_t<T, CharT, Traits>
#endif
>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
bool
operator>=(
const basic_static_string<N, CharT, Traits>& lhs,
const T& rhs)
{
detail::common_string_view_type<T, CharT, Traits> rhsv = rhs;
return detail::lexicographical_compare<CharT, Traits>(
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<CharT, Traits>& os,
const basic_static_string<N, CharT, Traits>& s)
{
#ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW
return os << basic_string_view<CharT, Traits>(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<N, CharT, Traits>& 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_ANY_STRING_VIEW)
using view_type = typename
boost::static_strings::basic_string_view<CharT, Traits>;
return std::hash<view_type>()(view_type(str.data(), str.size()));
#else
std::size_t seed = 0;
for (CharT const& c : str) {
mix_impl(std::integral_constant<bool, sizeof(std::size_t) >= 8>{}, seed, c);
}
return seed;
#endif
}
static
void
mix_impl(std::true_type, std::size_t& seed, CharT c)
{
seed += 0x9e3779b9 + std::hash<CharT>()( 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<CharT>()( 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

View File

@ -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]{};

View File

@ -26,7 +26,15 @@ namespace static_strings {
template class basic_static_string<420, char>;
#ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW
using string_view = basic_string_view<char, std::char_traits<char>>;
#endif
#ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW
using string_like = basic_string_view<char, std::char_traits<char>>;
#else
using string_like = std::string;
#endif
template <class S>
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_ANY_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_ANY_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_ANY_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_ANY_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);
}
{
@ -795,11 +844,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
@ -916,7 +974,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)
@ -997,6 +1055,7 @@ testInsert()
// insert(size_type index, T const& t)
{
#ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW
struct T
{
operator string_view() const noexcept
@ -1004,6 +1063,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);
@ -1011,6 +1087,7 @@ testInsert()
// insert(size_type index, T const& t, size_type index_str, size_type count = npos)
{
#ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW
struct T
{
operator string_view() const noexcept
@ -1018,6 +1095,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");
@ -1145,16 +1239,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);
}
{
@ -1986,7 +2080,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");
@ -2031,6 +2125,7 @@ testAppend()
// append(T const& t)
{
#ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW
struct T
{
operator string_view() const noexcept
@ -2038,12 +2133,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_ANY_STRING_VIEW
struct T
{
operator string_view() const noexcept
@ -2051,6 +2163,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);
@ -2141,7 +2269,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");
@ -2196,7 +2324,7 @@ static
void
testPlusEquals()
{
using sv = string_view;
using sv = string_like;
// operator+=(CharT ch)
BOOST_TEST((static_string<3>{"ab"} += 'c') == "abc");
@ -2252,7 +2380,7 @@ testPlusEquals()
std::length_error);
}
{
string_view s1("34");
string_like s1("34");
static_string<4> s2("12");
s2 += s1;
BOOST_TEST(s2 == "1234");
@ -2288,6 +2416,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_ANY_STRING_VIEW
BOOST_TEST(s1.compare(s2.subview()) < 0);
BOOST_TEST(s2.compare(s1.subview()) > 0);
@ -2296,6 +2425,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");
@ -2304,6 +2434,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");
@ -2339,6 +2477,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");
@ -2354,6 +2505,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");
@ -3815,8 +3979,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>;
@ -5139,8 +5303,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;
@ -5925,12 +6089,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);
{
@ -5956,7 +6120,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);
{
@ -7103,21 +7267,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
@ -7158,7 +7322,9 @@ testStream()
static_string<10> b = "abcdefghij";
a << b;
static_string<10> c(std::istream_iterator<char>{a}, std::istream_iterator<char>{});
#ifdef BOOST_STATIC_STRING_HAS_ANY_STRING_VIEW
BOOST_TEST(a.str() == b.subview());
#endif
BOOST_TEST(b == c);
}