]> gcc.gnu.org Git - gcc.git/commitdiff
libstdc++: Add noexcept specifiers to some range adaptors
authorJonathan Wakely <jwakely@redhat.com>
Tue, 15 Jun 2021 15:36:12 +0000 (16:36 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Tue, 15 Jun 2021 17:20:06 +0000 (18:20 +0100)
Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
libstdc++-v3/ChangeLog:

* include/bits/ranges_util.h (view_interface): Add noexcept to
empty, operator bool, data and size members.
(subrange): Add noexcept to constructors.
* include/std/ranges (single_view, ref_view): Add noexcept to
constructors.
(views::single, views::all): Add noexcept.
* testsuite/std/ranges/adaptors/all.cc: Check noexcept.
* testsuite/std/ranges/single_view.cc: Likewise.

libstdc++-v3/include/bits/ranges_util.h
libstdc++-v3/include/std/ranges
libstdc++-v3/testsuite/std/ranges/adaptors/all.cc
libstdc++-v3/testsuite/std/ranges/single_view.cc

index 02561ee63f96da828e8996264625371d262dbcfd..dd829ed957fc68998e99f7330629fa913401e103 100644 (file)
@@ -77,45 +77,67 @@ namespace ranges
        return static_cast<const _Derived&>(*this);
       }
 
+      static constexpr bool
+      _S_bool(bool) noexcept; // not defined
+
+      template<typename _Tp>
+       static constexpr bool
+       _S_empty(_Tp& __t)
+       noexcept(noexcept(_S_bool(ranges::begin(__t) == ranges::end(__t))))
+       { return ranges::begin(__t) == ranges::end(__t); }
+
+      template<typename _Tp>
+       static constexpr auto
+       _S_size(_Tp& __t)
+       noexcept(noexcept(ranges::end(__t) - ranges::begin(__t)))
+       { return ranges::end(__t) - ranges::begin(__t); }
+
     public:
       constexpr bool
-      empty() requires forward_range<_Derived>
-      { return ranges::begin(_M_derived()) == ranges::end(_M_derived()); }
+      empty()
+      noexcept(noexcept(_S_empty(_M_derived())))
+      requires forward_range<_Derived>
+      { return _S_empty(_M_derived()); }
 
       constexpr bool
-      empty() const requires forward_range<const _Derived>
-      { return ranges::begin(_M_derived()) == ranges::end(_M_derived()); }
+      empty() const
+      noexcept(noexcept(_S_empty(_M_derived())))
+      requires forward_range<const _Derived>
+      { return _S_empty(_M_derived()); }
 
       constexpr explicit
-      operator bool() requires requires { ranges::empty(_M_derived()); }
+      operator bool() noexcept(noexcept(ranges::empty(_M_derived())))
+      requires requires { ranges::empty(_M_derived()); }
       { return !ranges::empty(_M_derived()); }
 
       constexpr explicit
-      operator bool() const requires requires { ranges::empty(_M_derived()); }
+      operator bool() const noexcept(noexcept(ranges::empty(_M_derived())))
+      requires requires { ranges::empty(_M_derived()); }
       { return !ranges::empty(_M_derived()); }
 
       constexpr auto
-      data() requires contiguous_iterator<iterator_t<_Derived>>
-      { return to_address(ranges::begin(_M_derived())); }
+      data() noexcept(noexcept(ranges::begin(_M_derived())))
+      requires contiguous_iterator<iterator_t<_Derived>>
+      { return std::to_address(ranges::begin(_M_derived())); }
 
       constexpr auto
-      data() const
+      data() const noexcept(noexcept(ranges::begin(_M_derived())))
       requires range<const _Derived>
        && contiguous_iterator<iterator_t<const _Derived>>
-      { return to_address(ranges::begin(_M_derived())); }
+      { return std::to_address(ranges::begin(_M_derived())); }
 
       constexpr auto
-      size()
+      size() noexcept(noexcept(_S_size(_M_derived())))
       requires forward_range<_Derived>
        && sized_sentinel_for<sentinel_t<_Derived>, iterator_t<_Derived>>
-      { return ranges::end(_M_derived()) - ranges::begin(_M_derived()); }
+      { return _S_size(_M_derived()); }
 
       constexpr auto
-      size() const
+      size() const noexcept(noexcept(_S_size(_M_derived())))
       requires forward_range<const _Derived>
        && sized_sentinel_for<sentinel_t<const _Derived>,
                              iterator_t<const _Derived>>
-      { return ranges::end(_M_derived()) - ranges::begin(_M_derived()); }
+      { return _S_size(_M_derived()); }
 
       constexpr decltype(auto)
       front() requires forward_range<_Derived>
@@ -223,6 +245,8 @@ namespace ranges
 
       constexpr
       subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s)
+      noexcept(is_nothrow_constructible_v<_It, decltype(__i)>
+              && is_nothrow_constructible_v<_Sent, _Sent&>)
        requires (!_S_store_size)
       : _M_begin(std::move(__i)), _M_end(__s)
       { }
@@ -230,6 +254,8 @@ namespace ranges
       constexpr
       subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s,
               __size_type __n)
+      noexcept(is_nothrow_constructible_v<_It, decltype(__i)>
+              && is_nothrow_constructible_v<_Sent, _Sent&>)
        requires (_Kind == subrange_kind::sized)
       : _M_begin(std::move(__i)), _M_end(__s)
       {
@@ -242,7 +268,9 @@ namespace ranges
          && __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It>
          && convertible_to<sentinel_t<_Rng>, _Sent>
        constexpr
-       subrange(_Rng&& __r) requires _S_store_size && sized_range<_Rng>
+       subrange(_Rng&& __r)
+       noexcept(noexcept(subrange(__r, ranges::size(__r))))
+       requires _S_store_size && sized_range<_Rng>
        : subrange(__r, ranges::size(__r))
        { }
 
@@ -251,7 +279,9 @@ namespace ranges
          && __detail::__convertible_to_non_slicing<iterator_t<_Rng>, _It>
          && convertible_to<sentinel_t<_Rng>, _Sent>
        constexpr
-       subrange(_Rng&& __r) requires (!_S_store_size)
+       subrange(_Rng&& __r)
+       noexcept(noexcept(subrange(ranges::begin(__r), ranges::end(__r))))
+       requires (!_S_store_size)
        : subrange(ranges::begin(__r), ranges::end(__r))
        { }
 
@@ -260,6 +290,7 @@ namespace ranges
          && convertible_to<sentinel_t<_Rng>, _Sent>
        constexpr
        subrange(_Rng&& __r, __size_type __n)
+       noexcept(noexcept(subrange(ranges::begin(__r), ranges::end(__r), __n)))
        requires (_Kind == subrange_kind::sized)
        : subrange{ranges::begin(__r), ranges::end(__r), __n}
        { }
index 220a44e11a824a7270db5db192fb44644ba80fa9..b2943490e31ce31bf7f63f06b399e2e762d42407 100644 (file)
@@ -197,11 +197,13 @@ namespace ranges
 
       constexpr explicit
       single_view(const _Tp& __t)
+      noexcept(is_nothrow_copy_constructible_v<_Tp>)
       : _M_value(__t)
       { }
 
       constexpr explicit
       single_view(_Tp&& __t)
+      noexcept(is_nothrow_move_constructible_v<_Tp>)
       : _M_value(std::move(__t))
       { }
 
@@ -211,6 +213,7 @@ namespace ranges
        requires constructible_from<_Tp, _Args...>
        constexpr explicit
        single_view(in_place_t, _Args&&... __args)
+       noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
        : _M_value{in_place, std::forward<_Args>(__args)...}
        { }
 
@@ -604,6 +607,7 @@ namespace views
     template<typename _Tp>
       constexpr auto
       operator()(_Tp&& __e) const
+      noexcept(noexcept(single_view<decay_t<_Tp>>(std::forward<_Tp>(__e))))
       { return single_view<decay_t<_Tp>>(std::forward<_Tp>(__e)); }
   };
 
@@ -1022,6 +1026,7 @@ namespace views::__adaptor
          && requires { _S_fun(declval<_Tp>()); }
        constexpr
        ref_view(_Tp&& __t)
+       noexcept(noexcept(static_cast<_Range&>(std::declval<_Tp>())))
          : _M_r(std::__addressof(static_cast<_Range&>(std::forward<_Tp>(__t))))
        { }
 
@@ -1069,12 +1074,25 @@ namespace views::__adaptor
 
     struct _All : __adaptor::_RangeAdaptorClosure
     {
+      template<typename _Range>
+       static constexpr bool
+       _S_noexcept()
+       {
+         if constexpr (view<decay_t<_Range>>)
+           return is_nothrow_constructible_v<decay_t<_Range>, _Range>;
+         else if constexpr (__detail::__can_ref_view<_Range>)
+           return true;
+         else
+           return noexcept(subrange{std::declval<_Range>()});
+       }
+
       template<viewable_range _Range>
        requires view<decay_t<_Range>>
          || __detail::__can_ref_view<_Range>
          || __detail::__can_subrange<_Range>
        constexpr auto
        operator()(_Range&& __r) const
+       noexcept(_S_noexcept<_Range>())
        {
          if constexpr (view<decay_t<_Range>>)
            return std::forward<_Range>(__r);
index 42913ad38a303ce89cb97beca01d2ff3c673ae5f..9a6a31e6cb40985c2d50cdc3a833d8130a1b6f3e 100644 (file)
@@ -130,6 +130,35 @@ test05()
   static_assert(!requires { 0 | all; });
 }
 
+template<bool B1, bool B2>
+struct BorrowedRange
+{
+  int* ptr = nullptr;
+
+  BorrowedRange(int (&arr)[3]) noexcept : ptr(arr) { }
+
+  int* begin() const noexcept(B1) { return ptr; }
+  int* end() const noexcept(B2) { return ptr + 3; }
+};
+
+template<bool B1, bool B2>
+const bool std::ranges::enable_borrowed_range<BorrowedRange<B1, B2>> = true;
+
+void
+test06()
+{
+  int x[] { 1, 2, 3 };
+
+  // Using ref_view:
+  static_assert(noexcept(views::all(x)));
+
+  // Using subrange:
+  static_assert(noexcept(views::all(BorrowedRange<true, true>(x))));
+  static_assert(!noexcept(views::all(BorrowedRange<true, false>(x))));
+  static_assert(!noexcept(views::all(BorrowedRange<false, true>(x))));
+  static_assert(!noexcept(views::all(BorrowedRange<false, false>(x))));
+}
+
 int
 main()
 {
@@ -138,4 +167,5 @@ main()
   static_assert(test03());
   static_assert(test04());
   test05();
+  test06();
 }
index f530cc075658c10a87a78768da6701792a8551f8..c036fc8976a3d19495037ff3c6576e32a5ace67a 100644 (file)
@@ -73,10 +73,34 @@ test04()
   std::as_const(s).data();
 }
 
+void
+test05()
+{
+  int i = 0;
+  static_assert(noexcept(std::ranges::single_view<int>()));
+  static_assert(noexcept(std::ranges::single_view<int>(i)));
+  static_assert(noexcept(std::ranges::single_view<int>(1)));
+  static_assert(noexcept(std::ranges::single_view<int>(std::in_place, 2)));
+  static_assert(noexcept(std::ranges::views::single(i)));
+  auto s = std::ranges::views::single(i);
+  static_assert(noexcept(s.begin()));
+  static_assert(noexcept(s.end()));
+  static_assert(noexcept(s.size()));
+  static_assert(noexcept(s.data()));
+  static_assert(noexcept(s.empty())); // view_interface::empty()
+  const auto cs = s;
+  static_assert(noexcept(cs.begin()));
+  static_assert(noexcept(cs.end()));
+  static_assert(noexcept(cs.size()));
+  static_assert(noexcept(cs.data()));
+  static_assert(noexcept(cs.empty())); // view_interface::empty()
+}
+
 int main()
 {
   test01();
   test02();
   test03();
   test04();
+  test05();
 }
This page took 0.061232 seconds and 5 git commands to generate.