From 0a3430a68fb011ec38ae2b2a38b5879bc800570d Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 27 Jul 2022 13:45:50 -0700 Subject: [PATCH 01/18] P2408R5: parallel algorithms require `forward_iterator<_It>` instead of `_Is_fwd_iter_v<_It>` for parallel algorithms --- stl/inc/algorithm | 99 ++++++++++++++++++++-------------------- stl/inc/execution | 106 +++++++++++++++++++++---------------------- stl/inc/numeric | 8 ++-- stl/inc/xutility | 39 ++++++++++------ stl/inc/yvals_core.h | 12 +++-- 5 files changed, 141 insertions(+), 123 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 49158096e70..e5c39846386 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -647,8 +647,8 @@ template mismatch( _ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2) noexcept /* terminates */ { // return [_First1, _Last1)/[_First2, ...) mismatch - _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); - _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt1); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt2); return _STD mismatch(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, equal_to{}); } #endif // _HAS_CXX17 @@ -702,8 +702,8 @@ template mismatch( _ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) noexcept /* terminates */ { // return [_First1, _Last1)/[_First2, _Last2) mismatch - _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); - _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt1); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt2); return _STD mismatch(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to{}); } #endif // _HAS_CXX17 @@ -1448,8 +1448,8 @@ template partition_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _F _Pr _Pred) noexcept /* terminates */ { // copy true partition to _Dest_true, false to _Dest_false // not parallelized at present, parallelism expected to be feasible in a future release - _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); - _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); - _REQUIRE_PARALLEL_ITERATOR(_FwdIt3); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt1); + _REQUIRE_MUTABLE_PARALLEL_ITERATOR(_FwdIt2); + _REQUIRE_MUTABLE_PARALLEL_ITERATOR(_FwdIt3); return _STD partition_copy(_First, _Last, _Dest_true, _Dest_false, _Pass_fn(_Pred)); } @@ -3369,8 +3369,8 @@ _FwdIt2 replace_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, cons const _Ty& _Newval) noexcept /* terminates */ { // copy replacing each matching _Oldval with _Newval // not parallelized at present, parallelism expected to be feasible in a future release - _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); - _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt1); + _REQUIRE_MUTABLE_PARALLEL_ITERATOR(_FwdIt2); return _STD replace_copy(_First, _Last, _Dest, _Oldval, _Newval); } #endif // _HAS_CXX17 @@ -3464,8 +3464,8 @@ _FwdIt2 replace_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _ /* terminates */ { // copy replacing each satisfying _Pred with _Val // not parallelized at present, parallelism expected to be feasible in a future release - _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); - _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt1); + _REQUIRE_MUTABLE_PARALLEL_ITERATOR(_FwdIt2); return _STD replace_copy_if(_First, _Last, _Dest, _Pass_fn(_Pred), _Val); } #endif // _HAS_CXX17 @@ -3683,7 +3683,7 @@ template /* = 0 */> _NODISCARD bool all_of(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ { // test if all elements in [_First, _Last) satisfy _Pred with the indicated execution policy - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -1126,7 +1126,7 @@ _NODISCARD bool all_of(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept template /* = 0 */> _NODISCARD bool any_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ { // test if any element in [_First, _Last) satisfies _Pred with the indicated execution policy - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -1140,7 +1140,7 @@ _NODISCARD bool any_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pr template /* = 0 */> _NODISCARD bool none_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ { // test if no element in [_First, _Last) satisfies _Pred with the indicated execution policy - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -1189,7 +1189,7 @@ struct _Static_partitioned_for_each2 { // for_each task scheduled on the system template /* = 0 */> void for_each(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Fn _Func) noexcept /* terminates */ { // perform function for each element [_First, _Last) with the indicated execution policy - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_MUTABLE_PARALLEL_ITERATOR(_FwdIt); _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -1235,7 +1235,7 @@ _FwdIt _For_each_n_ivdep(_FwdIt _First, _Diff _Count, _Fn _Func) { template /* = 0 */> _FwdIt for_each_n(_ExPo&&, _FwdIt _First, const _Diff _Count_raw, _Fn _Func) noexcept /* terminates */ { // perform function for each element [_First, _First + _Count) - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_MUTABLE_PARALLEL_ITERATOR(_FwdIt); _Algorithm_int_t<_Diff> _Count = _Count_raw; if (0 < _Count) { auto _UFirst = _Get_unwrapped_n(_First, _Count); @@ -1337,7 +1337,7 @@ _FwdIt _Find_parallel_unchecked(_ExPo&&, const _FwdIt _First, const _FwdIt _Last template /* = 0 */> _NODISCARD _FwdIt find(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) noexcept /* terminates */ { // find first matching _Val - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); using _UFwdIt = _Unwrapped_t; _Adl_verify_range(_First, _Last); _Seek_wrapped(_First, @@ -1349,7 +1349,7 @@ _NODISCARD _FwdIt find(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, const _ template /* = 0 */> _NODISCARD _FwdIt find_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ { // find first satisfying _Pred - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); using _UFwdIt = _Unwrapped_t; _Adl_verify_range(_First, _Last); auto _Pass_pred = _Pass_fn(_Pred); @@ -1362,7 +1362,7 @@ _NODISCARD _FwdIt find_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr template /* = 0 */> _NODISCARD _FwdIt find_if_not(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ { // find first satisfying !_Pred - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); using _UFwdIt = _Unwrapped_t; _Adl_verify_range(_First, _Last); auto _Pass_pred = _Pass_fn(_Pred); @@ -1576,7 +1576,7 @@ template ; _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -1700,7 +1700,7 @@ template count_if(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ { // count elements satisfying _Pred - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -1735,7 +1735,7 @@ template count(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) noexcept /* terminates */ { // count elements that match _Val - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); _Adl_verify_range(_First, _Last); return _STD count_if(_STD forward<_ExPo>(_Exec), _Get_unwrapped(_First), _Get_unwrapped(_Last), [&_Val](auto&& _Iter_val) { return _STD forward(_Iter_val) == _Val; }); @@ -1862,8 +1862,8 @@ template mismatch( _ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _Pr _Pred) noexcept /* terminates */ { // return [_First1, _Last1)/[_First2, ...) mismatch - _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); - _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt1); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt2); _Adl_verify_range(_First1, _Last1); const auto _UFirst1 = _Get_unwrapped(_First1); const auto _ULast1 = _Get_unwrapped(_Last1); @@ -1904,8 +1904,8 @@ template mismatch( _ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) noexcept /* terminates */ { // return [_First1, _Last1)/[_First2, _Last2) mismatch - _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); - _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt1); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt2); _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); const auto _UFirst1 = _Get_unwrapped(_First1); @@ -1981,8 +1981,8 @@ template (_Exec), _First, _Last, [&](auto&& _Value) { if (_STD forward(_Value) == _Oldval) { _STD forward(_Value) = _Newval; @@ -2439,7 +2439,7 @@ template (_Exec), _First, _Last, [&_Val, _Lambda_pred = _Pass_fn(_Pred)](auto&& _Value) mutable { if (_Lambda_pred(_STD forward(_Value))) { @@ -3044,7 +3044,7 @@ struct _Static_partitioned_is_sorted_until { template /* = 0 */> _NODISCARD _FwdIt is_sorted_until(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ { // find extent of range that is ordered by predicate - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -3198,7 +3198,7 @@ struct _Static_partitioned_is_partitioned { template /* = 0 */> _NODISCARD bool is_partitioned(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ { // test if [_First, _Last) is partitioned by _Pred - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -3270,7 +3270,7 @@ struct _Static_partitioned_is_heap_until { template /* = 0 */> _NODISCARD _RanIt is_heap_until(_ExPo&&, _RanIt _First, _RanIt _Last, _Pr _Pred) noexcept /* terminates */ { // find extent of range that is a heap - _REQUIRE_PARALLEL_ITERATOR(_RanIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_RanIt); _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); @@ -3850,9 +3850,9 @@ template = 0> _NODISCARD _Ty reduce(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, _Ty _Val) noexcept /* terminates */ { // return commutative and associative reduction of _Val and [_First, _Last) - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); return _STD reduce(_STD forward<_ExPo>(_Exec), _First, _Last, _STD move(_Val), plus{}); } @@ -117,7 +117,7 @@ _NODISCARD _Iter_value_t<_FwdIt> reduce(_ExPo&& _Exec, const _FwdIt _First, cons /* terminates */ { // return commutative and associative reduction of // iterator_traits<_FwdIt>::value_type{} and [_First, _Last) - _REQUIRE_PARALLEL_ITERATOR(_FwdIt); + _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt); return _STD reduce(_STD forward<_ExPo>(_Exec), _First, _Last, _Iter_value_t<_FwdIt>{}, plus{}); } #endif // _HAS_CXX17 @@ -228,8 +228,8 @@ template (_Exec), _First1, _Last1, _First2, _STD move(_Val), plus{}, multiplies{}); } diff --git a/stl/inc/xutility b/stl/inc/xutility index c88fbe7274e..7ee25c8e94b 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -848,6 +848,14 @@ _INLINE_VAR constexpr bool _Is_input_iter_v = is_convertible_v<_Iter_cat_t<_Iter template _INLINE_VAR constexpr bool _Is_fwd_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, forward_iterator_tag>; +template +_INLINE_VAR constexpr bool _Is_ranges_fwd_iter_v = +#if defined(__cpp_lib_concepts) + forward_iterator<_Iter>; +#else + is_convertible_v<_Iter_cat_t<_Iter>, forward_iterator_tag>; +#endif + template _INLINE_VAR constexpr bool _Is_bidi_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, bidirectional_iterator_tag>; @@ -1036,8 +1044,11 @@ inline constexpr bool is_execution_policy_v = is_execution_policy<_Ty>::value; template using _Enable_if_execution_policy_t = typename remove_reference_t<_ExPo>::_Standard_execution_policy; -#define _REQUIRE_PARALLEL_ITERATOR(_Iter) \ - static_assert(_Is_fwd_iter_v<_Iter>, "Parallel algorithms require forward iterators or stronger.") +#define _REQUIRE_MUTABLE_PARALLEL_ITERATOR(_Iter) \ + static_assert(_Is_fwd_iter_v<_Iter>, \ + "Parallel algorithms require that mutable iterators be Cpp17ForwardIterators or stronger.") +#define _REQUIRE_CONST_PARALLEL_ITERATOR(_Iter) \ + static_assert(_Is_ranges_fwd_iter_v<_Iter>, "Parallel algorithms require forward iterators or stronger.") #endif // _HAS_CXX17 @@ -3687,8 +3698,8 @@ template Date: Wed, 27 Jul 2022 15:20:36 -0700 Subject: [PATCH 02/18] do the other changes also, add a `_Is_ranges_bidi_iter_v` type trait --- stl/inc/algorithm | 18 +++++++----------- stl/inc/functional | 6 +++--- stl/inc/vector | 18 ++++-------------- stl/inc/xutility | 14 +++++++++++--- 4 files changed, 25 insertions(+), 31 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index e5c39846386..1289768cee6 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -866,7 +866,9 @@ _NODISCARD _CONSTEXPR20 bool is_permutation( } return true; - } else if constexpr (_Is_fwd_iter_v<_FwdIt1> && _Is_fwd_iter_v<_FwdIt2>) { + } else { + static_assert(_Is_ranges_fwd_iter_v<_FwdIt1> && _Is_ranges_fwd_iter_v<_FwdIt2>, + "Iterators must be at least forward iterators"); for (;; ++_UFirst1, (void) ++_UFirst2) { // trim matching prefix if (_UFirst1 == _ULast1) { return _UFirst2 == _ULast2; @@ -896,8 +898,6 @@ _NODISCARD _CONSTEXPR20 bool is_permutation( return false; // sequence 1 is longer than sequence 2, not a permutation } } - } else { - static_assert(_Always_false<_FwdIt1>, "Iterators must be at least forward iterators"); } } @@ -4096,14 +4096,9 @@ namespace ranges { } // namespace ranges #endif // __cpp_lib_concepts -#ifdef __cpp_lib_concepts -template -concept _Can_reread_dest = forward_iterator<_OutIt> && same_as, iter_value_t<_OutIt>>; -#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv template _INLINE_VAR constexpr bool _Can_reread_dest = _Is_fwd_iter_v<_OutIt> // && is_same_v<_Iter_value_t<_InIt>, _Iter_value_t<_OutIt>>; -#endif // __cpp_lib_concepts template _CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { @@ -4119,7 +4114,7 @@ _CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pr auto _UDest = _Get_unwrapped_unverified(_Dest); - if constexpr (_Is_fwd_iter_v<_InIt>) { // can reread the source for comparison + if constexpr (_Is_ranges_fwd_iter_v<_InIt>) { // can reread the source for comparison auto _Firstb = _UFirst; *_UDest = *_Firstb; @@ -4728,8 +4723,9 @@ _SampleIt _Sample_selection_unchecked( template _SampleIt sample(_PopIt _First, _PopIt _Last, _SampleIt _Dest, _Diff _Count, _Urng&& _Func) { // randomly select _Count elements from [_First, _Last) into _Dest - static_assert(_Is_fwd_iter_v<_PopIt> || _Is_random_iter_v<_SampleIt>, + static_assert(_Is_ranges_fwd_iter_v<_PopIt> || _Is_random_iter_v<_SampleIt>, "If the source range is not forward, the destination range must be random-access."); + static_assert(is_integral_v<_Diff>, "The sample size must have an integer type."); _Adl_verify_range(_First, _Last); if (0 < _Count) { @@ -4737,7 +4733,7 @@ _SampleIt sample(_PopIt _First, _PopIt _Last, _SampleIt _Dest, _Diff _Count, _Ur auto _ULast = _Get_unwrapped(_Last); using _PopDiff = _Iter_diff_t<_PopIt>; _Rng_from_urng<_PopDiff, remove_reference_t<_Urng>> _RngFunc(_Func); - if constexpr (_Is_fwd_iter_v<_PopIt>) { + if constexpr (_Is_ranges_fwd_iter_v<_PopIt>) { // source is forward: use selection sampling (stable) using _CT = common_type_t<_Diff, _PopDiff>; const auto _Pop_size = _STD distance(_UFirst, _ULast); diff --git a/stl/inc/functional b/stl/inc/functional index 46fb311a28f..752fb7dc96e 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -2204,7 +2204,9 @@ _CONSTEXPR20 pair<_FwdItHaystack, _FwdItHaystack> _Search_pair_unchecked( } return {_Last1, _Last1}; - } else if constexpr (_Is_fwd_iter_v<_FwdItHaystack> && _Is_fwd_iter_v<_FwdItPat>) { + } else { + static_assert(_Is_ranges_fwd_iter_v<_FwdItHaystack> && _Is_ranges_fwd_iter_v<_FwdItPat>, + "Iterators must be at least forward iterators"); for (;; ++_First1) { // loop until match or end of a sequence _FwdItHaystack _Mid1 = _First1; for (_FwdItPat _Mid2 = _First2;; ++_Mid1, (void) ++_Mid2) { @@ -2221,8 +2223,6 @@ _CONSTEXPR20 pair<_FwdItHaystack, _FwdItHaystack> _Search_pair_unchecked( } } } - } else { - static_assert(_Always_false<_FwdItHaystack>, "Iterators must be at least forward iterators"); } } diff --git a/stl/inc/vector b/stl/inc/vector index 18977a33583..6336018278c 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -694,7 +694,7 @@ public: _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_fwd_iter_v<_Iter>) { + if constexpr (_Is_ranges_fwd_iter_v<_Iter>) { const auto _Count = _Convert_size(static_cast(_STD distance(_UFirst, _ULast))); _Construct_n(_Count, _STD move(_UFirst), _STD move(_ULast)); #ifdef __cpp_lib_concepts @@ -1206,12 +1206,7 @@ public: _Adl_verify_range(_First, _Last); const auto _Whereoff = static_cast(_Whereptr - _Oldfirst); -#ifdef __cpp_lib_concepts - constexpr bool _Is_fwd = _Is_fwd_iter_v<_Iter> || forward_iterator<_Iter>; -#else // ^^^ __cpp_lib_concepts ^^^ / vvv !__cpp_lib_concepts vvv - constexpr bool _Is_fwd = _Is_fwd_iter_v<_Iter>; -#endif // ^^^ !__cpp_lib_concepts ^^^ - if constexpr (_Is_fwd) { + if constexpr (_Is_ranges_fwd_iter_v<_Iter>) { _Insert_forward_range(_Where, _Get_unwrapped(_First), _Get_unwrapped(_Last)); } else { _Insert_input_range(_Where, _Get_unwrapped(_First), _Get_unwrapped(_Last)); @@ -1362,12 +1357,7 @@ public: template , int> = 0> _CONSTEXPR20 void assign(_Iter _First, _Iter _Last) { _Adl_verify_range(_First, _Last); -#ifdef __cpp_lib_concepts - constexpr bool _Is_fwd = _Is_fwd_iter_v<_Iter> || forward_iterator<_Iter>; -#else // ^^^ __cpp_lib_concepts ^^^ / vvv !__cpp_lib_concepts vvv - constexpr bool _Is_fwd = _Is_fwd_iter_v<_Iter>; -#endif // ^^^ !__cpp_lib_concepts ^^^ - if constexpr (_Is_fwd) { + if constexpr (_Is_ranges_fwd_iter_v<_Iter>) { _Assign_forward_range(_Get_unwrapped(_First), _Get_unwrapped(_Last)); } else { _Assign_input_range(_Get_unwrapped(_First), _Get_unwrapped(_Last)); @@ -3145,7 +3135,7 @@ public: _CONSTEXPR20 iterator insert(const_iterator _Where, _Iter _First, _Iter _Last) { const difference_type _Saved_offset = _Where - begin(); - if constexpr (_Is_fwd_iter_v<_Iter>) { + if constexpr (_Is_ranges_fwd_iter_v<_Iter>) { _Adl_verify_range(_First, _Last); const auto _Count = _Convert_size(static_cast(_STD distance(_First, _Last))); const size_type _Off = _Insert_x(_Where, _Count); diff --git a/stl/inc/xutility b/stl/inc/xutility index 7ee25c8e94b..1e984f71ce8 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -859,6 +859,14 @@ _INLINE_VAR constexpr bool _Is_ranges_fwd_iter_v = template _INLINE_VAR constexpr bool _Is_bidi_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, bidirectional_iterator_tag>; +template +_INLINE_VAR constexpr bool _Is_ranges_bidi_iter_v = +#if defined(__cpp_lib_concepts) + bidirectional_iterator<_Iter>; +#else + is_convertible_v<_Iter_cat_t<_Iter>, bidirectional_iterator_tag>; +#endif + template _INLINE_VAR constexpr bool _Is_random_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, random_access_iterator_tag>; @@ -1109,7 +1117,7 @@ constexpr bool _Debug_lt_pred(_Pr&& _Pred, _Ty1&& _Left, _Ty2&& _Right) noexcept template constexpr void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred) { // test if range is ordered by predicate - if constexpr (_Is_fwd_iter_v<_InIt>) { + if constexpr (_Is_ranges_fwd_iter_v<_InIt>) { if (_First != _Last) { for (auto _Next = _First; ++_Next != _Last; _First = _Next) { _STL_VERIFY(!static_cast(_Pred(*_Next, *_First)), "sequence not ordered"); @@ -1121,7 +1129,7 @@ constexpr void _Debug_order_unchecked(_InIt _First, _Sentinel _Last, _Pr&& _Pred template constexpr void _Debug_order_set_unchecked(_InIt _First, _InIt _Last, _Pr&& _Pred) { // test if range is ordered by predicate - if constexpr (is_same_v<_Iter_value_t<_OtherIt>, _Iter_value_t<_InIt>> && _Is_fwd_iter_v<_InIt>) { + if constexpr (is_same_v<_Iter_value_t<_OtherIt>, _Iter_value_t<_InIt>>) { _Debug_order_unchecked(_First, _Last, _Pred); } } @@ -1193,7 +1201,7 @@ constexpr _BidIt _Prev_iter(_BidIt _First) { // decrement iterator template _NODISCARD _CONSTEXPR17 _BidIt prev(_BidIt _First, _Iter_diff_t<_BidIt> _Off = 1) { // decrement iterator - static_assert(_Is_bidi_iter_v<_BidIt>, "prev requires bidirectional iterator"); + static_assert(_Is_ranges_bidi_iter_v<_BidIt>, "prev requires bidirectional iterator"); _STD advance(_First, -_Off); return _First; From 96c60cce9c45fffc68c1ec2367b323b73fb479b3 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 28 Jul 2022 11:58:30 -0700 Subject: [PATCH 03/18] frederick-vs-ja's comments --- stl/inc/xutility | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 1e984f71ce8..534f5235bb8 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -851,10 +851,9 @@ _INLINE_VAR constexpr bool _Is_fwd_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, template _INLINE_VAR constexpr bool _Is_ranges_fwd_iter_v = #if defined(__cpp_lib_concepts) - forward_iterator<_Iter>; -#else - is_convertible_v<_Iter_cat_t<_Iter>, forward_iterator_tag>; + forward_iterator<_Iter> || #endif + is_convertible_v<_Iter_cat_t<_Iter>, forward_iterator_tag>; template _INLINE_VAR constexpr bool _Is_bidi_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, bidirectional_iterator_tag>; @@ -862,10 +861,9 @@ _INLINE_VAR constexpr bool _Is_bidi_iter_v = is_convertible_v<_Iter_cat_t<_Iter> template _INLINE_VAR constexpr bool _Is_ranges_bidi_iter_v = #if defined(__cpp_lib_concepts) - bidirectional_iterator<_Iter>; -#else - is_convertible_v<_Iter_cat_t<_Iter>, bidirectional_iterator_tag>; + bidirectional_iterator<_Iter> || #endif + is_convertible_v<_Iter_cat_t<_Iter>, bidirectional_iterator_tag>; template _INLINE_VAR constexpr bool _Is_random_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, random_access_iterator_tag>; From f6d471f933010244be8d46ed528dd2fb5105a72e Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 28 Jul 2022 12:56:36 -0700 Subject: [PATCH 04/18] _Can_reread_dest can be a concept --- stl/inc/algorithm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 1289768cee6..b3a6b1c84cb 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -4097,7 +4097,12 @@ namespace ranges { #endif // __cpp_lib_concepts template -_INLINE_VAR constexpr bool _Can_reread_dest = _Is_fwd_iter_v<_OutIt> // +#if defined(__cpp_lib_concepts) +concept _Can_reread_dest +#else +_INLINE_VAR constexpr bool _Can_reread_dest +#endif + = _Is_fwd_iter_v<_OutIt> // && is_same_v<_Iter_value_t<_InIt>, _Iter_value_t<_OutIt>>; template From 4354bcd8bc090d0865867270b46c5f5175565ebb Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 29 Jul 2022 09:19:04 -0700 Subject: [PATCH 05/18] CR comments I agree with --- stl/inc/algorithm | 1 + stl/inc/execution | 3 ++- stl/inc/xutility | 4 ++-- stl/inc/yvals_core.h | 1 + .../test.compile.pass.cpp | 10 ++++++++++ 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index b3a6b1c84cb..c9a7758306b 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -4408,6 +4408,7 @@ template ; _Adl_verify_range(_First1, _Last1); _Adl_verify_range(_First2, _Last2); @@ -4389,7 +4390,7 @@ _FwdIt2 exclusive_scan(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last, _FwdI _BinOp _Reduce_op) noexcept /* terminates */ { // set each value in [_Dest, _Dest + (_Last - _First)) to the associative reduction of predecessors and _Val _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt1); - _REQUIRE_CONST_PARALLEL_ITERATOR(_FwdIt2); + _REQUIRE_MUTABLE_PARALLEL_ITERATOR(_FwdIt2); _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); diff --git a/stl/inc/xutility b/stl/inc/xutility index 534f5235bb8..c3da718ad29 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -853,7 +853,7 @@ _INLINE_VAR constexpr bool _Is_ranges_fwd_iter_v = #if defined(__cpp_lib_concepts) forward_iterator<_Iter> || #endif - is_convertible_v<_Iter_cat_t<_Iter>, forward_iterator_tag>; + _Is_fwd_iter_v<_Iter>; template _INLINE_VAR constexpr bool _Is_bidi_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, bidirectional_iterator_tag>; @@ -863,7 +863,7 @@ _INLINE_VAR constexpr bool _Is_ranges_bidi_iter_v = #if defined(__cpp_lib_concepts) bidirectional_iterator<_Iter> || #endif - is_convertible_v<_Iter_cat_t<_Iter>, bidirectional_iterator_tag>; + _Is_ranges_bidi_iter_v<_Iter>; template _INLINE_VAR constexpr bool _Is_random_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, random_access_iterator_tag>; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 4cd35ed672f..311737ff44a 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -270,6 +270,7 @@ // P2367R0 Remove Misuses Of List-Initialization From Clause 24 Ranges // P2372R3 Fixing Locale Handling In chrono Formatters // P2393R1 Cleaning Up Integer-Class Types +// P2408R5 Ranges Iterators As Inputs To Non-Ranges Algorithms // P2415R2 What Is A view? // P2418R2 Add Support For std::generator-like Types To std::format // P2432R1 Fix istream_view diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 34ca2d2adb7..e4ae5153533 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -30,6 +30,16 @@ STATIC_ASSERT(__cpp_lib_adaptor_iterator_pair_constructor == 202106L); STATIC_ASSERT(__cpp_lib_addressof_constexpr == 201603L); #endif +#if _HAS_CXX20 && defined(__cpp_lib_concepts) +#ifndef __cpp_lib_algorithm_iterator_requirements +#error __cpp_lib_algorithm_iterator_requirements is not defined +#elif __cpp_lib_algorithm_iterator_requirements != 202207L +#error __cpp_lib_algorithm_iterator_requirements is not 202207L +#else +STATIC_ASSERT(__cpp_lib_algorithm_iterator_requirements == 202207L); +#endif +#endif + #if _HAS_CXX23 && !defined(__EDG__) // TRANSITION, EDG concepts support #ifndef __cpp_lib_allocate_at_least #error __cpp_lib_allocate_at_least is not defined From aed6afc0de1e00e44a1421292377cb4866f4e92b Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 29 Jul 2022 10:26:19 -0700 Subject: [PATCH 06/18] add test framework still need to fill out the rest of the tests --- .../env.lst | 4 + .../test.cpp | 116 ++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/env.lst create mode 100644 tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp diff --git a/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/env.lst b/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/env.lst new file mode 100644 index 00000000000..7b6bcff4830 --- /dev/null +++ b/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp b/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp new file mode 100644 index 00000000000..a757daeb197 --- /dev/null +++ b/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +#include + +using namespace std; + +template +using second = U; + +template +struct iterator_adaptor { + std::vector v; + iterator_adaptor(initializer_list il) : v(il) {} + + using iterator = I; + using const_iterator = I::Consterator; + + iterator begin() { + return iterator{v.data()}; + } + iterator end() { + return iterator{v.data() + v.size()}; + } + + const_iterator cbegin() const { + return const_iterator{v.data()}; + } + const_iterator cend() const { + return const_iterator{v.data() + v.size()}; + } +}; + +template +struct helper { + helper(second>... ils) : tup(ils...) {} + + std::tuple...> tup; +}; + +template +auto hbegin(helper& h) { + return get(h.tup).begin(); +} +template +auto hend(helper& h) { + return get(h.tup).end(); +} + +template +auto hcbegin(const helper& h) { + return get(h.tup).cbegin(); +} +template +auto hcend(const helper& h) { + return get(h.tup).cend(); +} + +template +void test_algorithms() { + using execution::seq; + { + helper h{{0, 1, 2, 3, 4, 5}, {0, 1, 3, 4, 5}}; + auto pr = mismatch(seq, hcbegin<0>(h), hcend<0>(h), hcbegin<1>(h)); + assert(distance(hcbegin<0>(h), pr.first) == 2); + assert(*pr.first == 2); + assert(*pr.second == 3); + } + if constexpr (_Is_fwd_iter_v) { + helper h{{0, 1, 2, 3, 4, 5}, {0, 0, 0, 0, 0, 0}}; + initializer_list expected{0, 1, 2, 4, 5}; + auto it = copy_if(seq, hcbegin<0>(h), hcend<0>(h), hbegin<1>(h), [](int x) { return x != 3; }); + assert(std::equal(hbegin<1>(h), it, expected.begin(), expected.end())); + } +} + +using fwd_iter = test::iterator; +using bidi_iter = test::iterator; +using random_iter = test::iterator; +using cpp17_fwd_iter = + test::iterator; +using cpp17_bidi_iter = + test::iterator; +using cpp17_random_iter = test::iterator; +static_assert(!_Is_fwd_iter_v && forward_iterator); +static_assert(!_Is_fwd_iter_v && bidirectional_iterator); +static_assert(!_Is_fwd_iter_v && random_access_iterator); +static_assert(_Is_fwd_iter_v && forward_iterator); +static_assert(_Is_bidi_iter_v && bidirectional_iterator); +static_assert(_Is_random_iter_v && random_access_iterator); + + +template +void inst() { + test_algorithms(); + test_algorithms(); + test_algorithms(); + test_algorithms(); + test_algorithms(); + test_algorithms(); +}; + + +int main() { + inst(); + inst(); + inst(); + inst(); + inst(); + inst(); +} From 158d873b9f4f08c03d8d52c3a9ca963c038030f1 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 29 Jul 2022 10:27:37 -0700 Subject: [PATCH 07/18] forgot the test.lst --- tests/std/test.lst | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/test.lst b/tests/std/test.lst index 5121260b7f6..38192912100 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -488,6 +488,7 @@ tests\P2231R1_complete_constexpr_optional_variant tests\P2273R3_constexpr_unique_ptr tests\P2321R2_proxy_reference tests\P2401R0_conditional_noexcept_for_exchange +tests\P2408R5_ranges_iterators_to_classic_algorithms tests\P2415R2_owning_view tests\P2440R1_ranges_alg_shift_left tests\P2440R1_ranges_alg_shift_right From dd099a21f67fe0f90ba9b1bc5ba2b5fb6e93e71f Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 29 Jul 2022 10:32:00 -0700 Subject: [PATCH 08/18] wow that was a dumb bug --- stl/inc/xutility | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index c3da718ad29..4c48cb55929 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -863,7 +863,7 @@ _INLINE_VAR constexpr bool _Is_ranges_bidi_iter_v = #if defined(__cpp_lib_concepts) bidirectional_iterator<_Iter> || #endif - _Is_ranges_bidi_iter_v<_Iter>; + _Is_bidi_iter_v<_Iter>; template _INLINE_VAR constexpr bool _Is_random_iter_v = is_convertible_v<_Iter_cat_t<_Iter>, random_access_iterator_tag>; From 37898ed7b452086e96ed184bea3e1e3495a98290 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 29 Jul 2022 10:50:12 -0700 Subject: [PATCH 09/18] more dumb bug --- .../P2408R5_ranges_iterators_to_classic_algorithms/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp b/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp index a757daeb197..02fb22d995e 100644 --- a/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp +++ b/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp @@ -18,7 +18,7 @@ struct iterator_adaptor { iterator_adaptor(initializer_list il) : v(il) {} using iterator = I; - using const_iterator = I::Consterator; + using const_iterator = typename I::Consterator; iterator begin() { return iterator{v.data()}; From 8293ef24e66d9fefdad7262624e205d61080a1a1 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 29 Jul 2022 12:21:29 -0700 Subject: [PATCH 10/18] add tests --- .../test.cpp | 146 +++++++++++++----- 1 file changed, 109 insertions(+), 37 deletions(-) diff --git a/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp b/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp index 02fb22d995e..3352cf497a4 100644 --- a/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp +++ b/tests/std/tests/P2408R5_ranges_iterators_to_classic_algorithms/test.cpp @@ -11,11 +11,16 @@ using namespace std; template using second = U; +template +Input second_v(Input x) { + return x; +} -template +template struct iterator_adaptor { std::vector v; iterator_adaptor(initializer_list il) : v(il) {} + iterator_adaptor(size_t n) : v(n) {} using iterator = I; using const_iterator = typename I::Consterator; @@ -35,49 +40,105 @@ struct iterator_adaptor { } }; -template +template struct helper { helper(second>... ils) : tup(ils...) {} + helper(initializer_list il) requires(sizeof...(Is) > 1) : tup(second_v(il.size())...) { + get<0>(tup).v.assign(il); + } + std::tuple...> tup; }; -template +template auto hbegin(helper& h) { return get(h.tup).begin(); } -template +template auto hend(helper& h) { return get(h.tup).end(); } -template +template auto hcbegin(const helper& h) { return get(h.tup).cbegin(); } -template +template auto hcend(const helper& h) { return get(h.tup).cend(); } -template -void test_algorithms() { - using execution::seq; - { - helper h{{0, 1, 2, 3, 4, 5}, {0, 1, 3, 4, 5}}; - auto pr = mismatch(seq, hcbegin<0>(h), hcend<0>(h), hcbegin<1>(h)); - assert(distance(hcbegin<0>(h), pr.first) == 2); - assert(*pr.first == 2); - assert(*pr.second == 3); +template +struct unary_algorithms { + static void call() { + if constexpr (forward_iterator) { + // parallel algorithms + using execution::seq; + { + helper h({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); + auto res = reduce(seq, hcbegin<0>(h), hcend<0>(h), 0); + assert(res == 55); + } + } } - if constexpr (_Is_fwd_iter_v) { - helper h{{0, 1, 2, 3, 4, 5}, {0, 0, 0, 0, 0, 0}}; - initializer_list expected{0, 1, 2, 4, 5}; - auto it = copy_if(seq, hcbegin<0>(h), hcend<0>(h), hbegin<1>(h), [](int x) { return x != 3; }); - assert(std::equal(hbegin<1>(h), it, expected.begin(), expected.end())); +}; + +template +struct binary_algorithms { + static void call() { + if constexpr (forward_iterator || _Is_fwd_iter_v) { + helper h({0, 0, 1, 2, 3, 3, 4, 5}); + initializer_list exp{0, 1, 2, 3, 4, 5}; + auto it = unique_copy(hcbegin<0>(h), hcend<0>(h), hbegin<1>(h)); + assert(equal(hbegin<1>(h), it, exp.begin(), exp.end())); + } + + if constexpr (forward_iterator && forward_iterator) { + { + helper h{{0, 1, 2, 3, 4, 5}, {5, 4, 3, 2, 1, 0}}; + assert(is_permutation(hcbegin<0>(h), hcend<0>(h), hcbegin<1>(h), hcend<1>(h))); + } + + // parallel algorithms + using execution::seq; + { + helper h{{0, 1, 2, 3, 4, 5}, {0, 1, 3, 4, 5}}; + auto pr = mismatch(seq, hcbegin<0>(h), hcend<0>(h), hcbegin<1>(h), hcend<1>(h)); + assert(distance(hcbegin<0>(h), pr.first) == 2); + assert(*pr.first == 2); + assert(*pr.second == 3); + } + if constexpr (_Is_fwd_iter_v) { + helper h{{0, 1, 2, 3, 4, 5}}; + initializer_list expected{0, 1, 2, 4, 5}; + auto it = copy_if(seq, hcbegin<0>(h), hcend<0>(h), hbegin<1>(h), [](int x) { return x != 3; }); + assert(equal(hbegin<1>(h), it, expected.begin(), expected.end())); + } + } } -} +}; +template +struct ternary_algorithms { + static void call() { + if constexpr (forward_iterator && forward_iterator && forward_iterator) { + // parallel algorithms + using execution::seq; + if constexpr (_Is_fwd_iter_v && _Is_fwd_iter_v) { + helper h{{0, 1, 2, 3, 4, 5}}; + initializer_list exp1{0, 1}; + initializer_list exp2{2, 3, 4, 5}; + auto pr = partition_copy( + seq, hcbegin<0>(h), hcend<0>(h), hbegin<1>(h), hbegin<2>(h), [](int x) { return x < 2; }); + assert(equal(hbegin<1>(h), pr.first, exp1.begin(), exp1.end())); + assert(equal(hbegin<2>(h), pr.second, exp2.begin(), exp2.end())); + } + } + } +}; + +using input_iter = test::iterator; using fwd_iter = test::iterator; using bidi_iter = test::iterator; using random_iter = test::iterator; @@ -87,6 +148,9 @@ using cpp17_bidi_iter = test::iterator; using cpp17_random_iter = test::iterator; + +// Sanity checks +static_assert(!_Is_fwd_iter_v && !forward_iterator); static_assert(!_Is_fwd_iter_v && forward_iterator); static_assert(!_Is_fwd_iter_v && bidirectional_iterator); static_assert(!_Is_fwd_iter_v && random_access_iterator); @@ -94,23 +158,31 @@ static_assert(_Is_fwd_iter_v && forward_iterator static_assert(_Is_bidi_iter_v && bidirectional_iterator); static_assert(_Is_random_iter_v && random_access_iterator); - -template -void inst() { - test_algorithms(); - test_algorithms(); - test_algorithms(); - test_algorithms(); - test_algorithms(); - test_algorithms(); +template