aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2021-06-15 16:36:12 +0100
committerJonathan Wakely <jwakely@redhat.com>2021-06-15 18:20:06 +0100
commit9245b0e84c262cc5fd8373e94de3d23a3807b122 (patch)
treeb51e2c58f09b4ad71afc31ce2858c7e9fc64a8f8
parenta88fc03ba7e52d9a072f25d42bb9619fedb7892e (diff)
downloadgcc-9245b0e84c262cc5fd8373e94de3d23a3807b122.zip
gcc-9245b0e84c262cc5fd8373e94de3d23a3807b122.tar.gz
gcc-9245b0e84c262cc5fd8373e94de3d23a3807b122.tar.bz2
libstdc++: Add noexcept specifiers to some range adaptors
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.
-rw-r--r--libstdc++-v3/include/bits/ranges_util.h63
-rw-r--r--libstdc++-v3/include/std/ranges18
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/all.cc30
-rw-r--r--libstdc++-v3/testsuite/std/ranges/single_view.cc24
4 files changed, 119 insertions, 16 deletions
diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h
index 02561ee..dd829ed 100644
--- a/libstdc++-v3/include/bits/ranges_util.h
+++ b/libstdc++-v3/include/bits/ranges_util.h
@@ -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}
{ }
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 220a44e..b294349 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -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);
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc
index 42913ad..9a6a31e 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc
@@ -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();
}
diff --git a/libstdc++-v3/testsuite/std/ranges/single_view.cc b/libstdc++-v3/testsuite/std/ranges/single_view.cc
index f530cc0..c036fc89 100644
--- a/libstdc++-v3/testsuite/std/ranges/single_view.cc
+++ b/libstdc++-v3/testsuite/std/ranges/single_view.cc
@@ -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();
}