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.
This commit is contained in:
parent
a88fc03ba7
commit
9245b0e84c
4 changed files with 119 additions and 16 deletions
|
@ -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}
|
||||
{ }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue