[committed] libstdc++: Implement string_view range constructor for C++23

Jonathan Wakely jwakely@redhat.com
Mon Mar 22 23:16:58 GMT 2021


This implements the new string_view constructor proposed by P1989R2.
This hasn't been voted into the C++23 draft yet, but it's been reviewed
by LWG and is expected to be approved at the next WG21 meeting.

libstdc++-v3/ChangeLog:

	* include/std/string_view (basic_string_view(Range&&)): Define new
	constructor and deduction guide.
	* testsuite/21_strings/basic_string_view/cons/char/range_c++20.cc: New test.
	* testsuite/21_strings/basic_string_view/cons/wchar_t/range_c++20.cc: New test.

Tested powerpc64le-linux. Committed to trunk.

(I wrote "C++20" in the commit log summary but it's a C++23 feature,
which is why I'm confortable pushing it now in stage 4.)



-------------- next part --------------
commit 7c1006135ddeab216f376adc5f6135a22bfc0ff6
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Mar 22 17:11:21 2021

    libstdc++: Implement string_view range constructor for C++20
    
    This implements the new string_view constructor proposed by P1989R2.
    This hasn't been voted into the C++23 draft yet, but it's been reviewed
    by LWG and is expected to be approved at the next WG21 meeting.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/string_view (basic_string_view(Range&&)): Define new
            constructor and deduction guide.
            * testsuite/21_strings/basic_string_view/cons/char/range_c++20.cc: New test.
            * testsuite/21_strings/basic_string_view/cons/wchar_t/range_c++20.cc: New test.

diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index dba757fad6b..31502f7d58d 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -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
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/char/range_c++20.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/char/range_c++20.cc
new file mode 100644
index 00000000000..fa85f1994c9
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/char/range_c++20.cc
@@ -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();
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/wchar_t/range_c++20.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/wchar_t/range_c++20.cc
new file mode 100644
index 00000000000..cf73ae36a60
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/wchar_t/range_c++20.cc
@@ -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();
+}


More information about the Gcc-patches mailing list