зеркало из https://github.com/microsoft/STL.git
Implement views::all and views::reverse (#1229)
* Implement views:all and views::reverse Also, perma-workaround LLVM-37556. Co-authored-by: Michael Schellenberger Costa <mschellenbergercosta@gmail.com>
This commit is contained in:
Родитель
3b2956b18e
Коммит
e652e72bdf
|
@ -165,9 +165,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Swap
|
} // namespace _Swap
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Swap::_Cpo swap;
|
inline constexpr _Swap::_Cpo swap;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
} // namespace ranges
|
} // namespace ranges
|
||||||
|
|
||||||
// CONCEPT swappable
|
// CONCEPT swappable
|
||||||
|
|
390
stl/inc/ranges
390
stl/inc/ranges
|
@ -33,10 +33,192 @@ namespace ranges {
|
||||||
concept viewable_range = range<_Rng>
|
concept viewable_range = range<_Rng>
|
||||||
&& (borrowed_range<_Rng> || view<remove_cvref_t<_Rng>>);
|
&& (borrowed_range<_Rng> || view<remove_cvref_t<_Rng>>);
|
||||||
|
|
||||||
|
template <class _Rng>
|
||||||
|
concept _Simple_view = view<_Rng> && range<const _Rng>
|
||||||
|
&& same_as<iterator_t<_Rng>, iterator_t<const _Rng>>
|
||||||
|
&& same_as<sentinel_t<_Rng>, sentinel_t<const _Rng>>;
|
||||||
|
|
||||||
template <class _Ty>
|
template <class _Ty>
|
||||||
concept _Copy_constructible_object = copy_constructible<_Ty> && is_object_v<_Ty>;
|
concept _Copy_constructible_object = copy_constructible<_Ty> && is_object_v<_Ty>;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
namespace _Pipe {
|
||||||
|
// clang-format off
|
||||||
|
template <class _Left, class _Right>
|
||||||
|
concept _Can_pipe = requires(_Left&& __l, _Right&& __r) {
|
||||||
|
static_cast<_Right&&>(__r)(static_cast<_Left&&>(__l));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Left, class _Right>
|
||||||
|
concept _Can_compose = constructible_from<remove_cvref_t<_Left>, _Left>
|
||||||
|
&& constructible_from<remove_cvref_t<_Right>, _Right>;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
template <class, class>
|
||||||
|
struct _Pipeline;
|
||||||
|
|
||||||
|
template <class _Derived>
|
||||||
|
struct _Base {
|
||||||
|
// clang-format off
|
||||||
|
template <class _Other>
|
||||||
|
requires _Can_compose<_Derived, _Other>
|
||||||
|
constexpr auto operator|(_Base<_Other>&& __r) && noexcept(
|
||||||
|
noexcept(_Pipeline{static_cast<_Derived&&>(*this), static_cast<_Other&&>(__r)})) {
|
||||||
|
// clang-format on
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
|
||||||
|
return _Pipeline{static_cast<_Derived&&>(*this), static_cast<_Other&&>(__r)};
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
template <class _Other>
|
||||||
|
requires _Can_compose<_Derived, const _Other&>
|
||||||
|
constexpr auto operator|(const _Base<_Other>& __r) && noexcept(noexcept(
|
||||||
|
_Pipeline{static_cast<_Derived&&>(*this), static_cast<const _Other&>(__r)})) {
|
||||||
|
// clang-format on
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
|
||||||
|
return _Pipeline{static_cast<_Derived&&>(*this), static_cast<const _Other&>(__r)};
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
template <class _Other>
|
||||||
|
requires _Can_compose<const _Derived&, _Other>
|
||||||
|
constexpr auto operator|(_Base<_Other>&& __r) const& noexcept(
|
||||||
|
noexcept(_Pipeline{static_cast<const _Derived&>(*this), static_cast<_Other&&>(__r)})) {
|
||||||
|
// clang-format on
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
|
||||||
|
return _Pipeline{static_cast<const _Derived&>(*this), static_cast<_Other&&>(__r)};
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
template <class _Other>
|
||||||
|
requires _Can_compose<const _Derived&, const _Other&>
|
||||||
|
constexpr auto operator|(const _Base<_Other>& __r) const& noexcept(noexcept(
|
||||||
|
_Pipeline{static_cast<const _Derived&>(*this), static_cast<const _Other&>(__r)})) {
|
||||||
|
// clang-format on
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Derived, _Base<_Derived>>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(derived_from<_Other, _Base<_Other>>);
|
||||||
|
return _Pipeline{static_cast<const _Derived&>(*this), static_cast<const _Other&>(__r)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <_Can_pipe<const _Derived&> _Left>
|
||||||
|
friend constexpr auto operator|(_Left&& __l, const _Base& __r) noexcept(
|
||||||
|
noexcept(static_cast<const _Derived&>(__r)(_STD forward<_Left>(__l)))) {
|
||||||
|
return static_cast<const _Derived&>(__r)(_STD forward<_Left>(__l));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <_Can_pipe<_Derived> _Left>
|
||||||
|
friend constexpr auto operator|(_Left&& __l, _Base&& __r) noexcept(
|
||||||
|
noexcept(static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l)))) {
|
||||||
|
return static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Left, class _Right>
|
||||||
|
struct _Pipeline : _Base<_Pipeline<_Left, _Right>> {
|
||||||
|
/* [[no_unique_address]] */ _Left __l;
|
||||||
|
/* [[no_unique_address]] */ _Right __r;
|
||||||
|
|
||||||
|
template <class _Ty1, class _Ty2>
|
||||||
|
constexpr explicit _Pipeline(_Ty1&& _Val1, _Ty2&& _Val2) noexcept(
|
||||||
|
is_nothrow_convertible_v<_Ty1, _Left>&& is_nothrow_convertible_v<_Ty2, _Right>)
|
||||||
|
: __l(_STD forward<_Ty1>(_Val1)), __r(_STD forward<_Ty2>(_Val2)) {}
|
||||||
|
|
||||||
|
template <class _Ty>
|
||||||
|
_NODISCARD constexpr auto operator()(_Ty&& _Val) noexcept(
|
||||||
|
noexcept(__r(__l(_STD forward<_Ty>(_Val))))) requires requires {
|
||||||
|
__r(__l(static_cast<_Ty&&>(_Val)));
|
||||||
|
}
|
||||||
|
{ return __r(__l(_STD forward<_Ty>(_Val))); }
|
||||||
|
|
||||||
|
template <class _Ty>
|
||||||
|
_NODISCARD constexpr auto operator()(_Ty&& _Val) const
|
||||||
|
noexcept(noexcept(__r(__l(_STD forward<_Ty>(_Val))))) requires requires {
|
||||||
|
__r(__l(static_cast<_Ty&&>(_Val)));
|
||||||
|
}
|
||||||
|
{ return __r(__l(_STD forward<_Ty>(_Val))); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Ty1, class _Ty2>
|
||||||
|
_Pipeline(_Ty1, _Ty2) -> _Pipeline<_Ty1, _Ty2>;
|
||||||
|
} // namespace _Pipe
|
||||||
|
|
||||||
|
template <range _Rng, class _Derived>
|
||||||
|
class _Cached_position : public view_interface<_Derived> {
|
||||||
|
static_assert(_Always_false<_Rng>, "A range must be at least forward for position caching to be worthwhile.");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <forward_range _Rng, class _Derived>
|
||||||
|
class _Cached_position<_Rng, _Derived> : public view_interface<_Derived> {
|
||||||
|
private:
|
||||||
|
using _It = iterator_t<_Rng>;
|
||||||
|
|
||||||
|
/* [[no_unique_address]] */ _It _Pos{};
|
||||||
|
bool _Cached = false;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
_Cached_position() = default;
|
||||||
|
~_Cached_position() = default;
|
||||||
|
|
||||||
|
// a copied iterator doesn't point into a copied range, so cache values must not propagate via copy
|
||||||
|
constexpr _Cached_position(const _Cached_position&) noexcept(is_nothrow_default_constructible_v<_It>) {}
|
||||||
|
constexpr _Cached_position& operator=(const _Cached_position&) noexcept(
|
||||||
|
is_nothrow_default_constructible_v<_It>) {
|
||||||
|
_Pos = _It{};
|
||||||
|
_Cached = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD constexpr bool _Has_cache() const noexcept { // Is there a cached position?
|
||||||
|
return _Cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD constexpr _It _Get_cache(_Rng&) const noexcept(is_nothrow_copy_constructible_v<_It>) {
|
||||||
|
_STL_INTERNAL_CHECK(_Cached);
|
||||||
|
return _Pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD constexpr void _Set_cache(_Rng&, _It _Iter) noexcept(is_nothrow_move_assignable_v<_It>) {
|
||||||
|
_Pos = _STD move(_Iter);
|
||||||
|
_Cached = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <random_access_range _Rng, class _Derived>
|
||||||
|
class _Cached_position<_Rng, _Derived> : public view_interface<_Derived> {
|
||||||
|
private:
|
||||||
|
using _It = iterator_t<_Rng>;
|
||||||
|
|
||||||
|
range_difference_t<_Rng> _Off = -1;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
_Cached_position() = default;
|
||||||
|
~_Cached_position() = default;
|
||||||
|
|
||||||
|
// Offsets are oblivious to copying, so cache values _do_ propagate via copying.
|
||||||
|
_Cached_position(const _Cached_position&) = default;
|
||||||
|
_Cached_position& operator=(const _Cached_position&) = default;
|
||||||
|
|
||||||
|
_NODISCARD constexpr bool _Has_cache() const noexcept { // Is there a cached position?
|
||||||
|
return _Off >= range_difference_t<_Rng>{0};
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD constexpr _It _Get_cache(_Rng& _Range) const noexcept(noexcept(_RANGES begin(_Range) + _Off)) {
|
||||||
|
_STL_INTERNAL_CHECK(_Has_cache());
|
||||||
|
return _RANGES begin(_Range) + _Off;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD constexpr void _Set_cache(_Rng& _Range, const _It& _Iter) noexcept(
|
||||||
|
noexcept(_Off = _Iter - _RANGES begin(_Range))) {
|
||||||
|
_Off = _Iter - _RANGES begin(_Range);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool _Enable, class _Rng, class _Derived>
|
||||||
|
using _Cached_position_t = conditional_t<_Enable, _Cached_position<_Rng, _Derived>, view_interface<_Derived>>;
|
||||||
|
|
||||||
// CLASS TEMPLATE ranges::_Semiregular_box
|
// CLASS TEMPLATE ranges::_Semiregular_box
|
||||||
#if 0 // TRANSITION, VSO-1174090
|
#if 0 // TRANSITION, VSO-1174090
|
||||||
template <_Copy_constructible_object _Ty>
|
template <_Copy_constructible_object _Ty>
|
||||||
|
@ -417,10 +599,10 @@ namespace ranges {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
template <class _Ty>
|
template <class _Ty>
|
||||||
_NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(
|
_NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(
|
||||||
noexcept(single_view{static_cast<_Ty&&>(_Val)})) requires requires {
|
noexcept(single_view{_STD forward<_Ty>(_Val)})) requires requires {
|
||||||
single_view{static_cast<_Ty&&>(_Val)};
|
single_view{static_cast<_Ty&&>(_Val)};
|
||||||
} {
|
} {
|
||||||
return single_view{static_cast<_Ty&&>(_Val)};
|
return single_view{_STD forward<_Ty>(_Val)};
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
@ -486,6 +668,210 @@ namespace ranges {
|
||||||
|
|
||||||
template <class _Rng>
|
template <class _Rng>
|
||||||
inline constexpr bool enable_borrowed_range<ref_view<_Rng>> = true;
|
inline constexpr bool enable_borrowed_range<ref_view<_Rng>> = true;
|
||||||
|
|
||||||
|
namespace views {
|
||||||
|
// VARIABLE views::all
|
||||||
|
template <class _Rng>
|
||||||
|
concept _Can_ref_view = requires(_Rng&& __r) {
|
||||||
|
ref_view{static_cast<_Rng&&>(__r)};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Rng>
|
||||||
|
concept _Can_subrange = requires(_Rng&& __r) {
|
||||||
|
subrange{static_cast<_Rng&&>(__r)};
|
||||||
|
};
|
||||||
|
|
||||||
|
class _All_fn : public _Pipe::_Base<_All_fn> {
|
||||||
|
private:
|
||||||
|
enum class _St { _None, _View, _Ref, _Subrange };
|
||||||
|
|
||||||
|
template <class _Rng>
|
||||||
|
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
|
||||||
|
if constexpr (view<remove_cvref_t<_Rng>>) {
|
||||||
|
if constexpr (constructible_from<remove_cvref_t<_Rng>, _Rng>) {
|
||||||
|
return {_St::_View, is_nothrow_constructible_v<remove_cvref_t<_Rng>, _Rng>};
|
||||||
|
}
|
||||||
|
} else if constexpr (_Can_ref_view<_Rng>) {
|
||||||
|
return {_St::_Ref, noexcept(ref_view{_STD declval<_Rng>()})};
|
||||||
|
} else if constexpr (_Can_subrange<_Rng>) {
|
||||||
|
return {_St::_Subrange, noexcept(subrange{_STD declval<_Rng>()})};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {_St::_None};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Rng>
|
||||||
|
static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// clang-format off
|
||||||
|
template <viewable_range _Rng>
|
||||||
|
requires (_Choice<_Rng>._Strategy != _St::_None)
|
||||||
|
_NODISCARD constexpr auto operator()(_Rng&& _Range) const noexcept(_Choice<_Rng>._No_throw) {
|
||||||
|
// clang-format on
|
||||||
|
if constexpr (_Choice<_Rng>._Strategy == _St::_View) {
|
||||||
|
return _STD forward<_Rng>(_Range);
|
||||||
|
} else if constexpr (_Choice<_Rng>._Strategy == _St::_Ref) {
|
||||||
|
return ref_view{_STD forward<_Rng>(_Range)};
|
||||||
|
} else if constexpr (_Choice<_Rng>._Strategy == _St::_Subrange) {
|
||||||
|
return subrange{_STD forward<_Rng>(_Range)};
|
||||||
|
} else {
|
||||||
|
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr _All_fn all;
|
||||||
|
|
||||||
|
// ALIAS TEMPLATE views::all_t
|
||||||
|
template <viewable_range _Rng>
|
||||||
|
using all_t = decltype(all(_STD declval<_Rng>()));
|
||||||
|
} // namespace views
|
||||||
|
|
||||||
|
// CLASS TEMPLATE ranges::reverse_view
|
||||||
|
// clang-format off
|
||||||
|
template <view _Vw>
|
||||||
|
requires bidirectional_range<_Vw>
|
||||||
|
class reverse_view : public _Cached_position_t<!common_range<_Vw>, _Vw, reverse_view<_Vw>> {
|
||||||
|
// clang-format on
|
||||||
|
private:
|
||||||
|
/* [[no_unique_address]] */ _Vw _Base{};
|
||||||
|
|
||||||
|
template <class _Rng>
|
||||||
|
using _Rev_iter = reverse_iterator<iterator_t<_Rng>>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
reverse_view() = default;
|
||||||
|
constexpr explicit reverse_view(_Vw _Base_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
|
||||||
|
: _Base(_STD move(_Base_)) {}
|
||||||
|
|
||||||
|
_NODISCARD constexpr _Vw base() const& noexcept(
|
||||||
|
is_nothrow_copy_constructible_v<_Vw>) /* strengthened */ requires copy_constructible<_Vw> {
|
||||||
|
return _Base;
|
||||||
|
}
|
||||||
|
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
|
||||||
|
return _STD move(_Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD constexpr _Rev_iter<_Vw> begin() {
|
||||||
|
if constexpr (common_range<_Vw>) {
|
||||||
|
return _Rev_iter<_Vw>{_RANGES end(_Base)};
|
||||||
|
} else {
|
||||||
|
if (this->_Has_cache()) {
|
||||||
|
return _Rev_iter<_Vw>{this->_Get_cache(_Base)};
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator_t<_Vw> _First;
|
||||||
|
if constexpr (sized_range<_Vw>) {
|
||||||
|
_First = _RANGES next(_RANGES begin(_Base), _RANGES distance(_Base));
|
||||||
|
} else {
|
||||||
|
_First = _RANGES next(_RANGES begin(_Base), _RANGES end(_Base));
|
||||||
|
}
|
||||||
|
this->_Set_cache(_Base, _First);
|
||||||
|
return _Rev_iter<_Vw>{_STD move(_First)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD constexpr auto begin() const noexcept(
|
||||||
|
noexcept(_Rev_iter<const _Vw>{_RANGES end(_Base)})) /* strengthened */ requires common_range<const _Vw> {
|
||||||
|
return _Rev_iter<const _Vw>{_RANGES end(_Base)};
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD constexpr _Rev_iter<_Vw> end() noexcept(
|
||||||
|
noexcept(_Rev_iter<_Vw>{_RANGES begin(_Base)})) /* strengthened */ {
|
||||||
|
return _Rev_iter<_Vw>{_RANGES begin(_Base)};
|
||||||
|
}
|
||||||
|
_NODISCARD constexpr auto end() const noexcept(
|
||||||
|
noexcept(_Rev_iter<const _Vw>{_RANGES begin(_Base)})) /* strengthened */ requires common_range<const _Vw> {
|
||||||
|
return _Rev_iter<const _Vw>{_RANGES begin(_Base)};
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD constexpr auto size() noexcept(
|
||||||
|
noexcept(_RANGES size(_Base))) /* strengthened */ requires sized_range<_Vw> {
|
||||||
|
return _RANGES size(_Base);
|
||||||
|
}
|
||||||
|
_NODISCARD constexpr auto size() const
|
||||||
|
noexcept(noexcept(_RANGES size(_Base))) /* strengthened */ requires sized_range<const _Vw> {
|
||||||
|
return _RANGES size(_Base);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Rng>
|
||||||
|
reverse_view(_Rng &&) -> reverse_view<views::all_t<_Rng>>;
|
||||||
|
|
||||||
|
namespace views {
|
||||||
|
// VARIABLE views::reverse
|
||||||
|
template <class _Rng>
|
||||||
|
concept _Can_extract_base = requires(_Rng&& __r) {
|
||||||
|
static_cast<_Rng&&>(__r).base();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Rng>
|
||||||
|
concept _Can_reverse = requires(_Rng&& __r) {
|
||||||
|
reverse_view{static_cast<_Rng&&>(__r)};
|
||||||
|
};
|
||||||
|
|
||||||
|
class _Reverse_fn : public _Pipe::_Base<_Reverse_fn> {
|
||||||
|
private:
|
||||||
|
enum class _St { _None, _Base, _Subrange_unsized, _Subrange_sized, _Reverse };
|
||||||
|
|
||||||
|
template <class>
|
||||||
|
static constexpr auto _Reversed_subrange = -1;
|
||||||
|
|
||||||
|
template <class _It, subrange_kind _Ki>
|
||||||
|
static constexpr auto
|
||||||
|
_Reversed_subrange<subrange<reverse_iterator<_It>, reverse_iterator<_It>, _Ki>> = static_cast<int>(_Ki);
|
||||||
|
|
||||||
|
template <class _Rng>
|
||||||
|
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
|
||||||
|
if constexpr (bidirectional_range<_Rng>) {
|
||||||
|
if constexpr (_Is_specialization_v<_Rng, reverse_view>) {
|
||||||
|
if constexpr (_Can_extract_base<_Rng>) {
|
||||||
|
return {_St::_Base, noexcept(_STD declval<_Rng>().base())};
|
||||||
|
}
|
||||||
|
} else if constexpr (_Reversed_subrange<remove_cvref_t<_Rng>> == 0) {
|
||||||
|
using _It = decltype(_STD declval<_Rng&>().begin().base());
|
||||||
|
return {_St::_Subrange_unsized,
|
||||||
|
noexcept(subrange<_It, _It, subrange_kind::unsized>{
|
||||||
|
_STD declval<_Rng&>().end().base(), _STD declval<_Rng&>().begin().base()})};
|
||||||
|
} else if constexpr (_Reversed_subrange<remove_cvref_t<_Rng>> == 1) {
|
||||||
|
using _It = decltype(_STD declval<_Rng&>().begin().base());
|
||||||
|
return {_St::_Subrange_sized,
|
||||||
|
noexcept(subrange<_It, _It, subrange_kind::sized>{_STD declval<_Rng&>().end().base(),
|
||||||
|
_STD declval<_Rng&>().begin().base(), _STD declval<_Rng&>().size()})};
|
||||||
|
} else if constexpr (_Can_reverse<_Rng>) {
|
||||||
|
return {_St::_Reverse, noexcept(reverse_view{_STD declval<_Rng>()})};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {_St::_None};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Rng>
|
||||||
|
static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// clang-format off
|
||||||
|
template <viewable_range _Rng>
|
||||||
|
requires (_Choice<_Rng>._Strategy != _St::_None)
|
||||||
|
_NODISCARD constexpr auto operator()(_Rng&& _Range) const noexcept(_Choice<_Rng>._No_throw) {
|
||||||
|
// clang-format on
|
||||||
|
if constexpr (_Choice<_Rng>._Strategy == _St::_Base) {
|
||||||
|
return _STD forward<_Rng>(_Range).base();
|
||||||
|
} else if constexpr (_Choice<_Rng>._Strategy == _St::_Subrange_unsized) {
|
||||||
|
return subrange{_Range.end().base(), _Range.begin().base()};
|
||||||
|
} else if constexpr (_Choice<_Rng>._Strategy == _St::_Subrange_sized) {
|
||||||
|
return subrange{_Range.end().base(), _Range.begin().base(), _Range.size()};
|
||||||
|
} else if constexpr (_Choice<_Rng>._Strategy == _St::_Reverse) {
|
||||||
|
return reverse_view{_STD forward<_Rng>(_Range)};
|
||||||
|
} else {
|
||||||
|
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr _Reverse_fn reverse;
|
||||||
|
} // namespace views
|
||||||
} // namespace ranges
|
} // namespace ranges
|
||||||
|
|
||||||
namespace views = ranges::views;
|
namespace views = ranges::views;
|
||||||
|
|
|
@ -1048,7 +1048,7 @@ public:
|
||||||
constexpr _String_view_iterator& operator+=(const difference_type _Off) noexcept {
|
constexpr _String_view_iterator& operator+=(const difference_type _Off) noexcept {
|
||||||
#if _ITERATOR_DEBUG_LEVEL >= 1
|
#if _ITERATOR_DEBUG_LEVEL >= 1
|
||||||
_Verify_offset(_Off);
|
_Verify_offset(_Off);
|
||||||
_Myoff += _Off;
|
_Myoff += static_cast<size_t>(_Off);
|
||||||
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
|
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
|
||||||
_Myptr += _Off;
|
_Myptr += _Off;
|
||||||
#endif // _ITERATOR_DEBUG_LEVEL
|
#endif // _ITERATOR_DEBUG_LEVEL
|
||||||
|
@ -1077,7 +1077,7 @@ public:
|
||||||
"cannot seek string_view iterator after end");
|
"cannot seek string_view iterator after end");
|
||||||
}
|
}
|
||||||
|
|
||||||
_Myoff -= _Off;
|
_Myoff -= static_cast<size_t>(_Off);
|
||||||
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
|
#else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv
|
||||||
_Myptr -= _Off;
|
_Myptr -= _Off;
|
||||||
#endif // _ITERATOR_DEBUG_LEVEL
|
#endif // _ITERATOR_DEBUG_LEVEL
|
||||||
|
|
|
@ -645,7 +645,7 @@ struct iterator_traits<_Ty*> {
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT iter_move
|
// CUSTOMIZATION POINT OBJECT ranges::iter_move
|
||||||
namespace ranges {
|
namespace ranges {
|
||||||
// STRUCT TEMPLATE _Choice_t
|
// STRUCT TEMPLATE _Choice_t
|
||||||
template <class _Ty>
|
template <class _Ty>
|
||||||
|
@ -707,9 +707,10 @@ namespace ranges {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
} // namespace _Iter_move
|
} // namespace _Iter_move
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Iter_move::_Cpo iter_move;
|
inline constexpr _Iter_move::_Cpo iter_move;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
} // namespace ranges
|
} // namespace ranges
|
||||||
|
|
||||||
// iter_swap defined below since it depends on indirectly_movable_storable
|
// iter_swap defined below since it depends on indirectly_movable_storable
|
||||||
|
@ -1017,7 +1018,7 @@ concept indirectly_copyable_storable = indirectly_copyable<_In, _Out>
|
||||||
&& assignable_from<iter_value_t<_In>&, iter_reference_t<_In>>;
|
&& assignable_from<iter_value_t<_In>&, iter_reference_t<_In>>;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT iter_swap
|
// CUSTOMIZATION POINT OBJECT ranges::iter_swap
|
||||||
namespace ranges {
|
namespace ranges {
|
||||||
namespace _Iter_swap {
|
namespace _Iter_swap {
|
||||||
template <class _Ty1, class _Ty2>
|
template <class _Ty1, class _Ty2>
|
||||||
|
@ -1091,9 +1092,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Iter_swap
|
} // namespace _Iter_swap
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Iter_swap::_Cpo iter_swap;
|
inline constexpr _Iter_swap::_Cpo iter_swap;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
} // namespace ranges
|
} // namespace ranges
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -2408,9 +2410,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Begin
|
} // namespace _Begin
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Begin::_Cpo begin;
|
inline constexpr _Begin::_Cpo begin;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// ALIAS TEMPLATE ranges::iterator_t
|
// ALIAS TEMPLATE ranges::iterator_t
|
||||||
template <class _Ty>
|
template <class _Ty>
|
||||||
|
@ -2468,9 +2471,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Unchecked_begin
|
} // namespace _Unchecked_begin
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Unchecked_begin::_Cpo _Ubegin;
|
inline constexpr _Unchecked_begin::_Cpo _Ubegin;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::end
|
// CUSTOMIZATION POINT OBJECT ranges::end
|
||||||
namespace _End {
|
namespace _End {
|
||||||
|
@ -2542,9 +2546,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _End
|
} // namespace _End
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _End::_Cpo end;
|
inline constexpr _End::_Cpo end;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::_Uend
|
// CUSTOMIZATION POINT OBJECT ranges::_Uend
|
||||||
namespace _Unchecked_end {
|
namespace _Unchecked_end {
|
||||||
|
@ -2599,9 +2604,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Unchecked_end
|
} // namespace _Unchecked_end
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Unchecked_end::_Cpo _Uend;
|
inline constexpr _Unchecked_end::_Cpo _Uend;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CONCEPT ranges::range
|
// CONCEPT ranges::range
|
||||||
template <class _Rng>
|
template <class _Rng>
|
||||||
|
@ -2648,9 +2654,10 @@ namespace ranges {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Cbegin_fn cbegin;
|
inline constexpr _Cbegin_fn cbegin;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::cend
|
// CUSTOMIZATION POINT OBJECT ranges::cend
|
||||||
struct _Cend_fn {
|
struct _Cend_fn {
|
||||||
|
@ -2664,9 +2671,10 @@ namespace ranges {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Cend_fn cend;
|
inline constexpr _Cend_fn cend;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::rbegin
|
// CUSTOMIZATION POINT OBJECT ranges::rbegin
|
||||||
namespace _Rbegin {
|
namespace _Rbegin {
|
||||||
|
@ -2733,9 +2741,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Rbegin
|
} // namespace _Rbegin
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Rbegin::_Cpo rbegin;
|
inline constexpr _Rbegin::_Cpo rbegin;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::rend
|
// CUSTOMIZATION POINT OBJECT ranges::rend
|
||||||
namespace _Rend {
|
namespace _Rend {
|
||||||
|
@ -2803,9 +2812,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Rend
|
} // namespace _Rend
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Rend::_Cpo rend;
|
inline constexpr _Rend::_Cpo rend;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::crbegin
|
// CUSTOMIZATION POINT OBJECT ranges::crbegin
|
||||||
struct _Crbegin_fn {
|
struct _Crbegin_fn {
|
||||||
|
@ -2819,9 +2829,10 @@ namespace ranges {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Crbegin_fn crbegin;
|
inline constexpr _Crbegin_fn crbegin;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::crend
|
// CUSTOMIZATION POINT OBJECT ranges::crend
|
||||||
struct _Crend_fn {
|
struct _Crend_fn {
|
||||||
|
@ -2835,9 +2846,10 @@ namespace ranges {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Crend_fn crend;
|
inline constexpr _Crend_fn crend;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// VARIABLE TEMPLATE ranges::disable_sized_range
|
// VARIABLE TEMPLATE ranges::disable_sized_range
|
||||||
template <class>
|
template <class>
|
||||||
|
@ -2921,9 +2933,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Size
|
} // namespace _Size
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Size::_Cpo size;
|
inline constexpr _Size::_Cpo size;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::empty
|
// CUSTOMIZATION POINT OBJECT ranges::empty
|
||||||
namespace _Empty {
|
namespace _Empty {
|
||||||
|
@ -2989,9 +3002,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Empty
|
} // namespace _Empty
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Empty::_Cpo empty;
|
inline constexpr _Empty::_Cpo empty;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::data
|
// CUSTOMIZATION POINT OBJECT ranges::data
|
||||||
namespace _Data {
|
namespace _Data {
|
||||||
|
@ -3046,9 +3060,10 @@ namespace ranges {
|
||||||
};
|
};
|
||||||
} // namespace _Data
|
} // namespace _Data
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Data::_Cpo data;
|
inline constexpr _Data::_Cpo data;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// CUSTOMIZATION POINT OBJECT ranges::cdata
|
// CUSTOMIZATION POINT OBJECT ranges::cdata
|
||||||
struct _Cdata_fn {
|
struct _Cdata_fn {
|
||||||
|
@ -3062,9 +3077,10 @@ namespace ranges {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Cdata_fn cdata;
|
inline constexpr _Cdata_fn cdata;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
// CONCEPT ranges::sized_range
|
// CONCEPT ranges::sized_range
|
||||||
|
@ -3289,9 +3305,10 @@ namespace ranges {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
||||||
inline namespace _Cpos {
|
namespace _Cpos {
|
||||||
inline constexpr _Ssize_fn ssize;
|
inline constexpr _Ssize_fn ssize;
|
||||||
}
|
}
|
||||||
|
using namespace _Cpos;
|
||||||
|
|
||||||
// VARIABLE ranges::next
|
// VARIABLE ranges::next
|
||||||
class _Next_fn : private _Not_quite_object {
|
class _Next_fn : private _Not_quite_object {
|
||||||
|
@ -3584,7 +3601,9 @@ namespace ranges {
|
||||||
auto& _Self = _Cast();
|
auto& _Self = _Cast();
|
||||||
#if _CONTAINER_DEBUG_LEVEL > 0
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
||||||
if constexpr (sized_range<_Derived>) {
|
if constexpr (sized_range<_Derived>) {
|
||||||
_STL_VERIFY(_Idx < _RANGES size(_Self), "index out of range for view_interface");
|
using _U_diff = _Make_unsigned_like_t<range_difference_t<_Rng>>;
|
||||||
|
_STL_VERIFY(static_cast<_U_diff>(_Idx) < static_cast<_U_diff>(_RANGES size(_Self)),
|
||||||
|
"index out of range for view_interface");
|
||||||
}
|
}
|
||||||
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
||||||
return _RANGES begin(_Self)[_Idx];
|
return _RANGES begin(_Self)[_Idx];
|
||||||
|
@ -3595,7 +3614,9 @@ namespace ranges {
|
||||||
auto& _Self = _Cast();
|
auto& _Self = _Cast();
|
||||||
#if _CONTAINER_DEBUG_LEVEL > 0
|
#if _CONTAINER_DEBUG_LEVEL > 0
|
||||||
if constexpr (sized_range<_Derived>) {
|
if constexpr (sized_range<_Derived>) {
|
||||||
_STL_VERIFY(_Idx < _RANGES size(_Self), "index out of range for view_interface");
|
using _U_diff = _Make_unsigned_like_t<range_difference_t<_Rng>>;
|
||||||
|
_STL_VERIFY(static_cast<_U_diff>(_Idx) < static_cast<_U_diff>(_RANGES size(_Self)),
|
||||||
|
"index out of range for view_interface");
|
||||||
}
|
}
|
||||||
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
#endif // _CONTAINER_DEBUG_LEVEL > 0
|
||||||
return _RANGES begin(_Self)[_Idx];
|
return _RANGES begin(_Self)[_Idx];
|
||||||
|
|
|
@ -573,6 +573,93 @@ struct std::pointer_traits<::test::iterator<std::contiguous_iterator_tag, Elemen
|
||||||
namespace test {
|
namespace test {
|
||||||
enum class Sized : bool { no, yes };
|
enum class Sized : bool { no, yes };
|
||||||
enum class Common : bool { no, yes };
|
enum class Common : bool { no, yes };
|
||||||
|
enum class CanView : bool { no, yes };
|
||||||
|
enum class Copyability { immobile, move_only, copyable };
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template <class Element, Copyability Copy>
|
||||||
|
class range_base {
|
||||||
|
public:
|
||||||
|
static_assert(Copy == Copyability::immobile);
|
||||||
|
|
||||||
|
range_base() = default;
|
||||||
|
constexpr explicit range_base(span<Element> elements) noexcept : elements_{elements} {}
|
||||||
|
|
||||||
|
range_base(const range_base&) = delete;
|
||||||
|
range_base& operator=(const range_base&) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] constexpr bool moved_from() const noexcept {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
span<Element> elements_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Element>
|
||||||
|
class range_base<Element, Copyability::move_only> {
|
||||||
|
public:
|
||||||
|
range_base() = default;
|
||||||
|
constexpr explicit range_base(span<Element> elements) noexcept : elements_{elements} {}
|
||||||
|
|
||||||
|
constexpr range_base(range_base&& that) noexcept
|
||||||
|
: elements_{that.elements_}, moved_from_{that.moved_from_} {
|
||||||
|
that.elements_ = {};
|
||||||
|
that.moved_from_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr range_base& operator=(range_base&& that) noexcept {
|
||||||
|
elements_ = that.elements_;
|
||||||
|
moved_from_ = that.moved_from_;
|
||||||
|
that.elements_ = {};
|
||||||
|
that.moved_from_ = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] constexpr bool moved_from() const noexcept {
|
||||||
|
return moved_from_;
|
||||||
|
}
|
||||||
|
|
||||||
|
span<Element> elements_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool moved_from_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Element>
|
||||||
|
class range_base<Element, Copyability::copyable> {
|
||||||
|
public:
|
||||||
|
range_base() = default;
|
||||||
|
constexpr explicit range_base(span<Element> elements) noexcept : elements_{elements} {}
|
||||||
|
|
||||||
|
range_base(const range_base&) = default;
|
||||||
|
range_base& operator=(const range_base&) = default;
|
||||||
|
|
||||||
|
constexpr range_base(range_base&& that) noexcept
|
||||||
|
: elements_{that.elements_}, moved_from_{that.moved_from_} {
|
||||||
|
that.elements_ = {};
|
||||||
|
that.moved_from_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr range_base& operator=(range_base&& that) noexcept {
|
||||||
|
elements_ = that.elements_;
|
||||||
|
moved_from_ = that.moved_from_;
|
||||||
|
that.elements_ = {};
|
||||||
|
that.moved_from_ = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] constexpr bool moved_from() const noexcept {
|
||||||
|
return moved_from_;
|
||||||
|
}
|
||||||
|
|
||||||
|
span<Element> elements_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool moved_from_ = false;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
template <class Category, class Element,
|
template <class Category, class Element,
|
||||||
|
@ -585,25 +672,30 @@ namespace test {
|
||||||
// Iterator models sentinel_for with self
|
// Iterator models sentinel_for with self
|
||||||
CanCompare Eq = CanCompare{derived_from<Category, fwd>},
|
CanCompare Eq = CanCompare{derived_from<Category, fwd>},
|
||||||
// Use a ProxyRef reference type?
|
// Use a ProxyRef reference type?
|
||||||
ProxyRef Proxy = ProxyRef{!derived_from<Category, contiguous>}>
|
ProxyRef Proxy = ProxyRef{!derived_from<Category, contiguous>},
|
||||||
|
// Should this range satisfy the view concept?
|
||||||
|
CanView IsView = CanView::no,
|
||||||
|
// Should this range type be copyable/movable/neither?
|
||||||
|
Copyability Copy = IsView == CanView::yes ? Copyability::move_only : Copyability::immobile>
|
||||||
requires (!to_bool(IsCommon) || to_bool(Eq))
|
requires (!to_bool(IsCommon) || to_bool(Eq))
|
||||||
&& (to_bool(Eq) || !derived_from<Category, fwd>)
|
&& (to_bool(Eq) || !derived_from<Category, fwd>)
|
||||||
&& (!to_bool(Proxy) || !derived_from<Category, contiguous>)
|
&& (!to_bool(Proxy) || !derived_from<Category, contiguous>)
|
||||||
class range {
|
&& (!to_bool(IsView) || Copy != Copyability::immobile)
|
||||||
span<Element> elements_;
|
class range : public detail::range_base<Element, Copy> {
|
||||||
|
private:
|
||||||
mutable bool begin_called_ = false;
|
mutable bool begin_called_ = false;
|
||||||
|
using detail::range_base<Element, Copy>::elements_;
|
||||||
|
|
||||||
|
using detail::range_base<Element, Copy>::moved_from;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using I = iterator<Category, Element, Diff, Eq, Proxy, IsWrapped::yes>;
|
using I = iterator<Category, Element, Diff, Eq, Proxy, IsWrapped::yes>;
|
||||||
using S = conditional_t<to_bool(IsCommon), I, sentinel<Element, IsWrapped::yes>>;
|
using S = conditional_t<to_bool(IsCommon), I, sentinel<Element, IsWrapped::yes>>;
|
||||||
|
|
||||||
range() = default;
|
using detail::range_base<Element, Copy>::range_base;
|
||||||
constexpr explicit range(span<Element> elements) noexcept : elements_{elements} {}
|
|
||||||
|
|
||||||
range(range const&) = delete;
|
|
||||||
range& operator=(range const&) = delete;
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr I begin() const noexcept {
|
[[nodiscard]] constexpr I begin() const noexcept {
|
||||||
|
assert(!moved_from());
|
||||||
if constexpr (!derived_from<Category, fwd>) {
|
if constexpr (!derived_from<Category, fwd>) {
|
||||||
assert(!exchange(begin_called_, true));
|
assert(!exchange(begin_called_, true));
|
||||||
}
|
}
|
||||||
|
@ -611,10 +703,12 @@ namespace test {
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr S end() const noexcept {
|
[[nodiscard]] constexpr S end() const noexcept {
|
||||||
|
assert(!moved_from());
|
||||||
return S{elements_.data() + elements_.size()};
|
return S{elements_.data() + elements_.size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr ptrdiff_t size() const noexcept requires (to_bool(IsSized)) {
|
[[nodiscard]] constexpr ptrdiff_t size() const noexcept requires (to_bool(IsSized)) {
|
||||||
|
assert(!moved_from());
|
||||||
if constexpr (!derived_from<Category, fwd>) {
|
if constexpr (!derived_from<Category, fwd>) {
|
||||||
assert(!begin_called_);
|
assert(!begin_called_);
|
||||||
}
|
}
|
||||||
|
@ -622,6 +716,7 @@ namespace test {
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr Element* data() const noexcept requires derived_from<Category, contiguous> {
|
[[nodiscard]] constexpr Element* data() const noexcept requires derived_from<Category, contiguous> {
|
||||||
|
assert(!moved_from());
|
||||||
return elements_.data();
|
return elements_.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,12 +724,14 @@ namespace test {
|
||||||
using US = conditional_t<to_bool(IsCommon), UI, sentinel<Element, IsWrapped::no>>;
|
using US = conditional_t<to_bool(IsCommon), UI, sentinel<Element, IsWrapped::no>>;
|
||||||
|
|
||||||
[[nodiscard]] constexpr UI _Unchecked_begin() const noexcept {
|
[[nodiscard]] constexpr UI _Unchecked_begin() const noexcept {
|
||||||
|
assert(!moved_from());
|
||||||
if constexpr (!derived_from<Category, fwd>) {
|
if constexpr (!derived_from<Category, fwd>) {
|
||||||
assert(!exchange(begin_called_, true));
|
assert(!exchange(begin_called_, true));
|
||||||
}
|
}
|
||||||
return UI{elements_.data()};
|
return UI{elements_.data()};
|
||||||
}
|
}
|
||||||
[[nodiscard]] constexpr US _Unchecked_end() const noexcept {
|
[[nodiscard]] constexpr US _Unchecked_end() const noexcept {
|
||||||
|
assert(!moved_from());
|
||||||
return US{elements_.data() + elements_.size()};
|
return US{elements_.data() + elements_.size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,6 +746,11 @@ namespace test {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
|
template <class Category, class Element, test::Sized IsSized, test::CanDifference Diff, test::Common IsCommon,
|
||||||
|
test::CanCompare Eq, test::ProxyRef Proxy, test::Copyability Copy>
|
||||||
|
inline constexpr bool std::ranges::enable_view<
|
||||||
|
test::range<Category, Element, IsSized, Diff, IsCommon, Eq, Proxy, test::CanView::yes, Copy>> = true;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class basic_borrowed_range : public test::range<test::input, T, test::Sized::no, test::CanDifference::no,
|
class basic_borrowed_range : public test::range<test::input, T, test::Sized::no, test::CanDifference::no,
|
||||||
test::Common::no, test::CanCompare::no, test::ProxyRef::no> {
|
test::Common::no, test::CanCompare::no, test::ProxyRef::no> {
|
||||||
|
@ -1170,3 +1272,110 @@ struct get_nth_fn {
|
||||||
};
|
};
|
||||||
inline constexpr get_nth_fn<0> get_first;
|
inline constexpr get_nth_fn<0> get_first;
|
||||||
inline constexpr get_nth_fn<1> get_second;
|
inline constexpr get_nth_fn<1> get_second;
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanBegin = requires(R&& r) {
|
||||||
|
ranges::begin(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
template <class R>
|
||||||
|
concept CanMemberBegin = requires(R&& r) {
|
||||||
|
std::forward<R>(r).begin();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanEnd = requires(R&& r) {
|
||||||
|
ranges::end(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
template <class R>
|
||||||
|
concept CanMemberEnd = requires(R&& r) {
|
||||||
|
std::forward<R>(r).end();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanCBegin = requires(R&& r) {
|
||||||
|
ranges::cbegin(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
template <class R>
|
||||||
|
concept CanCEnd = requires(R&& r) {
|
||||||
|
ranges::cend(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanRBegin = requires(R&& r) {
|
||||||
|
ranges::rbegin(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
template <class R>
|
||||||
|
concept CanREnd = requires(R&& r) {
|
||||||
|
ranges::rend(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanCRBegin = requires(R&& r) {
|
||||||
|
ranges::crbegin(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
template <class R>
|
||||||
|
concept CanCREnd = requires(R&& r) {
|
||||||
|
ranges::crend(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanEmpty = requires(R&& r) {
|
||||||
|
ranges::empty(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanSize = requires(R&& r) {
|
||||||
|
ranges::size(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
template <class R>
|
||||||
|
concept CanMemberSize = requires(R&& r) {
|
||||||
|
std::forward<R>(r).size();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanSSize = requires(R&& r) {
|
||||||
|
ranges::ssize(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanData = requires(R&& r) {
|
||||||
|
ranges::data(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
template <class R>
|
||||||
|
concept CanMemberData = requires(R&& r) {
|
||||||
|
std::forward<R>(r).data();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanCData = requires(R&& r) {
|
||||||
|
ranges::cdata(std::forward<R>(r));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
concept CanMemberBase = requires(T&& t) {
|
||||||
|
std::forward<T>(t).base();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanMemberEmpty = requires(R&& r) {
|
||||||
|
std::forward<R>(r).empty();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanMemberFront = requires(R&& r) {
|
||||||
|
std::forward<R>(r).front();
|
||||||
|
};
|
||||||
|
template <class R>
|
||||||
|
concept CanMemberBack = requires(R&& r) {
|
||||||
|
std::forward<R>(r).back();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanIndex = requires(R&& r, const ranges::range_difference_t<R> i) {
|
||||||
|
std::forward<R>(r)[i];
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class R>
|
||||||
|
concept CanBool = requires(R&& r) {
|
||||||
|
std::forward<R>(r) ? true : false;
|
||||||
|
};
|
||||||
|
|
|
@ -317,7 +317,9 @@ tests\P0896R4_ranges_ref_view
|
||||||
tests\P0896R4_ranges_subrange
|
tests\P0896R4_ranges_subrange
|
||||||
tests\P0896R4_ranges_test_machinery
|
tests\P0896R4_ranges_test_machinery
|
||||||
tests\P0896R4_ranges_to_address
|
tests\P0896R4_ranges_to_address
|
||||||
|
tests\P0896R4_views_all
|
||||||
tests\P0896R4_views_empty
|
tests\P0896R4_views_empty
|
||||||
|
tests\P0896R4_views_reverse
|
||||||
tests\P0896R4_views_single
|
tests\P0896R4_views_single
|
||||||
tests\P0898R3_concepts
|
tests\P0898R3_concepts
|
||||||
tests\P0898R3_identity
|
tests\P0898R3_identity
|
||||||
|
|
|
@ -34,45 +34,10 @@ STATIC_ASSERT(std::same_as<std::make_unsigned_t<std::ptrdiff_t>, std::size_t>);
|
||||||
template <class T>
|
template <class T>
|
||||||
concept Decayed = std::same_as<std::decay_t<T>, T>;
|
concept Decayed = std::same_as<std::decay_t<T>, T>;
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
template <class R>
|
template <class R>
|
||||||
concept CanBegin = requires(R&& r) { ranges::begin(std::forward<R>(r)); };
|
concept CanSizeType = requires {
|
||||||
template <class R>
|
typename ranges::range_size_t<R>;
|
||||||
concept CanEnd = requires(R&& r) { ranges::end(std::forward<R>(r)); };
|
};
|
||||||
|
|
||||||
template <class R>
|
|
||||||
concept CanCBegin = requires(R&& r) { ranges::cbegin(std::forward<R>(r)); };
|
|
||||||
template <class R>
|
|
||||||
concept CanCEnd = requires(R&& r) {ranges::cend(std::forward<R>(r)); };
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
concept CanRBegin = requires(R&& r) { ranges::rbegin(std::forward<R>(r)); };
|
|
||||||
template <class R>
|
|
||||||
concept CanREnd = requires(R&& r) { ranges::rend(std::forward<R>(r)); };
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
concept CanCRBegin = requires(R&& r) { ranges::crbegin(std::forward<R>(r)); };
|
|
||||||
template <class R>
|
|
||||||
concept CanCREnd = requires(R&& r) { ranges::crend(std::forward<R>(r)); };
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
concept CanEmpty = requires(R&& r) { ranges::empty(std::forward<R>(r)); };
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
concept CanSize = requires(R&& r) { ranges::size(std::forward<R>(r)); };
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
concept CanSSize = requires(R&& r) { ranges::ssize(std::forward<R>(r)); };
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
concept CanSizeType = requires { typename ranges::range_size_t<R>; };
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
concept CanData = requires(R&& r) { ranges::data(std::forward<R>(r)); };
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
concept CanCData = requires(R&& r) { ranges::cdata(std::forward<R>(r)); };
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
struct invalid_type {};
|
struct invalid_type {};
|
||||||
|
|
||||||
|
@ -124,6 +89,8 @@ STATIC_ASSERT(test_cpo(ranges::empty));
|
||||||
STATIC_ASSERT(test_cpo(ranges::data));
|
STATIC_ASSERT(test_cpo(ranges::data));
|
||||||
STATIC_ASSERT(test_cpo(ranges::cdata));
|
STATIC_ASSERT(test_cpo(ranges::cdata));
|
||||||
|
|
||||||
|
STATIC_ASSERT(test_cpo(ranges::views::all));
|
||||||
|
STATIC_ASSERT(test_cpo(ranges::views::reverse));
|
||||||
STATIC_ASSERT(test_cpo(ranges::views::single));
|
STATIC_ASSERT(test_cpo(ranges::views::single));
|
||||||
|
|
||||||
void test_cpo_ambiguity() {
|
void test_cpo_ambiguity() {
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,218 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <ranges>
|
||||||
|
#include <span>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <range_algorithm_support.hpp>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
template <class Rng>
|
||||||
|
concept CanViewAll = requires(Rng&& r) {
|
||||||
|
views::all(static_cast<Rng&&>(r));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test a silly precomposed range adaptor pipeline
|
||||||
|
constexpr auto pipeline = views::all | views::all | views::all | views::all | views::all | views::all;
|
||||||
|
|
||||||
|
template <class Rng>
|
||||||
|
constexpr bool test_one(Rng&& rng) {
|
||||||
|
constexpr bool is_view = ranges::view<remove_cvref_t<Rng>>;
|
||||||
|
static_assert(is_view || is_lvalue_reference_v<Rng>);
|
||||||
|
|
||||||
|
using V = conditional_t<is_view, remove_cvref_t<Rng>, ranges::ref_view<remove_reference_t<Rng>>>;
|
||||||
|
|
||||||
|
static_assert(CanViewAll<Rng&> == (!is_view || copyable<V>) );
|
||||||
|
if constexpr (!is_view || copyable<V>) { // Validate lvalue
|
||||||
|
constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v<V>;
|
||||||
|
|
||||||
|
static_assert(same_as<views::all_t<Rng>, V>);
|
||||||
|
static_assert(same_as<decltype(views::all(rng)), V>);
|
||||||
|
static_assert(noexcept(views::all(rng)) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(rng | views::all), V>);
|
||||||
|
static_assert(noexcept(rng | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(views::all(rng)), decltype(rng | views::all | views::all | views::all)>);
|
||||||
|
static_assert(noexcept(rng | views::all | views::all | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(views::all(rng)), decltype(rng | pipeline)>);
|
||||||
|
static_assert(noexcept(rng | pipeline) == is_noexcept);
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(CanViewAll<const remove_cvref_t<Rng>&> == (!is_view || copyable<V>) );
|
||||||
|
if constexpr (is_view && copyable<V>) {
|
||||||
|
constexpr bool is_noexcept = is_nothrow_copy_constructible_v<V>;
|
||||||
|
|
||||||
|
static_assert(same_as<views::all_t<const remove_cvref_t<Rng>&>, V>);
|
||||||
|
static_assert(same_as<decltype(views::all(as_const(rng))), V>);
|
||||||
|
static_assert(noexcept(views::all(as_const(rng))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | views::all), V>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | views::all | views::all | views::all), V>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::all | views::all | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | pipeline), V>);
|
||||||
|
static_assert(noexcept(as_const(rng) | pipeline) == is_noexcept);
|
||||||
|
} else if constexpr (!is_view) {
|
||||||
|
using RV = ranges::ref_view<const remove_cvref_t<Rng>>;
|
||||||
|
|
||||||
|
static_assert(same_as<views::all_t<const remove_cvref_t<Rng>&>, RV>);
|
||||||
|
static_assert(same_as<decltype(views::all(as_const(rng))), RV>);
|
||||||
|
static_assert(noexcept(views::all(as_const(rng))));
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | views::all), RV>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::all));
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | views::all | views::all | views::all), RV>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::all | views::all | views::all));
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | pipeline), RV>);
|
||||||
|
static_assert(noexcept(as_const(rng) | pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate rvalue
|
||||||
|
static_assert(CanViewAll<remove_cvref_t<Rng>> == is_view || ranges::enable_borrowed_range<remove_cvref_t<Rng>>);
|
||||||
|
if constexpr (is_view) {
|
||||||
|
constexpr bool is_noexcept = is_nothrow_move_constructible_v<V>;
|
||||||
|
static_assert(same_as<views::all_t<remove_cvref_t<Rng>>, V>);
|
||||||
|
static_assert(same_as<decltype(views::all(move(rng))), V>);
|
||||||
|
static_assert(noexcept(views::all(move(rng))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | views::all), V>);
|
||||||
|
static_assert(noexcept(move(rng) | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | views::all | views::all | views::all), V>);
|
||||||
|
static_assert(noexcept(move(rng) | views::all | views::all | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | pipeline), V>);
|
||||||
|
static_assert(noexcept(move(rng) | pipeline) == is_noexcept);
|
||||||
|
} else if constexpr (ranges::enable_borrowed_range<Rng>) {
|
||||||
|
using S = decltype(ranges::subrange{declval<Rng>()});
|
||||||
|
constexpr bool is_noexcept = noexcept(S{declval<Rng>()});
|
||||||
|
|
||||||
|
static_assert(same_as<views::all_t<remove_cvref_t<Rng>>, S>);
|
||||||
|
static_assert(same_as<decltype(views::all(move(rng))), S>);
|
||||||
|
static_assert(noexcept(views::all(move(rng))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | views::all), S>);
|
||||||
|
static_assert(noexcept(move(rng) | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | views::all | views::all | views::all), S>);
|
||||||
|
static_assert(noexcept(move(rng) | views::all | views::all | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | pipeline), S>);
|
||||||
|
static_assert(noexcept(move(rng) | pipeline) == is_noexcept);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate const rvalue
|
||||||
|
static_assert(CanViewAll<const remove_cvref_t<Rng>> == (is_view && copyable<V>)
|
||||||
|
|| (!is_view && ranges::enable_borrowed_range<remove_cvref_t<Rng>>) );
|
||||||
|
if constexpr (is_view && copyable<V>) {
|
||||||
|
constexpr bool is_noexcept = is_nothrow_copy_constructible_v<V>;
|
||||||
|
|
||||||
|
static_assert(same_as<views::all_t<const remove_cvref_t<Rng>>, V>);
|
||||||
|
static_assert(same_as<decltype(views::all(move(as_const(rng)))), V>);
|
||||||
|
static_assert(noexcept(views::all(as_const(rng))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | views::all), V>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | views::all | views::all | views::all), V>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | views::all | views::all | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | pipeline), V>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | pipeline) == is_noexcept);
|
||||||
|
} else if constexpr (!is_view && ranges::enable_borrowed_range<const remove_cvref_t<Rng>>) {
|
||||||
|
using S = decltype(ranges::subrange{declval<const remove_cvref_t<Rng>>()});
|
||||||
|
constexpr bool is_noexcept = noexcept(S{declval<const remove_cvref_t<Rng>>()});
|
||||||
|
|
||||||
|
static_assert(same_as<views::all_t<const remove_cvref_t<Rng>>, S>);
|
||||||
|
static_assert(same_as<decltype(views::all(move(as_const(rng)))), S>);
|
||||||
|
static_assert(noexcept(views::all(move(as_const(rng)))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | views::all), S>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | views::all | views::all | views::all), S>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | views::all | views::all | views::all) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | pipeline), S>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | pipeline) == is_noexcept);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct non_view_borrowed_range {
|
||||||
|
int* begin() const;
|
||||||
|
int* end() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline constexpr bool ranges::enable_borrowed_range<non_view_borrowed_range> = true;
|
||||||
|
|
||||||
|
template <class Category, test::Common IsCommon, bool is_random = derived_from<Category, random_access_iterator_tag>>
|
||||||
|
using move_only_view = test::range<Category, const int, test::Sized{is_random}, test::CanDifference{is_random},
|
||||||
|
IsCommon, test::CanCompare{derived_from<Category, forward_iterator_tag>},
|
||||||
|
test::ProxyRef{!derived_from<Category, contiguous_iterator_tag>}, test::CanView::yes, test::Copyability::move_only>;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
static constexpr int some_ints[] = {0, 1, 2};
|
||||||
|
|
||||||
|
// Validate views
|
||||||
|
{ // ... copyable
|
||||||
|
constexpr string_view str{"Hello, World!"};
|
||||||
|
static_assert(test_one(str));
|
||||||
|
test_one(str);
|
||||||
|
assert(ranges::equal(views::all(str), str));
|
||||||
|
}
|
||||||
|
{ // ... move-only
|
||||||
|
test_one(move_only_view<input_iterator_tag, test::Common::no>{some_ints});
|
||||||
|
assert(ranges::equal(views::all(move_only_view<input_iterator_tag, test::Common::no>{some_ints}), some_ints));
|
||||||
|
test_one(move_only_view<forward_iterator_tag, test::Common::no>{some_ints});
|
||||||
|
assert(ranges::equal(views::all(move_only_view<forward_iterator_tag, test::Common::no>{some_ints}), some_ints));
|
||||||
|
test_one(move_only_view<forward_iterator_tag, test::Common::yes>{some_ints});
|
||||||
|
assert(
|
||||||
|
ranges::equal(views::all(move_only_view<forward_iterator_tag, test::Common::yes>{some_ints}), some_ints));
|
||||||
|
test_one(move_only_view<bidirectional_iterator_tag, test::Common::no>{some_ints});
|
||||||
|
assert(ranges::equal(
|
||||||
|
views::all(move_only_view<bidirectional_iterator_tag, test::Common::no>{some_ints}), some_ints));
|
||||||
|
test_one(move_only_view<bidirectional_iterator_tag, test::Common::yes>{some_ints});
|
||||||
|
assert(ranges::equal(
|
||||||
|
views::all(move_only_view<bidirectional_iterator_tag, test::Common::yes>{some_ints}), some_ints));
|
||||||
|
test_one(move_only_view<random_access_iterator_tag, test::Common::no>{some_ints});
|
||||||
|
assert(ranges::equal(
|
||||||
|
views::all(move_only_view<random_access_iterator_tag, test::Common::no>{some_ints}), some_ints));
|
||||||
|
test_one(move_only_view<random_access_iterator_tag, test::Common::yes>{some_ints});
|
||||||
|
assert(ranges::equal(
|
||||||
|
views::all(move_only_view<random_access_iterator_tag, test::Common::yes>{some_ints}), some_ints));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate non-views
|
||||||
|
{
|
||||||
|
static_assert(test_one(some_ints));
|
||||||
|
test_one(some_ints);
|
||||||
|
assert(ranges::equal(views::all(some_ints), some_ints));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
string str{"Hello, World!"};
|
||||||
|
test_one(str);
|
||||||
|
assert(ranges::equal(views::all(str), str));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate a non-view borrowed range
|
||||||
|
{
|
||||||
|
constexpr span s{some_ints};
|
||||||
|
static_assert(test_one(s));
|
||||||
|
test_one(s);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
RUNALL_INCLUDE ..\strict_concepts_matrix.lst
|
|
@ -0,0 +1,375 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <list>
|
||||||
|
#include <ranges>
|
||||||
|
#include <span>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <range_algorithm_support.hpp>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
template <class Rng>
|
||||||
|
concept CanViewReverse = requires(Rng&& r) {
|
||||||
|
views::reverse(static_cast<Rng&&>(r));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test a silly precomposed range adaptor pipeline
|
||||||
|
constexpr auto pipeline = views::all | views::reverse | views::all | views::reverse | views::all | views::reverse;
|
||||||
|
|
||||||
|
template <ranges::bidirectional_range Rng, class Expected>
|
||||||
|
constexpr bool test_one(Rng&& rng, Expected&& expected) {
|
||||||
|
using ranges::common_range, ranges::reverse_view, ranges::sized_range, ranges::begin, ranges::end, ranges::size,
|
||||||
|
ranges::iterator_t, ranges::range_size_t, ranges::random_access_range, ranges::prev,
|
||||||
|
ranges::enable_borrowed_range;
|
||||||
|
constexpr bool is_view = ranges::view<remove_cvref_t<Rng>>;
|
||||||
|
|
||||||
|
using V = views::all_t<Rng>;
|
||||||
|
using R = reverse_view<V>;
|
||||||
|
static_assert(ranges::view<R>);
|
||||||
|
static_assert(ranges::bidirectional_range<R>);
|
||||||
|
static_assert(random_access_range<R> == random_access_range<Rng>);
|
||||||
|
static_assert(!ranges::contiguous_range<R>);
|
||||||
|
|
||||||
|
// Validate range adapter object
|
||||||
|
// ...with lvalue argument
|
||||||
|
static_assert(CanViewReverse<Rng&> == (!is_view || copyable<V>) );
|
||||||
|
if constexpr (CanViewReverse<Rng&>) {
|
||||||
|
constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v<V>;
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(views::reverse(rng)), R>);
|
||||||
|
static_assert(noexcept(views::reverse(rng)) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(rng | views::reverse), R>);
|
||||||
|
static_assert(noexcept(rng | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(views::reverse(views::reverse(rng))), V>);
|
||||||
|
static_assert(noexcept(views::reverse(views::reverse(rng))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(rng | views::reverse | views::reverse | views::reverse), R>);
|
||||||
|
static_assert(noexcept(rng | views::reverse | views::reverse | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(rng | pipeline), R>);
|
||||||
|
static_assert(noexcept(rng | pipeline) == is_noexcept);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... with const lvalue argument
|
||||||
|
static_assert(CanViewReverse<const remove_reference_t<Rng>&> == (!is_view || copyable<V>) );
|
||||||
|
if constexpr (is_view && copyable<V>) {
|
||||||
|
constexpr bool is_noexcept = is_nothrow_copy_constructible_v<V>;
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(views::reverse(as_const(rng))), R>);
|
||||||
|
static_assert(noexcept(views::reverse(as_const(rng))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | views::reverse), R>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | views::reverse | views::reverse | views::reverse), R>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::reverse | views::reverse | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | pipeline), R>);
|
||||||
|
static_assert(noexcept(as_const(rng) | pipeline) == is_noexcept);
|
||||||
|
} else if constexpr (!is_view) {
|
||||||
|
using RC = reverse_view<views::all_t<const remove_reference_t<Rng>&>>;
|
||||||
|
constexpr bool is_noexcept = is_nothrow_constructible_v<RC, const remove_reference_t<Rng>&>;
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(views::reverse(as_const(rng))), RC>);
|
||||||
|
static_assert(noexcept(views::reverse(as_const(rng))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | views::reverse), RC>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | views::reverse | views::reverse | views::reverse), RC>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::reverse | views::reverse | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(as_const(rng) | pipeline), RC>);
|
||||||
|
static_assert(noexcept(as_const(rng) | pipeline) == is_noexcept);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... with rvalue argument
|
||||||
|
static_assert(CanViewReverse<remove_reference_t<Rng>> == is_view || enable_borrowed_range<remove_cvref_t<Rng>>);
|
||||||
|
if constexpr (is_view) {
|
||||||
|
constexpr bool is_noexcept = is_nothrow_move_constructible_v<V>;
|
||||||
|
static_assert(same_as<decltype(views::reverse(move(rng))), R>);
|
||||||
|
static_assert(noexcept(views::reverse(move(rng))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | views::reverse), R>);
|
||||||
|
static_assert(noexcept(move(rng) | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | views::reverse | views::reverse | views::reverse), R>);
|
||||||
|
static_assert(noexcept(move(rng) | views::reverse | views::reverse | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | pipeline), R>);
|
||||||
|
static_assert(noexcept(move(rng) | pipeline) == is_noexcept);
|
||||||
|
} else if constexpr (enable_borrowed_range<Rng>) {
|
||||||
|
using S = decltype(ranges::subrange{declval<Rng>()});
|
||||||
|
using RS = reverse_view<S>;
|
||||||
|
constexpr bool is_noexcept = noexcept(S{declval<Rng>()});
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(views::reverse(move(rng))), RS>);
|
||||||
|
static_assert(noexcept(views::reverse(move(rng))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | views::reverse), RS>);
|
||||||
|
static_assert(noexcept(move(rng) | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | views::reverse | views::reverse | views::reverse), RS>);
|
||||||
|
static_assert(noexcept(move(rng) | views::reverse | views::reverse | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(rng) | pipeline), RS>);
|
||||||
|
static_assert(noexcept(move(rng) | pipeline) == is_noexcept);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... with const rvalue argument
|
||||||
|
static_assert(CanViewReverse<const remove_reference_t<Rng>> == (is_view && copyable<V>)
|
||||||
|
|| (!is_view && enable_borrowed_range<remove_cvref_t<Rng>>) );
|
||||||
|
if constexpr (is_view && copyable<V>) {
|
||||||
|
constexpr bool is_noexcept = is_nothrow_copy_constructible_v<V>;
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(views::reverse(move(as_const(rng)))), R>);
|
||||||
|
static_assert(noexcept(views::reverse(as_const(rng))) == is_nothrow_copy_constructible_v<R>);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | views::reverse), R>);
|
||||||
|
static_assert(noexcept(as_const(rng) | views::reverse) == is_nothrow_copy_constructible_v<R>);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | views::reverse | views::reverse | views::reverse), R>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | views::reverse | views::reverse | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | pipeline), R>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | pipeline) == is_noexcept);
|
||||||
|
} else if constexpr (!is_view && enable_borrowed_range<const remove_cvref_t<Rng>>) {
|
||||||
|
using S = decltype(ranges::subrange{declval<const remove_cvref_t<Rng>>()});
|
||||||
|
using RS = reverse_view<S>;
|
||||||
|
constexpr bool is_noexcept = noexcept(S{declval<const remove_cvref_t<Rng>>()});
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(views::reverse(move(as_const(rng)))), RS>);
|
||||||
|
static_assert(noexcept(views::reverse(move(as_const(rng)))) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | views::reverse), RS>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | views::reverse | views::reverse | views::reverse), RS>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | views::reverse | views::reverse | views::reverse) == is_noexcept);
|
||||||
|
|
||||||
|
static_assert(same_as<decltype(move(as_const(rng)) | pipeline), RS>);
|
||||||
|
static_assert(noexcept(move(as_const(rng)) | pipeline) == is_noexcept);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate deduction guide
|
||||||
|
#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, DevCom-1159442
|
||||||
|
(void) 42;
|
||||||
|
#endif // TRANSITION, DevCom-1159442
|
||||||
|
same_as<R> auto r = reverse_view{forward<Rng>(rng)};
|
||||||
|
assert(ranges::equal(r, expected));
|
||||||
|
|
||||||
|
// Validate reverse_view::size
|
||||||
|
static_assert(CanMemberSize<R> == sized_range<Rng>);
|
||||||
|
if constexpr (sized_range<Rng>) {
|
||||||
|
assert(r.size() == static_cast<range_size_t<R>>(size(expected)));
|
||||||
|
static_assert(noexcept(r.size()) == noexcept(size(rng)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(CanMemberSize<const R> == sized_range<const Rng>);
|
||||||
|
if constexpr (sized_range<const Rng>) {
|
||||||
|
assert(as_const(r).size() == static_cast<range_size_t<R>>(size(expected)));
|
||||||
|
static_assert(noexcept(r.size()) == noexcept(size(as_const(rng))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate view_interface::empty and operator bool
|
||||||
|
const bool is_empty = ranges::empty(expected);
|
||||||
|
assert(r.empty() == is_empty);
|
||||||
|
assert(static_cast<bool>(r) == !is_empty);
|
||||||
|
static_assert(CanMemberEmpty<const R> == common_range<Rng>);
|
||||||
|
if constexpr (common_range<Rng>) {
|
||||||
|
assert(as_const(r).empty() == is_empty);
|
||||||
|
assert(static_cast<bool>(as_const(r)) == !is_empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate reverse_view::begin
|
||||||
|
static_assert(CanMemberBegin<R>);
|
||||||
|
{
|
||||||
|
// reverse_view sometimes caches begin, so let's make several extra calls
|
||||||
|
const same_as<reverse_iterator<iterator_t<V>>> auto i = r.begin();
|
||||||
|
if (!is_empty) {
|
||||||
|
assert(*i == *begin(expected));
|
||||||
|
}
|
||||||
|
assert(r.begin() == i);
|
||||||
|
assert(r.begin() == i);
|
||||||
|
// NB: non-const begin is unconditionally noexcept(false) due to caching
|
||||||
|
static_assert(!noexcept(r.begin()));
|
||||||
|
|
||||||
|
if constexpr (copyable<V>) {
|
||||||
|
auto r2 = r;
|
||||||
|
const same_as<reverse_iterator<iterator_t<V>>> auto i2 = r2.begin();
|
||||||
|
assert(r2.begin() == i2);
|
||||||
|
assert(r2.begin() == i2);
|
||||||
|
if (!is_empty) {
|
||||||
|
assert(*i2 == *i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(CanMemberBegin<const R> == common_range<Rng>);
|
||||||
|
if constexpr (common_range<Rng>) {
|
||||||
|
const same_as<reverse_iterator<iterator_t<const V>>> auto ci = as_const(r).begin();
|
||||||
|
assert(as_const(r).begin() == ci);
|
||||||
|
assert(as_const(r).begin() == ci);
|
||||||
|
if (!is_empty) {
|
||||||
|
assert(*ci == *i);
|
||||||
|
}
|
||||||
|
static_assert(noexcept(as_const(r).begin()) == noexcept(reverse_iterator{end(as_const(rng))}));
|
||||||
|
|
||||||
|
if constexpr (copyable<V>) {
|
||||||
|
const auto r2 = r;
|
||||||
|
const same_as<reverse_iterator<iterator_t<const V>>> auto ci2 = r2.begin();
|
||||||
|
assert(r2.begin() == ci2);
|
||||||
|
assert(r2.begin() == ci2);
|
||||||
|
if (!is_empty) {
|
||||||
|
assert(*ci2 == *i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate reverse_view::end
|
||||||
|
static_assert(CanMemberEnd<R>);
|
||||||
|
if (!is_empty) {
|
||||||
|
assert(*prev(r.end()) == *prev(end(expected)));
|
||||||
|
|
||||||
|
if constexpr (copyable<V>) {
|
||||||
|
auto r2 = r;
|
||||||
|
assert(*prev(r2.end()) == *prev(end(expected)));
|
||||||
|
}
|
||||||
|
static_assert(noexcept(r.end()) == noexcept(reverse_iterator{begin(rng)}));
|
||||||
|
|
||||||
|
static_assert(CanMemberEnd<const R> == common_range<Rng>);
|
||||||
|
if constexpr (common_range<Rng>) {
|
||||||
|
assert(*prev(as_const(r).end()) == *prev(end(expected)));
|
||||||
|
static_assert(noexcept(as_const(r).end()) == noexcept(reverse_iterator{begin(as_const(rng))}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate view_interface::data
|
||||||
|
static_assert(!CanData<R>);
|
||||||
|
static_assert(!CanData<const R>);
|
||||||
|
|
||||||
|
if (!is_empty) {
|
||||||
|
// Validate view_interface::operator[]
|
||||||
|
static_assert(CanIndex<R> == random_access_range<Rng>);
|
||||||
|
static_assert(CanIndex<const R> == (random_access_range<Rng> && common_range<Rng>) );
|
||||||
|
if constexpr (random_access_range<Rng>) {
|
||||||
|
assert(r[0] == *begin(expected));
|
||||||
|
|
||||||
|
if constexpr (common_range<Rng>) {
|
||||||
|
assert(as_const(r)[0] == *begin(expected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate view_interface::front and back
|
||||||
|
assert(r.front() == *begin(expected));
|
||||||
|
assert(r.back() == *prev(end(expected)));
|
||||||
|
|
||||||
|
static_assert(CanMemberFront<const R> == common_range<Rng>);
|
||||||
|
static_assert(CanMemberBack<const R> == common_range<Rng>);
|
||||||
|
if constexpr (common_range<Rng>) {
|
||||||
|
assert(as_const(r).front() == *begin(expected));
|
||||||
|
assert(as_const(r).back() == *prev(end(expected)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate reverse_view::base() const&
|
||||||
|
static_assert(CanMemberBase<const R&> == copy_constructible<V>);
|
||||||
|
if constexpr (copy_constructible<V>) {
|
||||||
|
same_as<V> auto b1 = as_const(r).base();
|
||||||
|
static_assert(noexcept(as_const(r).base()) == is_nothrow_copy_constructible_v<V>);
|
||||||
|
if (!is_empty) {
|
||||||
|
assert(*b1.begin() == *prev(end(expected)));
|
||||||
|
if constexpr (common_range<V>) {
|
||||||
|
assert(*prev(b1.end()) == *begin(expected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate reverse_view::base() && (NB: do this last since it leaves r moved-from)
|
||||||
|
#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, DevCom-1159442
|
||||||
|
(void) 42;
|
||||||
|
#endif // TRANSITION, DevCom-1159442
|
||||||
|
same_as<V> auto b2 = move(r).base();
|
||||||
|
static_assert(noexcept(move(r).base()) == is_nothrow_move_constructible_v<V>);
|
||||||
|
if (!is_empty) {
|
||||||
|
assert(*b2.begin() == *prev(end(expected)));
|
||||||
|
if constexpr (common_range<V>) {
|
||||||
|
assert(*prev(b2.end()) == *begin(expected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct instantiator {
|
||||||
|
template <ranges::bidirectional_range R>
|
||||||
|
static constexpr void call() {
|
||||||
|
R r{};
|
||||||
|
test_one(r, span<const int, 0>{});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Category, test::Common IsCommon, bool is_random = derived_from<Category, random_access_iterator_tag>>
|
||||||
|
using move_only_view = test::range<Category, const int, test::Sized{is_random}, test::CanDifference{is_random},
|
||||||
|
IsCommon, test::CanCompare{derived_from<Category, forward_iterator_tag>},
|
||||||
|
test::ProxyRef{!derived_from<Category, contiguous_iterator_tag>}, test::CanView::yes, test::Copyability::move_only>;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
static constexpr int some_ints[] = {0, 1, 2};
|
||||||
|
static constexpr int reversed_ints[] = {2, 1, 0};
|
||||||
|
|
||||||
|
// Validate views
|
||||||
|
{ // ...copyable
|
||||||
|
constexpr string_view str{"Hello, World!"};
|
||||||
|
constexpr auto expected = "!dlroW ,olleH"sv;
|
||||||
|
static_assert(test_one(str, expected));
|
||||||
|
test_one(str, expected);
|
||||||
|
}
|
||||||
|
{ // ... move-only
|
||||||
|
test_one(move_only_view<bidirectional_iterator_tag, test::Common::no>{some_ints}, reversed_ints);
|
||||||
|
test_one(move_only_view<bidirectional_iterator_tag, test::Common::yes>{some_ints}, reversed_ints);
|
||||||
|
test_one(move_only_view<random_access_iterator_tag, test::Common::no>{some_ints}, reversed_ints);
|
||||||
|
test_one(move_only_view<random_access_iterator_tag, test::Common::yes>{some_ints}, reversed_ints);
|
||||||
|
test_one(move_only_view<contiguous_iterator_tag, test::Common::no>{some_ints}, reversed_ints);
|
||||||
|
test_one(move_only_view<contiguous_iterator_tag, test::Common::yes>{some_ints}, reversed_ints);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate non-views
|
||||||
|
{ // ... C array
|
||||||
|
static_assert(test_one(some_ints, reversed_ints));
|
||||||
|
test_one(some_ints, reversed_ints);
|
||||||
|
}
|
||||||
|
{ // ... contiguous container
|
||||||
|
string str{"Hello, World!"};
|
||||||
|
constexpr auto expected = "!dlroW ,olleH"sv;
|
||||||
|
test_one(str, expected);
|
||||||
|
}
|
||||||
|
{ // ... bidi container
|
||||||
|
list<int> lst{3, 4, 5};
|
||||||
|
static constexpr int reversed[] = {5, 4, 3};
|
||||||
|
test_one(lst, reversed);
|
||||||
|
|
||||||
|
static constexpr int reversed_prefix[] = {4, 3};
|
||||||
|
assert(ranges::equal(
|
||||||
|
views::reverse(ranges::subrange{counted_iterator{lst.begin(), 2}, default_sentinel}), reversed_prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate a non-view borrowed range
|
||||||
|
{
|
||||||
|
constexpr span s{some_ints};
|
||||||
|
static_assert(test_one(s, reversed_ints));
|
||||||
|
test_one(s, reversed_ints);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get full instantiation coverage
|
||||||
|
static_assert((test_bidi<instantiator, const int>(), true));
|
||||||
|
test_bidi<instantiator, const int>();
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче