зеркало из https://github.com/microsoft/STL.git
Implement ranges::elements_view (#1406)
Co-authored-by: S. B. Tam <cpplearner@outlook.com> Co-authored-by: Casey Carter <cacarter@microsoft.com> Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
This commit is contained in:
Родитель
a6f285db8a
Коммит
7fd6501ece
531
stl/inc/ranges
531
stl/inc/ranges
|
@ -2336,6 +2336,116 @@ namespace ranges {
|
|||
inline constexpr _Drop_while_fn drop_while;
|
||||
} // namespace views
|
||||
|
||||
// CLASS TEMPLATE ranges::common_view
|
||||
// clang-format off
|
||||
template <view _Vw>
|
||||
requires (!common_range<_Vw> && copyable<iterator_t<_Vw>>)
|
||||
class common_view : public view_interface<common_view<_Vw>> {
|
||||
// clang-format on
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Vw _Base{};
|
||||
|
||||
public:
|
||||
common_view() = default;
|
||||
constexpr explicit common_view(_Vw _Base_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
|
||||
: _Base(_STD move(_Base_)) {}
|
||||
// converting constructor template omitted per LWG-3405
|
||||
|
||||
_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 auto begin() noexcept(
|
||||
noexcept(_RANGES begin(_Base)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */ {
|
||||
if constexpr (random_access_range<_Vw> && sized_range<_Vw>) {
|
||||
return _RANGES begin(_Base);
|
||||
} else {
|
||||
return common_iterator<iterator_t<_Vw>, sentinel_t<_Vw>>{_RANGES begin(_Base)};
|
||||
}
|
||||
}
|
||||
|
||||
_NODISCARD constexpr auto begin() const noexcept(
|
||||
noexcept(_RANGES begin(_Base))
|
||||
&& is_nothrow_move_constructible_v<iterator_t<const _Vw>>) /* strengthened */ requires range<const _Vw> {
|
||||
if constexpr (random_access_range<const _Vw> && sized_range<const _Vw>) {
|
||||
return _RANGES begin(_Base);
|
||||
} else {
|
||||
return common_iterator<iterator_t<const _Vw>, sentinel_t<const _Vw>>{_RANGES begin(_Base)};
|
||||
}
|
||||
}
|
||||
|
||||
_NODISCARD constexpr auto end() {
|
||||
if constexpr (random_access_range<_Vw> && sized_range<_Vw>) {
|
||||
return _RANGES begin(_Base) + _RANGES size(_Base);
|
||||
} else {
|
||||
return common_iterator<iterator_t<_Vw>, sentinel_t<_Vw>>{_RANGES end(_Base)};
|
||||
}
|
||||
}
|
||||
|
||||
_NODISCARD constexpr auto end() const requires range<const _Vw> {
|
||||
if constexpr (random_access_range<const _Vw> && sized_range<const _Vw>) {
|
||||
return _RANGES begin(_Base) + _RANGES size(_Base);
|
||||
} else {
|
||||
return common_iterator<iterator_t<const _Vw>, sentinel_t<const _Vw>>{_RANGES end(_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>
|
||||
common_view(_Rng &&) -> common_view<views::all_t<_Rng>>;
|
||||
|
||||
namespace views {
|
||||
// VARIABLE views::common
|
||||
class _Common_fn : public _Pipe::_Base<_Common_fn> {
|
||||
private:
|
||||
enum class _St { _None, _All, _Common };
|
||||
|
||||
template <class _Rng>
|
||||
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
|
||||
if constexpr (common_range<_Rng>) {
|
||||
return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))};
|
||||
} else if constexpr (copyable<iterator_t<_Rng>>) {
|
||||
return {_St::_Common, noexcept(common_view{_STD declval<_Rng>()})};
|
||||
} else {
|
||||
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::_All) {
|
||||
return views::all(_STD forward<_Rng>(_Range));
|
||||
} else if constexpr (_Choice<_Rng>._Strategy == _St::_Common) {
|
||||
return common_view{_STD forward<_Rng>(_Range)};
|
||||
} else {
|
||||
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _Common_fn common;
|
||||
} // namespace views
|
||||
|
||||
// CLASS TEMPLATE ranges::reverse_view
|
||||
// clang-format off
|
||||
template <view _Vw>
|
||||
|
@ -2481,114 +2591,379 @@ namespace ranges {
|
|||
inline constexpr _Reverse_fn reverse;
|
||||
} // namespace views
|
||||
|
||||
// CLASS TEMPLATE ranges::common_view
|
||||
// CLASS TEMPLATE ranges::elements_view
|
||||
template <class _Tuple, size_t _Index>
|
||||
concept _Has_tuple_element = requires(_Tuple __t) {
|
||||
typename tuple_size<_Tuple>::type;
|
||||
requires _Index < tuple_size_v<_Tuple>;
|
||||
typename tuple_element_t<_Index, _Tuple>;
|
||||
// clang-format off
|
||||
{ _STD get<_Index>(__t) } -> convertible_to<const tuple_element_t<_Index, _Tuple>&>;
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
template <view _Vw>
|
||||
requires (!common_range<_Vw> && copyable<iterator_t<_Vw>>)
|
||||
class common_view : public view_interface<common_view<_Vw>> {
|
||||
template <input_range _Vw, size_t _Index>
|
||||
requires view<_Vw> && _Has_tuple_element<range_value_t<_Vw>, _Index>
|
||||
&& _Has_tuple_element<remove_reference_t<range_reference_t<_Vw>>, _Index>
|
||||
class elements_view : public view_interface<elements_view<_Vw, _Index>> {
|
||||
// clang-format on
|
||||
private:
|
||||
/* [[no_unique_address]] */ _Vw _Base{};
|
||||
/* [[no_unique_address]] */ _Vw _Range{};
|
||||
|
||||
template <bool _Const>
|
||||
class _Sentinel;
|
||||
|
||||
template <class _Traits> // TRANSITION, LWG-3289
|
||||
struct _Category_base {};
|
||||
|
||||
// clang-format off
|
||||
template <_Has_member_iterator_category _Traits>
|
||||
struct _Category_base<_Traits> {
|
||||
// clang-format on
|
||||
using iterator_category = typename _Traits::iterator_category;
|
||||
};
|
||||
|
||||
template <bool _Const>
|
||||
class _Iterator : public _Category_base<iterator_traits<iterator_t<_Vw>>> {
|
||||
private:
|
||||
template <bool>
|
||||
friend class _Iterator;
|
||||
template <bool>
|
||||
friend class _Sentinel;
|
||||
|
||||
using _Base = _Maybe_const<_Const, _Vw>;
|
||||
|
||||
iterator_t<_Base> _Current{};
|
||||
|
||||
public:
|
||||
using iterator_concept = conditional_t<random_access_range<_Vw>, random_access_iterator_tag,
|
||||
conditional_t<bidirectional_range<_Vw>, bidirectional_iterator_tag,
|
||||
conditional_t<forward_range<_Vw>, forward_iterator_tag, input_iterator_tag>>>;
|
||||
using value_type = remove_cvref_t<tuple_element_t<_Index, range_value_t<_Base>>>;
|
||||
using difference_type = range_difference_t<_Base>;
|
||||
|
||||
_Iterator() = default;
|
||||
|
||||
constexpr explicit _Iterator(iterator_t<_Base> _Current_) noexcept(
|
||||
is_nothrow_move_constructible_v<iterator_t<_Base>>) // strengthened
|
||||
: _Current{_STD move(_Current_)} {}
|
||||
|
||||
// clang-format off
|
||||
constexpr _Iterator(_Iterator<!_Const> _It) noexcept(
|
||||
is_nothrow_constructible_v<iterator_t<_Base>, iterator_t<_Vw>>) // strengthened
|
||||
requires _Const && convertible_to<iterator_t<_Vw>, iterator_t<_Base>>
|
||||
: _Current{_STD move(_It._Current)} {}
|
||||
// clang-format on
|
||||
|
||||
_NODISCARD constexpr iterator_t<_Base> base() const& noexcept(
|
||||
is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
|
||||
requires copyable<iterator_t<_Base>> {
|
||||
return _Current;
|
||||
}
|
||||
|
||||
_NODISCARD constexpr iterator_t<_Base> base() && noexcept(
|
||||
is_nothrow_move_constructible_v<iterator_t<_Base>>) /* strengthened */ {
|
||||
return _STD move(_Current);
|
||||
}
|
||||
|
||||
_NODISCARD constexpr decltype(auto) operator*() const
|
||||
noexcept(noexcept(_STD get<_Index>(*_Current))) /* strengthened */ {
|
||||
return _STD get<_Index>(*_Current);
|
||||
}
|
||||
|
||||
constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ {
|
||||
++_Current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr void operator++(int) noexcept(noexcept(++_Current)) /* strengthened */ {
|
||||
// Constraint removed per LWG-3492
|
||||
++_Current;
|
||||
}
|
||||
|
||||
constexpr _Iterator operator++(int) noexcept(
|
||||
noexcept(++_Current) && is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
|
||||
requires forward_range<_Base> {
|
||||
auto _Tmp = *this;
|
||||
++_Current;
|
||||
return _Tmp;
|
||||
}
|
||||
|
||||
constexpr _Iterator& operator--() noexcept(noexcept(--_Current)) /* strengthened */
|
||||
requires bidirectional_range<_Base> {
|
||||
--_Current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr _Iterator operator--(int) noexcept(
|
||||
noexcept(--_Current) && is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
|
||||
requires bidirectional_range<_Base> {
|
||||
auto _Tmp = *this;
|
||||
--_Current;
|
||||
return _Tmp;
|
||||
}
|
||||
|
||||
constexpr void _Verify_offset(const difference_type _Off) const requires random_access_range<_Base> {
|
||||
#if _ITERATOR_DEBUG_LEVEL != 0
|
||||
(void) _Off;
|
||||
#else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 / _ITERATOR_DEBUG_LEVEL != 0 vvv
|
||||
if constexpr (_Offset_verifiable_v<iterator_t<_Base>>) {
|
||||
_Current._Verify_offset(_Off);
|
||||
}
|
||||
#endif // _ITERATOR_DEBUG_LEVEL == 0
|
||||
}
|
||||
|
||||
constexpr _Iterator& operator+=(const difference_type _Off) noexcept(
|
||||
noexcept(_Current += _Off)) /* strengthened */ requires random_access_range<_Base> {
|
||||
#if _ITERATOR_DEBUG_LEVEL != 0
|
||||
_Verify_offset(_Off);
|
||||
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
||||
_Current += _Off;
|
||||
return *this;
|
||||
}
|
||||
constexpr _Iterator& operator-=(const difference_type _Off) noexcept(
|
||||
noexcept(_Current -= _Off)) /* strengthened */ requires random_access_range<_Base> {
|
||||
#if _ITERATOR_DEBUG_LEVEL != 0
|
||||
_Verify_offset(-_Off);
|
||||
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
||||
_Current -= _Off;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_NODISCARD constexpr decltype(auto) operator[](const difference_type _Idx) const
|
||||
noexcept(noexcept(_STD get<_Index>(*(_Current + _Idx)))) /* strengthened */
|
||||
requires random_access_range<_Base> {
|
||||
#if _ITERATOR_DEBUG_LEVEL != 0
|
||||
_Verify_offset(_Idx);
|
||||
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
||||
return _STD get<_Index>(*(_Current + _Idx));
|
||||
}
|
||||
|
||||
_NODISCARD friend constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept(
|
||||
noexcept(_Left._Current == _Right._Current)) /* strengthened */
|
||||
requires equality_comparable<iterator_t<_Base>> {
|
||||
return _Left._Current == _Right._Current;
|
||||
}
|
||||
|
||||
_NODISCARD friend constexpr bool operator<(const _Iterator& _Left, const _Iterator& _Right) noexcept(
|
||||
noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> {
|
||||
return _Left._Current < _Right._Current;
|
||||
}
|
||||
_NODISCARD friend constexpr bool operator>(const _Iterator& _Left, const _Iterator& _Right) noexcept(
|
||||
noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> {
|
||||
return _Right < _Left;
|
||||
}
|
||||
_NODISCARD friend constexpr bool operator<=(const _Iterator& _Left, const _Iterator& _Right) noexcept(
|
||||
noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> {
|
||||
return !(_Right < _Left);
|
||||
}
|
||||
_NODISCARD friend constexpr bool operator>=(const _Iterator& _Left, const _Iterator& _Right) noexcept(
|
||||
noexcept(_Left._Current < _Right._Current)) /* strengthened */ requires random_access_range<_Base> {
|
||||
return !(_Left < _Right);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
_NODISCARD friend constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept(
|
||||
noexcept(_Left._Current <=> _Right._Current)) /* strengthened */
|
||||
requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>> {
|
||||
// clang-format on
|
||||
return _Left._Current <=> _Right._Current;
|
||||
}
|
||||
|
||||
_NODISCARD friend constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept(
|
||||
noexcept(_STD declval<iterator_t<_Base>&>() += _Off)
|
||||
&& is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
|
||||
requires random_access_range<_Base> {
|
||||
#if _ITERATOR_DEBUG_LEVEL != 0
|
||||
_It._Verify_offset(_Off);
|
||||
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
||||
auto _Copy = _It;
|
||||
_Copy._Current += _Off;
|
||||
return _Copy;
|
||||
}
|
||||
|
||||
_NODISCARD friend constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept(
|
||||
noexcept(_STD declval<iterator_t<_Base>&>() += _Off)
|
||||
&& is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
|
||||
requires random_access_range<_Base> {
|
||||
#if _ITERATOR_DEBUG_LEVEL != 0
|
||||
_It._Verify_offset(_Off);
|
||||
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
||||
auto _Copy = _It;
|
||||
_Copy._Current += _Off;
|
||||
return _Copy;
|
||||
}
|
||||
|
||||
_NODISCARD friend constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept(
|
||||
noexcept(_STD declval<iterator_t<_Base>&>() -= _Off)
|
||||
&& is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
|
||||
requires random_access_range<_Base> {
|
||||
#if _ITERATOR_DEBUG_LEVEL != 0
|
||||
_It._Verify_offset(-_Off);
|
||||
#endif // _ITERATOR_DEBUG_LEVEL != 0
|
||||
auto _Copy = _It;
|
||||
_Copy._Current -= _Off;
|
||||
return _Copy;
|
||||
}
|
||||
|
||||
_NODISCARD friend constexpr difference_type operator-(const _Iterator& _Left,
|
||||
const _Iterator& _Right) noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */
|
||||
requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>> { // Per LWG-3483
|
||||
return _Left._Current - _Right._Current;
|
||||
}
|
||||
};
|
||||
|
||||
template <bool _Const>
|
||||
class _Sentinel {
|
||||
private:
|
||||
template <bool>
|
||||
friend class _Sentinel;
|
||||
|
||||
using _Base = _Maybe_const<_Const, _Vw>;
|
||||
|
||||
sentinel_t<_Base> _Last{};
|
||||
|
||||
template <bool _OtherConst>
|
||||
_NODISCARD static constexpr const iterator_t<_Maybe_const<_OtherConst, _Vw>>& _Get_current(
|
||||
const _Iterator<_OtherConst>& _It) noexcept {
|
||||
return _It._Current;
|
||||
}
|
||||
|
||||
public:
|
||||
_Sentinel() = default;
|
||||
constexpr explicit _Sentinel(sentinel_t<_Base> _Last_) noexcept(
|
||||
is_nothrow_move_constructible_v<sentinel_t<_Base>>) // strengthened
|
||||
: _Last(_STD move(_Last_)) {}
|
||||
|
||||
// clang-format off
|
||||
constexpr _Sentinel(_Sentinel<!_Const> _Se)
|
||||
noexcept(is_nothrow_constructible_v<sentinel_t<_Base>, sentinel_t<_Vw>>) // strengthened
|
||||
requires _Const && convertible_to<sentinel_t<_Vw>, sentinel_t<_Base>>
|
||||
: _Last(_STD move(_Se._Last)) {}
|
||||
// clang-format on
|
||||
|
||||
_NODISCARD constexpr sentinel_t<_Base> base() const
|
||||
noexcept(is_nothrow_copy_constructible_v<sentinel_t<_Base>>) /* strengthened */ {
|
||||
return _Last;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <bool _OtherConst> // Per resolution of LWG-3406
|
||||
requires sentinel_for<sentinel_t<_Base>, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
|
||||
_NODISCARD friend constexpr bool operator==(const _Iterator<_OtherConst>& _Left,
|
||||
const _Sentinel& _Right) noexcept(noexcept(_Get_current(_Left) == _Right._Last)) /* strengthened */ {
|
||||
// clang-format on
|
||||
return _Get_current(_Left) == _Right._Last;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <bool _OtherConst> // Per resolution of LWG-3406
|
||||
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
|
||||
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
|
||||
const _Iterator<_OtherConst>& _Left, const _Sentinel& _Right) noexcept(
|
||||
noexcept(_Get_current(_Left) - _Right._Last)) /* strengthened */ {
|
||||
// clang-format on
|
||||
return _Get_current(_Left) - _Right._Last;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <bool _OtherConst> // Per resolution of LWG-3406
|
||||
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Maybe_const<_OtherConst, _Vw>>>
|
||||
_NODISCARD friend constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-(
|
||||
const _Sentinel& _Left, const _Iterator<_OtherConst>& _Right) noexcept(
|
||||
noexcept(_Left._Last - _Get_current(_Right))) /* strengthened */ {
|
||||
// clang-format on
|
||||
return _Left._Last - _Get_current(_Right);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
common_view() = default;
|
||||
constexpr explicit common_view(_Vw _Base_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
|
||||
: _Base(_STD move(_Base_)) {}
|
||||
// converting constructor template omitted per LWG-3405
|
||||
elements_view() = default;
|
||||
|
||||
_NODISCARD constexpr _Vw base() const& noexcept(
|
||||
is_nothrow_copy_constructible_v<_Vw>) /* strengthened */ requires copy_constructible<_Vw> {
|
||||
return _Base;
|
||||
constexpr explicit elements_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened
|
||||
: _Range(_STD move(_Range_)) {}
|
||||
|
||||
_NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */
|
||||
requires copy_constructible<_Vw> {
|
||||
return _Range;
|
||||
}
|
||||
|
||||
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
|
||||
return _STD move(_Base);
|
||||
return _STD move(_Range);
|
||||
}
|
||||
|
||||
_NODISCARD constexpr auto begin() noexcept(
|
||||
noexcept(_RANGES begin(_Base)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */ {
|
||||
if constexpr (random_access_range<_Vw> && sized_range<_Vw>) {
|
||||
return _RANGES begin(_Base);
|
||||
// clang-format off
|
||||
_NODISCARD constexpr _Iterator<false> begin() noexcept(
|
||||
noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v<iterator_t<_Vw>>) /* strengthened */
|
||||
requires (!_Simple_view<_Vw>) {
|
||||
// clang-format on
|
||||
return _Iterator<false>{_RANGES begin(_Range)};
|
||||
}
|
||||
|
||||
_NODISCARD constexpr _Iterator<true> begin() const
|
||||
noexcept(noexcept(_RANGES begin(_Range))
|
||||
&& is_nothrow_move_constructible_v<iterator_t<const _Vw>>) /* strengthened */
|
||||
requires range<const _Vw> { // Per resolution of LWG-3406
|
||||
return _Iterator<true>{_RANGES begin(_Range)};
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
_NODISCARD constexpr auto end() noexcept(noexcept(
|
||||
_RANGES end(_Range)) && is_nothrow_move_constructible_v<sentinel_t<_Vw>>) /* strengthened */
|
||||
requires (!_Simple_view<_Vw>) { // Per resolution of LWG-3406
|
||||
// clang-format on
|
||||
if constexpr (common_range<_Vw>) {
|
||||
return _Iterator<false>{_RANGES end(_Range)};
|
||||
} else {
|
||||
return common_iterator<iterator_t<_Vw>, sentinel_t<_Vw>>{_RANGES begin(_Base)};
|
||||
return _Sentinel<false>{_RANGES end(_Range)};
|
||||
}
|
||||
}
|
||||
|
||||
_NODISCARD constexpr auto begin() const noexcept(
|
||||
noexcept(_RANGES begin(_Base))
|
||||
&& is_nothrow_move_constructible_v<iterator_t<const _Vw>>) /* strengthened */ requires range<const _Vw> {
|
||||
if constexpr (random_access_range<const _Vw> && sized_range<const _Vw>) {
|
||||
return _RANGES begin(_Base);
|
||||
// clang-format off
|
||||
_NODISCARD constexpr auto end() const noexcept(noexcept(
|
||||
_RANGES end(_Range)) && is_nothrow_move_constructible_v<sentinel_t<const _Vw>>) /* strengthened */
|
||||
requires range<const _Vw> {
|
||||
// clang-format on
|
||||
if constexpr (common_range<const _Vw>) {
|
||||
return _Iterator<true>{_RANGES end(_Range)};
|
||||
} else {
|
||||
return common_iterator<iterator_t<const _Vw>, sentinel_t<const _Vw>>{_RANGES begin(_Base)};
|
||||
return _Sentinel<true>{_RANGES end(_Range)};
|
||||
}
|
||||
}
|
||||
|
||||
_NODISCARD constexpr auto end() {
|
||||
if constexpr (random_access_range<_Vw> && sized_range<_Vw>) {
|
||||
return _RANGES begin(_Base) + _RANGES size(_Base);
|
||||
} else {
|
||||
return common_iterator<iterator_t<_Vw>, sentinel_t<_Vw>>{_RANGES end(_Base)};
|
||||
}
|
||||
_NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) /* strengthened */
|
||||
requires sized_range<_Vw> {
|
||||
return _RANGES size(_Range);
|
||||
}
|
||||
|
||||
_NODISCARD constexpr auto end() const requires range<const _Vw> {
|
||||
if constexpr (random_access_range<const _Vw> && sized_range<const _Vw>) {
|
||||
return _RANGES begin(_Base) + _RANGES size(_Base);
|
||||
} else {
|
||||
return common_iterator<iterator_t<const _Vw>, sentinel_t<const _Vw>>{_RANGES end(_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);
|
||||
_NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) /* strengthened */
|
||||
requires sized_range<const _Vw> {
|
||||
return _RANGES size(_Range);
|
||||
}
|
||||
};
|
||||
|
||||
template <class _Rng>
|
||||
common_view(_Rng &&) -> common_view<views::all_t<_Rng>>;
|
||||
using keys_view = elements_view<views::all_t<_Rng>, 0>;
|
||||
template <class _Rng>
|
||||
using values_view = elements_view<views::all_t<_Rng>, 1>;
|
||||
|
||||
namespace views {
|
||||
// VARIABLE views::common
|
||||
class _Common_fn : public _Pipe::_Base<_Common_fn> {
|
||||
private:
|
||||
enum class _St { _None, _All, _Common };
|
||||
|
||||
template <class _Rng>
|
||||
_NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept {
|
||||
if constexpr (common_range<_Rng>) {
|
||||
return {_St::_All, noexcept(views::all(_STD declval<_Rng>()))};
|
||||
} else if constexpr (copyable<iterator_t<_Rng>>) {
|
||||
return {_St::_Common, noexcept(common_view{_STD declval<_Rng>()})};
|
||||
} else {
|
||||
return {_St::_None};
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Rng>
|
||||
static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>();
|
||||
|
||||
// VARIABLE views::elements
|
||||
template <size_t _Index>
|
||||
class _Elements_fn : public _Pipe::_Base<_Elements_fn<_Index>> {
|
||||
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::_All) {
|
||||
return views::all(_STD forward<_Rng>(_Range));
|
||||
} else if constexpr (_Choice<_Rng>._Strategy == _St::_Common) {
|
||||
return common_view{_STD forward<_Rng>(_Range)};
|
||||
} else {
|
||||
static_assert(_Always_false<_Rng>, "Should be unreachable");
|
||||
}
|
||||
_NODISCARD constexpr auto operator()(_Rng&& _Range) const noexcept(
|
||||
noexcept(elements_view<views::all_t<_Rng>, _Index>{_STD forward<_Rng>(_Range)})) requires requires {
|
||||
elements_view<views::all_t<_Rng>, _Index>{static_cast<_Rng&&>(_Range)};
|
||||
}
|
||||
{ return elements_view<views::all_t<_Rng>, _Index>{_STD forward<_Rng>(_Range)}; }
|
||||
};
|
||||
|
||||
inline constexpr _Common_fn common;
|
||||
template <size_t _Index>
|
||||
inline constexpr _Elements_fn<_Index> elements;
|
||||
inline constexpr auto keys = elements<0>;
|
||||
inline constexpr auto values = elements<1>;
|
||||
} // namespace views
|
||||
} // namespace ranges
|
||||
|
||||
|
|
|
@ -351,6 +351,7 @@ tests\P0896R4_views_counted_death
|
|||
tests\P0896R4_views_drop
|
||||
tests\P0896R4_views_drop_while
|
||||
tests\P0896R4_views_drop_while_death
|
||||
tests\P0896R4_views_elements
|
||||
tests\P0896R4_views_empty
|
||||
tests\P0896R4_views_filter
|
||||
tests\P0896R4_views_filter_death
|
||||
|
|
|
@ -102,12 +102,15 @@ STATIC_ASSERT(test_cpo(ranges::views::common));
|
|||
STATIC_ASSERT(test_cpo(ranges::views::counted));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::drop));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::drop_while));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::elements<42>));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::filter));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::keys));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::reverse));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::single));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::take));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::take_while));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::transform));
|
||||
STATIC_ASSERT(test_cpo(ranges::views::values));
|
||||
|
||||
void test_cpo_ambiguity() {
|
||||
using namespace std::ranges;
|
||||
|
|
|
@ -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,417 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <forward_list>
|
||||
#include <ranges>
|
||||
#include <span>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <range_algorithm_support.hpp>
|
||||
using namespace std;
|
||||
using P = pair<int, int>;
|
||||
|
||||
// Validate views::keys and views::values
|
||||
STATIC_ASSERT(same_as<remove_const_t<decltype(views::keys)>, remove_const_t<decltype(views::elements<0>)>>);
|
||||
STATIC_ASSERT(same_as<remove_const_t<decltype(views::values)>, remove_const_t<decltype(views::elements<1>)>>);
|
||||
|
||||
constexpr auto pipeline = views::elements<0> | views::all;
|
||||
|
||||
template <class Rng, class V = views::all_t<Rng>>
|
||||
using pipeline_t = ranges::elements_view<V, 0>;
|
||||
|
||||
template <class Rng>
|
||||
concept CanViewElements = requires(Rng&& r) {
|
||||
views::elements<0>(static_cast<Rng&&>(r));
|
||||
};
|
||||
|
||||
constexpr P some_pairs[] = {{0, -1}, {1, -2}, {2, -3}, {3, -4}, {4, -5}, {5, -6}, {6, -7}, {7, -8}};
|
||||
constexpr int expected_keys[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
constexpr int expected_values[] = {-1, -2, -3, -4, -5, -6, -7, -8};
|
||||
|
||||
template <ranges::input_range Rng>
|
||||
constexpr bool test_one(Rng&& rng) {
|
||||
using ranges::elements_view, ranges::bidirectional_range, ranges::common_range, ranges::contiguous_range,
|
||||
ranges::enable_borrowed_range, ranges::forward_range, ranges::input_range, ranges::iterator_t, ranges::prev,
|
||||
ranges::random_access_range, ranges::range, ranges::range_reference_t, ranges::sentinel_t;
|
||||
|
||||
using V = views::all_t<Rng>;
|
||||
using R = elements_view<V, 0>;
|
||||
STATIC_ASSERT(ranges::view<R>);
|
||||
STATIC_ASSERT(input_range<R>);
|
||||
STATIC_ASSERT(forward_range<R> == forward_range<Rng>);
|
||||
STATIC_ASSERT(bidirectional_range<R> == bidirectional_range<Rng>);
|
||||
STATIC_ASSERT(random_access_range<R> == random_access_range<Rng>);
|
||||
STATIC_ASSERT(!contiguous_range<R>);
|
||||
|
||||
// ... with lvalue argument
|
||||
STATIC_ASSERT(CanViewElements<Rng&>);
|
||||
constexpr bool is_view = ranges::view<remove_cvref_t<Rng>>;
|
||||
if constexpr (CanViewElements<Rng&>) { // Validate lvalue
|
||||
constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v<V>;
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(views::elements<0>(rng)), R>);
|
||||
STATIC_ASSERT(noexcept(views::elements<0>(rng)) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(rng | views::elements<0>), R>);
|
||||
STATIC_ASSERT(noexcept(rng | views::elements<0>) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(rng | pipeline), pipeline_t<Rng&>>);
|
||||
STATIC_ASSERT(noexcept(rng | pipeline) == is_noexcept);
|
||||
}
|
||||
|
||||
// ... with const lvalue argument
|
||||
STATIC_ASSERT(CanViewElements<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::elements<0>(as_const(rng))), R>);
|
||||
STATIC_ASSERT(noexcept(views::elements<0>(as_const(rng))) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(as_const(rng) | views::elements<0>), R>);
|
||||
STATIC_ASSERT(noexcept(as_const(rng) | views::elements<0>) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(as_const(rng) | pipeline), pipeline_t<const remove_reference_t<Rng>&>>);
|
||||
STATIC_ASSERT(noexcept(as_const(rng) | pipeline) == is_noexcept);
|
||||
} else if constexpr (!is_view) {
|
||||
using RC = elements_view<views::all_t<const remove_reference_t<Rng>&>, 0>;
|
||||
constexpr bool is_noexcept = is_nothrow_constructible_v<RC, const remove_reference_t<Rng>&>;
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(views::elements<0>(as_const(rng))), RC>);
|
||||
STATIC_ASSERT(noexcept(views::elements<0>(as_const(rng))) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(as_const(rng) | views::elements<0>), RC>);
|
||||
STATIC_ASSERT(noexcept(as_const(rng) | views::elements<0>) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(as_const(rng) | pipeline), pipeline_t<const remove_reference_t<Rng>&>>);
|
||||
STATIC_ASSERT(noexcept(as_const(rng) | pipeline) == is_noexcept);
|
||||
}
|
||||
|
||||
// ... with rvalue argument
|
||||
STATIC_ASSERT(CanViewElements<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::elements<0>(move(rng))), R>);
|
||||
STATIC_ASSERT(noexcept(views::elements<0>(move(rng))) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(move(rng) | views::elements<0>), R>);
|
||||
STATIC_ASSERT(noexcept(move(rng) | views::elements<0>) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(move(rng) | pipeline), pipeline_t<remove_reference_t<Rng>>>);
|
||||
STATIC_ASSERT(noexcept(move(rng) | pipeline) == is_noexcept);
|
||||
} else if constexpr (enable_borrowed_range<remove_cvref_t<Rng>>) {
|
||||
using S = decltype(ranges::subrange{move(rng)});
|
||||
using RS = elements_view<S, 0>;
|
||||
constexpr bool is_noexcept = noexcept(S{move(rng)});
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(views::elements<0>(move(rng))), RS>);
|
||||
STATIC_ASSERT(noexcept(views::elements<0>(move(rng))) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(move(rng) | views::elements<0>), RS>);
|
||||
STATIC_ASSERT(noexcept(move(rng) | views::elements<0>) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(move(rng) | pipeline), pipeline_t<remove_reference_t<Rng>>>);
|
||||
STATIC_ASSERT(noexcept(move(rng) | pipeline) == is_noexcept);
|
||||
}
|
||||
|
||||
// ... with const rvalue argument
|
||||
STATIC_ASSERT(CanViewElements<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::elements<0>(move(as_const(rng)))), R>);
|
||||
STATIC_ASSERT(noexcept(views::elements<0>(move(as_const(rng)))) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(move(as_const(rng)) | views::elements<0>), R>);
|
||||
STATIC_ASSERT(noexcept(move(as_const(rng)) | views::elements<0>) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(move(as_const(rng)) | pipeline), pipeline_t<const remove_reference_t<Rng>>>);
|
||||
STATIC_ASSERT(noexcept(move(as_const(rng)) | pipeline) == is_noexcept);
|
||||
} else if constexpr (!is_view && enable_borrowed_range<remove_cvref_t<Rng>>) {
|
||||
using S = decltype(ranges::subrange{move(as_const(rng))});
|
||||
using RS = elements_view<S, 0>;
|
||||
constexpr bool is_noexcept = noexcept(S{move(as_const(rng))});
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(views::elements<0>(move(as_const(rng)))), RS>);
|
||||
STATIC_ASSERT(noexcept(views::elements<0>(move(as_const(rng)))) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(move(as_const(rng)) | views::elements<0>), RS>);
|
||||
STATIC_ASSERT(noexcept(move(as_const(rng)) | views::elements<0>) == is_noexcept);
|
||||
|
||||
STATIC_ASSERT(same_as<decltype(move(as_const(rng)) | pipeline), pipeline_t<const remove_reference_t<Rng>>>);
|
||||
STATIC_ASSERT(noexcept(move(as_const(rng)) | pipeline) == is_noexcept);
|
||||
}
|
||||
|
||||
// Validate concepts are properly modeled
|
||||
R r{forward<Rng>(rng)};
|
||||
STATIC_ASSERT(ranges::view<R>);
|
||||
STATIC_ASSERT(input_range<R>);
|
||||
STATIC_ASSERT(forward_range<R> == forward_range<Rng>);
|
||||
STATIC_ASSERT(bidirectional_range<R> == bidirectional_range<Rng>);
|
||||
STATIC_ASSERT(random_access_range<R> == random_access_range<Rng>);
|
||||
STATIC_ASSERT(!contiguous_range<R>);
|
||||
|
||||
// Validate elements_view::size
|
||||
STATIC_ASSERT(CanMemberSize<R> == CanSize<V>);
|
||||
STATIC_ASSERT(CanSize<R> == CanMemberSize<R>);
|
||||
STATIC_ASSERT(CanMemberSize<const R> == CanSize<const V>);
|
||||
STATIC_ASSERT(CanSize<const R> == CanMemberSize<const R>);
|
||||
if constexpr (CanMemberSize<R>) {
|
||||
assert(r.size() == static_cast<decltype(r.size())>(ranges::size(expected_keys)));
|
||||
if constexpr (CanMemberSize<const R>) {
|
||||
assert(as_const(r).size() == static_cast<decltype(r.size())>(ranges::size(expected_keys)));
|
||||
}
|
||||
}
|
||||
|
||||
const bool is_empty = ranges::empty(expected_keys);
|
||||
|
||||
// Validate view_interface::empty and operator bool
|
||||
STATIC_ASSERT(CanMemberEmpty<R> == forward_range<Rng>);
|
||||
STATIC_ASSERT(CanBool<R> == CanEmpty<R>);
|
||||
if constexpr (CanMemberEmpty<R>) {
|
||||
assert(r.empty() == is_empty);
|
||||
assert(static_cast<bool>(r) == !is_empty);
|
||||
} else {
|
||||
STATIC_ASSERT(CanEmpty<R> == CanSize<R>);
|
||||
if constexpr (CanEmpty<R>) {
|
||||
assert(ranges::empty(r) == is_empty);
|
||||
assert(static_cast<bool>(r) == !is_empty);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_ASSERT(CanMemberEmpty<const R> == forward_range<const Rng>);
|
||||
STATIC_ASSERT(CanBool<const R> == CanEmpty<const R>);
|
||||
if constexpr (CanMemberEmpty<const R>) {
|
||||
assert(as_const(r).empty() == is_empty);
|
||||
assert(static_cast<bool>(as_const(r)) == !is_empty);
|
||||
} else {
|
||||
STATIC_ASSERT(CanEmpty<const R> == CanSize<const R>);
|
||||
if constexpr (CanEmpty<const R>) {
|
||||
assert(ranges::empty(as_const(r)) == is_empty);
|
||||
assert(static_cast<bool>(as_const(r)) == !is_empty);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate content
|
||||
assert(ranges::equal(r, expected_keys));
|
||||
|
||||
// Validate keys_view and values_view
|
||||
STATIC_ASSERT(same_as<ranges::keys_view<Rng>, R>);
|
||||
STATIC_ASSERT(same_as<ranges::values_view<Rng>, elements_view<V, 1>>);
|
||||
if constexpr (forward_range<Rng> && is_lvalue_reference_v<Rng>) {
|
||||
assert(ranges::equal(ranges::values_view<Rng>{rng}, expected_values));
|
||||
}
|
||||
|
||||
// Validate elements_view::begin
|
||||
STATIC_ASSERT(CanMemberBegin<R>);
|
||||
STATIC_ASSERT(CanBegin<const R&> == (range<const V>) );
|
||||
if (forward_range<V>) { // intentionally not if constexpr
|
||||
const same_as<iterator_t<R>> auto i = r.begin();
|
||||
if (!is_empty) {
|
||||
assert(*i == *begin(expected_keys));
|
||||
}
|
||||
|
||||
if constexpr (copyable<V>) {
|
||||
auto r2 = r;
|
||||
const same_as<iterator_t<R>> auto i2 = r2.begin();
|
||||
if (!is_empty) {
|
||||
assert(*i2 == *i);
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (CanBegin<const R&>) {
|
||||
const same_as<iterator_t<const R>> auto i3 = as_const(r).begin();
|
||||
if (!is_empty) {
|
||||
assert(*i3 == *i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate elements_view::end
|
||||
STATIC_ASSERT(CanMemberEnd<R>);
|
||||
STATIC_ASSERT(CanEnd<const R&> == range<const V>);
|
||||
if (!is_empty) {
|
||||
same_as<sentinel_t<R>> auto i = r.end();
|
||||
static_assert(common_range<R> == common_range<V>);
|
||||
if constexpr (bidirectional_range<R> && common_range<R>) {
|
||||
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1243263
|
||||
assert(*prev(i) == *prev(end(expected_keys)));
|
||||
#else // ^^^ no workaround / workaround vvv
|
||||
assert(*ranges::prev(i) == *ranges::prev(end(expected_keys)));
|
||||
#endif // ^^^ workaround ^^^
|
||||
}
|
||||
|
||||
if constexpr (CanEnd<const R&>) {
|
||||
same_as<sentinel_t<const R>> auto i2 = as_const(r).end();
|
||||
static_assert(common_range<const R> == common_range<const V>);
|
||||
if constexpr (bidirectional_range<const R> && common_range<const R>) {
|
||||
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1243263
|
||||
assert(*prev(i2) == *prev(end(expected_keys)));
|
||||
#else // ^^^ no workaround / workaround vvv
|
||||
assert(*ranges::prev(i2) == *ranges::prev(end(expected_keys)));
|
||||
#endif // ^^^ workaround ^^^
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate view_interface::data
|
||||
STATIC_ASSERT(!CanData<R>);
|
||||
STATIC_ASSERT(!CanData<const R>);
|
||||
|
||||
// Validate view_interface::front and back
|
||||
if (!is_empty) {
|
||||
STATIC_ASSERT(CanMemberFront<R> == forward_range<V>);
|
||||
if constexpr (CanMemberFront<R>) {
|
||||
assert(r.front() == *begin(expected_keys));
|
||||
}
|
||||
|
||||
STATIC_ASSERT(CanMemberBack<R> == (bidirectional_range<V> && common_range<V>) );
|
||||
if constexpr (CanMemberBack<R>) {
|
||||
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1243263
|
||||
assert(r.back() == *prev(end(expected_keys)));
|
||||
#else // ^^^ no workaround / workaround vvv
|
||||
assert(r.back() == *ranges::prev(end(expected_keys)));
|
||||
#endif // ^^^ workaround ^^^
|
||||
}
|
||||
|
||||
STATIC_ASSERT(CanMemberFront<const R> == (forward_range<const V>) );
|
||||
if constexpr (CanMemberFront<const R>) {
|
||||
assert(as_const(r).front() == *begin(expected_keys));
|
||||
}
|
||||
|
||||
STATIC_ASSERT(CanMemberBack<const R> == (bidirectional_range<const V> && common_range<const V>) );
|
||||
if constexpr (CanMemberBack<const R>) {
|
||||
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1243263
|
||||
assert(as_const(r).back() == *prev(end(expected_keys)));
|
||||
#else // ^^^ no workaround / workaround vvv
|
||||
assert(as_const(r).back() == *ranges::prev(end(expected_keys)));
|
||||
#endif // ^^^ workaround ^^^
|
||||
}
|
||||
}
|
||||
|
||||
// Validate view_interface::operator[]
|
||||
if (!is_empty) {
|
||||
STATIC_ASSERT(CanIndex<R> == random_access_range<V>);
|
||||
if constexpr (CanIndex<R>) {
|
||||
assert(r[0] == *r.begin());
|
||||
}
|
||||
|
||||
STATIC_ASSERT(CanIndex<const R> == random_access_range<const V>);
|
||||
if constexpr (CanIndex<const R>) {
|
||||
assert(as_const(r)[0] == *as_const(r).begin());
|
||||
}
|
||||
}
|
||||
|
||||
// Validate elements_view::base() const&
|
||||
STATIC_ASSERT(CanMemberBase<const R&> == copy_constructible<V>);
|
||||
if constexpr (copy_constructible<V> && forward_range<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() == pair{0, -1})); // NB: depends on the test data
|
||||
if constexpr (bidirectional_range<V> && common_range<V>) {
|
||||
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1243263
|
||||
assert((*prev(b1.end()) == pair{7, -8})); // NB: depends on the test data
|
||||
#else // ^^^ no workaround / workaround vvv
|
||||
assert((*ranges::prev(b1.end()) == pair{7, -8})); // NB: depends on the test data
|
||||
#endif // ^^^ workaround ^^^
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate elements_view::base() && (NB: do this last since it leaves r moved-from)
|
||||
if (forward_range<V>) { // intentionally not if constexpr
|
||||
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() == pair{0, -1})); // NB: depends on the test data
|
||||
if constexpr (bidirectional_range<V> && common_range<V>) {
|
||||
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1243263
|
||||
assert((*prev(b2.end()) == pair{7, -8})); // NB: depends on the test data
|
||||
#else // ^^^ no workaround / workaround vvv
|
||||
assert((*ranges::prev(b2.end()) == pair{7, -8})); // NB: depends on the test data
|
||||
#endif // ^^^ workaround ^^^
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct instantiator {
|
||||
template <ranges::input_range R>
|
||||
static constexpr void call() {
|
||||
R r{some_pairs};
|
||||
test_one(r);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Category, test::Sized IsSized, test::Common IsCommon>
|
||||
using test_range =
|
||||
test::range<Category, const P, IsSized, test::CanDifference{derived_from<Category, random_access_iterator_tag>},
|
||||
IsCommon, test::CanCompare{derived_from<Category, forward_iterator_tag> || IsCommon == test::Common::yes},
|
||||
test::ProxyRef::no>;
|
||||
|
||||
constexpr void instantiation_test() {
|
||||
#ifdef TEST_EVERYTHING
|
||||
test_in<instantiator, const P>();
|
||||
#else // ^^^ test all input range permutations / test only "interesting" permutations vvv
|
||||
// The view is sensitive to category, commonality, size, and differencing, but cannot handle proxies.
|
||||
using test::Common, test::Sized;
|
||||
|
||||
instantiator::call<test_range<input_iterator_tag, Sized::no, Common::no>>();
|
||||
instantiator::call<test_range<input_iterator_tag, Sized::no, Common::yes>>();
|
||||
instantiator::call<test_range<input_iterator_tag, Sized::yes, Common::no>>();
|
||||
instantiator::call<test_range<input_iterator_tag, Sized::yes, Common::yes>>();
|
||||
instantiator::call<test_range<forward_iterator_tag, Sized::no, Common::no>>();
|
||||
instantiator::call<test_range<forward_iterator_tag, Sized::no, Common::yes>>();
|
||||
instantiator::call<test_range<forward_iterator_tag, Sized::yes, Common::no>>();
|
||||
instantiator::call<test_range<forward_iterator_tag, Sized::yes, Common::yes>>();
|
||||
instantiator::call<test_range<bidirectional_iterator_tag, Sized::no, Common::no>>();
|
||||
instantiator::call<test_range<bidirectional_iterator_tag, Sized::no, Common::yes>>();
|
||||
instantiator::call<test_range<bidirectional_iterator_tag, Sized::yes, Common::no>>();
|
||||
instantiator::call<test_range<bidirectional_iterator_tag, Sized::yes, Common::yes>>();
|
||||
instantiator::call<test_range<random_access_iterator_tag, Sized::no, Common::no>>();
|
||||
instantiator::call<test_range<random_access_iterator_tag, Sized::no, Common::yes>>();
|
||||
instantiator::call<test_range<random_access_iterator_tag, Sized::yes, Common::no>>();
|
||||
instantiator::call<test_range<random_access_iterator_tag, Sized::yes, Common::yes>>();
|
||||
instantiator::call<test_range<contiguous_iterator_tag, Sized::no, Common::no>>();
|
||||
instantiator::call<test_range<contiguous_iterator_tag, Sized::no, Common::yes>>();
|
||||
instantiator::call<test_range<contiguous_iterator_tag, Sized::yes, Common::no>>();
|
||||
instantiator::call<test_range<contiguous_iterator_tag, Sized::yes, Common::yes>>();
|
||||
#endif // TEST_EVERYTHING
|
||||
}
|
||||
|
||||
int main() {
|
||||
{ // Validate copyable views
|
||||
constexpr span<const P> s{some_pairs};
|
||||
STATIC_ASSERT(test_one(s));
|
||||
test_one(s);
|
||||
}
|
||||
|
||||
{ // Validate non-views
|
||||
STATIC_ASSERT(test_one(some_pairs));
|
||||
test_one(some_pairs);
|
||||
|
||||
{
|
||||
vector vec(ranges::begin(some_pairs), ranges::end(some_pairs));
|
||||
test_one(vec);
|
||||
}
|
||||
{
|
||||
forward_list lst(ranges::begin(some_pairs), ranges::end(some_pairs));
|
||||
test_one(lst);
|
||||
}
|
||||
|
||||
STATIC_ASSERT((instantiation_test(), true));
|
||||
instantiation_test();
|
||||
}
|
||||
|
||||
{ // Validate a non-view borrowed range
|
||||
constexpr span s{some_pairs};
|
||||
STATIC_ASSERT(test_one(s));
|
||||
test_one(s);
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче