[ranges] Implement some range concepts (#389)

P1456R1 Move-Only Views
P1870R1 safe_range
This commit is contained in:
Michael Schellenberger Costa 2019-12-17 06:58:58 +01:00 коммит произвёл Stephan T. Lavavej
Родитель 47881a869f
Коммит 4aaa0135d9
4 изменённых файлов: 81 добавлений и 92 удалений

Просмотреть файл

@ -28,6 +28,10 @@ namespace ranges {
// CONCEPT ranges::common_range
template <class _Rng>
concept common_range = range<_Rng> && same_as<iterator_t<_Rng>, sentinel_t<_Rng>>;
// CONCEPT ranges::viewable_range
template <class _Rng>
concept viewable_range = range<_Rng> && (safe_range<_Rng> || view<remove_cvref_t<_Rng>>);
// clang-format on
} // namespace ranges
_STD_END

Просмотреть файл

@ -1204,17 +1204,6 @@ public:
#endif // _ITERATOR_DEBUG_LEVEL
}
#ifdef __cpp_lib_concepts
_NODISCARD friend constexpr const_iterator begin(basic_string_view _Right) noexcept {
// non-member overload to model the exposition-only forwarding-range concept
return _Right.begin();
}
_NODISCARD friend constexpr const_iterator end(basic_string_view _Right) noexcept {
// Ditto modeling forwarding-range
return _Right.end();
}
#endif // __cpp_lib_concepts
_NODISCARD constexpr const_iterator cbegin() const noexcept {
return begin();
}
@ -1584,6 +1573,12 @@ private:
size_type _Mysize;
};
#ifdef __cpp_lib_concepts
namespace ranges {
template <class _Elem, class _Traits>
inline constexpr bool enable_safe_range<basic_string_view<_Elem, _Traits>> = true;
} // namespace ranges
#endif // __cpp_lib_concepts
// FUNCTION TEMPLATES operator== FOR basic_string_view
template <class _Elem, class _Traits>

Просмотреть файл

@ -2072,6 +2072,13 @@ _NODISCARD _Ty _Fake_decay_copy(_Ty) noexcept;
// (3) is non-throwing if and only if both conversion from decltype((E)) to T and destruction of T are non-throwing.
namespace ranges {
// VARIABLE TEMPLATE ranges::enable_safe_range
template <class>
inline constexpr bool enable_safe_range = false;
template <class _Rng>
concept _Should_range_access = is_lvalue_reference_v<_Rng> || enable_safe_range<remove_cvref_t<_Rng>>;
// CUSTOMIZATION POINT OBJECT ranges::begin
namespace _Begin {
#ifndef __clang__ // TRANSITION, VSO-895622
@ -2090,8 +2097,8 @@ namespace ranges {
};
template <class _Ty>
concept _Has_ADL = requires(_Ty&& __t) {
{ _Fake_decay_copy(begin(static_cast<_Ty&&>(__t))) } -> input_or_output_iterator;
concept _Has_ADL = requires(_Ty& __t) {
{ _Fake_decay_copy(begin(__t)) } -> input_or_output_iterator;
};
// clang-format on
@ -2101,19 +2108,15 @@ namespace ranges {
template <class _Ty>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
constexpr bool _Is_lvalue = is_lvalue_reference_v<_Ty>;
if constexpr (is_array_v<remove_reference_t<_Ty>>) {
if constexpr (_Is_lvalue) {
return {_St::_Array, true};
}
} else if constexpr (_Is_lvalue && _Has_member<_Ty>) {
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty>().begin()))};
} else if constexpr (_Has_ADL<_Ty>) {
return {_St::_Non_member, noexcept(_Fake_decay_copy(begin(_STD declval<_Ty>())))};
return {_St::_Array, true};
} else if constexpr (_Has_member<_Ty&>) {
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty&>().begin()))};
} else if constexpr (_Has_ADL<_Ty&>) {
return {_St::_Non_member, noexcept(_Fake_decay_copy(begin(_STD declval<_Ty&>())))};
} else {
return {_St::_None};
}
return {_St::_None};
}
template <class _Ty>
@ -2121,7 +2124,7 @@ namespace ranges {
public:
// clang-format off
template <class _Ty>
template <_Should_range_access _Ty>
requires (_Choice<_Ty>._Strategy != _St::_None)
_NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(_Choice<_Ty>._No_throw) {
if constexpr (_Choice<_Ty>._Strategy == _St::_Array) {
@ -2129,7 +2132,7 @@ namespace ranges {
} else if constexpr (_Choice<_Ty>._Strategy == _St::_Member) {
return _Val.begin();
} else if constexpr (_Choice<_Ty>._Strategy == _St::_Non_member) {
return begin(static_cast<_Ty&&>(_Val));
return begin(_Val);
} else {
static_assert(_Always_false<_Ty>, "Should be unreachable");
}
@ -2160,9 +2163,8 @@ namespace ranges {
};
template <class _Ty>
concept _Has_ADL = requires(_Ty&& __t) {
{ _Fake_decay_copy(end(static_cast<_Ty&&>(__t))) } ->
sentinel_for<decltype(_RANGES begin(static_cast<_Ty&&>(__t)))>;
concept _Has_ADL = requires(_Ty& __t) {
{ _Fake_decay_copy(end(__t)) } -> sentinel_for<decltype(_RANGES begin(__t))>;
};
// clang-format on
@ -2172,19 +2174,15 @@ namespace ranges {
template <class _Ty>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
constexpr bool _Is_lvalue = is_lvalue_reference_v<_Ty>;
if constexpr (is_array_v<remove_reference_t<_Ty>>) {
if constexpr (_Is_lvalue) {
return {_St::_Array, true};
}
} else if constexpr (_Is_lvalue && _Has_member<_Ty>) {
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty>().end()))};
} else if constexpr (_Has_ADL<_Ty>) {
return {_St::_Non_member, noexcept(_Fake_decay_copy(end(_STD declval<_Ty>())))};
return {_St::_Array, true};
} else if constexpr (_Has_member<_Ty&>) {
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty&>().end()))};
} else if constexpr (_Has_ADL<_Ty&>) {
return {_St::_Non_member, noexcept(_Fake_decay_copy(end(_STD declval<_Ty&>())))};
} else {
return {_St::_None};
}
return {_St::_None};
}
template <class _Ty>
@ -2192,7 +2190,7 @@ namespace ranges {
public:
// clang-format off
template <class _Ty>
template <_Should_range_access _Ty>
requires (_Choice<_Ty>._Strategy != _St::_None)
_NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(_Choice<_Ty>._No_throw) {
if constexpr (_Choice<_Ty>._Strategy == _St::_Array) {
@ -2200,7 +2198,7 @@ namespace ranges {
} else if constexpr (_Choice<_Ty>._Strategy == _St::_Member) {
return _Val.end();
} else if constexpr (_Choice<_Ty>._Strategy == _St::_Non_member) {
return end(static_cast<_Ty&&>(_Val));
return end(_Val);
} else {
static_assert(_Always_false<_Ty>, "should be unreachable");
}
@ -2215,18 +2213,15 @@ namespace ranges {
// CONCEPT ranges::range
template <class _Rng>
concept _Range_impl = requires(_Rng&& __r) {
_RANGES begin(static_cast<_Rng&&>(__r));
_RANGES end(static_cast<_Rng&&>(__r));
concept range = requires(_Rng& __r) {
_RANGES begin(__r);
_RANGES end(__r);
};
template <class _Rng>
concept range = _Range_impl<_Rng&>;
// CONCEPT ranges::_Forwarding_range
// CONCEPT ranges::safe_range
// clang-format off
template <class _Rng>
concept _Forwarding_range = range<_Rng> && _Range_impl<_Rng>;
concept safe_range = range<_Rng> && _Should_range_access<_Rng>;
// clang-format on
// ALIAS TEMPLATE ranges::iterator_t
@ -2298,19 +2293,19 @@ namespace ranges {
// clang-format off
template <class _Ty>
concept _Has_member = is_lvalue_reference_v<_Ty> && requires(_Ty& __t) {
concept _Has_member = requires(_Ty& __t) {
{ _Fake_decay_copy(__t.rbegin()) } -> input_or_output_iterator;
};
template <class _Ty>
concept _Has_ADL = requires(_Ty&& __t) {
{ _Fake_decay_copy(rbegin(static_cast<_Ty&&>(__t))) } -> input_or_output_iterator;
concept _Has_ADL = requires(_Ty& __t) {
{ _Fake_decay_copy(rbegin(__t)) } -> input_or_output_iterator;
};
template <class _Ty>
concept _Can_make_reverse = requires(_Ty&& __t) {
{ _RANGES begin(static_cast<_Ty&&>(__t)) } -> bidirectional_iterator;
{ _RANGES end(static_cast<_Ty&&>(__t)) } -> same_as<decltype(_RANGES begin(static_cast<_Ty&&>(__t)))>;
concept _Can_make_reverse = requires(_Ty& __t) {
{ _RANGES begin(__t) } -> bidirectional_iterator;
{ _RANGES end(__t) } -> same_as<decltype(_RANGES begin(__t))>;
};
// clang-format on
@ -2320,12 +2315,13 @@ namespace ranges {
template <class _Ty>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
if constexpr (_Has_member<_Ty>) {
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty>().rbegin()))};
} else if constexpr (_Has_ADL<_Ty>) {
return {_St::_Non_member, noexcept(_Fake_decay_copy(rbegin(_STD declval<_Ty>())))};
} else if constexpr (_Can_make_reverse<_Ty>) {
return {_St::_Make_reverse, noexcept(_STD make_reverse_iterator(_RANGES end(_STD declval<_Ty>())))};
if constexpr (_Has_member<_Ty&>) {
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty&>().rbegin()))};
} else if constexpr (_Has_ADL<_Ty&>) {
return {_St::_Non_member, noexcept(_Fake_decay_copy(rbegin(_STD declval<_Ty&>())))};
} else if constexpr (_Can_make_reverse<_Ty&>) {
return {
_St::_Make_reverse, noexcept(_STD make_reverse_iterator(_RANGES end(_STD declval<_Ty&>())))};
} else {
return {_St::_None};
}
@ -2336,15 +2332,15 @@ namespace ranges {
public:
// clang-format off
template <class _Ty>
template <_Should_range_access _Ty>
requires (_Choice<_Ty>._Strategy != _St::_None)
_NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(_Choice<_Ty>._No_throw) {
if constexpr (_Choice<_Ty>._Strategy == _St::_Member) {
return _Val.rbegin();
} else if constexpr (_Choice<_Ty>._Strategy == _St::_Non_member) {
return rbegin(static_cast<_Ty&&>(_Val));
return rbegin(_Val);
} else if constexpr (_Choice<_Ty>._Strategy == _St::_Make_reverse) {
return _STD make_reverse_iterator(_RANGES end(static_cast<_Ty&&>(_Val)));
return _STD make_reverse_iterator(_RANGES end(_Val));
} else {
static_assert(_Always_false<_Ty>, "should be unreachable");
}
@ -2370,25 +2366,19 @@ namespace ranges {
// clang-format off
template <class _Ty>
concept _Can_rbegin = requires(_Ty&& __t) {
_RANGES rbegin(static_cast<_Ty&&>(__t));
};
template <class _Ty>
concept _Has_member = is_lvalue_reference_v<_Ty> && requires(_Ty& __t) {
concept _Has_member = requires(_Ty& __t) {
{ _Fake_decay_copy(__t.rend()) } -> sentinel_for<decltype(_RANGES rbegin(__t))>;
};
template <class _Ty>
concept _Has_ADL = requires(_Ty&& __t) {
{ _Fake_decay_copy(rend(static_cast<_Ty&&>(__t))) } ->
sentinel_for<decltype(_RANGES rbegin(static_cast<_Ty&&>(__t)))>;
concept _Has_ADL = requires(_Ty& __t) {
{ _Fake_decay_copy(rend(__t)) } -> sentinel_for<decltype(_RANGES rbegin(__t))>;
};
template <class _Ty>
concept _Can_make_reverse = requires(_Ty&& __t) {
{ _RANGES begin(static_cast<_Ty&&>(__t)) } -> bidirectional_iterator;
{ _RANGES end(static_cast<_Ty&&>(__t)) } -> same_as<decltype(_RANGES begin(static_cast<_Ty&&>(__t)))>;
concept _Can_make_reverse = requires(_Ty& __t) {
{ _RANGES begin(__t) } -> bidirectional_iterator;
{ _RANGES end(__t) } -> same_as<decltype(_RANGES begin(__t))>;
};
// clang-format on
@ -2398,18 +2388,16 @@ namespace ranges {
template <class _Ty>
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
if constexpr (_Can_rbegin<_Ty>) {
if constexpr (_Has_member<_Ty>) {
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty>().rend()))};
} else if constexpr (_Has_ADL<_Ty>) {
return {_St::_Non_member, noexcept(_Fake_decay_copy(rend(_STD declval<_Ty>())))};
} else if constexpr (_Can_make_reverse<_Ty>) {
return {_St::_Make_reverse,
noexcept(_STD make_reverse_iterator(_RANGES begin(_STD declval<_Ty>())))};
}
if constexpr (_Has_member<_Ty&>) {
return {_St::_Member, noexcept(_Fake_decay_copy(_STD declval<_Ty&>().rend()))};
} else if constexpr (_Has_ADL<_Ty&>) {
return {_St::_Non_member, noexcept(_Fake_decay_copy(rend(_STD declval<_Ty&>())))};
} else if constexpr (_Can_make_reverse<_Ty&>) {
return {
_St::_Make_reverse, noexcept(_STD make_reverse_iterator(_RANGES begin(_STD declval<_Ty&>())))};
} else {
return {_St::_None};
}
return {_St::_None};
}
template <class _Ty>
@ -2417,15 +2405,15 @@ namespace ranges {
public:
// clang-format off
template <class _Ty>
template <_Should_range_access _Ty>
requires (_Choice<_Ty>._Strategy != _St::_None)
_NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(_Choice<_Ty>._No_throw) {
if constexpr (_Choice<_Ty>._Strategy == _St::_Member) {
return _Val.rend();
} else if constexpr (_Choice<_Ty>._Strategy == _St::_Non_member) {
return rend(static_cast<_Ty&&>(_Val));
return rend(_Val);
} else if constexpr (_Choice<_Ty>._Strategy == _St::_Make_reverse) {
return _STD make_reverse_iterator(_RANGES begin(static_cast<_Ty&&>(_Val)));
return _STD make_reverse_iterator(_RANGES begin(_Val));
} else {
static_assert(_Always_false<_Ty>, "should be unreachable");
}
@ -2719,7 +2707,7 @@ namespace ranges {
// clang-format off
// CONCEPT ranges::view
template <class _Ty>
concept view = range<_Ty> && semiregular<_Ty> && enable_view<_Ty>;
concept view = range<_Ty> && movable<_Ty> && default_initializable<_Ty> && enable_view<_Ty>;
// CONCEPT ranges::output_range
template <class _Rng, class _Ty>

Просмотреть файл

@ -163,10 +163,12 @@
// P1227R2 Signed std::ssize(), Unsigned span::size()
// (partially implemented)
// P1357R1 is_bounded_array, is_unbounded_array
// P1456R1 Move-Only Views
// P1612R1 Relocating endian To <bit>
// P1651R0 bind_front() Should Not Unwrap reference_wrapper
// P1690R1 Refining Heterogeneous Lookup For Unordered Containers
// P1754R1 Rename Concepts To standard_case
// P1870R1 safe_range
// P1959R0 Removing weak_equality And strong_equality
// P????R? directory_entry::clear_cache()