diff --git a/stl/inc/xutility b/stl/inc/xutility index 83693c452f..c13002e4a4 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -981,7 +981,7 @@ namespace ranges { if constexpr (_Has_ADL<_Ty1, _Ty2>) { return {_St::_Custom, noexcept(iter_swap(_STD declval<_Ty1>(), _STD declval<_Ty2>()))}; } else if constexpr (_Can_swap_references<_Ty1, _Ty2>) { - return {_St::_Swap, noexcept(swap(*_STD declval<_Ty1>(), *_STD declval<_Ty2>()))}; + return {_St::_Swap, noexcept(_RANGES swap(*_STD declval<_Ty1>(), *_STD declval<_Ty2>()))}; } else if constexpr (indirectly_movable_storable, remove_reference_t<_Ty2>> && indirectly_movable_storable, remove_reference_t<_Ty1>>) { constexpr auto _Nothrow = noexcept( @@ -1002,7 +1002,7 @@ namespace ranges { if constexpr (_Choice<_Ty1, _Ty2>._Strategy == _St::_Custom) { iter_swap(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2)); } else if constexpr (_Choice<_Ty1, _Ty2>._Strategy == _St::_Swap) { - swap(*static_cast<_Ty1&&>(_Val1), *static_cast<_Ty2&&>(_Val2)); + _RANGES swap(*static_cast<_Ty1&&>(_Val1), *static_cast<_Ty2&&>(_Val2)); } else if constexpr (_Choice<_Ty1, _Ty2>._Strategy == _St::_Exchange) { *static_cast<_Ty1&&>(_Val1) = _Iter_exchange_move(static_cast<_Ty1&&>(_Val1), static_cast<_Ty2&&>(_Val2)); @@ -3063,8 +3063,494 @@ namespace ranges { template concept common_range = range<_Rng> && same_as, sentinel_t<_Rng>>; + + // CLASS TEMPLATE ranges::view_interface + template + concept _Can_empty = requires(_Ty __t) { _RANGES empty(__t); }; + + template + requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>> + class view_interface : public view_base { + private: + _NODISCARD constexpr _Derived& _Cast() noexcept { + static_assert(derived_from<_Derived, view_interface>, + "view_interface's template argument D must derive from view_interface (N4849 [view.interface]/2)."); + static_assert(view<_Derived>, + "view_interface's template argument must model the view concept (N4849 [view.interface]/2)."); + return static_cast<_Derived&>(*this); + } + + _NODISCARD constexpr const _Derived& _Cast() const noexcept { + static_assert(derived_from<_Derived, view_interface>, + "view_interface's template argument D must derive from view_interface (N4849 [view.interface]/2)."); + static_assert(view<_Derived>, + "view_interface's template argument must model the view concept (N4849 [view.interface]/2)."); + return static_cast(*this); + } + + public: +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr bool empty() requires forward_range<_Dx> +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr bool empty() requires forward_range<_Derived> +#endif // TRANSITION, LLVM-44833 + { + auto& _Self = _Cast(); + return _RANGES begin(_Self) == _RANGES end(_Self); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr bool empty() const requires forward_range +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr bool empty() const requires forward_range +#endif // TRANSITION, LLVM-44833 + { + auto& _Self = _Cast(); + return _RANGES begin(_Self) == _RANGES end(_Self); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + constexpr explicit operator bool() requires _Can_empty<_Dx> +#else // ^^^ workaround / no workaround vvv + constexpr explicit operator bool() requires _Can_empty<_Derived> +#endif // TRANSITION, LLVM-44833 + { + return !_RANGES empty(_Cast()); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + constexpr explicit operator bool() const requires _Can_empty +#else // ^^^ workaround / no workaround vvv + constexpr explicit operator bool() const requires _Can_empty +#endif // TRANSITION, LLVM-44833 + { + return !_RANGES empty(_Cast()); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr auto data() requires contiguous_iterator> +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr auto data() requires contiguous_iterator> +#endif // TRANSITION, LLVM-44833 + { + return _STD to_address(_RANGES begin(_Cast())); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr auto data() const + requires range && contiguous_iterator> +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr auto data() const + requires range && contiguous_iterator> +#endif // TRANSITION, LLVM-44833 + { + return _STD to_address(_RANGES begin(_Cast())); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr auto size() + requires forward_range<_Dx> && sized_sentinel_for, iterator_t<_Dx>> +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr auto size() + requires forward_range<_Derived> && sized_sentinel_for, iterator_t<_Derived>> +#endif // TRANSITION, LLVM-44833 + { + auto& _Self = _Cast(); + return _RANGES end(_Self) - _RANGES begin(_Self); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr auto size() const requires forward_range + && sized_sentinel_for, iterator_t> +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr auto size() const requires forward_range + && sized_sentinel_for, iterator_t> +#endif // TRANSITION, LLVM-44833 + { + auto& _Self = _Cast(); + return _RANGES end(_Self) - _RANGES begin(_Self); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr decltype(auto) front() requires forward_range<_Dx> +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr decltype(auto) front() requires forward_range<_Derived> +#endif // TRANSITION, LLVM-44833 + { + auto& _Self = _Cast(); +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(!_RANGES empty(_Self), "front called on empty view_interface"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 + return *_RANGES begin(_Self); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr decltype(auto) front() const requires forward_range +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr decltype(auto) front() const requires forward_range +#endif // TRANSITION, LLVM-44833 + { + auto& _Self = _Cast(); +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(!_RANGES empty(_Self), "front called on empty view_interface"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 + return *_RANGES begin(_Self); + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr decltype(auto) back() requires bidirectional_range<_Dx> && common_range<_Dx> +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr decltype(auto) back() requires bidirectional_range<_Derived> && common_range<_Derived> +#endif // TRANSITION, LLVM-44833 + { + auto& _Self = _Cast(); +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(!_RANGES empty(_Self), "back called on empty view_interface"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 + auto _Last = _RANGES end(_Self); + return *--_Last; + } + +#ifdef __clang__ // TRANSITION, LLVM-44833 + template + _NODISCARD constexpr decltype(auto) back() const + requires bidirectional_range && common_range +#else // ^^^ workaround / no workaround vvv + _NODISCARD constexpr decltype(auto) back() const + requires bidirectional_range && common_range +#endif // TRANSITION, LLVM-44833 + { + auto& _Self = _Cast(); +#if _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(!_RANGES empty(_Self), "back called on empty view_interface"); +#endif // _CONTAINER_DEBUG_LEVEL > 0 + auto _Last = _RANGES end(_Self); + return *--_Last; + } + + template + _NODISCARD constexpr decltype(auto) operator[](const range_difference_t<_Rng> _Idx) { + 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"); + } +#endif // _CONTAINER_DEBUG_LEVEL > 0 + return _RANGES begin(_Self)[_Idx]; + } + + template + _NODISCARD constexpr decltype(auto) operator[](const range_difference_t<_Rng> _Idx) const { + 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"); + } +#endif // _CONTAINER_DEBUG_LEVEL > 0 + return _RANGES begin(_Self)[_Idx]; + } + }; + + // ENUM CLASS ranges::subrange_kind + enum class subrange_kind : bool { unsized, sized }; // clang-format on +} // namespace ranges +// These declarations must be visible to qualified name lookup for _STD get in _Pair_like below, even if hasn't +// yet been included. +template +_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept; +template +_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>& get(const tuple<_Types...>& _Tuple) noexcept; +template +_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>&& get(tuple<_Types...>&& _Tuple) noexcept; +template +_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>&& get(const tuple<_Types...>&& _Tuple) noexcept; + +namespace ranges { + // clang-format off + // CLASS TEMPLATE ranges::subrange + template + concept _Convertible_to_non_slicing = convertible_to<_From, _To> + && !(is_pointer_v> + && is_pointer_v> + && _Not_same_as>, remove_pointer_t>>); + + template + concept _Pair_like = !is_reference_v<_Ty> && requires(_Ty __t) { + typename tuple_size<_Ty>::type; + requires derived_from, integral_constant>; + typename tuple_element_t<0, remove_const_t<_Ty>>; + typename tuple_element_t<1, remove_const_t<_Ty>>; + { _STD get<0>(__t) } -> convertible_to&>; + { _STD get<1>(__t) } -> convertible_to&>; + }; + + template + concept _Pair_like_convertible_from = !range<_Ty> && _Pair_like<_Ty> + && constructible_from<_Ty, _First, _Second> + && _Convertible_to_non_slicing<_First, tuple_element_t<0, _Ty>> + && convertible_to<_Second, tuple_element_t<1, _Ty>>; + + template _Se = _It, + subrange_kind _Ki = sized_sentinel_for<_Se, _It> ? subrange_kind::sized : subrange_kind::unsized> + requires (_Ki == subrange_kind::sized || !sized_sentinel_for<_Se, _It>) + class subrange; + // clang-format on + + template > + class _Subrange_base : public view_interface> { // TRANSITION, [[no_unique_address]] + protected: + using _Size_type = _Make_unsigned_like_t>; + static constexpr bool _Store_size = true; + + _Size_type _Size = 0; + + public: + _Subrange_base() = default; + explicit constexpr _Subrange_base(const _Size_type& _Size_) noexcept : _Size(_Size_) {} + }; + + template + class _Subrange_base<_It, _Se, _Ki, false> : public view_interface> { + protected: + using _Size_type = _Make_unsigned_like_t>; + static constexpr bool _Store_size = false; + + public: + _Subrange_base() = default; + explicit constexpr _Subrange_base(const _Size_type&) noexcept {} + }; + + // clang-format off + template _Se, subrange_kind _Ki> + requires (_Ki == subrange_kind::sized || !sized_sentinel_for<_Se, _It>) + class subrange : public _Subrange_base<_It, _Se, _Ki> { + private: + using _Mybase = _Subrange_base<_It, _Se, _Ki>; + using typename _Mybase::_Size_type; + using _Mybase::_Store_size; + + // TRANSITION, [[no_unique_address]]: + /* [[no_unique_address]] */ _It _First{}; + /* [[no_unique_address]] */ _Se _Last{}; + // [[no_unique_address]] conditional_t<_Store_size, _Size_type, _Nil> _Size{}; + + template + constexpr subrange(true_type, _Rng&& _Val) : subrange{_STD forward<_Rng>(_Val), _RANGES size(_Val)} { + // delegation target for subrange(_Rng&&) when we must store the range size + _STL_INTERNAL_STATIC_ASSERT(_Store_size); + } + + template + constexpr subrange(false_type, _Rng&& _Val) : subrange{_RANGES begin(_Val), _RANGES end(_Val)} { + // delegation target for subrange(_Rng&&) when we need not store the range size + _STL_INTERNAL_STATIC_ASSERT(!_Store_size); + } + + public: + subrange() = default; + + template <_Convertible_to_non_slicing<_It> _It2> + constexpr subrange(_It2 _First_, _Se _Last_) requires (!_Store_size) + : _First(_STD move(_First_)), _Last(_STD move(_Last_)) {} + + template <_Convertible_to_non_slicing<_It> _It2> + constexpr subrange(_It2 _First_, _Se _Last_, const _Size_type _Size_) requires (_Ki == subrange_kind::sized) + : _Mybase(_Size_), _First(_STD move(_First_)), _Last(_STD move(_Last_)) { + if constexpr (sized_sentinel_for<_Se, _It>) { + _STL_ASSERT(_Size_ == static_cast<_Size_type>(_Last - _First), + "This constructor's third argument should be equal to the distance " + "between the first and second arguments (N4849 [range.subrange.ctor]/3)."); + } + } + + template <_Not_same_as _Rng> + requires borrowed_range<_Rng> + && _Convertible_to_non_slicing, _It> + && convertible_to, _Se> + constexpr subrange(_Rng&& _Val) requires (!_Store_size || sized_range<_Rng>) + : subrange{bool_constant<_Store_size>{}, _STD forward<_Rng>(_Val)} {} + + template + requires _Convertible_to_non_slicing, _It> && convertible_to, _Se> + constexpr subrange(_Rng&& _Val, const _Size_type _Count) requires (_Ki == subrange_kind::sized) + : subrange{_RANGES begin(_Val), _RANGES end(_Val), _Count} {} + + template <_Not_same_as _Pair_like> + requires _Pair_like_convertible_from<_Pair_like, const _It&, const _Se&> + constexpr operator _Pair_like() const { + return _Pair_like(_First, _Last); + } + + _NODISCARD constexpr _It begin() const requires copyable<_It> { + return _First; + } + _NODISCARD constexpr _It begin() requires (!copyable<_It>) { + return _STD move(_First); + } + + _NODISCARD constexpr _Se end() const { + return _Last; + } + + _NODISCARD constexpr bool empty() const { + return _First == _Last; + } + + _NODISCARD constexpr _Size_type size() const requires (_Ki == subrange_kind::sized) { + if constexpr (_Store_size) { + return this->_Size; + } else { + return static_cast<_Size_type>(_Last - _First); + } + } + + _NODISCARD constexpr subrange next() const & requires forward_iterator<_It> { + auto _Tmp = *this; + if (_Tmp._First != _Tmp._Last) { + ++_Tmp._First; + if constexpr (_Store_size) { + --_Tmp._Size; + } + } + return _Tmp; + } + _NODISCARD constexpr subrange next(const iter_difference_t<_It> _Count) const & requires forward_iterator<_It> { + auto _Tmp = *this; + _Tmp.advance(_Count); + return _Tmp; + } + + _NODISCARD constexpr subrange next() && { + if (_First != _Last) { + ++_First; + if constexpr (_Store_size) { + --this->_Size; + } + } + return _STD move(*this); + } + _NODISCARD constexpr subrange next(const iter_difference_t<_It> _Count) && { + advance(_Count); + return _STD move(*this); + } + + _NODISCARD constexpr subrange prev() const requires bidirectional_iterator<_It> { + auto _Tmp = *this; + --_Tmp._First; + if constexpr (_Store_size) { + ++_Tmp._Size; + } + return _Tmp; + } + _NODISCARD constexpr subrange prev(const iter_difference_t<_It> _Count) const + requires bidirectional_iterator<_It> { + auto _Tmp = *this; + _Tmp.advance(-_Count); + return _Tmp; + } + + constexpr subrange& advance(const iter_difference_t<_It> _Count) { + // Per LWG issue submitted but not numbered as of 2020-04-21, this has defined behavior when _Count < 0. + if constexpr (bidirectional_iterator<_It>) { + if (_Count < 0) { + _RANGES advance(_First, _Count); + if constexpr (_Store_size) { + this->_Size += static_cast<_Size_type>(-_Count); + } + return *this; + } + } + + const auto _Remainder = _RANGES advance(_First, _Count, _Last); + if constexpr (_Store_size) { + this->_Size -= static_cast<_Size_type>(_Count - _Remainder); + } + return *this; + } + }; + // clang-format on + + template _Se> + subrange(_It, _Se) -> subrange<_It, _Se>; + + template _Se> + subrange(_It, _Se, _Make_unsigned_like_t>) -> subrange<_It, _Se, subrange_kind::sized>; + + template + subrange(_Rng &&) -> subrange, sentinel_t<_Rng>, + (sized_range<_Rng> || sized_sentinel_for, iterator_t<_Rng>>) ? subrange_kind::sized + : subrange_kind::unsized>; + + template + subrange(_Rng&&, _Make_unsigned_like_t>) + -> subrange, sentinel_t<_Rng>, subrange_kind::sized>; + + template + inline constexpr bool enable_borrowed_range> = true; + + // clang-format off + template + requires (_Idx < 2) + _NODISCARD constexpr auto get(const subrange<_It, _Se, _Ki>& _Val) { + if constexpr (_Idx == 0) { + return _Val.begin(); + } else { + return _Val.end(); + } + } + + template + requires (_Idx < 2) + _NODISCARD constexpr auto get(subrange<_It, _Se, _Ki>&& _Val) { + if constexpr (_Idx == 0) { + return _Val.begin(); + } else { + return _Val.end(); + } + } + // clang-format on +} // namespace ranges + +using ranges::get; + +template +struct tuple_size> : integral_constant {}; + +template +struct tuple_element<0, ranges::subrange<_It, _Se, _Ki>> { + using type = _It; +}; + +template +struct tuple_element<1, ranges::subrange<_It, _Se, _Ki>> { + using type = _Se; +}; + +template +struct tuple_element<0, const ranges::subrange<_It, _Se, _Ki>> { + using type = _It; +}; + +template +struct tuple_element<1, const ranges::subrange<_It, _Se, _Ki>> { + using type = _Se; +}; + +namespace ranges { // STRUCT ranges::dangling struct dangling { constexpr dangling() noexcept = default; @@ -3075,6 +3561,10 @@ namespace ranges { // ALIAS TEMPLATE ranges::borrowed_iterator_t template using borrowed_iterator_t = conditional_t, iterator_t<_Rng>, dangling>; + + // ALIAS TEMPLATE ranges::borrowed_subrange_t + template + using borrowed_subrange_t = conditional_t, subrange>, dangling>; } // namespace ranges #endif // __cpp_lib_concepts diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 7be4fc5af5..2120c6b454 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -106,7 +106,7 @@ class move_only_range::iterator { public: using iterator_concept = std::input_iterator_tag; - using iterator_category = std::output_iterator_tag; + using iterator_category = void; // TRANSITION, LWG-3289 using value_type = std::remove_cv_t; using difference_type = std::ptrdiff_t; using pointer = void; @@ -222,9 +222,6 @@ struct test_iterator { STATIC_ASSERT(always_false); } - friend void iter_move(test_iterator const&) { - STATIC_ASSERT(always_false); - } friend void iter_swap(test_iterator const&, test_iterator const&) { STATIC_ASSERT(always_false); } diff --git a/tests/std/test.lst b/tests/std/test.lst index aca5c46b5d..321e25f2b3 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -245,6 +245,7 @@ tests\P0896R4_ranges_alg_mismatch tests\P0896R4_ranges_alg_none_of tests\P0896R4_ranges_iterator_machinery tests\P0896R4_ranges_range_machinery +tests\P0896R4_ranges_subrange tests\P0896R4_ranges_to_address tests\P0898R3_concepts tests\P0898R3_identity diff --git a/tests/std/tests/P0896R4_ranges_algorithm_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_algorithm_machinery/test.cpp index 8f82c2e1fd..d665e3cc7a 100644 --- a/tests/std/tests/P0896R4_ranges_algorithm_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_algorithm_machinery/test.cpp @@ -348,7 +348,7 @@ namespace indirectly_comparable_test { namespace dangling_test { // Also test borrowed_iterator_t and borrowed_subrange_t - using ranges::dangling, ranges::borrowed_iterator_t; + using ranges::dangling, ranges::borrowed_iterator_t, ranges::borrowed_subrange_t; using std::is_nothrow_constructible_v, std::same_as; STATIC_ASSERT(std::is_class_v); @@ -367,10 +367,8 @@ namespace dangling_test { STATIC_ASSERT(same_as>, dangling>); STATIC_ASSERT(same_as>, int*>); -#if 0 // TRANSITION, subrange STATIC_ASSERT(same_as>, dangling>); STATIC_ASSERT(same_as>, ranges::subrange>); -#endif // TRANSITION, subrange } // namespace dangling_test namespace result_test { diff --git a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp index ee35e6933d..74194c0030 100644 --- a/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_range_machinery/test.cpp @@ -1503,9 +1503,7 @@ namespace borrowed_range_testing { STATIC_ASSERT(test_borrowed_range()); STATIC_ASSERT(test_borrowed_range, std::span::iterator>()); STATIC_ASSERT(test_borrowed_range, std::span::iterator>()); -#if 0 // TRANSITION, subrange STATIC_ASSERT(test_borrowed_range, int*>()); -#endif // TRANSITION, subrange #if 0 // TRANSITION, future STATIC_ASSERT(test_borrowed_range, int*>()); STATIC_ASSERT(test_borrowed_range, ...>()); diff --git a/tests/std/tests/P0896R4_ranges_subrange/env.lst b/tests/std/tests/P0896R4_ranges_subrange/env.lst new file mode 100644 index 0000000000..f3ccc8613c --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_subrange/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_ranges_subrange/test.cpp b/tests/std/tests/P0896R4_ranges_subrange/test.cpp new file mode 100644 index 0000000000..c375272462 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_subrange/test.cpp @@ -0,0 +1,1224 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Covers ranges::view_interface and ranges::subrange + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// +#include "range_algorithm_support.hpp" + +#define ASSERT(...) assert((__VA_ARGS__)) + +using std::output_iterator_tag, std::input_iterator_tag, std::forward_iterator_tag, std::bidirectional_iterator_tag, + std::random_access_iterator_tag, std::contiguous_iterator_tag; + +int main() {} // COMPILE-ONLY + +struct empty {}; + +namespace test_view_interface { + template + concept CanViewInterface = requires { + typename ranges::view_interface; + }; + + template + constexpr bool test_template_id() { + // view_interface is a valid template-id only if T is a cv-unqualified class type + STATIC_ASSERT(std::is_same_v>); + STATIC_ASSERT(CanViewInterface == std::is_class_v); + if constexpr (!std::is_function_v) { + STATIC_ASSERT(!CanViewInterface); + STATIC_ASSERT(!CanViewInterface); + STATIC_ASSERT(!CanViewInterface); + } + + if constexpr (!std::is_void_v) { + STATIC_ASSERT(!CanViewInterface); + STATIC_ASSERT(!CanViewInterface); + if constexpr (!std::is_function_v) { + STATIC_ASSERT(!CanViewInterface); + STATIC_ASSERT(!CanViewInterface); + STATIC_ASSERT(!CanViewInterface); + STATIC_ASSERT(!CanViewInterface); + STATIC_ASSERT(!CanViewInterface); + STATIC_ASSERT(!CanViewInterface); + } + } + return true; + } + + STATIC_ASSERT(test_template_id()); + STATIC_ASSERT(test_template_id()); + 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]; + }; + + template + struct fake_view : ranges::view_interface> { + using iterator = test_iterator; + using sentinel = std::conditional_t; + + iterator begin(); + iterator begin() const requires ConstRange; + + sentinel end(); + sentinel end() const requires ConstRange; + }; + + namespace output_unsized_onlymutable { + using V = fake_view; + 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); + } // namespace output_unsized_onlymutable + + namespace output_unsized_allowconst { + using V = fake_view; + 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); + } // namespace output_unsized_allowconst + + namespace output_sized_onlymutable { + using V = fake_view; + 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); + } // namespace output_sized_onlymutable + + namespace output_sized_allowconst { + using V = fake_view; + 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); + } // namespace output_sized_allowconst + + namespace input_unsized_onlymutable { + using V = fake_view; + 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); + } // namespace input_unsized_onlymutable + + namespace input_unsized_allowconst { + using V = fake_view; + 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); + } // namespace input_unsized_allowconst + + namespace input_sized_onlymutable { + using V = fake_view; + 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); + } // namespace input_sized_onlymutable + + namespace input_sized_allowconst { + using V = fake_view; + 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); + } // namespace input_sized_allowconst + + namespace forward_uncommon_unsized_onlymutable { + using V = fake_view; + 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); + } // namespace forward_uncommon_unsized_onlymutable + + namespace forward_uncommon_unsized_allowconst { + using V = fake_view; + 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); + } // namespace forward_uncommon_unsized_allowconst + + namespace forward_uncommon_sized_onlymutable { + using V = fake_view; + 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); + } // namespace forward_uncommon_sized_onlymutable + + namespace forward_uncommon_sized_allowconst { + using V = fake_view; + 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); + } // namespace forward_uncommon_sized_allowconst + + namespace forward_common_unsized_onlymutable { + using V = fake_view; + 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); + } // namespace forward_common_unsized_onlymutable + + namespace forward_common_unsized_allowconst { + using V = fake_view; + 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); + } // namespace forward_common_unsized_allowconst + + namespace forward_common_sized_onlymutable { + using V = fake_view; + 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); + } // namespace forward_common_sized_onlymutable + + namespace forward_common_sized_allowconst { + using V = fake_view; + 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); + } // namespace forward_common_sized_allowconst + + namespace bidi_uncommon_unsized_onlymutable { + using V = fake_view; + 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); + } // namespace bidi_uncommon_unsized_onlymutable + + namespace bidi_uncommon_unsized_allowconst { + using V = fake_view; + 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); + } // namespace bidi_uncommon_unsized_allowconst + + namespace bidi_uncommon_sized_onlymutable { + using V = fake_view; + 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); + } // namespace bidi_uncommon_sized_onlymutable + + namespace bidi_uncommon_sized_allowconst { + using V = fake_view; + 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); + } // namespace bidi_uncommon_sized_allowconst + + namespace bidi_common_unsized_onlymutable { + using V = fake_view; + 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); + } // namespace bidi_common_unsized_onlymutable + + namespace bidi_common_unsized_allowconst { + using V = fake_view; + 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); + } // namespace bidi_common_unsized_allowconst + + namespace bidi_common_sized_onlymutable { + using V = fake_view; + 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); + } // namespace bidi_common_sized_onlymutable + + namespace bidi_common_sized_allowconst { + using V = fake_view; + 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); + } // namespace bidi_common_sized_allowconst + + namespace random_uncommon_unsized_onlymutable { + using V = fake_view; + 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); + } // namespace random_uncommon_unsized_onlymutable + + namespace random_uncommon_unsized_allowconst { + using V = fake_view; + 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); + } // namespace random_uncommon_unsized_allowconst + + namespace random_uncommon_sized_onlymutable { + using V = fake_view; + 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); + } // namespace random_uncommon_sized_onlymutable + + namespace random_uncommon_sized_allowconst { + using V = fake_view; + 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); + } // namespace random_uncommon_sized_allowconst + + namespace random_common_sized_onlymutable { + using V = fake_view; + 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); + } // namespace random_common_sized_onlymutable + + namespace random_common_sized_allowconst { + using V = fake_view; + 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); + } // namespace random_common_sized_allowconst + + namespace contiguous_uncommon_unsized_onlymutable { + using V = fake_view; + 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); + } // namespace contiguous_uncommon_unsized_onlymutable + + namespace contiguous_uncommon_unsized_allowconst { + using V = fake_view; + 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); + } // namespace contiguous_uncommon_unsized_allowconst + + namespace contiguous_uncommon_sized_onlymutable { + using V = fake_view; + 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); + } // namespace contiguous_uncommon_sized_onlymutable + + namespace contiguous_uncommon_sized_allowconst { + using V = fake_view; + 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); + } // namespace contiguous_uncommon_sized_allowconst + + namespace contiguous_common_sized_onlymutable { + using V = fake_view; + 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); + } // namespace contiguous_common_sized_onlymutable + + namespace contiguous_common_sized_allowconst { + using V = fake_view; + 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); + } // namespace contiguous_common_sized_allowconst +} // namespace test_view_interface + +namespace test_subrange { + using ranges::borrowed_range, ranges::range, ranges::sized_range, ranges::subrange, ranges::subrange_kind; + using std::constructible_from, std::copyable, std::default_initializable, std::movable, std::same_as, + std::sized_sentinel_for; + + // * template-id: subrange is a valid template-id iff I models input_or_output_iterator, S models + // sentinel_for, and sized_sentinel_for implies K == sized. + template + concept CanSubrange = requires { + typename subrange; + }; + STATIC_ASSERT(CanSubrange); + STATIC_ASSERT(!CanSubrange); + STATIC_ASSERT(!CanSubrange); + STATIC_ASSERT(!CanSubrange); + STATIC_ASSERT(CanSubrange); + STATIC_ASSERT(!CanSubrange); + STATIC_ASSERT(CanSubrange); + + // clang-format off + template + concept HasMemberEmpty = requires(std::remove_reference_t const r) { + { r.empty() } -> same_as; + }; + + template + concept HasMemberSize = requires(std::remove_reference_t const r) { + { r.size() } -> std::integral; + }; + // clang-format on + + // Validate default template arguments: second defaults to first, and third defaults to subrange_kind::sized iff + // sized_sentinel_for. + STATIC_ASSERT(same_as, subrange>); + STATIC_ASSERT(same_as, + subrange>); + STATIC_ASSERT(same_as>, + subrange, test_iterator, + subrange_kind::unsized>>); + + // Validate many properties of a specialization of subrange + template + inline constexpr bool is_subrange = false; + template + inline constexpr bool is_subrange> = true; + + template + inline constexpr auto kind_of = illformed(); + template + inline constexpr auto kind_of> = K; + + template + constexpr bool test_subrange() { + STATIC_ASSERT(same_as>); + STATIC_ASSERT(is_subrange); + + using I = ranges::iterator_t; + using S = ranges::sentinel_t; + constexpr bool sized = kind_of == subrange_kind::sized; + static_assert( + std::integral>, "make_unsigned_t below needs to be make-unsigned-like-t"); + using size_type = std::make_unsigned_t>; + + // Validate SMFs + STATIC_ASSERT(default_initializable); + STATIC_ASSERT(movable); + STATIC_ASSERT(!copyable || copyable); + + STATIC_ASSERT(constructible_from == (!sized || sized_sentinel_for) ); + STATIC_ASSERT( + constructible_from == (copyable && (!sized || sized_sentinel_for) )); + STATIC_ASSERT(constructible_from == sized); + STATIC_ASSERT(constructible_from == (copyable && sized)); + + STATIC_ASSERT(constructible_from == (!sized || sized_range || sized_sentinel_for) ); + STATIC_ASSERT(constructible_from == sized); + STATIC_ASSERT(constructible_from == (borrowed_range && (!sized || sized_range || sized_sentinel_for) )); + STATIC_ASSERT(constructible_from == (sized && borrowed_range) ); + + // Validate begin/end/empty + STATIC_ASSERT(range); + STATIC_ASSERT(HasMemberEmpty); + STATIC_ASSERT(!copyable || range); + + // Validate size + STATIC_ASSERT(sized == HasMemberSize); + + return true; + } + + template + constexpr bool test_construction() { + STATIC_ASSERT(same_as>); + + using I = ranges::iterator_t; + using S = ranges::sentinel_t; + + STATIC_ASSERT(test_subrange, Rng>()); + if constexpr (!sized_sentinel_for) { + STATIC_ASSERT(test_subrange, Rng>()); + } + + return true; + } + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction>()); + STATIC_ASSERT(test_construction()); + + // Validate that slicing conversions are forbidden + struct Base {}; + struct Derived : Base {}; + STATIC_ASSERT(!std::constructible_from, Derived*, Derived*>); + STATIC_ASSERT(!std::constructible_from, Derived*, Derived*, std::make_unsigned_t>); + STATIC_ASSERT(!std::constructible_from, subrange>); + STATIC_ASSERT(!std::constructible_from, subrange, std::make_unsigned_t>); + + struct with_converting_iterators { + template + struct iterator { + using iterator_concept = input_iterator_tag; + using iterator_category = void; // TRANSITION, LWG-3289 + using value_type = int; + using difference_type = int; + using pointer = void; + using reference = int; + + iterator() = default; + iterator(iterator) requires IsConst; + + iterator(iterator&&) = default; + iterator& operator=(iterator&&) = default; + + int operator*() const; + iterator& operator++(); + void operator++(int); + }; + + template + struct sentinel { + sentinel() = default; + sentinel(sentinel) requires IsConst; + + bool operator==(iterator const&) const; + }; + + iterator begin(); + sentinel end(); + iterator begin() const; + sentinel end() const; + }; + + void test_non_slicing_conversions() { + // and non-slicing conversions are ok + using LI = std::list::iterator; + STATIC_ASSERT(std::constructible_from::const_iterator>, LI const&, LI const&>); + STATIC_ASSERT(std::constructible_from::const_iterator>, LI, LI>); + + using I = ranges::iterator_t; + using S = ranges::sentinel_t; + using CI = ranges::iterator_t; + using CS = ranges::sentinel_t; + + using SizedSubrange = subrange; + STATIC_ASSERT(test_subrange()); + + STATIC_ASSERT(!constructible_from); // lvalues are not convertible + STATIC_ASSERT(!constructible_from); // ditto + STATIC_ASSERT(!constructible_from); // missing size + STATIC_ASSERT(constructible_from); + + using UnsizedSubrange = subrange; + STATIC_ASSERT(test_subrange()); + + STATIC_ASSERT(!constructible_from); // lvalues are not convertible + STATIC_ASSERT(!constructible_from); // ditto + STATIC_ASSERT(constructible_from); // but rvalues are + STATIC_ASSERT(!constructible_from); // !sized + } + + // Validate deduction guides + template + constexpr bool test_ctad() { + using I = ranges::iterator_t; + using S = ranges::sentinel_t; + constexpr bool diff = sized_sentinel_for; + + { + using T = decltype(subrange(std::declval(), std::declval())); + STATIC_ASSERT(same_as>); + + STATIC_ASSERT(range); + STATIC_ASSERT(!copyable || range); + } + + static_assert( + std::integral>, "make_unsigned_t below needs to be make-unsigned-like-t"); + using size_type = std::make_unsigned_t>; + { + using T = decltype(subrange(std::declval(), std::declval(), std::declval())); + STATIC_ASSERT(same_as>); + + STATIC_ASSERT(range); + STATIC_ASSERT(!copyable || range); + } + + constexpr bool is_sized = diff | sized_range; + { + using T = decltype(subrange(std::declval())); + STATIC_ASSERT(same_as>); + + STATIC_ASSERT(range); + STATIC_ASSERT(!copyable || range); + + if constexpr (borrowed_range) { + using U = decltype(subrange(std::declval())); + STATIC_ASSERT(same_as); + } + } + + { + using T = decltype(subrange(std::declval(), std::declval())); + STATIC_ASSERT(same_as>); + + STATIC_ASSERT(range); + STATIC_ASSERT(!copyable || range); + + if constexpr (borrowed_range) { + using U = decltype(subrange(std::declval(), std::declval())); + STATIC_ASSERT(same_as); + } + } + + return true; + } + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad>()); + STATIC_ASSERT(test_ctad()); + + // Validate conversion to PairLike + STATIC_ASSERT(std::is_convertible_v, std::pair>); + STATIC_ASSERT(!std::is_convertible_v, std::pair>); + STATIC_ASSERT(std::is_convertible_v, std::pair>); + STATIC_ASSERT(std::is_convertible_v, std::pair>); + STATIC_ASSERT(std::is_convertible_v, std::tuple>); + STATIC_ASSERT(!std::is_convertible_v, std::tuple>); + STATIC_ASSERT(std::is_convertible_v, std::tuple>); + STATIC_ASSERT(std::is_convertible_v, std::tuple>); + + constexpr bool test_advance_next_prev() { + // Validate advance/next/prev + int const some_ints[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + auto const first = ranges::begin(some_ints); + auto const last = ranges::end(some_ints); + + ASSERT(subrange{some_ints}.begin() == first); + ASSERT(subrange{some_ints}.end() == last); + + ASSERT(subrange{some_ints}.next().begin() == first + 1); + ASSERT(subrange{some_ints}.next().end() == last); + + ASSERT(subrange{first + 1, last}.prev().begin() == first); + ASSERT(subrange{first + 1, last}.prev().end() == last); + + for (std::ptrdiff_t i = 0; i <= last - first; ++i) { + ASSERT(subrange{some_ints}.next(i).begin() == first + i); + ASSERT(subrange{some_ints}.next(i).end() == last); + + subrange s0{some_ints}; + s0.advance(i); + ASSERT(s0.begin() == first + i); + ASSERT(s0.end() == last); + + ASSERT(subrange{first + i, last}.prev(i).begin() == first); + ASSERT(subrange{first + i, last}.prev(i).end() == last); + + subrange s1{first + i, last}; + s1.advance(-i); + ASSERT(s1.begin() == first); + ASSERT(s1.end() == last); + } + + return true; + } + STATIC_ASSERT(test_advance_next_prev()); + + // Validate tuple interface + template + constexpr bool test_tuple() { + using std::declval, std::tuple_element_t, std::tuple_size_v; + + using I = ranges::iterator_t; + using S = ranges::sentinel_t; + + STATIC_ASSERT(tuple_size_v == 2); + STATIC_ASSERT(tuple_size_v == 2); + + STATIC_ASSERT(same_as, I>); + STATIC_ASSERT(same_as, I>); + STATIC_ASSERT(same_as, S>); + STATIC_ASSERT(same_as, S>); + + STATIC_ASSERT(same_as(declval())), I>); + STATIC_ASSERT(same_as(declval())), I>); + STATIC_ASSERT(same_as(declval())), I>); + STATIC_ASSERT(same_as(declval())), I>); + STATIC_ASSERT(same_as(declval())), I>); + STATIC_ASSERT(same_as(declval())), I>); + STATIC_ASSERT(same_as(declval())), I>); + STATIC_ASSERT(same_as(declval())), I>); + + STATIC_ASSERT(same_as(declval())), S>); + STATIC_ASSERT(same_as(declval())), S>); + STATIC_ASSERT(same_as(declval())), S>); + STATIC_ASSERT(same_as(declval())), S>); + STATIC_ASSERT(same_as(declval())), S>); + STATIC_ASSERT(same_as(declval())), S>); + STATIC_ASSERT(same_as(declval())), S>); + STATIC_ASSERT(same_as(declval())), S>); + + return true; + } + STATIC_ASSERT(test_tuple>()); + STATIC_ASSERT(test_tuple>()); + STATIC_ASSERT(test_tuple>()); +} // namespace test_subrange