@@ -45,6 +45,10 @@
#include <bits/ostream_insert.h>
#include <ext/numeric_traits.h>
+#if __cplusplus > 202002L
+# include <bits/ranges_base.h>
+#endif
+
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -135,7 +139,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: _M_len{__len}, _M_str{__str}
{ }
-#if __cplusplus > 201703L && __cpp_lib_concepts
+#if __cplusplus >= 202002L && __cpp_lib_concepts
template<contiguous_iterator _It, sized_sentinel_for<_It> _End>
requires same_as<iter_value_t<_It>, _CharT>
&& (!convertible_to<_End, size_type>)
@@ -143,7 +147,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
basic_string_view(_It __first, _End __last)
: _M_len(__last - __first), _M_str(std::to_address(__first))
{ }
-#endif
+
+#if __cplusplus > 202002L
+ template<typename _Range, typename _DRange = remove_cvref_t<_Range>>
+ requires (!is_same_v<_DRange, basic_string_view>)
+ && ranges::contiguous_range<_Range>
+ && ranges::sized_range<_Range>
+ && is_same_v<ranges::range_value_t<_Range>, _CharT>
+ && (!is_convertible_v<_Range, const _CharT*>)
+ && (!requires (_DRange& __d) {
+ __d.operator ::std::basic_string_view<_CharT, _Traits>();
+ })
+ && (!requires { typename _DRange::traits_type; }
+ || is_same_v<typename _DRange::traits_type, _Traits>)
+ constexpr
+ basic_string_view(_Range&& __r)
+ noexcept(noexcept(ranges::size(__r)) && noexcept(ranges::data(__r)))
+ : _M_len(ranges::size(__r)), _M_str(ranges::data(__r))
+ { }
+#endif // C++23
+#endif // C++20
constexpr basic_string_view&
operator=(const basic_string_view&) noexcept = default;
@@ -490,6 +513,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus > 201703L && __cpp_lib_concepts && __cpp_deduction_guides
template<contiguous_iterator _It, sized_sentinel_for<_It> _End>
basic_string_view(_It, _End) -> basic_string_view<iter_value_t<_It>>;
+
+#if __cplusplus > 202002L
+ template<ranges::contiguous_range _Range>
+ basic_string_view(_Range&&)
+ -> basic_string_view<ranges::range_value_t<_Range>>;
+#endif
#endif
// [string.view.comparison], non-member basic_string_view comparison function
new file mode 100644
@@ -0,0 +1,170 @@
+// Copyright (C) 2021 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++23" }
+// { dg-do run { target c++23 } }
+
+#include <string_view>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ struct R
+ {
+ const char* begin() const
+ { return str; }
+
+ const char* end() const
+ { return str + std::char_traits<char>::length(str); }
+
+ const char* str = "Home on the range";
+ };
+
+ R r;
+ std::string_view s = r;
+ VERIFY( s == r.str );
+ VERIFY( s.data() == std::ranges::data(r) );
+ VERIFY( s.size() == std::ranges::size(r) );
+
+ struct R2 : R
+ {
+ using R::begin;
+ using R::end;
+ operator std::string_view() const { return "Out of range"; }
+ };
+ static_assert( std::ranges::contiguous_range<R2> );
+ static_assert( std::ranges::sized_range<R2> );
+ R2 r2;
+ std::string_view s2 = r2; // uses conversion to string_view
+ VERIFY( s2 == "Out of range" );
+ VERIFY( std::string_view(const_cast<const R2&>(r2)) == s2 );
+
+ struct R3 : R
+ {
+ using R::begin;
+ using R::end;
+ operator const char*() { return "Orange"; }
+ };
+ static_assert( std::ranges::contiguous_range<R3> );
+ static_assert( std::ranges::sized_range<R3> );
+ R3 r3;
+ std::string_view s3(r3); // uses conversion to const char*
+ VERIFY( s3 == "Orange" );
+ s3 = std::string_view(const_cast<const R3&>(r3)); // uses range constructor
+ VERIFY( s3 == "Home on the range" );
+
+ struct R4 : R
+ {
+ using R::begin;
+ using R::end;
+ operator std::string_view() { return "Strange"; }
+ };
+ static_assert( std::ranges::contiguous_range<R4> );
+ static_assert( std::ranges::sized_range<R4> );
+ R4 r4;
+ std::string_view s4 = r4; // Uses conversion to string_view
+ VERIFY( s4 == "Strange" );
+ // Cannot construct from const R4 because of non-const conversion op:
+ static_assert( ! std::is_constructible_v<std::string_view, const R4&> );
+
+ struct R5 : R
+ {
+ using R::begin;
+ using R::end;
+ operator std::string_view() && { return "Stranger"; }
+ };
+ static_assert( std::ranges::contiguous_range<R5> );
+ static_assert( std::ranges::sized_range<R5> );
+ R5 r5;
+ std::string_view s5 = r5; // Uses range constructor
+ VERIFY( s5 == r5.str );
+ s5 = std::string_view(std::move(r5)); // In C++20 this used conversion op.
+ VERIFY( s5 == r5.str ); // In C++23 it uses range constructor.
+
+ char arr[] = "arrangement\0with\0nulls";
+ std::string_view sa = arr; // Does not use range constructor
+ VERIFY( sa.data() == arr );
+ VERIFY( sa == "arrangement" );
+ VERIFY( std::end(sa) != std::end(arr) );
+}
+
+void
+test02()
+{
+ using V1 = std::basic_string_view<signed char>;
+ // range_value_t<V1> is not the right type
+ static_assert( ! std::is_constructible_v<std::string_view, V1> );
+
+ using V2 = std::basic_string_view<char, __gnu_cxx::char_traits<char>>;
+ // V2::traits_type is not the right type
+ static_assert( ! std::is_constructible_v<std::string_view, V2> );
+
+ struct V3 : V2
+ {
+ private:
+ using V2::traits_type;
+ };
+ // V3::traits_type is not a valid (accessible) type
+ static_assert( std::is_constructible_v<std::string_view, V3> );
+
+ struct V4 : V2
+ {
+ using traits_type = std::string_view::traits_type;
+ };
+ // V4::traits_type is the right type
+ static_assert( std::is_constructible_v<std::string_view, V4> );
+}
+
+void
+test03()
+{
+ struct R
+ {
+ char* begin() { return nullptr; }
+ const char* begin() const noexcept { return nullptr; }
+
+ char* end() { return nullptr; }
+ const char* end() const noexcept { return nullptr; }
+ };
+
+ static_assert( ! noexcept(std::string_view(std::declval<R&>())) );
+ static_assert( noexcept(std::string_view(std::declval<const R&>())) );
+}
+
+void
+test04()
+{
+ struct R
+ {
+ const char* begin() const { return nullptr; }
+ const char* end() const { return nullptr; }
+ };
+
+ R r;
+ std::basic_string_view s = r; // Use deduction guide.
+
+ static_assert( std::is_same_v<decltype(s), std::string_view> );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
new file mode 100644
@@ -0,0 +1,170 @@
+// Copyright (C) 2021 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++23" }
+// { dg-do run { target c++23 } }
+
+#include <string_view>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ struct R
+ {
+ const wchar_t* begin() const
+ { return str; }
+
+ const wchar_t* end() const
+ { return str + std::char_traits<wchar_t>::length(str); }
+
+ const wchar_t* str = L"Home on the range";
+ };
+
+ R r;
+ std::wstring_view s = r;
+ VERIFY( s == r.str );
+ VERIFY( s.data() == std::ranges::data(r) );
+ VERIFY( s.size() == std::ranges::size(r) );
+
+ struct R2 : R
+ {
+ using R::begin;
+ using R::end;
+ operator std::wstring_view() const { return L"Out of range"; }
+ };
+ static_assert( std::ranges::contiguous_range<R2> );
+ static_assert( std::ranges::sized_range<R2> );
+ R2 r2;
+ std::wstring_view s2 = r2; // uses conversion to wstring_view
+ VERIFY( s2 == L"Out of range" );
+ VERIFY( std::wstring_view(const_cast<const R2&>(r2)) == s2 );
+
+ struct R3 : R
+ {
+ using R::begin;
+ using R::end;
+ operator const wchar_t*() { return L"Orange"; }
+ };
+ static_assert( std::ranges::contiguous_range<R3> );
+ static_assert( std::ranges::sized_range<R3> );
+ R3 r3;
+ std::wstring_view s3(r3); // uses conversion to const wchar_t*
+ VERIFY( s3 == L"Orange" );
+ s3 = std::wstring_view(const_cast<const R3&>(r3)); // uses range constructor
+ VERIFY( s3 == L"Home on the range" );
+
+ struct R4 : R
+ {
+ using R::begin;
+ using R::end;
+ operator std::wstring_view() { return L"Strange"; }
+ };
+ static_assert( std::ranges::contiguous_range<R4> );
+ static_assert( std::ranges::sized_range<R4> );
+ R4 r4;
+ std::wstring_view s4 = r4; // Uses conversion to wstring_view
+ VERIFY( s4 == L"Strange" );
+ // Cannot construct from const R4 because of non-const conversion op:
+ static_assert( ! std::is_constructible_v<std::wstring_view, const R4&> );
+
+ struct R5 : R
+ {
+ using R::begin;
+ using R::end;
+ operator std::wstring_view() && { return L"Stranger"; }
+ };
+ static_assert( std::ranges::contiguous_range<R5> );
+ static_assert( std::ranges::sized_range<R5> );
+ R5 r5;
+ std::wstring_view s5 = r5; // Uses range constructor
+ VERIFY( s5 == r5.str );
+ s5 = std::wstring_view(std::move(r5)); // In C++20 this used conversion op.
+ VERIFY( s5 == r5.str ); // In C++23 it uses range constructor.
+
+ wchar_t arr[] = L"arrangement\0with\0nulls";
+ std::wstring_view sa = arr; // Does not use range constructor
+ VERIFY( sa.data() == arr );
+ VERIFY( sa == L"arrangement" );
+ VERIFY( std::end(sa) != std::end(arr) );
+}
+
+void
+test02()
+{
+ using V1 = std::basic_string_view<char>;
+ // range_value_t<V1> is not the right type
+ static_assert( ! std::is_constructible_v<std::wstring_view, V1> );
+
+ using V2 = std::basic_string_view<wchar_t, __gnu_cxx::char_traits<wchar_t>>;
+ // V2::traits_type is not the right type
+ static_assert( ! std::is_constructible_v<std::wstring_view, V2> );
+
+ struct V3 : V2
+ {
+ private:
+ using V2::traits_type;
+ };
+ // V3::traits_type is not a valid (accessible) type
+ static_assert( std::is_constructible_v<std::wstring_view, V3> );
+
+ struct V4 : V2
+ {
+ using traits_type = std::wstring_view::traits_type;
+ };
+ // V4::traits_type is the right type
+ static_assert( std::is_constructible_v<std::wstring_view, V4> );
+}
+
+void
+test03()
+{
+ struct R
+ {
+ wchar_t* begin() { return nullptr; }
+ const wchar_t* begin() const noexcept { return nullptr; }
+
+ wchar_t* end() { return nullptr; }
+ const wchar_t* end() const noexcept { return nullptr; }
+ };
+
+ static_assert( ! noexcept(std::wstring_view(std::declval<R&>())) );
+ static_assert( noexcept(std::wstring_view(std::declval<const R&>())) );
+}
+
+void
+test04()
+{
+ struct R
+ {
+ const wchar_t* begin() const { return nullptr; }
+ const wchar_t* end() const { return nullptr; }
+ };
+
+ R r;
+ std::basic_string_view s = r; // Use deduction guide.
+
+ static_assert( std::is_same_v<decltype(s), std::wstring_view> );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}