2019-04-24 Jonathan Wakely <jwakely@redhat.com>
+ * 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<wstring_view>): 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.
+
PR libstdc++/90220
* include/std/any (__any_caster): Use remove_cv_t instead of decay_t.
Avoid a runtime check for types that can never be stored in std::any.
{
__sv_type __sv = __svt;
return _M_append(__sv.data()
- + __sv._M_check(__pos, "basic_string::append"),
- __sv._M_limit(__pos, __n));
+ + std::__sv_check(__sv.size(), __pos, "basic_string::append"),
+ std::__sv_limit(__sv.size(), __pos, __n));
}
#endif // C++17
assign(const _Tp& __svt, size_type __pos, size_type __n = npos)
{
__sv_type __sv = __svt;
- return _M_replace(size_type(0), this->size(), __sv.data()
- + __sv._M_check(__pos, "basic_string::assign"),
- __sv._M_limit(__pos, __n));
+ return _M_replace(size_type(0), this->size(),
+ __sv.data()
+ + std::__sv_check(__sv.size(), __pos, "basic_string::assign"),
+ std::__sv_limit(__sv.size(), __pos, __n));
}
#endif // C++17
size_type __pos2, size_type __n = npos)
{
__sv_type __sv = __svt;
- return this->replace(__pos1, size_type(0), __sv.data()
- + __sv._M_check(__pos2, "basic_string::insert"),
- __sv._M_limit(__pos2, __n));
+ return this->replace(__pos1, size_type(0),
+ __sv.data()
+ + std::__sv_check(__sv.size(), __pos2, "basic_string::insert"),
+ std::__sv_limit(__sv.size(), __pos2, __n));
}
#endif // C++17
size_type __pos2, size_type __n2 = npos)
{
__sv_type __sv = __svt;
- return this->replace(__pos1, __n1, __sv.data()
- + __sv._M_check(__pos2, "basic_string::replace"),
- __sv._M_limit(__pos2, __n2));
+ return this->replace(__pos1, __n1,
+ __sv.data()
+ + std::__sv_check(__sv.size(), __pos2, "basic_string::replace"),
+ std::__sv_limit(__sv.size(), __pos2, __n2));
}
/**
{
__sv_type __sv = __svt;
return append(__sv.data()
- + __sv._M_check(__pos, "basic_string::append"),
- __sv._M_limit(__pos, __n));
+ + std::__sv_check(__sv.size(), __pos, "basic_string::append"),
+ std::__sv_limit(__sv.size(), __pos, __n));
}
#endif // C++17
{
__sv_type __sv = __svt;
return assign(__sv.data()
- + __sv._M_check(__pos, "basic_string::assign"),
- __sv._M_limit(__pos, __n));
+ + std::__sv_check(__sv.size(), __pos, "basic_string::assign"),
+ std::__sv_limit(__sv.size(), __pos, __n));
}
#endif // C++17
{
__sv_type __sv = __svt;
return this->replace(__pos1, size_type(0), __sv.data()
- + __sv._M_check(__pos2, "basic_string::insert"),
- __sv._M_limit(__pos2, __n));
+ + std::__sv_check(__sv.size(), __pos2, "basic_string::insert"),
+ std::__sv_limit(__sv.size(), __pos2, __n));
}
#endif // C++17
{
__sv_type __sv = __svt;
return this->replace(__pos1, __n1,
- __sv.data() + __sv._M_check(__pos2, "basic_string::replace"),
- __sv._M_limit(__pos2, __n2));
+ __sv.data()
+ + std::__sv_check(__sv.size(), __pos2, "basic_string::replace"),
+ std::__sv_limit(__sv.size(), __pos2, __n2));
}
/**
// types
using traits_type = _Traits;
using value_type = _CharT;
- using pointer = const _CharT*;
+ using pointer = _CharT*;
using const_pointer = const _CharT*;
- using reference = const _CharT&;
+ using reference = _CharT&;
using const_reference = const _CharT&;
using const_iterator = const _CharT*;
using iterator = const_iterator;
#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 <string_view>
* @brief A non-owning reference to a string.
template<typename _CharT, typename _Traits = std::char_traits<_CharT>>
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<const_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
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
// [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.
return *(this->_M_str + __pos);
}
- constexpr const _CharT&
+ constexpr const_reference
at(size_type __pos) const
{
if (__pos >= _M_len)
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.
return *this->_M_str;
}
- constexpr const _CharT&
+ constexpr const_reference
back() const noexcept
{
// TODO: Assert to restore in a way compatible with the constexpr.
return *(this->_M_str + this->_M_len - 1);
}
- constexpr const _CharT*
+ constexpr const_pointer
data() const noexcept
{ return this->_M_str; }
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
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};
}
.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); }
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
#ifdef _GLIBCXX_USE_WCHAR_T
template<>
struct hash<wstring_view>
- : public __hash_base<size_t, wstring>
+ : public __hash_base<size_t, wstring_view>
{
size_t
operator()(const wstring_view& __s) const noexcept
using std::string_view;
string_view str0{"olympus mons"};
- string_view::pointer p = str0.data();
+ string_view::const_pointer p = str0.data();
str0.remove_prefix(4);
VERIFY( str0.data() == p + 4);
VERIFY( str0.length() == 8 );
using std::string_view;
string_view str0{"olympus mons"};
- string_view::pointer p = str0.data();
+ string_view::const_pointer p = str0.data();
str0.remove_prefix(4);
if ( str0.data() != p + 4)
return false;
using std::wstring_view;
wstring_view str0{L"olympus mons"};
- wstring_view::pointer p = str0.data();
+ wstring_view::const_pointer p = str0.data();
str0.remove_prefix(4);
VERIFY( str0.data() == p + 4);
VERIFY( str0.length() == 8 );
using std::wstring_view;
wstring_view str0{L"olympus mons"};
- wstring_view::pointer p = str0.data();
+ wstring_view::const_pointer p = str0.data();
str0.remove_prefix(4);
if ( str0.data() != p + 4)
return false;
using std::string_view;
string_view str0{"olympus mons"};
- string_view::pointer p = str0.data();
+ string_view::const_pointer p = str0.data();
str0.remove_suffix(2);
VERIFY( str0.data() == p);
VERIFY( str0.length() == 10 );
using std::string_view;
string_view str0{"olympus mons"};
- string_view::pointer p = str0.data();
+ string_view::const_pointer p = str0.data();
str0.remove_suffix(2);
if ( str0.data() != p)
return false;
using std::wstring_view;
wstring_view str0{L"olympus mons"};
- wstring_view::pointer p = str0.data();
+ wstring_view::const_pointer p = str0.data();
str0.remove_suffix(2);
VERIFY( str0.data() == p);
VERIFY( str0.length() == 10 );
using std::wstring_view;
wstring_view str0{L"olympus mons"};
- wstring_view::pointer p = str0.data();
+ wstring_view::const_pointer p = str0.data();
str0.remove_suffix(2);
if ( str0.data() != p)
return false;
--- /dev/null
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+// C++98 21.1 [lib.char.traits] p3
+// C++03 21.1 [lib.char.traits] p3
+// C++11 21.2 [char.traits] p3
+// C++14 21.2 [char.traits] p3
+// C++17 24.2 [char.traits] p3
+// "Traits::char_type shall be the same as CharT."
+// C++17 24.4.2 [string.view.template] p1
+// "the type traits::char_type shall name the same type as charT"
+// C++2a 21.2 [char.traits] p3 (post-P1148R0)
+// "If X::char_type is not the same type as C, the program is ill-formed."
+
+std::basic_string_view<char, std::char_traits<char16_t>> s1; // { dg-error "here" }
+std::basic_string_view<char32_t, std::char_traits<char>> s2; // { dg-error "here" }
+
+// { dg-prune-output "static assertion failed" }
__gnu_test::reversible_types<std::wstring_view> t2r;
typedef typename std::wstring_view::traits_type traits_type2;
#endif
+
+static_assert(std::is_same<std::string_view::pointer, char*>(),
+ "pointer should be value_type*");
+static_assert(std::is_same<std::string_view::const_pointer, const char*>(),
+ "const_pointer should be const value_type*");
+static_assert(std::is_same<std::string_view::reference, char&>(),
+ "reference should be value_type&");
+static_assert(std::is_same<std::string_view::const_reference, const char&>(),
+ "const_reference should be const value_type&");
using namespace std::experimental;
string_view str0{"olympus mons"};
- string_view::pointer p = str0.data();
+ string_view::const_pointer p = str0.data();
str0.remove_prefix(4);
VERIFY( str0.data() == p + 4);
VERIFY( str0.length() == 8 );
using namespace std::experimental;
wstring_view str0{L"olympus mons"};
- wstring_view::pointer p = str0.data();
+ wstring_view::const_pointer p = str0.data();
str0.remove_prefix(4);
VERIFY( str0.data() == p + 4);
VERIFY( str0.length() == 8 );
using namespace std::experimental;
string_view str0{"olympus mons"};
- string_view::pointer p = str0.data();
+ string_view::const_pointer p = str0.data();
str0.remove_suffix(2);
VERIFY( str0.data() == p);
VERIFY( str0.length() == 10 );
using namespace std::experimental;
wstring_view str0{L"olympus mons"};
- wstring_view::pointer p = str0.data();
+ wstring_view::const_pointer p = str0.data();
str0.remove_suffix(2);
VERIFY( str0.data() == p);
VERIFY( str0.length() == 10 );
__gnu_test::reversible_types<std::experimental::wstring_view> t2r;
typedef typename std::experimental::wstring_view::traits_type traits_type2;
#endif
+
+static_assert(
+ std::is_same<std::experimental::string_view::pointer, char*>(),
+ "pointer should be value_type*");
+static_assert(
+ std::is_same<std::experimental::string_view::const_pointer, const char*>(),
+ "const_pointer should be const value_type*");
+static_assert(
+ std::is_same<std::experimental::string_view::reference, char&>(),
+ "reference should be value_type&");
+static_assert(
+ std::is_same<std::experimental::string_view::const_reference, const char&>(),
+ "const_reference should be const value_type&");