From ce81544d33adbf198483b8b0f0a0e6ad36f06707 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 20 Aug 2020 11:44:51 -0700 Subject: [PATCH 01/10] Implement views:all and views::reverse Also, perma-workaround LLVM-37556. --- stl/inc/concepts | 3 +- stl/inc/ranges | 390 ++++++++++++++++++ stl/inc/xstring | 4 +- stl/inc/xutility | 61 ++- tests/std/include/range_algorithm_support.hpp | 168 +++++++- tests/std/test.lst | 2 + .../P0896R4_ranges_range_machinery/test.cpp | 3 + tests/std/tests/P0896R4_views_all/env.lst | 4 + tests/std/tests/P0896R4_views_all/test.cpp | 218 ++++++++++ tests/std/tests/P0896R4_views_reverse/env.lst | 4 + .../std/tests/P0896R4_views_reverse/test.cpp | 375 +++++++++++++++++ 11 files changed, 1200 insertions(+), 32 deletions(-) create mode 100644 tests/std/tests/P0896R4_views_all/env.lst create mode 100644 tests/std/tests/P0896R4_views_all/test.cpp create mode 100644 tests/std/tests/P0896R4_views_reverse/env.lst create mode 100644 tests/std/tests/P0896R4_views_reverse/test.cpp diff --git a/stl/inc/concepts b/stl/inc/concepts index 4da6a23f497..fad9a75caa8 100644 --- a/stl/inc/concepts +++ b/stl/inc/concepts @@ -165,9 +165,10 @@ namespace ranges { }; } // namespace _Swap - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Swap::_Cpo swap; } + using namespace _Cpos; } // namespace ranges // CONCEPT swappable diff --git a/stl/inc/ranges b/stl/inc/ranges index fe0e967e46f..d78aba0049c 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -30,6 +30,191 @@ namespace ranges { concept viewable_range = range<_Rng> && (borrowed_range<_Rng> || view>); + template + concept _Simple_view = view<_Rng> && range + && same_as, iterator_t> + && same_as, sentinel_t>; + + namespace _Pipe { + template + struct _Base; + + template + struct _Pipeline; + + // clang-format off + template + concept _Can_pipe = requires(_Left&& __l, _Right&& __r) { + static_cast<_Right&&>(__r)(static_cast<_Left&&>(__l)); + }; + + template + concept _Can_compose = constructible_from, _Left> + && constructible_from, _Right>; + // clang-format on + + template + struct _Base { + // clang-format off + template + requires _Can_compose<_Derived&&, _Other&&> + friend constexpr auto operator|(_Base&& __l, _Base<_Other>&& __r) noexcept(noexcept( + _Pipeline{static_cast<_Derived&&>(__l), 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&&>(__l), static_cast<_Other&&>(__r)}; + } + + // clang-format off + template + requires _Can_compose<_Derived&&, const _Other&> + friend constexpr auto operator|(_Base&& __l, const _Base<_Other>& __r) noexcept(noexcept( + _Pipeline{static_cast<_Derived&&>(__l), static_cast(__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&&>(__l), static_cast(__r)}; + } + + // clang-format off + template + requires _Can_compose + friend constexpr auto operator|(const _Base& __l, _Base<_Other>&& __r) noexcept(noexcept( + _Pipeline{static_cast(__l), 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(__l), static_cast<_Other&&>(__r)}; + } + + // clang-format off + template + requires _Can_compose + friend constexpr auto operator|(const _Base& __l, const _Base<_Other>& __r) noexcept(noexcept( + _Pipeline{static_cast(__l), static_cast(__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(__l), static_cast(__r)}; + } + + template <_Can_pipe _Left> + friend constexpr auto operator|(_Left&& __l, const _Base& __r) noexcept( + noexcept(static_cast(__r)(static_cast<_Left&&>(__l)))) { + return static_cast(__r)(static_cast<_Left&&>(__l)); + } + + template <_Can_pipe<_Derived> _Left> + friend constexpr auto operator|(_Left&& __l, _Base&& __r) noexcept( + noexcept(static_cast(__r)(static_cast<_Left&&>(__l)))) { + return static_cast<_Derived&&>(__r)(static_cast<_Left&&>(__l)); + } + }; + + template + struct _Pipeline : _Base<_Pipeline<_Left, _Right>> { + /* [[no_unique_address]] */ _Left __l; + /* [[no_unique_address]] */ _Right __r; + + template + constexpr explicit _Pipeline(_Ty1&& _Val1, _Ty2&& _Val2) noexcept( + is_nothrow_convertible_v<_Ty1, _Left>&& is_nothrow_convertible_v<_Ty2, _Right>) + : __l(static_cast<_Ty1&&>(_Val1)), __r(static_cast<_Ty2&&>(_Val2)) {} + + template + _NODISCARD constexpr auto operator()(_Ty&& _Val) noexcept( + noexcept(__r(__l(static_cast<_Ty&&>(_Val))))) requires requires { + __r(__l(static_cast<_Ty&&>(_Val))); + } + { return __r(__l(static_cast<_Ty&&>(_Val))); } + + template + _NODISCARD constexpr auto operator()(_Ty&& _Val) const + noexcept(noexcept(__r(__l(static_cast<_Ty&&>(_Val))))) requires requires { + __r(__l(static_cast<_Ty&&>(_Val))); + } + { return __r(__l(static_cast<_Ty&&>(_Val))); } + }; + + template + _Pipeline(_Ty1, _Ty2) -> _Pipeline<_Ty1, _Ty2>; + } // namespace _Pipe + + template + class _Cached_position { + static_assert(_Always_false<_Rng>, "A range must be at least forward for position caching to be worthwhile."); + }; + + template + 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 + 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 + using _Cached_position_t = conditional_t<_Enable, _Cached_position<_Rng, _Derived>, view_interface<_Derived>>; + // CLASS TEMPLATE ranges::ref_view // clang-format off template @@ -88,8 +273,213 @@ namespace ranges { template inline constexpr bool enable_borrowed_range> = true; + + namespace views { + // VARIABLE views::all + template + concept _Can_ref_view = requires(_Rng&& __r) { + ref_view{static_cast<_Rng&&>(__r)}; + }; + + template + 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 + _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + if constexpr (view>) { + if constexpr (constructible_from, _Rng>) { + return {_St::_View, is_nothrow_constructible_v, _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 + static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>(); + + public: + // clang-format off + template + 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 static_cast<_Rng&&>(_Range); + } else if constexpr (_Choice<_Rng>._Strategy == _St::_Ref) { + return ref_view{static_cast<_Rng&&>(_Range)}; + } else if constexpr (_Choice<_Rng>._Strategy == _St::_Subrange) { + return subrange{static_cast<_Rng&&>(_Range)}; + } else { + static_assert(_Always_false<_Rng>, "Should be unreachable"); + } + } + }; + + inline constexpr _All_fn all; + + // ALIAS TEMPLATE views::all_t + template + using all_t = decltype(all(_STD declval<_Rng>())); + } // namespace views + + // CLASS TEMPLATE ranges::reverse_view + // clang-format off + template + requires bidirectional_range<_Vw> + class reverse_view : public _Cached_position_t, _Vw, reverse_view<_Vw>> { + // clang-format on + private: + /* [[no_unique_address]] */ _Vw _Base{}; + + template + using _Rev_iter = reverse_iterator>; + + 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{_RANGES end(_Base)})) /* strengthened */ requires common_range { + return _Rev_iter{_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{_RANGES begin(_Base)})) /* strengthened */ requires common_range { + return _Rev_iter{_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 { + return _RANGES size(_Base); + } + }; + + template + reverse_view(_Rng &&) -> reverse_view>; + + namespace views { + // VARIABLE views::reverse + template + concept _Can_extract_base = requires(_Rng&& __r) { + static_cast<_Rng&&>(__r).base(); + }; + + template + 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 + static constexpr auto _Reversed_subrange = -1; + template + static constexpr auto + _Reversed_subrange, reverse_iterator<_It>, _Ki>> = static_cast(_Ki); + + template + _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> == 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> == 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 + static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>(); + + public: + // clang-format off + template + 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 static_cast<_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{static_cast<_Rng&&>(_Range)}; + } else { + static_assert(_Always_false<_Rng>, "Should be unreachable"); + } + } + }; + + inline constexpr _Reverse_fn reverse; + } // namespace views } // namespace ranges +namespace views = ranges::views; + _STD_END #pragma pop_macro("new") diff --git a/stl/inc/xstring b/stl/inc/xstring index 787ba828f27..075778bff13 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -1048,7 +1048,7 @@ public: constexpr _String_view_iterator& operator+=(const difference_type _Off) noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 _Verify_offset(_Off); - _Myoff += _Off; + _Myoff += static_cast(_Off); #else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv _Myptr += _Off; #endif // _ITERATOR_DEBUG_LEVEL @@ -1077,7 +1077,7 @@ public: "cannot seek string_view iterator after end"); } - _Myoff -= _Off; + _Myoff -= static_cast(_Off); #else // ^^^ _ITERATOR_DEBUG_LEVEL >= 1 ^^^ // vvv _ITERATOR_DEBUG_LEVEL == 0 vvv _Myptr -= _Off; #endif // _ITERATOR_DEBUG_LEVEL diff --git a/stl/inc/xutility b/stl/inc/xutility index b67ee654df1..ef2dd2ce61f 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -645,7 +645,7 @@ struct iterator_traits<_Ty*> { }; // clang-format on -// CUSTOMIZATION POINT OBJECT iter_move +// CUSTOMIZATION POINT OBJECT ranges::iter_move namespace ranges { // STRUCT TEMPLATE _Choice_t template @@ -707,9 +707,10 @@ namespace ranges { // clang-format on } // namespace _Iter_move - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Iter_move::_Cpo iter_move; } + using namespace _Cpos; } // namespace ranges // 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_reference_t<_In>>; // clang-format on -// CUSTOMIZATION POINT OBJECT iter_swap +// CUSTOMIZATION POINT OBJECT ranges::iter_swap namespace ranges { namespace _Iter_swap { template @@ -1091,9 +1092,10 @@ namespace ranges { }; } // namespace _Iter_swap - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Iter_swap::_Cpo iter_swap; } + using namespace _Cpos; } // namespace ranges // clang-format off @@ -2408,9 +2410,10 @@ namespace ranges { }; } // namespace _Begin - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Begin::_Cpo begin; } + using namespace _Cpos; // ALIAS TEMPLATE ranges::iterator_t template @@ -2468,9 +2471,10 @@ namespace ranges { }; } // namespace _Unchecked_begin - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Unchecked_begin::_Cpo _Ubegin; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::end namespace _End { @@ -2542,9 +2546,10 @@ namespace ranges { }; } // namespace _End - inline namespace _Cpos { + namespace _Cpos { inline constexpr _End::_Cpo end; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::_Uend namespace _Unchecked_end { @@ -2599,9 +2604,10 @@ namespace ranges { }; } // namespace _Unchecked_end - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Unchecked_end::_Cpo _Uend; } + using namespace _Cpos; // CONCEPT ranges::range template @@ -2648,9 +2654,10 @@ namespace ranges { // clang-format on }; - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Cbegin_fn cbegin; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::cend struct _Cend_fn { @@ -2664,9 +2671,10 @@ namespace ranges { // clang-format on }; - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Cend_fn cend; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::rbegin namespace _Rbegin { @@ -2733,9 +2741,10 @@ namespace ranges { }; } // namespace _Rbegin - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Rbegin::_Cpo rbegin; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::rend namespace _Rend { @@ -2803,9 +2812,10 @@ namespace ranges { }; } // namespace _Rend - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Rend::_Cpo rend; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::crbegin struct _Crbegin_fn { @@ -2819,9 +2829,10 @@ namespace ranges { // clang-format on }; - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Crbegin_fn crbegin; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::crend struct _Crend_fn { @@ -2835,9 +2846,10 @@ namespace ranges { // clang-format on }; - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Crend_fn crend; } + using namespace _Cpos; // VARIABLE TEMPLATE ranges::disable_sized_range template @@ -2921,9 +2933,10 @@ namespace ranges { }; } // namespace _Size - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Size::_Cpo size; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::empty namespace _Empty { @@ -2989,9 +3002,10 @@ namespace ranges { }; } // namespace _Empty - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Empty::_Cpo empty; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::data namespace _Data { @@ -3046,9 +3060,10 @@ namespace ranges { }; } // namespace _Data - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Data::_Cpo data; } + using namespace _Cpos; // CUSTOMIZATION POINT OBJECT ranges::cdata struct _Cdata_fn { @@ -3062,9 +3077,10 @@ namespace ranges { // clang-format on }; - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Cdata_fn cdata; } + using namespace _Cpos; // clang-format off // CONCEPT ranges::sized_range @@ -3289,9 +3305,10 @@ namespace ranges { // clang-format on }; - inline namespace _Cpos { + namespace _Cpos { inline constexpr _Ssize_fn ssize; } + using namespace _Cpos; // VARIABLE ranges::next class _Next_fn : private _Not_quite_object { @@ -3584,7 +3601,8 @@ namespace ranges { auto& _Self = _Cast(); #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (sized_range<_Derived>) { - _STL_VERIFY(_Idx < _RANGES size(_Self), "index out of range for view_interface"); + using _Ty = _Make_unsigned_like_t>; + _STL_VERIFY(static_cast<_Ty>(_Idx) < static_cast<_Ty>(_RANGES size(_Self)), "index out of range for view_interface"); } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _RANGES begin(_Self)[_Idx]; @@ -3595,7 +3613,8 @@ namespace ranges { auto& _Self = _Cast(); #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (sized_range<_Derived>) { - _STL_VERIFY(_Idx < _RANGES size(_Self), "index out of range for view_interface"); + using _Ty = _Make_unsigned_like_t>; + _STL_VERIFY(static_cast<_Ty>(_Idx) < static_cast<_Ty>(_RANGES size(_Self)), "index out of range for view_interface"); } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _RANGES begin(_Self)[_Idx]; diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 60fa690bc52..31ef37220f0 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -573,6 +573,87 @@ struct std::pointer_traits<::test::iterator + class range_base { + public: + range_base() = default; + constexpr explicit range_base(span 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 elements_; + }; + + template + class range_base { + public: + range_base() = default; + constexpr explicit range_base(span 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 elements_; + mutable bool moved_from_ = false; + }; + + template + class range_base { + public: + range_base() = default; + constexpr explicit range_base(span 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 elements_; + mutable bool moved_from_ = false; + }; + } // namespace detail // clang-format off template }, // Use a ProxyRef reference type? - ProxyRef Proxy = ProxyRef{!derived_from}> + ProxyRef Proxy = ProxyRef{!derived_from}, + // 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)) && (to_bool(Eq) || !derived_from) && (!to_bool(Proxy) || !derived_from) - class range { - span elements_; + && (!to_bool(IsView) || Copy != Copyability::immobile) + class range : public detail::range_base { + private: mutable bool begin_called_ = false; + using detail::range_base::elements_; + + using detail::range_base::moved_from; public: using I = iterator; using S = conditional_t>; - range() = default; - constexpr explicit range(span elements) noexcept : elements_{elements} {} - - range(range const&) = delete; - range& operator=(range const&) = delete; + using detail::range_base::range_base; [[nodiscard]] constexpr I begin() const noexcept { + assert(!moved_from()); if constexpr (!derived_from) { assert(!exchange(begin_called_, true)); } @@ -611,10 +697,12 @@ namespace test { } [[nodiscard]] constexpr S end() const noexcept { + assert(!moved_from()); return S{elements_.data() + elements_.size()}; } [[nodiscard]] constexpr ptrdiff_t size() const noexcept requires (to_bool(IsSized)) { + assert(!moved_from()); if constexpr (!derived_from) { assert(!begin_called_); } @@ -622,6 +710,7 @@ namespace test { } [[nodiscard]] constexpr Element* data() const noexcept requires derived_from { + assert(!moved_from()); return elements_.data(); } @@ -629,12 +718,14 @@ namespace test { using US = conditional_t>; [[nodiscard]] constexpr UI _Unchecked_begin() const noexcept { + assert(!moved_from()); if constexpr (!derived_from) { assert(!exchange(begin_called_, true)); } return UI{elements_.data()}; } [[nodiscard]] constexpr US _Unchecked_end() const noexcept { + assert(!moved_from()); return US{elements_.data() + elements_.size()}; } @@ -649,6 +740,11 @@ namespace test { // clang-format on } // namespace test +template +inline constexpr bool std::ranges::enable_view< + test::range> = true; + template class basic_borrowed_range : public test::range { @@ -1170,3 +1266,59 @@ struct get_nth_fn { }; inline constexpr get_nth_fn<0> get_first; inline constexpr get_nth_fn<1> get_second; + +template +concept CanSize = requires(Rng& r) { + ranges::size(r); +}; +template +concept CanMemberSize = requires(Rng& r) { + r.size(); +}; + +template +concept CanMemberData = requires(Rng& r) { + r.data(); +}; + +template +concept CanBegin = requires(Rng& r) { + ranges::begin(r); +}; +template +concept CanMemberBegin = requires(Rng& r) { + r.begin(); +}; + +template +concept CanEnd = requires(Rng& r) { + ranges::end(r); +}; +template +concept CanMemberEnd = requires(Rng& r) { + r.end(); +}; + +template +concept CanMemberBase = requires(T&& t) { + static_cast(t).base(); +}; + +template +concept CanMemberEmpty = requires(Rng& r) { + r.empty(); +}; + +template +concept CanMemberFront = requires(Rng& r) { + r.front(); +}; +template +concept CanMemberBack = requires(Rng& r) { + r.back(); +}; + +template +concept CanIndex = requires(Rng& r, const ranges::range_difference_t i) { + r[i]; +}; diff --git a/tests/std/test.lst b/tests/std/test.lst index f749fbff8d7..4f2db5ff395 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -317,6 +317,8 @@ tests\P0896R4_ranges_ref_view tests\P0896R4_ranges_subrange tests\P0896R4_ranges_test_machinery tests\P0896R4_ranges_to_address +tests\P0896R4_views_all +tests\P0896R4_views_reverse tests\P0898R3_concepts tests\P0898R3_identity tests\P0912R5_coroutine diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index f424befb4ee..cb4455e0907 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp @@ -124,6 +124,9 @@ STATIC_ASSERT(test_cpo(ranges::empty)); STATIC_ASSERT(test_cpo(ranges::data)); STATIC_ASSERT(test_cpo(ranges::cdata)); +STATIC_ASSERT(test_cpo(ranges::views::all)); +STATIC_ASSERT(test_cpo(ranges::views::reverse)); + void test_cpo_ambiguity() { using namespace std::ranges; diff --git a/tests/std/tests/P0896R4_views_all/env.lst b/tests/std/tests/P0896R4_views_all/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_views_all/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_views_all/test.cpp b/tests/std/tests/P0896R4_views_all/test.cpp new file mode 100644 index 00000000000..9c4e8938495 --- /dev/null +++ b/tests/std/tests/P0896R4_views_all/test.cpp @@ -0,0 +1,218 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +using namespace std; + +template +concept CanViewAll = requires(Rng&& r) { + views::all(static_cast(r)); +}; + +// Test a silly precomposed range adaptor pipeline +constexpr auto pipeline = views::all | views::all | views::all | views::all | views::all | views::all; + +template +constexpr bool test_one(Rng&& rng) { + constexpr bool is_view = ranges::view>; + static_assert(is_view || is_lvalue_reference_v); + + using V = conditional_t, ranges::ref_view>>; + + static_assert(CanViewAll == (!is_view || copyable) ); + if constexpr (!is_view || copyable) { // Validate lvalue + constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v; + + static_assert(same_as, V>); + static_assert(same_as); + static_assert(noexcept(views::all(rng)) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(rng | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(rng | views::all | views::all | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(rng | pipeline) == is_noexcept); + } + + static_assert(CanViewAll&> == (!is_view || copyable) ); + if constexpr (is_view && copyable) { + constexpr bool is_noexcept = is_nothrow_copy_constructible_v; + + static_assert(same_as&>, V>); + static_assert(same_as); + static_assert(noexcept(views::all(as_const(rng))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::all | views::all | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | pipeline) == is_noexcept); + } else if constexpr (!is_view) { + using RV = ranges::ref_view>; + + static_assert(same_as&>, RV>); + static_assert(same_as); + static_assert(noexcept(views::all(as_const(rng)))); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::all)); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::all | views::all | views::all)); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | pipeline)); + } + + // Validate rvalue + static_assert(CanViewAll> == is_view || ranges::enable_borrowed_range>); + if constexpr (is_view) { + constexpr bool is_noexcept = is_nothrow_move_constructible_v; + static_assert(same_as>, V>); + static_assert(same_as); + static_assert(noexcept(views::all(move(rng))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | views::all | views::all | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | pipeline) == is_noexcept); + } else if constexpr (ranges::enable_borrowed_range) { + using S = decltype(ranges::subrange{declval()}); + constexpr bool is_noexcept = noexcept(noexcept(S{declval()})); + + static_assert(same_as>, S>); + static_assert(same_as); + static_assert(noexcept(views::all(move(rng))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | views::all | views::all | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | pipeline) == is_noexcept); + } + + // Validate const rvalue + static_assert(CanViewAll> == (is_view && copyable) + || (!is_view && ranges::enable_borrowed_range>) ); + if constexpr (is_view && copyable) { + constexpr bool is_noexcept = is_nothrow_copy_constructible_v; + + static_assert(same_as>, V>); + static_assert(same_as); + static_assert(noexcept(views::all(as_const(rng))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(as_const(rng)) | views::all | views::all | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(as_const(rng)) | pipeline) == is_noexcept); + } else if constexpr (!is_view && ranges::enable_borrowed_range>) { + using S = decltype(ranges::subrange{declval>()}); + constexpr bool is_noexcept = noexcept(noexcept(S{declval>()})); + + static_assert(same_as>, S>); + static_assert(same_as); + static_assert(noexcept(views::all(move(as_const(rng)))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(as_const(rng)) | views::all) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(as_const(rng)) | views::all | views::all | views::all) == is_noexcept); + + static_assert(same_as); + 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 = true; + +template > +using move_only_view = test::range}, + test::ProxyRef{!derived_from}, 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{some_ints}); + assert(ranges::equal(views::all(move_only_view{some_ints}), some_ints)); + test_one(move_only_view{some_ints}); + assert(ranges::equal(views::all(move_only_view{some_ints}), some_ints)); + test_one(move_only_view{some_ints}); + assert( + ranges::equal(views::all(move_only_view{some_ints}), some_ints)); + test_one(move_only_view{some_ints}); + assert(ranges::equal( + views::all(move_only_view{some_ints}), some_ints)); + test_one(move_only_view{some_ints}); + assert(ranges::equal( + views::all(move_only_view{some_ints}), some_ints)); + test_one(move_only_view{some_ints}); + assert(ranges::equal( + views::all(move_only_view{some_ints}), some_ints)); + test_one(move_only_view{some_ints}); + assert(ranges::equal( + views::all(move_only_view{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); + } +} diff --git a/tests/std/tests/P0896R4_views_reverse/env.lst b/tests/std/tests/P0896R4_views_reverse/env.lst new file mode 100644 index 00000000000..62a24024479 --- /dev/null +++ b/tests/std/tests/P0896R4_views_reverse/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\strict_concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_views_reverse/test.cpp b/tests/std/tests/P0896R4_views_reverse/test.cpp new file mode 100644 index 00000000000..2078e8f77e8 --- /dev/null +++ b/tests/std/tests/P0896R4_views_reverse/test.cpp @@ -0,0 +1,375 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +using namespace std; + +template +inline constexpr bool std::ranges::enable_view> = true; + +template +concept CanViewReverse = requires(Rng&& r) { + views::reverse(static_cast(r)); +}; + +// Test a silly precomposed range adaptor pipeline +constexpr auto pipeline = views::all | views::reverse | views::all | views::reverse | views::all | views::reverse; + +template +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>; + + using V = views::all_t; + using R = reverse_view; + + // Validate range adapter object + // ...with lvalue argument + static_assert(CanViewReverse == (!is_view || copyable) ); + if constexpr (CanViewReverse) { + constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v; + + static_assert(same_as); + static_assert(noexcept(views::reverse(rng)) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(rng | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(views::reverse(views::reverse(rng))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(rng | views::reverse | views::reverse | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(rng | pipeline) == is_noexcept); + } + + // ... with const lvalue argument + static_assert(CanViewReverse&> == (!is_view || copyable) ); + if constexpr (is_view && copyable) { + constexpr bool is_noexcept = is_nothrow_copy_constructible_v; + + static_assert(same_as); + static_assert(noexcept(views::reverse(as_const(rng))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::reverse | views::reverse | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | pipeline) == is_noexcept); + } else if constexpr (!is_view) { + using RC = reverse_view&>>; + constexpr bool is_noexcept = is_nothrow_constructible_v&>; + + static_assert(same_as); + static_assert(noexcept(views::reverse(as_const(rng))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::reverse | views::reverse | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | pipeline) == is_noexcept); + } + + // ... with rvalue argument + static_assert(CanViewReverse> == is_view || enable_borrowed_range>); + if constexpr (is_view) { + constexpr bool is_noexcept = is_nothrow_move_constructible_v; + static_assert(same_as); + static_assert(noexcept(views::reverse(move(rng))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | views::reverse | views::reverse | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | pipeline) == is_noexcept); + } else if constexpr (enable_borrowed_range) { + using S = decltype(ranges::subrange{declval()}); + using RS = reverse_view; + constexpr bool is_noexcept = noexcept(noexcept(S{declval()})); + + static_assert(same_as); + static_assert(noexcept(views::reverse(move(rng))) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | views::reverse | views::reverse | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(rng) | pipeline) == is_noexcept); + } + + // ... with const rvalue argument + static_assert(CanViewReverse> == (is_view && copyable) + || (!is_view && enable_borrowed_range>) ); + if constexpr (is_view && copyable) { + constexpr bool is_noexcept = is_nothrow_copy_constructible_v; + + static_assert(same_as); + static_assert(noexcept(views::reverse(as_const(rng))) == is_nothrow_copy_constructible_v); + + static_assert(same_as); + static_assert(noexcept(as_const(rng) | views::reverse) == is_nothrow_copy_constructible_v); + + static_assert(same_as); + static_assert(noexcept(move(as_const(rng)) | views::reverse | views::reverse | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(as_const(rng)) | pipeline) == is_noexcept); + } else if constexpr (!is_view && enable_borrowed_range>) { + using S = decltype(ranges::subrange{declval>()}); + using RS = reverse_view; + constexpr bool is_noexcept = noexcept(noexcept(S{declval>()})); + + static_assert(same_as); + static_assert(noexcept(views::reverse(move(as_const(rng)))) == is_noexcept); + static_assert(same_as); + static_assert(noexcept(move(as_const(rng)) | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(as_const(rng)) | views::reverse | views::reverse | views::reverse) == is_noexcept); + + static_assert(same_as); + static_assert(noexcept(move(as_const(rng)) | pipeline) == is_noexcept); + } + + // Validate reverse_view deduction guide +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, DevCom-1159442 + (void) 42; +#endif // TRANSITION, DevCom-1159442 + same_as auto r = reverse_view{forward(rng)}; + assert(ranges::equal(r, expected)); + + // Validate reverse_view::size + static_assert(CanMemberSize == sized_range); + if constexpr (sized_range) { + assert(r.size() == static_cast>(size(expected))); + static_assert(noexcept(r.size()) == noexcept(size(rng))); + } + + static_assert(CanMemberSize == sized_range); + if constexpr (sized_range) { + assert(as_const(r).size() == static_cast>(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(r) == !is_empty); + static_assert(CanMemberEmpty == common_range); + if constexpr (common_range) { + assert(as_const(r).empty() == is_empty); + assert(static_cast(as_const(r)) == !is_empty); + } + + // Validate reverse_view::begin + static_assert(CanMemberBegin); + { + // reverse_view sometimes caches begin, so let's make several extra calls + const same_as>> 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) { + auto r2 = r; + const same_as>> auto i2 = r2.begin(); + assert(r2.begin() == i2); + assert(r2.begin() == i2); + if (!is_empty) { + assert(*i2 == *i); + } + } + + static_assert(CanMemberBegin == common_range); + if constexpr (common_range) { + const same_as>> 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) { + const auto r2 = r; + const same_as>> 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); + if (!is_empty) { + assert(*prev(r.end()) == *prev(end(expected))); + + if constexpr (copyable) { + auto r2 = r; + assert(*prev(r2.end()) == *prev(end(expected))); + } + static_assert(noexcept(r.end()) == noexcept(reverse_iterator{begin(rng)})); + + static_assert(CanMemberEnd == common_range); + if constexpr (common_range) { + 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(!CanMemberData); + static_assert(!CanMemberData); + + if (!is_empty) { + // Validate view_interface::operator[] + static_assert(CanIndex == random_access_range); + static_assert(CanIndex == (random_access_range && common_range) ); + if constexpr (random_access_range) { + assert(r[0] == *begin(expected)); + + if constexpr (common_range) { + 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 == common_range); + static_assert(CanMemberBack == common_range); + if constexpr (common_range) { + assert(as_const(r).front() == *begin(expected)); + assert(as_const(r).back() == *prev(end(expected))); + } + } + + // Validate reverse_view::base() const& + static_assert(CanMemberBase == copy_constructible); + if constexpr (copy_constructible) { + same_as auto b1 = as_const(r).base(); + static_assert(noexcept(as_const(r).base()) == is_nothrow_copy_constructible_v); + if (!is_empty) { + assert(*b1.begin() == *prev(end(expected))); + if constexpr (common_range) { + 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 auto b2 = move(r).base(); + static_assert(same_as); + static_assert(noexcept(move(r).base())); + static_assert(noexcept(move(r).base()) == is_nothrow_move_constructible_v); + if (!is_empty) { + assert(*b2.begin() == *prev(end(expected))); + if constexpr (common_range) { + assert(*prev(b2.end()) == *begin(expected)); + } + } + + return true; +} + +struct instantiator { + template + static constexpr void call() { + R r{}; + test_one(r, span{}); + } +}; + +template > +using move_only_view = test::range}, + test::ProxyRef{!derived_from}, 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{some_ints}, reversed_ints); + test_one(move_only_view{some_ints}, reversed_ints); + test_one(move_only_view{some_ints}, reversed_ints); + test_one(move_only_view{some_ints}, reversed_ints); + test_one(move_only_view{some_ints}, reversed_ints); + test_one(move_only_view{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 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(), true)); + test_bidi(); +} From 2847849bda69167455eebfdf273f50271ba893a4 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 24 Aug 2020 13:43:38 -0700 Subject: [PATCH 02/10] Fix overlength lines --- stl/inc/xutility | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index ef2dd2ce61f..49a2ede6e78 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3602,7 +3602,8 @@ namespace ranges { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (sized_range<_Derived>) { using _Ty = _Make_unsigned_like_t>; - _STL_VERIFY(static_cast<_Ty>(_Idx) < static_cast<_Ty>(_RANGES size(_Self)), "index out of range for view_interface"); + _STL_VERIFY(static_cast<_Ty>(_Idx) < static_cast<_Ty>(_RANGES size(_Self)), + "index out of range for view_interface"); } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _RANGES begin(_Self)[_Idx]; @@ -3614,7 +3615,8 @@ namespace ranges { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (sized_range<_Derived>) { using _Ty = _Make_unsigned_like_t>; - _STL_VERIFY(static_cast<_Ty>(_Idx) < static_cast<_Ty>(_RANGES size(_Self)), "index out of range for view_interface"); + _STL_VERIFY(static_cast<_Ty>(_Idx) < static_cast<_Ty>(_RANGES size(_Self)), + "index out of range for view_interface"); } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _RANGES begin(_Self)[_Idx]; From f1a53fd5624f80a634a3a31e259c948a8a754596 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 24 Aug 2020 17:40:29 -0700 Subject: [PATCH 03/10] Eliminate redundant definitions ... of the `CanBegin` etc. concepts now centralized in ``. --- tests/std/include/range_algorithm_support.hpp | 119 ++- .../P0896R4_ranges_range_machinery/test.cpp | 41 +- .../tests/P0896R4_ranges_subrange/test.cpp | 925 +++++++++--------- 3 files changed, 536 insertions(+), 549 deletions(-) diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 31ef37220f0..6100bbfd14b 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -1267,58 +1267,109 @@ struct get_nth_fn { inline constexpr get_nth_fn<0> get_first; inline constexpr get_nth_fn<1> get_second; -template -concept CanSize = requires(Rng& r) { - ranges::size(r); +template +concept CanBegin = requires(R&& r) { + ranges::begin(std::forward(r)); }; -template -concept CanMemberSize = requires(Rng& r) { - r.size(); +template +concept CanMemberBegin = requires(R&& r) { + std::forward(r).begin(); }; -template -concept CanMemberData = requires(Rng& r) { - r.data(); +template +concept CanEnd = requires(R&& r) { + ranges::end(std::forward(r)); +}; +template +concept CanMemberEnd = requires(R&& r) { + std::forward(r).end(); +}; + +template +concept CanCBegin = requires(R&& r) { + ranges::cbegin(std::forward(r)); +}; +template +concept CanCEnd = requires(R&& r) { + ranges::cend(std::forward(r)); +}; + +template +concept CanRBegin = requires(R&& r) { + ranges::rbegin(std::forward(r)); +}; +template +concept CanREnd = requires(R&& r) { + ranges::rend(std::forward(r)); +}; + +template +concept CanCRBegin = requires(R&& r) { + ranges::crbegin(std::forward(r)); +}; +template +concept CanCREnd = requires(R&& r) { + ranges::crend(std::forward(r)); +}; + +template +concept CanEmpty = requires(R&& r) { + ranges::empty(std::forward(r)); }; -template -concept CanBegin = requires(Rng& r) { - ranges::begin(r); +template +concept CanSize = requires(R&& r) { + ranges::size(std::forward(r)); }; -template -concept CanMemberBegin = requires(Rng& r) { - r.begin(); +template +concept CanMemberSize = requires(R&& r) { + std::forward(r).size(); +}; + +template +concept CanSSize = requires(R&& r) { + ranges::ssize(std::forward(r)); }; -template -concept CanEnd = requires(Rng& r) { - ranges::end(r); +template +concept CanData = requires(R&& r) { + ranges::data(std::forward(r)); }; -template -concept CanMemberEnd = requires(Rng& r) { - r.end(); +template +concept CanMemberData = requires(R&& r) { + std::forward(r).data(); +}; + +template +concept CanCData = requires(R&& r) { + ranges::cdata(std::forward(r)); }; template concept CanMemberBase = requires(T&& t) { - static_cast(t).base(); + std::forward(t).base(); }; -template -concept CanMemberEmpty = requires(Rng& r) { - r.empty(); +template +concept CanMemberEmpty = requires(R&& r) { + std::forward(r).empty(); }; -template -concept CanMemberFront = requires(Rng& r) { - r.front(); +template +concept CanMemberFront = requires(R&& r) { + std::forward(r).front(); }; -template -concept CanMemberBack = requires(Rng& r) { - r.back(); +template +concept CanMemberBack = requires(R&& r) { + std::forward(r).back(); +}; + +template +concept CanIndex = requires(R&& r, const ranges::range_difference_t i) { + std::forward(r)[i]; }; -template -concept CanIndex = requires(Rng& r, const ranges::range_difference_t i) { - r[i]; +template +concept CanBool = requires(R&& r) { + std::forward(r) ? true : false; }; diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index cb4455e0907..0526eed391b 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp @@ -34,45 +34,10 @@ STATIC_ASSERT(std::same_as, std::size_t>); template concept Decayed = std::same_as, T>; -// clang-format off template -concept CanBegin = requires(R&& r) { ranges::begin(std::forward(r)); }; -template -concept CanEnd = requires(R&& r) { ranges::end(std::forward(r)); }; - -template -concept CanCBegin = requires(R&& r) { ranges::cbegin(std::forward(r)); }; -template -concept CanCEnd = requires(R&& r) {ranges::cend(std::forward(r)); }; - -template -concept CanRBegin = requires(R&& r) { ranges::rbegin(std::forward(r)); }; -template -concept CanREnd = requires(R&& r) { ranges::rend(std::forward(r)); }; - -template -concept CanCRBegin = requires(R&& r) { ranges::crbegin(std::forward(r)); }; -template -concept CanCREnd = requires(R&& r) { ranges::crend(std::forward(r)); }; - -template -concept CanEmpty = requires(R&& r) { ranges::empty(std::forward(r)); }; - -template -concept CanSize = requires(R&& r) { ranges::size(std::forward(r)); }; - -template -concept CanSSize = requires(R&& r) { ranges::ssize(std::forward(r)); }; - -template -concept CanSizeType = requires { typename ranges::range_size_t; }; - -template -concept CanData = requires(R&& r) { ranges::data(std::forward(r)); }; - -template -concept CanCData = requires(R&& r) { ranges::cdata(std::forward(r)); }; -// clang-format on +concept CanSizeType = requires { + typename ranges::range_size_t; +}; struct invalid_type {}; diff --git a/tests/std/tests/P0896R4_ranges_subrange/test.cpp b/tests/std/tests/P0896R4_ranges_subrange/test.cpp index 961505a64ce..d3e67fbcc01 100644 --- a/tests/std/tests/P0896R4_ranges_subrange/test.cpp +++ b/tests/std/tests/P0896R4_ranges_subrange/test.cpp @@ -62,35 +62,6 @@ namespace test_view_interface { STATIC_ASSERT(test_template_id()); STATIC_ASSERT(test_template_id()); - template - concept CanEmpty = requires(T& t) { - ranges::empty(t); - }; - template - concept CanBool = requires(T& t) { - static_cast(t); - }; - template - concept CanData = requires(T& t) { - ranges::data(t); - }; - template - concept CanSize = requires(T& t) { - ranges::size(t); - }; - template - concept CanFront = requires(T& t) { - t.front(); - }; - template - concept CanBack = requires(T& t) { - t.back(); - }; - template - concept CanIndex = requires(T& t) { - t[42]; - }; - using test::CanCompare, test::CanDifference, test::Common, test::ProxyRef, test::to_bool; enum class ConstRange : bool { no, yes }; @@ -113,20 +84,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace output_unsized_onlymutable namespace output_unsized_allowconst { @@ -134,20 +105,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace output_unsized_allowconst namespace output_sized_onlymutable { @@ -155,20 +126,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace output_sized_onlymutable namespace output_sized_allowconst { @@ -176,20 +147,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace output_sized_allowconst namespace input_unsized_onlymutable { @@ -197,20 +168,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace input_unsized_onlymutable namespace input_unsized_allowconst { @@ -218,20 +189,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace input_unsized_allowconst namespace input_sized_onlymutable { @@ -239,20 +210,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace input_sized_onlymutable namespace input_sized_allowconst { @@ -260,20 +231,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace input_sized_allowconst namespace forward_uncommon_unsized_onlymutable { @@ -281,20 +252,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace forward_uncommon_unsized_onlymutable namespace forward_uncommon_unsized_allowconst { @@ -302,20 +273,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace forward_uncommon_unsized_allowconst namespace forward_uncommon_sized_onlymutable { @@ -323,20 +294,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace forward_uncommon_sized_onlymutable namespace forward_uncommon_sized_allowconst { @@ -344,20 +315,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace forward_uncommon_sized_allowconst namespace forward_common_unsized_onlymutable { @@ -365,20 +336,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace forward_common_unsized_onlymutable namespace forward_common_unsized_allowconst { @@ -386,20 +357,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace forward_common_unsized_allowconst namespace forward_common_sized_onlymutable { @@ -407,20 +378,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace forward_common_sized_onlymutable namespace forward_common_sized_allowconst { @@ -428,20 +399,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace forward_common_sized_allowconst namespace bidi_uncommon_unsized_onlymutable { @@ -449,20 +420,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace bidi_uncommon_unsized_onlymutable namespace bidi_uncommon_unsized_allowconst { @@ -470,20 +441,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace bidi_uncommon_unsized_allowconst namespace bidi_uncommon_sized_onlymutable { @@ -491,20 +462,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace bidi_uncommon_sized_onlymutable namespace bidi_uncommon_sized_allowconst { @@ -512,20 +483,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace bidi_uncommon_sized_allowconst namespace bidi_common_unsized_onlymutable { @@ -533,20 +504,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace bidi_common_unsized_onlymutable namespace bidi_common_unsized_allowconst { @@ -554,20 +525,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace bidi_common_unsized_allowconst namespace bidi_common_sized_onlymutable { @@ -575,20 +546,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace bidi_common_sized_onlymutable namespace bidi_common_sized_allowconst { @@ -596,20 +567,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(!CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace bidi_common_sized_allowconst namespace random_uncommon_sized_onlymutable { @@ -617,20 +588,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace random_uncommon_sized_onlymutable namespace random_uncommon_sized_allowconst { @@ -638,20 +609,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(CanIndex); - STATIC_ASSERT(CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(CanIndex); + STATIC_ASSERT(CanIndex); } // namespace random_uncommon_sized_allowconst namespace random_common_sized_onlymutable { @@ -659,20 +630,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace random_common_sized_onlymutable namespace random_common_sized_allowconst { @@ -680,20 +651,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(CanIndex); - STATIC_ASSERT(CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(CanIndex); + STATIC_ASSERT(CanIndex); } // namespace random_common_sized_allowconst namespace contiguous_uncommon_sized_onlymutable { @@ -701,20 +672,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace contiguous_uncommon_sized_onlymutable namespace contiguous_uncommon_sized_allowconst { @@ -722,20 +693,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanData); - STATIC_ASSERT(CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(CanIndex); - STATIC_ASSERT(CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanData); + STATIC_ASSERT(CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(CanIndex); + STATIC_ASSERT(CanIndex); } // namespace contiguous_uncommon_sized_allowconst namespace contiguous_common_sized_onlymutable { @@ -743,20 +714,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(!ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(!CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(!CanBool); - STATIC_ASSERT(CanData); - STATIC_ASSERT(!CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(!CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(!CanFront); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(!CanBack); - STATIC_ASSERT(CanIndex); - STATIC_ASSERT(!CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(!CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(!CanBool); + STATIC_ASSERT(CanData); + STATIC_ASSERT(!CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(!CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(!CanMemberFront); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(!CanMemberBack); + STATIC_ASSERT(CanIndex); + STATIC_ASSERT(!CanIndex); } // namespace contiguous_common_sized_onlymutable namespace contiguous_common_sized_allowconst { @@ -764,20 +735,20 @@ namespace test_view_interface { STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::range); STATIC_ASSERT(ranges::view); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanEmpty); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanBool); - STATIC_ASSERT(CanData); - STATIC_ASSERT(CanData); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanSize); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanFront); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(CanBack); - STATIC_ASSERT(CanIndex); - STATIC_ASSERT(CanIndex); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanEmpty); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanBool); + STATIC_ASSERT(CanData); + STATIC_ASSERT(CanData); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanSize); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberFront); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(CanMemberBack); + STATIC_ASSERT(CanIndex); + STATIC_ASSERT(CanIndex); } // namespace contiguous_common_sized_allowconst } // namespace test_view_interface From dd7c1e80d66d175865f8bdfebf160abb72e292d2 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 24 Aug 2020 19:58:14 -0700 Subject: [PATCH 04/10] Casey's review comments --- tests/std/include/range_algorithm_support.hpp | 10 ++++++++-- tests/std/tests/P0896R4_views_reverse/test.cpp | 3 --- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 6100bbfd14b..055ef4cb0a7 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -580,6 +580,8 @@ namespace test { template class range_base { public: + static_assert(Copy == Copyability::immobile); + range_base() = default; constexpr explicit range_base(span elements) noexcept : elements_{elements} {} @@ -619,7 +621,9 @@ namespace test { } span elements_; - mutable bool moved_from_ = false; + + private: + bool moved_from_ = false; }; template @@ -651,7 +655,9 @@ namespace test { } span elements_; - mutable bool moved_from_ = false; + + private: + bool moved_from_ = false; }; } // namespace detail diff --git a/tests/std/tests/P0896R4_views_reverse/test.cpp b/tests/std/tests/P0896R4_views_reverse/test.cpp index 2078e8f77e8..35c7bf807a0 100644 --- a/tests/std/tests/P0896R4_views_reverse/test.cpp +++ b/tests/std/tests/P0896R4_views_reverse/test.cpp @@ -14,9 +14,6 @@ #include using namespace std; -template -inline constexpr bool std::ranges::enable_view> = true; - template concept CanViewReverse = requires(Rng&& r) { views::reverse(static_cast(r)); From fdfc99a5bf74019137d5328335f21fa31539bfde Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 25 Aug 2020 08:22:01 -0700 Subject: [PATCH 05/10] Apply suggestions from code review From miscco. Co-authored-by: Michael Schellenberger Costa --- stl/inc/ranges | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index d78aba0049c..979df742956 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -107,7 +107,7 @@ namespace ranges { template <_Can_pipe<_Derived> _Left> friend constexpr auto operator|(_Left&& __l, _Base&& __r) noexcept( - noexcept(static_cast(__r)(static_cast<_Left&&>(__l)))) { + noexcept(static_cast<_Derived&&>(__r)(static_cast<_Left&&>(__l)))) { return static_cast<_Derived&&>(__r)(static_cast<_Left&&>(__l)); } }; @@ -422,6 +422,7 @@ namespace ranges { template static constexpr auto _Reversed_subrange = -1; + template static constexpr auto _Reversed_subrange, reverse_iterator<_It>, _Ki>> = static_cast(_Ki); From 4c7ec01d832604ebe54c00ce7b0e4b5051c97528 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 24 Aug 2020 23:57:57 -0700 Subject: [PATCH 06/10] reverse cleanup --- .../std/tests/P0896R4_views_reverse/test.cpp | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/std/tests/P0896R4_views_reverse/test.cpp b/tests/std/tests/P0896R4_views_reverse/test.cpp index 35c7bf807a0..899845d6cba 100644 --- a/tests/std/tests/P0896R4_views_reverse/test.cpp +++ b/tests/std/tests/P0896R4_views_reverse/test.cpp @@ -55,8 +55,8 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } // ... with const lvalue argument - static_assert(CanViewReverse&> == (!is_view || copyable) ); - if constexpr (is_view && copyable) { + static_assert(CanViewReverse&> == (!is_view || copyable) ); + if constexpr (is_view && copyable) { constexpr bool is_noexcept = is_nothrow_copy_constructible_v; static_assert(same_as); @@ -71,8 +71,8 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { static_assert(same_as); static_assert(noexcept(as_const(rng) | pipeline) == is_noexcept); } else if constexpr (!is_view) { - using RC = reverse_view&>>; - constexpr bool is_noexcept = is_nothrow_constructible_v&>; + using RC = reverse_view&>>; + constexpr bool is_noexcept = is_nothrow_constructible_v&>; static_assert(same_as); static_assert(noexcept(views::reverse(as_const(rng))) == is_noexcept); @@ -88,7 +88,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } // ... with rvalue argument - static_assert(CanViewReverse> == is_view || enable_borrowed_range>); + static_assert(CanViewReverse> == is_view || enable_borrowed_range>); if constexpr (is_view) { constexpr bool is_noexcept = is_nothrow_move_constructible_v; static_assert(same_as); @@ -121,9 +121,9 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } // ... with const rvalue argument - static_assert(CanViewReverse> == (is_view && copyable) + static_assert(CanViewReverse> == (is_view && copyable) || (!is_view && enable_borrowed_range>) ); - if constexpr (is_view && copyable) { + if constexpr (is_view && copyable) { constexpr bool is_noexcept = is_nothrow_copy_constructible_v; static_assert(same_as); @@ -144,6 +144,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { static_assert(same_as); static_assert(noexcept(views::reverse(move(as_const(rng)))) == is_noexcept); + static_assert(same_as); static_assert(noexcept(move(as_const(rng)) | views::reverse) == is_noexcept); @@ -154,7 +155,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { static_assert(noexcept(move(as_const(rng)) | pipeline) == is_noexcept); } - // Validate reverse_view deduction guide + // Validate deduction guide #if !defined(__clang__) && !defined(__EDG__) // TRANSITION, DevCom-1159442 (void) 42; #endif // TRANSITION, DevCom-1159442 @@ -248,8 +249,8 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } // Validate view_interface::data - static_assert(!CanMemberData); - static_assert(!CanMemberData); + static_assert(!CanData); + static_assert(!CanData); if (!is_empty) { // Validate view_interface::operator[] @@ -293,8 +294,6 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { (void) 42; #endif // TRANSITION, DevCom-1159442 same_as auto b2 = move(r).base(); - static_assert(same_as); - static_assert(noexcept(move(r).base())); static_assert(noexcept(move(r).base()) == is_nothrow_move_constructible_v); if (!is_empty) { assert(*b2.begin() == *prev(end(expected))); From 05187ed339865c9c0514c7c362d82e49d73a6475 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 25 Aug 2020 08:57:24 -0700 Subject: [PATCH 07/10] miscco review comment --- stl/inc/xutility | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 49a2ede6e78..f8cc24a52a8 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3601,8 +3601,8 @@ namespace ranges { auto& _Self = _Cast(); #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (sized_range<_Derived>) { - using _Ty = _Make_unsigned_like_t>; - _STL_VERIFY(static_cast<_Ty>(_Idx) < static_cast<_Ty>(_RANGES size(_Self)), + using _U_diff = _Make_unsigned_like_t>; + _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 @@ -3614,8 +3614,8 @@ namespace ranges { auto& _Self = _Cast(); #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (sized_range<_Derived>) { - using _Ty = _Make_unsigned_like_t>; - _STL_VERIFY(static_cast<_Ty>(_Idx) < static_cast<_Ty>(_RANGES size(_Self)), + using _U_diff = _Make_unsigned_like_t>; + _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 From 79ec3f3d37a03de231ae70bf89b7f9314a9a459c Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 25 Aug 2020 09:41:05 -0700 Subject: [PATCH 08/10] Fix noexcept(noexcept(/*...*/)) expressions ... which are a complicated spelling of `true`. --- tests/std/tests/P0896R4_views_all/test.cpp | 4 ++-- tests/std/tests/P0896R4_views_reverse/test.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/std/tests/P0896R4_views_all/test.cpp b/tests/std/tests/P0896R4_views_all/test.cpp index 9c4e8938495..b44020a9344 100644 --- a/tests/std/tests/P0896R4_views_all/test.cpp +++ b/tests/std/tests/P0896R4_views_all/test.cpp @@ -97,7 +97,7 @@ constexpr bool test_one(Rng&& rng) { static_assert(noexcept(move(rng) | pipeline) == is_noexcept); } else if constexpr (ranges::enable_borrowed_range) { using S = decltype(ranges::subrange{declval()}); - constexpr bool is_noexcept = noexcept(noexcept(S{declval()})); + constexpr bool is_noexcept = noexcept(S{declval()}); static_assert(same_as>, S>); static_assert(same_as); @@ -133,7 +133,7 @@ constexpr bool test_one(Rng&& rng) { static_assert(noexcept(move(as_const(rng)) | pipeline) == is_noexcept); } else if constexpr (!is_view && ranges::enable_borrowed_range>) { using S = decltype(ranges::subrange{declval>()}); - constexpr bool is_noexcept = noexcept(noexcept(S{declval>()})); + constexpr bool is_noexcept = noexcept(S{declval>()}); static_assert(same_as>, S>); static_assert(same_as); diff --git a/tests/std/tests/P0896R4_views_reverse/test.cpp b/tests/std/tests/P0896R4_views_reverse/test.cpp index 899845d6cba..00220ed5805 100644 --- a/tests/std/tests/P0896R4_views_reverse/test.cpp +++ b/tests/std/tests/P0896R4_views_reverse/test.cpp @@ -105,7 +105,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } else if constexpr (enable_borrowed_range) { using S = decltype(ranges::subrange{declval()}); using RS = reverse_view; - constexpr bool is_noexcept = noexcept(noexcept(S{declval()})); + constexpr bool is_noexcept = noexcept(S{declval()}); static_assert(same_as); static_assert(noexcept(views::reverse(move(rng))) == is_noexcept); @@ -140,7 +140,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { } else if constexpr (!is_view && enable_borrowed_range>) { using S = decltype(ranges::subrange{declval>()}); using RS = reverse_view; - constexpr bool is_noexcept = noexcept(noexcept(S{declval>()})); + constexpr bool is_noexcept = noexcept(S{declval>()}); static_assert(same_as); static_assert(noexcept(views::reverse(move(as_const(rng)))) == is_noexcept); From e3a888b9a02fbf55169eaa70a15732938b67a984 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 25 Aug 2020 13:25:16 -0700 Subject: [PATCH 09/10] Assert concepts that reverse_view models --- tests/std/tests/P0896R4_views_reverse/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P0896R4_views_reverse/test.cpp b/tests/std/tests/P0896R4_views_reverse/test.cpp index 00220ed5805..c21a1f5bed2 100644 --- a/tests/std/tests/P0896R4_views_reverse/test.cpp +++ b/tests/std/tests/P0896R4_views_reverse/test.cpp @@ -31,6 +31,10 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) { using V = views::all_t; using R = reverse_view; + static_assert(ranges::view); + static_assert(ranges::bidirectional_range); + static_assert(random_access_range == random_access_range); + static_assert(!ranges::contiguous_range); // Validate range adapter object // ...with lvalue argument From 052711eaf493e34ebd8f591f8595559c8f589c4e Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sat, 29 Aug 2020 19:37:35 -0700 Subject: [PATCH 10/10] miscco and STL review comments --- stl/inc/ranges | 73 ++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 119e4f8166d..ead69fbcd17 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -43,12 +43,6 @@ namespace ranges { // clang-format on namespace _Pipe { - template - struct _Base; - - template - struct _Pipeline; - // clang-format off template concept _Can_pipe = requires(_Left&& __l, _Right&& __r) { @@ -60,62 +54,65 @@ namespace ranges { && constructible_from, _Right>; // clang-format on + template + struct _Pipeline; + template struct _Base { // clang-format off template - requires _Can_compose<_Derived&&, _Other&&> - friend constexpr auto operator|(_Base&& __l, _Base<_Other>&& __r) noexcept(noexcept( - _Pipeline{static_cast<_Derived&&>(__l), static_cast<_Other&&>(__r)})) { + 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&&>(__l), static_cast<_Other&&>(__r)}; + return _Pipeline{static_cast<_Derived&&>(*this), static_cast<_Other&&>(__r)}; } // clang-format off template - requires _Can_compose<_Derived&&, const _Other&> - friend constexpr auto operator|(_Base&& __l, const _Base<_Other>& __r) noexcept(noexcept( - _Pipeline{static_cast<_Derived&&>(__l), static_cast(__r)})) { + requires _Can_compose<_Derived, const _Other&> + constexpr auto operator|(const _Base<_Other>& __r) && noexcept(noexcept( + _Pipeline{static_cast<_Derived&&>(*this), static_cast(__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&&>(__l), static_cast(__r)}; + return _Pipeline{static_cast<_Derived&&>(*this), static_cast(__r)}; } // clang-format off template - requires _Can_compose - friend constexpr auto operator|(const _Base& __l, _Base<_Other>&& __r) noexcept(noexcept( - _Pipeline{static_cast(__l), static_cast<_Other&&>(__r)})) { + requires _Can_compose + constexpr auto operator|(_Base<_Other>&& __r) const& noexcept( + noexcept(_Pipeline{static_cast(*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(__l), static_cast<_Other&&>(__r)}; + return _Pipeline{static_cast(*this), static_cast<_Other&&>(__r)}; } // clang-format off template requires _Can_compose - friend constexpr auto operator|(const _Base& __l, const _Base<_Other>& __r) noexcept(noexcept( - _Pipeline{static_cast(__l), static_cast(__r)})) { + constexpr auto operator|(const _Base<_Other>& __r) const& noexcept(noexcept( + _Pipeline{static_cast(*this), static_cast(__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(__l), static_cast(__r)}; + return _Pipeline{static_cast(*this), static_cast(__r)}; } template <_Can_pipe _Left> friend constexpr auto operator|(_Left&& __l, const _Base& __r) noexcept( - noexcept(static_cast(__r)(static_cast<_Left&&>(__l)))) { - return static_cast(__r)(static_cast<_Left&&>(__l)); + noexcept(static_cast(__r)(_STD forward<_Left>(__l)))) { + return static_cast(__r)(_STD forward<_Left>(__l)); } template <_Can_pipe<_Derived> _Left> friend constexpr auto operator|(_Left&& __l, _Base&& __r) noexcept( - noexcept(static_cast<_Derived&&>(__r)(static_cast<_Left&&>(__l)))) { - return static_cast<_Derived&&>(__r)(static_cast<_Left&&>(__l)); + noexcept(static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l)))) { + return static_cast<_Derived&&>(__r)(_STD forward<_Left>(__l)); } }; @@ -127,21 +124,21 @@ namespace ranges { template constexpr explicit _Pipeline(_Ty1&& _Val1, _Ty2&& _Val2) noexcept( is_nothrow_convertible_v<_Ty1, _Left>&& is_nothrow_convertible_v<_Ty2, _Right>) - : __l(static_cast<_Ty1&&>(_Val1)), __r(static_cast<_Ty2&&>(_Val2)) {} + : __l(_STD forward<_Ty1>(_Val1)), __r(_STD forward<_Ty2>(_Val2)) {} template _NODISCARD constexpr auto operator()(_Ty&& _Val) noexcept( - noexcept(__r(__l(static_cast<_Ty&&>(_Val))))) requires requires { + noexcept(__r(__l(_STD forward<_Ty>(_Val))))) requires requires { __r(__l(static_cast<_Ty&&>(_Val))); } - { return __r(__l(static_cast<_Ty&&>(_Val))); } + { return __r(__l(_STD forward<_Ty>(_Val))); } template _NODISCARD constexpr auto operator()(_Ty&& _Val) const - noexcept(noexcept(__r(__l(static_cast<_Ty&&>(_Val))))) requires requires { + noexcept(noexcept(__r(__l(_STD forward<_Ty>(_Val))))) requires requires { __r(__l(static_cast<_Ty&&>(_Val))); } - { return __r(__l(static_cast<_Ty&&>(_Val))); } + { return __r(__l(_STD forward<_Ty>(_Val))); } }; template @@ -149,7 +146,7 @@ namespace ranges { } // namespace _Pipe template - class _Cached_position { + 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."); }; @@ -602,10 +599,10 @@ namespace ranges { // clang-format off template _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)}; } { - return single_view{static_cast<_Ty&&>(_Val)}; + return single_view{_STD forward<_Ty>(_Val)}; } // clang-format on }; @@ -713,11 +710,11 @@ namespace ranges { _NODISCARD constexpr auto operator()(_Rng&& _Range) const noexcept(_Choice<_Rng>._No_throw) { // clang-format on if constexpr (_Choice<_Rng>._Strategy == _St::_View) { - return static_cast<_Rng&&>(_Range); + return _STD forward<_Rng>(_Range); } else if constexpr (_Choice<_Rng>._Strategy == _St::_Ref) { - return ref_view{static_cast<_Rng&&>(_Range)}; + return ref_view{_STD forward<_Rng>(_Range)}; } else if constexpr (_Choice<_Rng>._Strategy == _St::_Subrange) { - return subrange{static_cast<_Rng&&>(_Range)}; + return subrange{_STD forward<_Rng>(_Range)}; } else { static_assert(_Always_false<_Rng>, "Should be unreachable"); } @@ -860,13 +857,13 @@ namespace ranges { _NODISCARD constexpr auto operator()(_Rng&& _Range) const noexcept(_Choice<_Rng>._No_throw) { // clang-format on if constexpr (_Choice<_Rng>._Strategy == _St::_Base) { - return static_cast<_Rng&&>(_Range).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{static_cast<_Rng&&>(_Range)}; + return reverse_view{_STD forward<_Rng>(_Range)}; } else { static_assert(_Always_false<_Rng>, "Should be unreachable"); }