diff mbox series

[committed] libstdc++: P1970R2 Consistency for size() functions: Add ranges::ssize

Message ID 20200217183330.GA1574903@redhat.com
State New
Headers show
Series [committed] libstdc++: P1970R2 Consistency for size() functions: Add ranges::ssize | expand

Commit Message

Jonathan Wakely Feb. 17, 2020, 6:33 p.m. UTC
This defines ranges::ssize as approved in Prague. It's unclear what is
supposed to happen for types for which range_difference_t is not a valid
type. I've assumed they are not meant to be usable with ranges::ssize,
despite being usable with ranges::size.

	* include/bits/range_access.h (_SSize, ssize): Define for C++20.
	* testsuite/std/ranges/access/ssize.cc: New test.

Tested powerpc64le-linux, committed to master.
commit 7ab36231a17d8a78f4355289ebbd9d32bb8ede7b
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Feb 17 17:58:09 2020 +0000

    libstdc++: P1970R2 Consistency for size() functions: Add ranges::ssize
    
    This defines ranges::ssize as approved in Prague. It's unclear what is
    supposed to happen for types for which range_difference_t is not a valid
    type. I've assumed they are not meant to be usable with ranges::ssize,
    despite being usable with ranges::size.
    
            * include/bits/range_access.h (_SSize, ssize): Define for C++20.
            * testsuite/std/ranges/access/ssize.cc: New test.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index 8b546a58840..8bac0efc6ed 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -35,6 +35,7 @@ 
 #if __cplusplus >= 201103L
 #include <initializer_list>
 #include <bits/iterator_concepts.h>
+#include <bits/int_limits.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -723,6 +724,32 @@  namespace ranges
 	}
     };
 
+    struct _SSize
+    {
+      template<typename _Tp>
+	requires requires (_Tp&& __e)
+	  {
+	    _Begin{}(std::forward<_Tp>(__e));
+	    _Size{}(std::forward<_Tp>(__e));
+	  }
+	constexpr auto
+	operator()(_Tp&& __e) const
+	noexcept(noexcept(_Size{}(std::forward<_Tp>(__e))))
+	{
+	  using __iter_type = decltype(_Begin{}(std::forward<_Tp>(__e)));
+	  using __diff_type = iter_difference_t<__iter_type>;
+	  using std::__detail::__int_limits;
+	  auto __size = _Size{}(std::forward<_Tp>(__e));
+	  if constexpr (integral<__diff_type>)
+	    {
+	      if constexpr (__int_limits<__diff_type>::digits
+			    < __int_limits<ptrdiff_t>::digits)
+		return static_cast<ptrdiff_t>(__size);
+	    }
+	  return static_cast<__diff_type>(__size);
+	}
+    };
+
     template<typename _Tp>
       concept __member_empty = requires(_Tp&& __t)
 	{ bool(std::forward<_Tp>(__t).empty()); };
@@ -834,6 +861,7 @@  namespace ranges
     inline constexpr __cust_access::_CRBegin crbegin{};
     inline constexpr __cust_access::_CREnd crend{};
     inline constexpr __cust_access::_Size size{};
+    inline constexpr __cust_access::_SSize ssize{};
     inline constexpr __cust_access::_Empty empty{};
     inline constexpr __cust_access::_Data data{};
     inline constexpr __cust_access::_CData cdata{};
diff --git a/libstdc++-v3/testsuite/std/ranges/access/ssize.cc b/libstdc++-v3/testsuite/std/ranges/access/ssize.cc
new file mode 100644
index 00000000000..5aa05be8f20
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/access/ssize.cc
@@ -0,0 +1,98 @@ 
+// Copyright (C) 2020 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++2a" }
+// { dg-do run { target c++2a } }
+
+#include <ranges>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using std::ptrdiff_t;
+
+void
+test01()
+{
+  constexpr int a[10] = { };
+  static_assert( std::same_as<decltype(std::ranges::ssize(a)), ptrdiff_t> );
+  static_assert( std::ranges::ssize(a) == 10 );
+  static_assert( noexcept(std::ranges::ssize(a)) );
+
+  int a2[2];
+  static_assert( std::same_as<decltype(std::ranges::ssize(a2)), ptrdiff_t> );
+  VERIFY( std::ranges::ssize(a2) == 2);
+  static_assert( noexcept(std::ranges::ssize(a2)) );
+
+  struct Incomplete;
+  using A = Incomplete[2]; // bounded array of incomplete type
+  extern A& f();
+  static_assert( std::same_as<decltype(std::ranges::ssize(f())), ptrdiff_t> );
+}
+
+void
+test02()
+{
+  int a[3] = { };
+  __gnu_test::test_sized_range<int, __gnu_test::input_iterator_wrapper> ri(a);
+  VERIFY( std::ranges::ssize(ri) == 3 );
+  static_assert( noexcept(std::ranges::ssize(ri)) );
+}
+
+void
+test04()
+{
+  int a[] = { 0, 1 };
+  __gnu_test::test_range<int, __gnu_test::random_access_iterator_wrapper> r(a);
+  VERIFY( std::ranges::ssize(r) == std::ranges::end(r) - std::ranges::begin(r) );
+}
+
+struct R5
+{
+  int size() const noexcept { return 0; }
+  R5* begin() { return this; }
+  R5* end() { return this + 1; }
+};
+
+template<>
+constexpr bool std::ranges::disable_sized_range<R5> = true;
+
+void
+test05()
+{
+  R5 r;
+  VERIFY( std::ranges::ssize(r) == 1 );
+}
+
+void
+test06()
+{
+  auto i = std::views::iota(1ull, 5);
+  auto s = std::ranges::ssize(i);
+  using R = std::ranges::range_difference_t<decltype(i)>;
+  static_assert( std::same_as<decltype(s), R> );
+  VERIFY( s == 4 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test04();
+  test05();
+  test06();
+}