From fb8b3e2993f4f1bb646369feab59b3bd80d1d0e1 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 24 Apr 2019 16:17:53 +0100 Subject: Fix basic_string_view typedefs and enforce preconditions The basic_string_view::pointer and basic_string_view::reference typedefs are supposed to refer to the non-const value type. In previous standards having traits_type::char_type different to value_type was simply undefined, but in the C++2a draft it's ill-formed, as changed by P1148R0. For std::basic_string and iostreams we might want to only enforce this conditionally for __cplusplus > 201703L but for std::basic_string_view we don't have backwards compatibility concerns. Also add assertions to verify the _CharT argument is a "char-like" type (non-array, trivial, standard layout type). Also remove the non-standard basic_string_view::_M_check and basic_string_view::_M_limit member functions, replacing them with non-member functions that will still exist even if basic_string_view is specialized by the program. * include/experimental/string_view (basic_string_view::pointer) (basic_string_view::reference): Fix to refer to non-const value_type. * include/bits/basic_string.h (basic_string): Use __sv_check and __sv_limit instead of basic_string_view::_M_check and basic_string_view::_M_limit. * include/std/string_view (__sv_check, __sv_limit): New helper functions to replace basic_string_view::_M_check and basic_string_view::_M_limit. (basic_string_view): Add static assertions to enforce ill-formed requirement for traits_type::char_type from P1148R0, and to enforce required properties of char-like types. (basic_string_view::pointer, basic_string_view::reference): Fix to refer to non-const value_type. (basic_string_view::operator[], basic_string_view::at) (basic_string_view::front, basic_string_view::back) (basic_string_view::data): Use const_reference and const_pointer typedefs for return types. (basic_string_view::_M_check, basic_string_view::_M_limit): Remove. (hash): Fix argument_type typedef. * testsuite/21_strings/basic_string_view/modifiers/remove_prefix/ char/1.cc: Fix expected return type of basic_string_view::data(). * testsuite/21_strings/basic_string_view/modifiers/remove_prefix/ wchar_t/1.cc: Likewise. * testsuite/21_strings/basic_string_view/modifiers/remove_suffix/ char/1.cc: Likewise. * testsuite/21_strings/basic_string_view/modifiers/remove_suffix/ wchar_t/1.cc: Likewise. * testsuite/21_strings/basic_string_view/requirements/traits_neg.cc: New test. * testsuite/21_strings/basic_string_view/requirements/typedefs.cc: Check reference and pointer typedefs. * testsuite/experimental/string_view/requirements/typedefs.cc: Likewise. * testsuite/experimental/string_view/modifiers/remove_prefix/char/1.cc: Fix expected return type of basic_string_view::data(). * testsuite/experimental/string_view/modifiers/remove_prefix/wchar_t/ 1.cc: Likewise. * testsuite/experimental/string_view/modifiers/remove_suffix/char/1.cc: Likewise. * testsuite/experimental/string_view/modifiers/remove_suffix/wchar_t/ 1.cc: Likewise. From-SVN: r270548 --- libstdc++-v3/include/std/string_view | 143 ++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 68 deletions(-) (limited to 'libstdc++-v3/include/std') diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view index 844cfb1..42822cc 100644 --- a/libstdc++-v3/include/std/string_view +++ b/libstdc++-v3/include/std/string_view @@ -49,6 +49,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __cpp_lib_string_view 201603 + // Helper for basic_string and basic_string_view members. + constexpr size_t + __sv_check(size_t __size, size_t __pos, const char* __s) + { + if (__pos > __size) + __throw_out_of_range_fmt(__N("%s: __pos (which is %zu) > __size " + "(which is %zu)"), __s, __pos, __size); + return __pos; + } + + // Helper for basic_string members. + // NB: __sv_limit doesn't check for a bad __pos value. + constexpr size_t + __sv_limit(size_t __size, size_t __pos, size_t __off) noexcept + { + const bool __testoff = __off < __size - __pos; + return __testoff ? __off : __size - __pos; + } + /** * @class basic_string_view * @brief A non-owning reference to a string. @@ -70,24 +89,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template> class basic_string_view { + static_assert(!is_array_v<_CharT>); + static_assert(is_trivial_v<_CharT> && is_standard_layout_v<_CharT>); + static_assert(is_same_v<_CharT, typename _Traits::char_type>); + public: // types - using traits_type = _Traits; - using value_type = _CharT; - using pointer = const _CharT*; - using const_pointer = const _CharT*; - using reference = const _CharT&; - using const_reference = const _CharT&; - using const_iterator = const _CharT*; - using iterator = const_iterator; + using traits_type = _Traits; + using value_type = _CharT; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using const_iterator = const value_type*; + using iterator = const_iterator; using const_reverse_iterator = std::reverse_iterator; - using reverse_iterator = const_reverse_iterator; - using size_type = size_t; - using difference_type = ptrdiff_t; + using reverse_iterator = const_reverse_iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; static constexpr size_type npos = size_type(-1); - // [string.view.cons], construct/copy + // [string.view.cons], construction and assignment constexpr basic_string_view() noexcept @@ -110,7 +133,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default; - // [string.view.iterators], iterators + // [string.view.iterators], iterator support constexpr const_iterator begin() const noexcept @@ -167,7 +190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // [string.view.access], element access - constexpr const _CharT& + constexpr const_reference operator[](size_type __pos) const noexcept { // TODO: Assert to restore in a way compatible with the constexpr. @@ -175,7 +198,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *(this->_M_str + __pos); } - constexpr const _CharT& + constexpr const_reference at(size_type __pos) const { if (__pos >= _M_len) @@ -185,7 +208,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *(this->_M_str + __pos); } - constexpr const _CharT& + constexpr const_reference front() const noexcept { // TODO: Assert to restore in a way compatible with the constexpr. @@ -193,7 +216,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this->_M_str; } - constexpr const _CharT& + constexpr const_reference back() const noexcept { // TODO: Assert to restore in a way compatible with the constexpr. @@ -201,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *(this->_M_str + this->_M_len - 1); } - constexpr const _CharT* + constexpr const_pointer data() const noexcept { return this->_M_str; } @@ -233,7 +256,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION copy(_CharT* __str, size_type __n, size_type __pos = 0) const { __glibcxx_requires_string_len(__str, __n); - __pos = _M_check(__pos, "basic_string_view::copy"); + __pos = std::__sv_check(size(), __pos, "basic_string_view::copy"); const size_type __rlen = std::min(__n, _M_len - __pos); // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2777. basic_string_view::copy should use char_traits::copy @@ -244,7 +267,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr basic_string_view substr(size_type __pos = 0, size_type __n = npos) const noexcept(false) { - __pos = _M_check(__pos, "basic_string_view::substr"); + __pos = std::__sv_check(size(), __pos, "basic_string_view::substr"); const size_type __rlen = std::min(__n, _M_len - __pos); return basic_string_view{_M_str + __pos, __rlen}; } @@ -286,6 +309,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION .compare(basic_string_view(__str, __n2)); } +#if __cplusplus > 201703L + constexpr bool + starts_with(basic_string_view __x) const noexcept + { return this->substr(0, __x.size()) == __x; } + + constexpr bool + starts_with(_CharT __x) const noexcept + { return !this->empty() && traits_type::eq(this->front(), __x); } + + constexpr bool + starts_with(const _CharT* __x) const noexcept + { return this->starts_with(basic_string_view(__x)); } + + constexpr bool + ends_with(basic_string_view __x) const noexcept + { + return this->size() >= __x.size() + && this->compare(this->size() - __x.size(), npos, __x) == 0; + } + + constexpr bool + ends_with(_CharT __x) const noexcept + { return !this->empty() && traits_type::eq(this->back(), __x); } + + constexpr bool + ends_with(const _CharT* __x) const noexcept + { return this->ends_with(basic_string_view(__x)); } +#endif // C++20 + + // [string.view.find], searching + constexpr size_type find(basic_string_view __str, size_type __pos = 0) const noexcept { return this->find(__str._M_str, __pos, __str._M_len); } @@ -386,53 +440,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION traits_type::length(__str)); } -#if __cplusplus > 201703L - constexpr bool - starts_with(basic_string_view __x) const noexcept - { return this->substr(0, __x.size()) == __x; } - - constexpr bool - starts_with(_CharT __x) const noexcept - { return !this->empty() && traits_type::eq(this->front(), __x); } - - constexpr bool - starts_with(const _CharT* __x) const noexcept - { return this->starts_with(basic_string_view(__x)); } - - constexpr bool - ends_with(basic_string_view __x) const noexcept - { - return this->size() >= __x.size() - && this->compare(this->size() - __x.size(), npos, __x) == 0; - } - - constexpr bool - ends_with(_CharT __x) const noexcept - { return !this->empty() && traits_type::eq(this->back(), __x); } - - constexpr bool - ends_with(const _CharT* __x) const noexcept - { return this->ends_with(basic_string_view(__x)); } -#endif // C++20 - - constexpr size_type - _M_check(size_type __pos, const char* __s) const noexcept(false) - { - if (__pos > this->size()) - __throw_out_of_range_fmt(__N("%s: __pos (which is %zu) > " - "this->size() (which is %zu)"), - __s, __pos, this->size()); - return __pos; - } - - // NB: _M_limit doesn't check for a bad __pos value. - constexpr size_type - _M_limit(size_type __pos, size_type __off) const noexcept - { - const bool __testoff = __off < this->size() - __pos; - return __testoff ? __off : this->size() - __pos; - } - private: static constexpr int @@ -610,7 +617,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #ifdef _GLIBCXX_USE_WCHAR_T template<> struct hash - : public __hash_base + : public __hash_base { size_t operator()(const wstring_view& __s) const noexcept -- cgit v1.1