diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 13801421fc7..945936ee546 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -84,18 +84,18 @@ namespace ranges { #endif // __clang__ // STRUCT TEMPLATE in_fun_result - template + template struct in_fun_result { [[no_unique_address]] _In in; - [[no_unique_address]] _Fn fun; + [[no_unique_address]] _Fun fun; - template <_Convertible_from _IIn, _Convertible_from _FFn> - constexpr operator in_fun_result<_IIn, _FFn>() const& { + template <_Convertible_from _IIn, _Convertible_from _FFun> + constexpr operator in_fun_result<_IIn, _FFun>() const& { return {in, fun}; } - template <_Convertible_from<_In> _IIn, _Convertible_from<_Fn> _FFn> - constexpr operator in_fun_result<_IIn, _FFn>() && { + template <_Convertible_from<_In> _IIn, _Convertible_from<_Fun> _FFun> + constexpr operator in_fun_result<_IIn, _FFun>() && { return {_STD move(in), _STD move(fun)}; } }; @@ -324,8 +324,8 @@ _FwdIt for_each_n(_ExPo&& _Exec, _FwdIt _First, _Diff _Count_raw, _Fn _Func) noe #ifdef __cpp_lib_concepts namespace ranges { // ALIAS TEMPLATE for_each_result - template - using for_each_result = in_fun_result<_It, _Fn>; + template + using for_each_result = in_fun_result<_In, _Fun>; // VARIABLE ranges::for_each class _For_each_fn : private _Not_quite_object { @@ -357,8 +357,8 @@ namespace ranges { inline constexpr _For_each_fn for_each{_Not_quite_object::_Construct_tag{}}; // ALIAS TEMPLATE for_each_n_result - template - using for_each_n_result = in_fun_result<_It, _Fn>; + template + using for_each_n_result = in_fun_result<_In, _Fun>; // VARIABLE ranges::for_each_n class _For_each_n_fn : private _Not_quite_object { @@ -539,7 +539,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt adjacent_find(const _FwdIt _First, _FwdIt _Last, template _NODISCARD _CONSTEXPR20 _FwdIt adjacent_find(const _FwdIt _First, const _FwdIt _Last) { // find first matching successor - return _STD adjacent_find(_First, _Last, equal_to<>()); + return _STD adjacent_find(_First, _Last, equal_to<>{}); } #if _HAS_CXX17 @@ -549,7 +549,7 @@ _NODISCARD _FwdIt adjacent_find(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr template = 0> _NODISCARD _FwdIt adjacent_find(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last) noexcept /* terminates */ { // find first matching successor - return _STD adjacent_find(_STD forward<_ExPo>(_Exec), _First, _Last, equal_to<>()); + return _STD adjacent_find(_STD forward<_ExPo>(_Exec), _First, _Last, equal_to{}); } #endif // _HAS_CXX17 @@ -606,26 +606,33 @@ namespace ranges { _NODISCARD constexpr iter_difference_t<_It> operator()( _It _First, _Se _Last, const _Ty& _Val, _Pj _Proj = {}) const { _Adl_verify_range(_First, _Last); + return _Count_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Val, _Pass_fn(_Proj)); + } - auto _UFirst = _Get_unwrapped(_STD move(_First)); - const auto _ULast = _Get_unwrapped(_STD move(_Last)); - iter_difference_t<_It> _Count = 0; + template + requires indirect_binary_predicate, _Pj>, const _Ty*> + _NODISCARD constexpr range_difference_t<_Rng> operator()(_Rng&& _Range, const _Ty& _Val, _Pj _Proj = {}) const { + return _Count_unchecked(_Ubegin(_Range), _Uend(_Range), _Val, _Pass_fn(_Proj)); + } + // clang-format on + private: + template + _NODISCARD static constexpr iter_difference_t<_It> _Count_unchecked( + _It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate, const _Ty*>); - for (; _UFirst != _ULast; ++_UFirst) { - if (_STD invoke(_Proj, *_UFirst) == _Val) { + iter_difference_t<_It> _Count = 0; + for (; _First != _Last; ++_First) { + if (_STD invoke(_Proj, *_First) == _Val) { ++_Count; } } return _Count; } - - template - requires indirect_binary_predicate, _Pj>, const _Ty*> - _NODISCARD constexpr range_difference_t<_Rng> operator()(_Rng&& _Range, const _Ty& _Val, _Pj _Proj = {}) const { - return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Val, _Pass_fn(_Proj)); - } - // clang-format on }; inline constexpr _Count_fn count{_Not_quite_object::_Construct_tag{}}; @@ -666,23 +673,33 @@ namespace ranges { indirect_unary_predicate> _Pr> _NODISCARD constexpr iter_difference_t<_It> operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const { _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_STD move(_First)); - const auto _ULast = _Get_unwrapped(_STD move(_Last)); + return _Count_if_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Pred), _Pass_fn(_Proj)); + } + + template , _Pj>> _Pr> + _NODISCARD constexpr range_difference_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const { + return _Count_if_unchecked(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); + } + + private: + template + _NODISCARD static constexpr iter_difference_t<_It> _Count_if_unchecked( + _It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + iter_difference_t<_It> _Count = 0; - for (; _UFirst != _ULast; ++_UFirst) { - if (_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { + for (; _First != _Last; ++_First) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { ++_Count; } } return _Count; } - - template , _Pj>> _Pr> - _NODISCARD constexpr range_difference_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const { - return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); - } }; inline constexpr _Count_if_fn count_if{_Not_quite_object::_Construct_tag{}}; @@ -716,7 +733,7 @@ _NODISCARD pair<_FwdIt1, _FwdIt2> mismatch( template _NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2) { // return [_First1, _Last1)/[_First2, ...) mismatch - return _STD mismatch(_First1, _Last1, _First2, equal_to<>()); + return _STD mismatch(_First1, _Last1, _First2, equal_to<>{}); } #if _HAS_CXX17 @@ -726,7 +743,7 @@ _NODISCARD pair<_FwdIt1, _FwdIt2> mismatch( // return [_First1, _Last1)/[_First2, ...) mismatch _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); - return _STD mismatch(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, equal_to<>()); + return _STD mismatch(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, equal_to{}); } #endif // _HAS_CXX17 @@ -808,7 +825,7 @@ _NODISCARD pair<_FwdIt1, _FwdIt2> mismatch( template _NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { // return [_First1, _Last1)/[_First2, _Last2) mismatch - return _STD mismatch(_First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD mismatch(_First1, _Last1, _First2, _Last2, equal_to<>{}); } #if _HAS_CXX17 @@ -818,7 +835,7 @@ _NODISCARD pair<_FwdIt1, _FwdIt2> mismatch( // return [_First1, _Last1)/[_First2, _Last2) mismatch _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); - return _STD mismatch(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD mismatch(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to{}); } #endif // _HAS_CXX17 @@ -1507,6 +1524,18 @@ namespace ranges { using copy_result = in_out_result<_In, _Out>; // VARIABLE ranges::copy + // clang-format off + template _Se, weakly_incrementable _Out> + requires indirectly_copyable<_It, _Out> + _NODISCARD constexpr copy_result<_It, _Out> _Copy_unchecked(_It _First, const _Se _Last, _Out _Result) { + for (; _First != _Last; ++_First, (void) ++_Result) { + *_Result = *_First; + } + + return {_STD move(_First), _STD move(_Result)}; + } + // clang-format on + class _Copy_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -1516,20 +1545,19 @@ namespace ranges { requires indirectly_copyable<_It, _Out> constexpr copy_result<_It, _Out> operator()(_It _First, _Se _Last, _Out _Result) const { _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_STD move(_First)); - const auto _ULast = _Get_unwrapped(_STD move(_Last)); - for (; _UFirst != _ULast; ++_UFirst, (void) ++_Result) { - *_Result = *_UFirst; - } - - _Seek_wrapped(_First, _STD move(_UFirst)); - return {_STD move(_First), _STD move(_Result)}; + auto _UResult = _RANGES _Copy_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _STD move(_Result)); + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; } template requires indirectly_copyable, _Out> constexpr copy_result, _Out> operator()(_Rng&& _Range, _Out _Result) const { - return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Result)); + auto _First = _RANGES begin(_Range); + auto _UResult = _RANGES _Copy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _STD move(_Result)); + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; } // clang-format on }; @@ -1557,12 +1585,6 @@ namespace ranges { _Seek_wrapped(_First, _STD move(_UFirst)); return {_STD move(_First), _STD move(_Result)}; } - - template - requires indirectly_copyable, _Out> - constexpr copy_n_result, _Out> operator()(_Rng&& _Range, _Out _Result) const { - return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Result)); - } // clang-format on }; @@ -1617,17 +1639,10 @@ namespace ranges { constexpr copy_if_result<_It, _Out> operator()( _It _First, _Se _Last, _Out _Result, _Pr _Pred, _Pj _Proj = {}) const { _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_STD move(_First)); - const auto _ULast = _Get_unwrapped(_STD move(_Last)); - for (; _UFirst != _ULast; ++_UFirst) { - if (_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { - *_Result = *_UFirst; - ++_Result; - } - } - - _Seek_wrapped(_First, _STD move(_UFirst)); - return {_STD move(_First), _STD move(_Result)}; + auto _UResult = _Copy_if_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), + _STD move(_Result), _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; } template , _Out> constexpr copy_if_result, _Out> operator()( _Rng&& _Range, _Out _Result, _Pr _Pred, _Pj _Proj = {}) const { - return (*this)( - _RANGES begin(_Range), _RANGES end(_Range), _STD move(_Result), _Pass_fn(_Pred), _Pass_fn(_Proj)); + auto _First = _RANGES begin(_Range); + auto _UResult = _Copy_if_unchecked( + _Get_unwrapped(_STD move(_First)), _Uend(_Range), _STD move(_Result), _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; } // clang-format on + + private: + template + _NODISCARD static constexpr copy_if_result<_It, _Out> _Copy_if_unchecked( + _It _First, const _Se _Last, _Out _Result, _Pr _Pred, _Pj _Proj) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); + + for (; _First != _Last; ++_First) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + *_Result = *_First; + ++_Result; + } + } + + return {_STD move(_First), _STD move(_Result)}; + } }; inline constexpr _Copy_if_fn copy_if{_Not_quite_object::_Construct_tag{}}; @@ -1657,22 +1694,38 @@ namespace ranges { requires indirectly_movable<_It, _Out> constexpr move_result<_It, _Out> operator()(_It _First, _Se _Last, _Out _Result) const { _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_STD move(_First)); - const auto _ULast = _Get_unwrapped(_STD move(_Last)); - for (; _UFirst != _ULast; ++_UFirst, (void) ++_Result) { - *_Result = _RANGES iter_move(_UFirst); - } + auto _UResult = _Move_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _STD move(_Result)); - _Seek_wrapped(_First, _STD move(_UFirst)); - return {_STD move(_First), _STD move(_Result)}; + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; } template requires indirectly_movable, _Out> constexpr move_result, _Out> operator()(_Rng&& _Range, _Out _Result) const { - return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Result)); + auto _First = _RANGES begin(_Range); + auto _UResult = _Move_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _STD move(_Result)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; } // clang-format on + + private: + template + _NODISCARD static constexpr move_result<_It, _Out> _Move_unchecked(_It _First, const _Se _Last, _Out _Result) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_movable<_It, _Out>); + + for (; _First != _Last; ++_First, (void) ++_Result) { + *_Result = _RANGES iter_move(_First); + } + + return {_STD move(_First), _STD move(_Result)}; + } }; inline constexpr _Move_fn move{_Not_quite_object::_Construct_tag{}}; @@ -1715,6 +1768,77 @@ pair<_FwdIt2, _FwdIt3> partition_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _F _REQUIRE_PARALLEL_ITERATOR(_FwdIt3); return _STD partition_copy(_First, _Last, _Dest_true, _Dest_false, _Pass_fn(_Pred)); } + +#ifdef __cpp_lib_concepts +namespace ranges { + // ALIAS TEMPLATE partition_copy_result + template + using partition_copy_result = in_out_out_result<_In, _Out1, _Out2>; + + // VARIABLE ranges::partition_copy + class _Partition_copy_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, weakly_incrementable _Out1, weakly_incrementable _Out2, + class _Pj = identity, indirect_unary_predicate> _Pr> + requires indirectly_copyable<_It, _Out1> && indirectly_copyable<_It, _Out2> + constexpr partition_copy_result<_It, _Out1, _Out2> operator()( + _It _First, _Se _Last, _Out1 _Dest_true, _Out2 _Dest_false, _Pr _Pred, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Partition_copy_unchecked(_Get_unwrapped(_STD move(_First)), + _Get_unwrapped(_STD move(_Last)), _Get_unwrapped_unverified(_STD move(_Dest_true)), + _Get_unwrapped_unverified(_STD move(_Dest_false)), _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Seek_wrapped(_First, _STD move(_UResult.in)); + _Seek_wrapped(_Dest_true, _STD move(_UResult.out1)); + _Seek_wrapped(_Dest_false, _STD move(_UResult.out2)); + return {_STD move(_First), _STD move(_Dest_true), _STD move(_Dest_false)}; + } + + template , _Pj>> _Pr> + requires indirectly_copyable, _Out1> && indirectly_copyable, _Out2> + constexpr partition_copy_result, _Out1, _Out2> operator()( + _Rng&& _Range, _Out1 _Dest_true, _Out2 _Dest_false, _Pr _Pred, _Pj _Proj = {}) const { + auto _First = _RANGES begin(_Range); + auto _UResult = _Partition_copy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), + _Get_unwrapped_unverified(_STD move(_Dest_true)), _Get_unwrapped_unverified(_STD move(_Dest_false)), + _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Seek_wrapped(_First, _STD move(_UResult.in)); + _Seek_wrapped(_Dest_true, _STD move(_UResult.out1)); + _Seek_wrapped(_Dest_false, _STD move(_UResult.out2)); + return {_STD move(_First), _STD move(_Dest_true), _STD move(_Dest_false)}; + } + // clang-format on + private: + template + _NODISCARD static constexpr partition_copy_result<_It, _Out1, _Out2> _Partition_copy_unchecked( + _It _First, const _Se _Last, _Out1 _Dest_true, _Out2 _Dest_false, _Pr _Pred, _Pj _Proj) { + // copy true partition to _Dest_true, false to _Dest_false + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out1> && weakly_incrementable<_Out2>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out1> && indirectly_copyable<_It, _Out2>); + + for (; _First != _Last; ++_First) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + *_Dest_true = *_First; + ++_Dest_true; + } else { + *_Dest_false = *_First; + ++_Dest_false; + } + } + + return {_STD move(_First), _STD move(_Dest_true), _STD move(_Dest_false)}; + } + }; + + inline constexpr _Partition_copy_fn partition_copy{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts #endif // _HAS_CXX17 // FUNCTION TEMPLATE is_partitioned @@ -1749,6 +1873,59 @@ template _Se, class _Pj = identity, + indirect_unary_predicate> _Pr> + _NODISCARD constexpr bool operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + return _Is_partitioned_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Pred), _Pass_fn(_Proj)); + } + + template , _Pj>> _Pr> + _NODISCARD constexpr bool operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const { + return _Is_partitioned_unchecked(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); + } + + private: + template + _NODISCARD static constexpr bool _Is_partitioned_unchecked(_It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) { + // test if [_First, _Last) is partitioned with respect to _Pred and _Proj + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + + for (;; ++_First) { // skip true partition + if (_First == _Last) { + return true; + } + + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + break; + } + } + + while (++_First != _Last) { // verify false partition + if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + return false; // found out of place element + } + } + + return true; + } + }; + + inline constexpr _Is_partitioned_fn is_partitioned{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE partition_point template _NODISCARD _CONSTEXPR20 _FwdIt partition_point(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { @@ -1774,6 +1951,105 @@ _NODISCARD _CONSTEXPR20 _FwdIt partition_point(_FwdIt _First, _FwdIt _Last, _Pr return _First; } +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::partition_point + class _Partition_point_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template _Se, class _Pj = identity, + indirect_unary_predicate> _Pr> + _NODISCARD constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UFirst = _Get_unwrapped(_STD move(_First)); + if constexpr (sized_sentinel_for<_Se, _It>) { + const auto _Length = _Get_unwrapped(_STD move(_Last)) - _UFirst; + _UFirst = _Partition_point_n_unchecked(_STD move(_UFirst), _Length, _Pass_fn(_Pred), _Pass_fn(_Proj)); + } else { + _UFirst = _Partition_point_unchecked( + _STD move(_UFirst), _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Pred), _Pass_fn(_Proj)); + } + + _Seek_wrapped(_First, _STD move(_UFirst)); + return _First; + } + + template , _Pj>> _Pr> + _NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const { + if constexpr (sized_range<_Rng>) { + const auto _Length = _RANGES distance(_Range); + auto _UFirst = _Partition_point_n_unchecked(_Ubegin(_Range), _Length, _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _Rewrap_iterator(_Range, _STD move(_UFirst)); + } else { + auto _UFirst = + _Partition_point_unchecked(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _Rewrap_iterator(_Range, _STD move(_UFirst)); + } + } + + private: + template + _NODISCARD static constexpr _It _Partition_point_n_unchecked( + _It _First, iter_difference_t<_It> _Length, _Pr _Pred, _Pj _Proj) { + _STL_INTERNAL_STATIC_ASSERT(forward_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + _STL_INTERNAL_CHECK(_Length >= 0); + + while (_Length > 0) { + const auto _Half = static_cast>(_Length / 2); + auto _Mid = _RANGES next(_First, _Half); + if (_STD invoke(_Pred, _STD invoke(_Proj, *_Mid))) { // _Mid is before the partition point + _First = _STD move(_Mid); + ++_First; + _Length -= _Half; + --_Length; + } else { // _Mid is at or past the partition point + _Length = _Half; + } + } + + return _First; + } + + template + _NODISCARD static constexpr _It _Partition_point_unchecked(_It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) { + _STL_INTERNAL_STATIC_ASSERT(forward_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + + // Instead of blindly seeking the end of the range, probe elements at exponentially increasing intervals to + // find an element past the partition point. + iter_difference_t<_It> _Skip = 2; + for (;;) { + auto _Mid = _First; + _Skip -= _RANGES advance(_Mid, _Skip, _Last); + if (_Mid == _Last) { // we've located the end of the range + break; + } + + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_Mid))) { // _Mid is at or past the partition point + break; + } + + _First = _STD move(_Mid); + ++_First; + + using _Uty = _Make_unsigned_like_t>; + if (static_cast<_Uty>(_Skip) <= (static_cast<_Uty>(-1) >> 1)) { + _Skip <<= 1; + } + } + + return _Partition_point_n_unchecked(_STD move(_First), _Skip, _Pred, _Proj); + } + }; + + inline constexpr _Partition_point_fn partition_point{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE _Equal_rev_pred_unchecked #if _HAS_IF_CONSTEXPR template @@ -1928,7 +2204,7 @@ template _NODISCARD _CONSTEXPR20 _FwdItHaystack search( const _FwdItHaystack _First1, const _FwdItHaystack _Last1, const _FwdItPat _First2, const _FwdItPat _Last2) { // find first [_First2, _Last2) match - return _STD search(_First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD search(_First1, _Last1, _First2, _Last2, equal_to<>{}); } #if _HAS_CXX17 @@ -1936,7 +2212,7 @@ template (_Exec), _First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD search(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to{}); } #endif // _HAS_CXX17 @@ -2262,14 +2538,14 @@ _NODISCARD _FwdIt search_n(_ExPo&& _Exec, const _FwdIt _First, _FwdIt _Last, con template _NODISCARD _CONSTEXPR20 _FwdIt search_n(const _FwdIt _First, const _FwdIt _Last, const _Diff _Count, const _Ty& _Val) { // find first _Count * _Val match - return _STD search_n(_First, _Last, _Count, _Val, equal_to<>()); + return _STD search_n(_First, _Last, _Count, _Val, equal_to<>{}); } #if _HAS_CXX17 template = 0> _NODISCARD _FwdIt search_n(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Diff _Count, const _Ty& _Val) noexcept /* terminates */ { // find first _Count * _Val match - return _STD search_n(_STD forward<_ExPo>(_Exec), _First, _Last, _Count, _Val, equal_to<>()); + return _STD search_n(_STD forward<_ExPo>(_Exec), _First, _Last, _Count, _Val, equal_to{}); } #endif // _HAS_CXX17 @@ -2613,7 +2889,7 @@ template _NODISCARD _CONSTEXPR20 _FwdIt1 find_end( _FwdIt1 const _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2) { // find last [_First2, _Last2) match - return _STD find_end(_First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD find_end(_First1, _Last1, _First2, _Last2, equal_to<>{}); } #if _HAS_CXX17 @@ -2624,7 +2900,7 @@ _NODISCARD _FwdIt1 find_end( template = 0> _NODISCARD _FwdIt1 find_end(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) noexcept /* terminates */ { // find last [_First2, _Last2) match - return _STD find_end(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD find_end(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to{}); } #endif // _HAS_CXX17 @@ -2821,7 +3097,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of( template _NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of(const _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2) { // look for one of [_First2, _Last2) that matches element - return _STD find_first_of(_First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD find_first_of(_First1, _Last1, _First2, _Last2, equal_to<>{}); } #if _HAS_CXX17 @@ -2832,7 +3108,7 @@ _NODISCARD _FwdIt1 find_first_of(_ExPo&& _Exec, const _FwdIt1 _First1, _FwdIt1 _ template = 0> _NODISCARD _FwdIt1 find_first_of(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2) noexcept /* terminates */ { // look for one of [_First2, _Last2) that matches element - return _STD find_first_of(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD find_first_of(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to{}); } #endif // _HAS_CXX17 @@ -3010,6 +3286,64 @@ void replace(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty& const _Ty& _Newval) noexcept; // terminates #endif // _HAS_CXX17 +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::replace + class _Replace_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, class _Ty1, class _Ty2, class _Pj = identity> + requires indirectly_writable<_It, const _Ty2&> + && indirect_binary_predicate, const _Ty1*> + constexpr _It operator()( + _It _First, _Se _Last, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Replace_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Oldval, _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + + template + requires indirectly_writable, const _Ty2&> + && indirect_binary_predicate, _Pj>, const _Ty1*> + constexpr borrowed_iterator_t<_Rng> operator()( + _Rng&& _Range, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj = {}) const { + auto _First = _RANGES begin(_Range); + auto _UResult = _Replace_unchecked( + _Get_unwrapped(_STD move(_First)), _Uend(_Range), _Oldval, _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + // clang-format on + private: + template + _NODISCARD static constexpr _It _Replace_unchecked( + _It _First, const _Se _Last, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj) { + // replace projected _Oldval with _Newval in [_First, _Last) + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_writable<_It, const _Ty2&>); + _STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate, const _Ty1*>); + + for (; _First != _Last; ++_First) { + if (_STD invoke(_Proj, *_First) == _Oldval) { + *_First = _Newval; + } + } + + return _First; + } + }; + + inline constexpr _Replace_fn replace{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE replace_if template _CONSTEXPR20 void replace_if(const _FwdIt _First, const _FwdIt _Last, _Pr _Pred, const _Ty& _Val) { @@ -3118,6 +3452,72 @@ _FwdIt2 replace_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, cons } #endif // _HAS_CXX17 +#ifdef __cpp_lib_concepts +namespace ranges { + // ALIAS TEMPLATE replace_copy_result + template + using replace_copy_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::replace_copy + class _Replace_copy_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, class _Ty1, class _Ty2, output_iterator _Out, + class _Pj = identity> + requires indirectly_copyable<_It, _Out> + && indirect_binary_predicate, const _Ty1*> + constexpr replace_copy_result<_It, _Out> operator()( + _It _First, _Se _Last, _Out _Result, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Replace_copy_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), + _STD move(_Result), _Oldval, _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; + } + + template _Out, class _Pj = identity> + requires indirectly_copyable, _Out> + && indirect_binary_predicate, _Pj>, const _Ty1*> + constexpr replace_copy_result, _Out> operator()( + _Rng&& _Range, _Out _Result, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj = {}) const { + auto _First = _RANGES begin(_Range); + auto _UResult = _Replace_copy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), + _STD move(_Result), _Oldval, _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; + } + // clang-format on + private: + template + _NODISCARD static constexpr replace_copy_result<_It, _Out> _Replace_copy_unchecked( + _It _First, const _Se _Last, _Out _Result, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj) { + // copy [_First, _Last) to _Result while replacing projected _Oldval with _Newval + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(output_iterator<_Out, const _Ty2&>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); + _STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate, const _Ty1*>); + + for (; _First != _Last; ++_First, (void) ++_Result) { + if (_STD invoke(_Proj, *_First) == _Oldval) { + *_Result = _Newval; + } else { + *_Result = *_First; + } + } + + return {_STD move(_First), _STD move(_Result)}; + } + }; + + inline constexpr _Replace_copy_fn replace_copy{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE replace_copy_if template _CONSTEXPR20 _OutIt replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, const _Ty& _Val) { @@ -3152,6 +3552,67 @@ _FwdIt2 replace_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _ #ifdef __cpp_lib_concepts namespace ranges { + // ALIAS TEMPLATE replace_copy_if_result + template + using replace_copy_if_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::replace_copy_if + class _Replace_copy_if_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, class _Ty, output_iterator _Out, + class _Pj = identity, indirect_unary_predicate> _Pr> + requires indirectly_copyable<_It, _Out> + constexpr replace_copy_if_result<_It, _Out> operator()( + _It _First, _Se _Last, _Out _Result, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Replace_copy_if_unchecked(_Get_unwrapped(_STD move(_First)), + _Get_unwrapped(_STD move(_Last)), _STD move(_Result), _Pass_fn(_Pred), _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; + } + + template _Out, class _Pj = identity, + indirect_unary_predicate, _Pj>> _Pr> + requires indirectly_copyable, _Out> + constexpr replace_copy_if_result, _Out> operator()( + _Rng&& _Range, _Out _Result, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) const { + auto _First = _RANGES begin(_Range); + auto _UResult = _Replace_copy_if_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), + _STD move(_Result), _Pass_fn(_Pred), _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; + } + // clang-format on + private: + template + _NODISCARD static constexpr replace_copy_if_result<_It, _Out> _Replace_copy_if_unchecked( + _It _First, const _Se _Last, _Out _Result, _Pr _Pred, const _Ty& _Newval, _Pj _Proj) { + // copy [_First, _Last) to _Result while replacing _Oldval with _Newval if projected _Oldval fulfills _Pred + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(output_iterator<_Out, const _Ty&>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + + for (; _First != _Last; ++_First, (void) ++_Result) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + *_Result = _Newval; + } else { + *_Result = *_First; + } + } + + return {_STD move(_First), _STD move(_Result)}; + } + }; + + inline constexpr _Replace_copy_if_fn replace_copy_if{_Not_quite_object::_Construct_tag{}}; + // VARIABLE ranges::fill class _Fill_fn : private _Not_quite_object { public: @@ -3226,6 +3687,74 @@ namespace ranges { }; inline constexpr _Fill_n_fn fill_n{_Not_quite_object::_Construct_tag{}}; + + // VARIABLE ranges::generate + class _Generate_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, copy_constructible _Fn> + requires invocable<_Fn&> && indirectly_writable<_Out, invoke_result_t<_Fn&>> + constexpr _Out operator()(_Out _First, _Se _Last, _Fn _Gen) const { + _Adl_verify_range(_First, _Last); + _Seek_wrapped(_First, _Generate_unchecked(_Get_unwrapped(_STD move(_First)), + _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Gen))); + return _First; + } + + template + requires invocable<_Fn&> && output_range<_Rng, invoke_result_t<_Fn&>> + constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Fn _Gen) const { + auto _First = _RANGES begin(_Range); + _Seek_wrapped( + _First, _Generate_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Pass_fn(_Gen))); + return _First; + } + // clang-format on + private: + template + _NODISCARD static constexpr _Out _Generate_unchecked(_Out _First, const _Se _Last, _Fn _Gen) { + _STL_INTERNAL_STATIC_ASSERT(input_or_output_iterator<_Out>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _Out>); + _STL_INTERNAL_STATIC_ASSERT(copy_constructible<_Fn>); + _STL_INTERNAL_STATIC_ASSERT(invocable<_Fn&>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_writable<_Out, invoke_result_t<_Fn&>>); + + for (; _First != _Last; ++_First) { + *_First = _Gen(); + } + + return _First; + } + }; + + inline constexpr _Generate_fn generate{_Not_quite_object::_Construct_tag{}}; + + // VARIABLE ranges::generate_n + class _Generate_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template + requires invocable<_Fn&> && indirectly_writable<_Out, invoke_result_t<_Fn&>> + constexpr _Out operator()(_Out _First, iter_difference_t<_Out> _Count, _Fn _Gen) const { + if (_Count > 0) { + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + do { + *_UFirst = _Gen(); + ++_UFirst; + } while (--_Count > 0); + + _Seek_wrapped(_First, _STD move(_UFirst)); + } + + return _First; + } + }; + + inline constexpr _Generate_n_fn generate_n{_Not_quite_object::_Construct_tag{}}; } // namespace ranges #endif // __cpp_lib_concepts @@ -3377,7 +3906,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { template _NODISCARD _CONSTEXPR20 _FwdIt unique(_FwdIt _First, _FwdIt _Last) { // remove each matching previous - return _STD unique(_First, _Last, equal_to<>()); + return _STD unique(_First, _Last, equal_to<>{}); } #if _HAS_CXX17 @@ -3544,7 +4073,7 @@ _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy template _CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy compressing pairs that match - return _STD unique_copy(_First, _Last, _Dest, equal_to<>()); + return _STD unique_copy(_First, _Last, _Dest, equal_to<>{}); } #if _HAS_CXX17 @@ -4015,6 +4544,89 @@ _FwdIt partition(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) { #if _HAS_CXX17 template = 0> _FwdIt partition(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates + +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::partition + class _Partition_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template _Se, class _Pj = identity, + indirect_unary_predicate> _Pr> + constexpr subrange<_It> operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Partition_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _Rewrap_subrange>(_First, _STD move(_UResult)); + } + + // clang-format off + template , _Pj>> _Pr> + requires permutable> + constexpr borrowed_subrange_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const { + auto _UResult = _Partition_unchecked(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); + return _Rewrap_subrange>(_Range, _STD move(_UResult)); + } + // clang-format on + private: + template + _NODISCARD static constexpr subrange<_It> _Partition_unchecked(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj) { + _STL_INTERNAL_STATIC_ASSERT(permutable<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + + if constexpr (_Bidi_common<_It, _Se>) { + auto _Saved_last = _Last; + for (;; ++_First) { // find any out-of-order pair + for (;; ++_First) { // skip in-place elements at beginning + if (_First == _Last) { + return {_STD move(_First), _STD move(_Saved_last)}; + } + + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + break; + } + } + + do { // skip in-place elements at end + --_Last; + if (_First == _Last) { + return {_STD move(_First), _STD move(_Saved_last)}; + } + } while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Last))); + + _RANGES iter_swap(_First, _Last); // out of place, swap and loop + } + + return {_STD move(_First), _STD move(_Saved_last)}; + } else { + for (;; ++_First) { // skip in-place elements at beginning + if (_First == _Last) { + return {_First, _First}; + } + + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + break; + } + } + + auto _Next = _First; + while (++_Next != _Last) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_Next))) { + _RANGES iter_swap(_First, _Next); // out of place, swap and loop + ++_First; + } + } + + return {_STD move(_First), _STD move(_Next)}; + } + } + }; + + inline constexpr _Partition_fn partition{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts #endif // _HAS_CXX17 // FUNCTION TEMPLATE stable_partition @@ -4221,7 +4833,7 @@ _CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { template _CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last) { // push *(_Last - 1) onto heap at [_First, _Last - 1) - _STD push_heap(_First, _Last, less<>()); + _STD push_heap(_First, _Last, less<>{}); } #ifdef __cpp_lib_concepts @@ -4359,7 +4971,7 @@ _CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { template _CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last) { // pop *_First to *(_Last - 1) and reheap - _STD pop_heap(_First, _Last, less<>()); + _STD pop_heap(_First, _Last, less<>{}); } #ifdef __cpp_lib_concepts @@ -4486,7 +5098,7 @@ _CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // make [_ template _CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Last) into a heap - _STD make_heap(_First, _Last, less<>()); + _STD make_heap(_First, _Last, less<>{}); } #ifdef __cpp_lib_concepts @@ -4578,12 +5190,12 @@ _NODISCARD _CONSTEXPR20 bool is_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { template _NODISCARD _CONSTEXPR20 _RanIt is_heap_until(_RanIt _First, _RanIt _Last) { // find extent of range that is a heap ordered by operator< - return _STD is_heap_until(_First, _Last, less<>()); + return _STD is_heap_until(_First, _Last, less<>{}); } template _NODISCARD _CONSTEXPR20 bool is_heap(_RanIt _First, _RanIt _Last) { // test if range is a heap ordered by operator< - return _STD is_heap(_First, _Last, less<>()); + return _STD is_heap(_First, _Last, less<>{}); } #if _HAS_CXX17 @@ -4719,7 +5331,7 @@ _CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // order h template _CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last) { // order heap by repeatedly popping - _STD sort_heap(_First, _Last, less<>()); + _STD sort_heap(_First, _Last, less<>{}); } #ifdef __cpp_lib_concepts @@ -4853,7 +5465,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _T template _NODISCARD _CONSTEXPR20 _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // find first element that _Val is before - return _STD upper_bound(_First, _Last, _Val, less<>()); + return _STD upper_bound(_First, _Last, _Val, less<>{}); } #ifdef __cpp_lib_concepts @@ -4955,7 +5567,7 @@ _NODISCARD _CONSTEXPR20 pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _ template _NODISCARD _CONSTEXPR20 pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // find range equivalent to _Val - return _STD equal_range(_First, _Last, _Val, less<>()); + return _STD equal_range(_First, _Last, _Val, less<>{}); } #ifdef __cpp_lib_concepts @@ -5036,7 +5648,7 @@ _NODISCARD _CONSTEXPR20 bool binary_search(_FwdIt _First, _FwdIt _Last, const _T template _NODISCARD _CONSTEXPR20 bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // test if _Val equivalent to some element - return _STD binary_search(_First, _Last, _Val, less<>()); + return _STD binary_search(_First, _Last, _Val, less<>{}); } #ifdef __cpp_lib_concepts @@ -5137,7 +5749,7 @@ _CONSTEXPR20 _OutIt merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 template _CONSTEXPR20 _OutIt merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // copy merging ranges - return _STD merge(_First1, _Last1, _First2, _Last2, _Dest, less<>()); + return _STD merge(_First1, _Last1, _First2, _Last2, _Dest, less<>{}); } #if _HAS_CXX17 @@ -5409,7 +6021,7 @@ void inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Pr _Pred) { template void inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last) { // merge [_First, _Mid) with [_Mid, _Last) - _STD inplace_merge(_First, _Mid, _Last, less<>()); + _STD inplace_merge(_First, _Mid, _Last, less<>{}); } #if _HAS_CXX17 @@ -5594,7 +6206,7 @@ _CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // template _CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last) { // order [_First, _Last) - _STD sort(_First, _Last, less<>()); + _STD sort(_First, _Last, less<>{}); } #if _HAS_CXX17 @@ -5604,7 +6216,7 @@ void sort(_ExPo&& _Exec, _RanIt _First, _RanIt _Last, _Pr _Pred) noexcept; // te template = 0> void sort(_ExPo&& _Exec, const _RanIt _First, const _RanIt _Last) noexcept /* terminates */ { // order [_First, _Last) - _STD sort(_STD forward<_ExPo>(_Exec), _First, _Last, less<>{}); + _STD sort(_STD forward<_ExPo>(_Exec), _First, _Last, less{}); } #endif // _HAS_CXX17 @@ -5791,14 +6403,14 @@ void stable_sort(_ExPo&& _Exec, const _BidIt _First, const _BidIt _Last, _Pr _Pr template void stable_sort(const _BidIt _First, const _BidIt _Last) { // sort preserving order of equivalents - _STD stable_sort(_First, _Last, less<>()); + _STD stable_sort(_First, _Last, less<>{}); } #if _HAS_CXX17 template = 0> void stable_sort(_ExPo&& _Exec, _BidIt _First, _BidIt _Last) noexcept /* terminates */ { // sort preserving order of equivalents - _STD stable_sort(_STD forward<_ExPo>(_Exec), _First, _Last, less<>()); + _STD stable_sort(_STD forward<_ExPo>(_Exec), _First, _Last, less{}); } #endif // _HAS_CXX17 @@ -5830,7 +6442,7 @@ _CONSTEXPR20 void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pr template _CONSTEXPR20 void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last) { // order [_First, _Last) up to _Mid - _STD partial_sort(_First, _Mid, _Last, less<>()); + _STD partial_sort(_First, _Mid, _Last, less<>{}); } #if _HAS_CXX17 @@ -5885,7 +6497,7 @@ _CONSTEXPR20 _RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First template _CONSTEXPR20 _RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First2, _RanIt _Last2) { // copy [_First1, _Last1) into [_First2, _Last2) - return _STD partial_sort_copy(_First1, _Last1, _First2, _Last2, less<>()); + return _STD partial_sort_copy(_First1, _Last1, _First2, _Last2, less<>{}); } #if _HAS_CXX17 @@ -5938,7 +6550,7 @@ _CONSTEXPR20 void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr _Pre template _CONSTEXPR20 void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last) { // order Nth element - _STD nth_element(_First, _Nth, _Last, less<>()); + _STD nth_element(_First, _Nth, _Last, less<>{}); } #if _HAS_CXX17 @@ -5985,7 +6597,7 @@ _NODISCARD _CONSTEXPR20 bool includes(_InIt1 _First1, _InIt1 _Last1, _InIt2 _Fir template _NODISCARD _CONSTEXPR20 bool includes(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { // test if every element in sorted [_First2, _Last2) is in sorted [_First1, _Last1) - return _STD includes(_First1, _Last1, _First2, _Last2, less<>()); + return _STD includes(_First1, _Last1, _First2, _Last2, less<>{}); } #if _HAS_CXX17 @@ -6046,7 +6658,7 @@ _CONSTEXPR20 _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _In template _CONSTEXPR20 _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // OR sets [_First1, _Last1) and [_First2, _Last2) - return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest, less<>()); + return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest, less<>{}); } #if _HAS_CXX17 @@ -6107,7 +6719,7 @@ _CONSTEXPR20 _OutIt set_intersection( template _CONSTEXPR20 _OutIt set_intersection(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // AND sets [_First1, _Last1) and [_First2, _Last2) - return _STD set_intersection(_First1, _Last1, _First2, _Last2, _Dest, less<>()); + return _STD set_intersection(_First1, _Last1, _First2, _Last2, _Dest, less<>{}); } #if _HAS_CXX17 @@ -6158,7 +6770,7 @@ _CONSTEXPR20 _OutIt set_difference( template _CONSTEXPR20 _OutIt set_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // take set [_First2, _Last2) from [_First1, _Last1) - return _STD set_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>()); + return _STD set_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>{}); } #if _HAS_CXX17 @@ -6212,7 +6824,7 @@ template _CONSTEXPR20 _OutIt set_symmetric_difference( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) { // XOR sets [_First1, _Last1) and [_First2, _Last2) - return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>()); + return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>{}); } #if _HAS_CXX17 @@ -6263,7 +6875,7 @@ _NODISCARD constexpr _FwdIt max_element(_FwdIt _First, _FwdIt _Last, _Pr _Pred) template _NODISCARD constexpr _FwdIt max_element(_FwdIt _First, _FwdIt _Last) { // find largest element - return _STD max_element(_First, _Last, less<>()); + return _STD max_element(_First, _Last, less<>{}); } #if _HAS_CXX17 @@ -6356,7 +6968,7 @@ _NODISCARD constexpr _FwdIt min_element(_FwdIt _First, _FwdIt _Last, _Pr _Pred) template _NODISCARD constexpr _FwdIt min_element(_FwdIt _First, _FwdIt _Last) { // find smallest element - return _STD min_element(_First, _Last, less<>()); + return _STD min_element(_First, _Last, less<>{}); } #if _HAS_CXX17 @@ -6477,7 +7089,7 @@ _NODISCARD constexpr pair<_FwdIt, _FwdIt> minmax_element(_FwdIt _First, _FwdIt _ template _NODISCARD constexpr pair<_FwdIt, _FwdIt> minmax_element(_FwdIt _First, _FwdIt _Last) { // find smallest and largest elements - return _STD minmax_element(_First, _Last, less<>()); + return _STD minmax_element(_First, _Last, less<>{}); } #if _HAS_CXX17 @@ -6499,8 +7111,8 @@ _NODISCARD pair<_FwdIt, _FwdIt> minmax_element(_ExPo&&, _FwdIt _First, _FwdIt _L #ifdef __cpp_lib_concepts namespace ranges { // ALIAS TEMPLATE minmax_element_result - template - using minmax_element_result = min_max_result<_It>; + template + using minmax_element_result = min_max_result<_Ty>; // VARIABLE ranges::minmax_element template @@ -6598,7 +7210,7 @@ _NODISCARD constexpr _Ty(max)(initializer_list<_Ty> _Ilist, _Pr _Pred) { template _NODISCARD constexpr _Ty(max)(initializer_list<_Ty> _Ilist) { // return leftmost/largest - return (_STD max)(_Ilist, less<>()); + return (_STD max)(_Ilist, less<>{}); } #ifdef __cpp_lib_concepts @@ -6678,7 +7290,7 @@ _NODISCARD constexpr _Ty(min)(initializer_list<_Ty> _Ilist, _Pr _Pred) { template _NODISCARD constexpr _Ty(min)(initializer_list<_Ty> _Ilist) { // return leftmost/smallest - return (_STD min)(_Ilist, less<>()); + return (_STD min)(_Ilist, less<>{}); } #ifdef __cpp_lib_concepts @@ -6773,7 +7385,7 @@ _NODISCARD constexpr pair minmax(const _Ty& _Left, const template _NODISCARD constexpr pair<_Ty, _Ty> minmax(initializer_list<_Ty> _Ilist) { // return {leftmost/smallest, rightmost/largest} - return _STD minmax(_Ilist, less<>()); + return _STD minmax(_Ilist, less<>{}); } #ifdef __cpp_lib_concepts @@ -6907,7 +7519,7 @@ _CONSTEXPR20 bool next_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) { template _CONSTEXPR20 bool next_permutation(_BidIt _First, _BidIt _Last) { // permute and test for pure ascending - return _STD next_permutation(_First, _Last, less<>()); + return _STD next_permutation(_First, _Last, less<>{}); } // FUNCTION TEMPLATE prev_permutation @@ -6945,7 +7557,7 @@ _CONSTEXPR20 bool prev_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) { template _CONSTEXPR20 bool prev_permutation(_BidIt _First, _BidIt _Last) { // reverse permute and test for pure descending - return _STD prev_permutation(_First, _Last, less<>()); + return _STD prev_permutation(_First, _Last, less<>{}); } // FUNCTION TEMPLATES is_sorted AND is_sorted_until @@ -6980,12 +7592,12 @@ _NODISCARD _CONSTEXPR20 bool is_sorted(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { template _NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(_FwdIt _First, _FwdIt _Last) { // find extent of range that is ordered by operator< - return _STD is_sorted_until(_First, _Last, less<>()); + return _STD is_sorted_until(_First, _Last, less<>{}); } template _NODISCARD _CONSTEXPR20 bool is_sorted(_FwdIt _First, _FwdIt _Last) { // test if range is ordered by operator< - return _STD is_sorted(_First, _Last, less<>()); + return _STD is_sorted(_First, _Last, less<>{}); } #if _HAS_CXX17 diff --git a/stl/inc/execution b/stl/inc/execution index db0d9360b7a..d632e4c4788 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -719,7 +719,7 @@ struct _Work_stealing_team { // inter-thread communication for threads working o _Work_stealing_team(size_t _Threads, _Diff _Total_work) : _Queues(_Threads), _Queues_used(0), _Remaining_work(_Total_work), _Available_mutex(), - _Available_queues(greater<>{}, _Get_queues(_Threads)) {} // register work with the thread pool + _Available_queues(greater{}, _Get_queues(_Threads)) {} // register work with the thread pool _Work_stealing_membership<_Ty> _Join_team() noexcept { size_t _Id; diff --git a/stl/inc/forward_list b/stl/inc/forward_list index 94194542051..24227c66c43 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -1187,7 +1187,7 @@ public: } auto unique() { // erase each element matching previous - return unique(equal_to<>()); + return unique(equal_to<>{}); } template @@ -1217,11 +1217,11 @@ public: } void merge(forward_list& _Right) { // merge in elements from _Right, both ordered by operator< - _Merge1(_Right, less<>()); + _Merge1(_Right, less<>{}); } void merge(forward_list&& _Right) { // merge in elements from _Right, both ordered by operator< - _Merge1(_Right, less<>()); + _Merge1(_Right, less<>{}); } template diff --git a/stl/inc/list b/stl/inc/list index de912dd25e4..a223036db12 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -1626,7 +1626,7 @@ public: } auto unique() { // erase each element matching previous - return unique(equal_to<>()); + return unique(equal_to<>{}); } template @@ -1653,11 +1653,11 @@ public: } void merge(list& _Right) { // merge in elements from _Right, both ordered by operator< - _Merge1(_Right, less<>()); + _Merge1(_Right, less<>{}); } void merge(list&& _Right) { // merge in elements from _Right, both ordered by operator< - _Merge1(_Right, less<>()); + _Merge1(_Right, less<>{}); } template @@ -1707,7 +1707,7 @@ private: public: void sort() { // order sequence - sort(less<>()); + sort(less<>{}); } template diff --git a/stl/inc/map b/stl/inc/map index 60a14db3308..f33f3df84f3 100644 --- a/stl/inc/map +++ b/stl/inc/map @@ -363,6 +363,38 @@ template map(initializer_list>, _Alloc) -> map<_Kty, _Ty, less<_Kty>, _Alloc>; #endif // _HAS_CXX17 +template +_NODISCARD bool operator==(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return _Left.size() == _Right.size() + && _STD equal(_Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin()); +} + +template +_NODISCARD bool operator!=(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return _STD lexicographical_compare( + _Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin(), _Right._Unchecked_end_iter()); +} + +template +_NODISCARD bool operator>(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return _Right < _Left; +} + +template +_NODISCARD bool operator<=(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return !(_Right < _Left); +} + +template +_NODISCARD bool operator>=(const map<_Kty, _Ty, _Pr, _Alloc>& _Left, const map<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return !(_Left < _Right); +} + template void swap(map<_Kty, _Ty, _Pr, _Alloc>& _Left, map<_Kty, _Ty, _Pr, _Alloc>& _Right) noexcept( noexcept(_Left.swap(_Right))) { @@ -518,6 +550,44 @@ template multimap(initializer_list>, _Alloc) -> multimap<_Kty, _Ty, less<_Kty>, _Alloc>; #endif // _HAS_CXX17 +template +_NODISCARD bool operator==( + const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return _Left.size() == _Right.size() + && _STD equal(_Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin()); +} + +template +_NODISCARD bool operator!=( + const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<( + const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return _STD lexicographical_compare( + _Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin(), _Right._Unchecked_end_iter()); +} + +template +_NODISCARD bool operator>( + const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return _Right < _Left; +} + +template +_NODISCARD bool operator<=( + const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return !(_Right < _Left); +} + +template +_NODISCARD bool operator>=( + const multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, const multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) { + return !(_Left < _Right); +} + template void swap(multimap<_Kty, _Ty, _Pr, _Alloc>& _Left, multimap<_Kty, _Ty, _Pr, _Alloc>& _Right) noexcept( noexcept(_Left.swap(_Right))) { diff --git a/stl/inc/numeric b/stl/inc/numeric index bb22f2d3cda..134385db5e4 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -41,7 +41,7 @@ _NODISCARD _CONSTEXPR20 _Ty accumulate(const _InIt _First, const _InIt _Last, _T template _NODISCARD _CONSTEXPR20 _Ty accumulate(const _InIt _First, const _InIt _Last, _Ty _Val) { // return noncommutative and nonassociative reduction of _Val and all in [_First, _Last) - return _STD accumulate(_First, _Last, _Val, plus<>()); + return _STD accumulate(_First, _Last, _Val, plus<>{}); } #if _HAS_CXX17 @@ -94,14 +94,14 @@ _NODISCARD _CONSTEXPR20 _Ty reduce(const _InIt _First, const _InIt _Last, _Ty _V template _NODISCARD _CONSTEXPR20 _Ty reduce(const _InIt _First, const _InIt _Last, _Ty _Val) { // return commutative and associative reduction of _Val and [_First, _Last) - return _STD reduce(_First, _Last, _STD move(_Val), plus<>{}); + return _STD reduce(_First, _Last, _STD move(_Val), plus{}); } template _NODISCARD _CONSTEXPR20 _Iter_value_t<_InIt> reduce(const _InIt _First, const _InIt _Last) { // return commutative and associative reduction of // iterator_traits<_InIt>::value_type{} and [_First, _Last) - return _STD reduce(_First, _Last, _Iter_value_t<_InIt>{}, plus<>{}); + return _STD reduce(_First, _Last, _Iter_value_t<_InIt>{}, plus{}); } template = 0> @@ -111,7 +111,7 @@ template (_Exec), _First, _Last, _STD move(_Val), plus<>{}); + return _STD reduce(_STD forward<_ExPo>(_Exec), _First, _Last, _STD move(_Val), plus{}); } template = 0> @@ -120,7 +120,7 @@ _NODISCARD _Iter_value_t<_FwdIt> reduce(_ExPo&& _Exec, const _FwdIt _First, cons // return commutative and associative reduction of // iterator_traits<_FwdIt>::value_type{} and [_First, _Last) _REQUIRE_PARALLEL_ITERATOR(_FwdIt); - return _STD reduce(_STD forward<_ExPo>(_Exec), _First, _Last, _Iter_value_t<_FwdIt>{}, plus<>{}); + return _STD reduce(_STD forward<_ExPo>(_Exec), _First, _Last, _Iter_value_t<_FwdIt>{}, plus{}); } #endif // _HAS_CXX17 @@ -148,7 +148,7 @@ _NODISCARD _CONSTEXPR20 _Ty inner_product( template _NODISCARD _CONSTEXPR20 _Ty inner_product(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _Ty _Val) { // return noncommutative and nonassociative transform-reduction of sequences - return _STD inner_product(_First1, _Last1, _First2, _STD move(_Val), plus<>(), multiplies<>()); + return _STD inner_product(_First1, _Last1, _First2, _STD move(_Val), plus<>{}, multiplies<>{}); } #if _HAS_CXX17 @@ -205,7 +205,7 @@ _NODISCARD _CONSTEXPR20 _Ty transform_reduce( template _NODISCARD _CONSTEXPR20 _Ty transform_reduce(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _Ty _Val) { // return commutative and associative transform-reduction of sequences - return _STD transform_reduce(_First1, _Last1, _First2, _STD move(_Val), plus<>{}, multiplies<>{}); + return _STD transform_reduce(_First1, _Last1, _First2, _STD move(_Val), plus{}, multiplies{}); } template @@ -235,7 +235,7 @@ _NODISCARD _Ty transform_reduce(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _REQUIRE_PARALLEL_ITERATOR(_FwdIt1); _REQUIRE_PARALLEL_ITERATOR(_FwdIt2); return _STD transform_reduce( - _STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _STD move(_Val), plus<>{}, multiplies<>{}); + _STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _STD move(_Val), plus{}, multiplies{}); } template = 0> @@ -276,7 +276,7 @@ _CONSTEXPR20 _OutIt partial_sum(const _InIt _First, const _InIt _Last, _OutIt _D template _CONSTEXPR20 _OutIt partial_sum(_InIt _First, _InIt _Last, _OutIt _Dest) { // compute partial noncommutative and nonassociative reductions into _Dest - return _STD partial_sum(_First, _Last, _Dest, plus<>()); + return _STD partial_sum(_First, _Last, _Dest, plus<>{}); } #if _HAS_CXX17 @@ -309,7 +309,7 @@ _CONSTEXPR20 _OutIt exclusive_scan(const _InIt _First, const _InIt _Last, _OutIt template _CONSTEXPR20 _OutIt exclusive_scan(const _InIt _First, const _InIt _Last, const _OutIt _Dest, _Ty _Val) { // set each value in [_Dest, _Dest + (_Last - _First)) to the associative reduction of predecessors and _Val - return _STD exclusive_scan(_First, _Last, _Dest, _STD move(_Val), plus<>{}); + return _STD exclusive_scan(_First, _Last, _Dest, _STD move(_Val), plus{}); } template = 0> @@ -320,7 +320,7 @@ template (_Exec), _First, _Last, _Dest, _STD move(_Val), plus<>{}); + return _STD exclusive_scan(_STD forward<_ExPo>(_Exec), _First, _Last, _Dest, _STD move(_Val), plus{}); } // FUNCTION TEMPLATE inclusive_scan @@ -369,7 +369,7 @@ _CONSTEXPR20 _OutIt inclusive_scan(const _InIt _First, const _InIt _Last, _OutIt template _CONSTEXPR20 _OutIt inclusive_scan(const _InIt _First, const _InIt _Last, const _OutIt _Dest) { // compute partial noncommutative and associative reductions into _Dest - return _STD inclusive_scan(_First, _Last, _Dest, plus<>{}); + return _STD inclusive_scan(_First, _Last, _Dest, plus{}); } template = 0> @@ -384,7 +384,7 @@ template (_Exec), _First, _Last, _Dest, plus<>()); + return _STD inclusive_scan(_STD forward<_ExPo>(_Exec), _First, _Last, _Dest, plus{}); } // FUNCTION TEMPLATE transform_exclusive_scan @@ -506,7 +506,7 @@ _CONSTEXPR20 _OutIt adjacent_difference(const _InIt _First, const _InIt _Last, _ template _CONSTEXPR20 _OutIt adjacent_difference(const _InIt _First, const _InIt _Last, const _OutIt _Dest) { // compute adjacent differences into _Dest - return _STD adjacent_difference(_First, _Last, _Dest, minus<>()); + return _STD adjacent_difference(_First, _Last, _Dest, minus<>{}); } #if _HAS_CXX17 @@ -518,7 +518,7 @@ template (_Exec), _First, _Last, _Dest, minus<>()); + return _STD adjacent_difference(_STD forward<_ExPo>(_Exec), _First, _Last, _Dest, minus{}); } #endif // _HAS_CXX17 diff --git a/stl/inc/set b/stl/inc/set index 1817da70218..a049d279f22 100644 --- a/stl/inc/set +++ b/stl/inc/set @@ -174,6 +174,38 @@ template ::value, in set(initializer_list<_Kty>, _Alloc) -> set<_Kty, less<_Kty>, _Alloc>; #endif // _HAS_CXX17 +template +_NODISCARD bool operator==(const set<_Kty, _Pr, _Alloc>& _Left, const set<_Kty, _Pr, _Alloc>& _Right) { + return _Left.size() == _Right.size() + && _STD equal(_Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin()); +} + +template +_NODISCARD bool operator!=(const set<_Kty, _Pr, _Alloc>& _Left, const set<_Kty, _Pr, _Alloc>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<(const set<_Kty, _Pr, _Alloc>& _Left, const set<_Kty, _Pr, _Alloc>& _Right) { + return _STD lexicographical_compare( + _Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin(), _Right._Unchecked_end_iter()); +} + +template +_NODISCARD bool operator>(const set<_Kty, _Pr, _Alloc>& _Left, const set<_Kty, _Pr, _Alloc>& _Right) { + return _Right < _Left; +} + +template +_NODISCARD bool operator<=(const set<_Kty, _Pr, _Alloc>& _Left, const set<_Kty, _Pr, _Alloc>& _Right) { + return !(_Right < _Left); +} + +template +_NODISCARD bool operator>=(const set<_Kty, _Pr, _Alloc>& _Left, const set<_Kty, _Pr, _Alloc>& _Right) { + return !(_Left < _Right); +} + template void swap(set<_Kty, _Pr, _Alloc>& _Left, set<_Kty, _Pr, _Alloc>& _Right) noexcept(noexcept(_Left.swap(_Right))) { _Left.swap(_Right); @@ -314,6 +346,38 @@ template ::value, in multiset(initializer_list<_Kty>, _Alloc) -> multiset<_Kty, less<_Kty>, _Alloc>; #endif // _HAS_CXX17 +template +_NODISCARD bool operator==(const multiset<_Kty, _Pr, _Alloc>& _Left, const multiset<_Kty, _Pr, _Alloc>& _Right) { + return _Left.size() == _Right.size() + && _STD equal(_Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin()); +} + +template +_NODISCARD bool operator!=(const multiset<_Kty, _Pr, _Alloc>& _Left, const multiset<_Kty, _Pr, _Alloc>& _Right) { + return !(_Left == _Right); +} + +template +_NODISCARD bool operator<(const multiset<_Kty, _Pr, _Alloc>& _Left, const multiset<_Kty, _Pr, _Alloc>& _Right) { + return _STD lexicographical_compare( + _Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin(), _Right._Unchecked_end_iter()); +} + +template +_NODISCARD bool operator>(const multiset<_Kty, _Pr, _Alloc>& _Left, const multiset<_Kty, _Pr, _Alloc>& _Right) { + return _Right < _Left; +} + +template +_NODISCARD bool operator<=(const multiset<_Kty, _Pr, _Alloc>& _Left, const multiset<_Kty, _Pr, _Alloc>& _Right) { + return !(_Right < _Left); +} + +template +_NODISCARD bool operator>=(const multiset<_Kty, _Pr, _Alloc>& _Left, const multiset<_Kty, _Pr, _Alloc>& _Right) { + return !(_Left < _Right); +} + template void swap(multiset<_Kty, _Pr, _Alloc>& _Left, multiset<_Kty, _Pr, _Alloc>& _Right) noexcept( noexcept(_Left.swap(_Right))) { diff --git a/stl/inc/xtree b/stl/inc/xtree index b0ad982042c..26e9416211d 100644 --- a/stl/inc/xtree +++ b/stl/inc/xtree @@ -2054,38 +2054,6 @@ protected: private: _Compressed_pair> _Mypair; }; - -template -_NODISCARD bool operator==(const _Tree<_Traits>& _Left, const _Tree<_Traits>& _Right) { - return _Left.size() == _Right.size() - && _STD equal(_Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin()); -} - -template -_NODISCARD bool operator!=(const _Tree<_Traits>& _Left, const _Tree<_Traits>& _Right) { - return !(_Left == _Right); -} - -template -_NODISCARD bool operator<(const _Tree<_Traits>& _Left, const _Tree<_Traits>& _Right) { - return _STD lexicographical_compare( - _Left._Unchecked_begin(), _Left._Unchecked_end_iter(), _Right._Unchecked_begin(), _Right._Unchecked_end_iter()); -} - -template -_NODISCARD bool operator>(const _Tree<_Traits>& _Left, const _Tree<_Traits>& _Right) { - return _Right < _Left; -} - -template -_NODISCARD bool operator<=(const _Tree<_Traits>& _Left, const _Tree<_Traits>& _Right) { - return !(_Right < _Left); -} - -template -_NODISCARD bool operator>=(const _Tree<_Traits>& _Left, const _Tree<_Traits>& _Right) { - return !(_Left < _Right); -} _STD_END #pragma pop_macro("new") diff --git a/stl/inc/xutility b/stl/inc/xutility index cbadf02aa31..26299d2612e 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4989,7 +4989,7 @@ _NODISCARD bool equal(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1 template _NODISCARD _CONSTEXPR20 bool equal(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2) { // compare [_First1, _Last1) to [_First2, ...) - return _STD equal(_First1, _Last1, _First2, equal_to<>()); + return _STD equal(_First1, _Last1, _First2, equal_to<>{}); } #if _HAS_CXX17 @@ -4997,7 +4997,7 @@ template (_Exec), _First1, _Last1, _First2, equal_to<>()); + return _STD equal(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, equal_to{}); } #endif // _HAS_CXX17 @@ -5091,7 +5091,7 @@ template _NODISCARD _CONSTEXPR20 bool equal( const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, const _InIt2 _Last2) { // compare [_First1, _Last1) to [_First2, _Last2) - return _STD equal(_First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD equal(_First1, _Last1, _First2, _Last2, equal_to<>{}); } #if _HAS_CXX17 @@ -5099,7 +5099,7 @@ template (_Exec), _First1, _Last1, _First2, _Last2, equal_to<>()); + return _STD equal(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to{}); } #endif // _HAS_CXX17 @@ -5206,7 +5206,7 @@ _NODISCARD _CONSTEXPR20 bool lexicographical_compare( template _NODISCARD _CONSTEXPR20 bool lexicographical_compare(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { // order [_First1, _Last1) vs. [_First2, _Last2) - return _STD lexicographical_compare(_First1, _Last1, _First2, _Last2, less<>()); + return _STD lexicographical_compare(_First1, _Last1, _First2, _Last2, less<>{}); } #if _HAS_CXX17 @@ -5797,7 +5797,7 @@ _NODISCARD _CONSTEXPR20 _FwdIt lower_bound(_FwdIt _First, const _FwdIt _Last, co template _NODISCARD _CONSTEXPR20 _FwdIt lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { // find first element not before _Val - return _STD lower_bound(_First, _Last, _Val, less<>()); + return _STD lower_bound(_First, _Last, _Val, less<>{}); } // FUNCTION TEMPLATE _Swap_ranges_unchecked diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 5ca29afc99e..d5fa87ddd08 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -40,6 +40,9 @@ namespace detail { } // namespace detail constexpr bool is_permissive = detail::Derived::test(); +template +inline constexpr T* nullptr_to = nullptr; + template struct borrowed { // borrowed is a borrowed_range; borrowed is not int* begin() const; @@ -163,7 +166,7 @@ namespace test { using Value = std::remove_cv_t; public: - constexpr explicit proxy_reference(Element& ref) : ref_{ref} {} + constexpr explicit proxy_reference(Element& r) : ref_{r} {} proxy_reference(proxy_reference const&) = default; constexpr proxy_reference const& operator=(proxy_reference const& that) const @@ -173,14 +176,16 @@ namespace test { } // clang-format off - constexpr operator Value() const requires derived_from && copy_constructible { + constexpr operator Element&() const requires derived_from { return ref_; } - // clang-format on - constexpr void operator=(Value const& val) const requires assignable_from { - ref_ = val; + template + requires (!std::same_as, proxy_reference> && assignable_from) + constexpr void operator=(T&& val) const { + ref_ = std::forward(val); } + // clang-format on template constexpr boolish operator==(proxy_reference that) const requires CanEq { @@ -208,41 +213,41 @@ namespace test { } // clang-format off - friend constexpr boolish operator==(proxy_reference ref, Value const& val) requires CanEq { - return {ref.ref_ == val}; + friend constexpr boolish operator==(proxy_reference r, Value const& val) requires CanEq { + return {r.ref_ == val}; } - friend constexpr boolish operator==(Value const& val, proxy_reference ref) requires CanEq { - return {ref.ref_ == val}; + friend constexpr boolish operator==(Value const& val, proxy_reference r) requires CanEq { + return {r.ref_ == val}; } - friend constexpr boolish operator!=(proxy_reference ref, Value const& val) requires CanNEq { - return {ref.ref_ != val}; + friend constexpr boolish operator!=(proxy_reference r, Value const& val) requires CanNEq { + return {r.ref_ != val}; } - friend constexpr boolish operator!=(Value const& val, proxy_reference ref) requires CanNEq { - return {ref.ref_ != val}; + friend constexpr boolish operator!=(Value const& val, proxy_reference r) requires CanNEq { + return {r.ref_ != val}; } - friend constexpr boolish operator<(Value const& val, proxy_reference ref) requires CanLt { - return {val < ref.ref_}; + friend constexpr boolish operator<(Value const& val, proxy_reference r) requires CanLt { + return {val < r.ref_}; } - friend constexpr boolish operator<(proxy_reference ref, Value const& val) requires CanLt { - return {ref.ref_ < val}; + friend constexpr boolish operator<(proxy_reference r, Value const& val) requires CanLt { + return {r.ref_ < val}; } - friend constexpr boolish operator>(Value const& val, proxy_reference ref) requires CanGt { - return {val > ref.ref_}; + friend constexpr boolish operator>(Value const& val, proxy_reference r) requires CanGt { + return {val > r.ref_}; } - friend constexpr boolish operator>(proxy_reference ref, Value const& val) requires CanGt { - return {ref.ref_ > val}; + friend constexpr boolish operator>(proxy_reference r, Value const& val) requires CanGt { + return {r.ref_ > val}; } - friend constexpr boolish operator<=(Value const& val, proxy_reference ref) requires CanLtE { - return {val <= ref.ref_}; + friend constexpr boolish operator<=(Value const& val, proxy_reference r) requires CanLtE { + return {val <= r.ref_}; } - friend constexpr boolish operator<=(proxy_reference ref, Value const& val) requires CanLtE { - return {ref.ref_ <= val}; + friend constexpr boolish operator<=(proxy_reference r, Value const& val) requires CanLtE { + return {r.ref_ <= val}; } - friend constexpr boolish operator>=(Value const& val, proxy_reference ref) requires CanGtE { - return {val >= ref.ref_}; + friend constexpr boolish operator>=(Value const& val, proxy_reference r) requires CanGtE { + return {val >= r.ref_}; } - friend constexpr boolish operator>=(proxy_reference ref, Value const& val) requires CanGtE { - return {ref.ref_ >= val}; + friend constexpr boolish operator>=(proxy_reference r, Value const& val) requires CanGtE { + return {r.ref_ >= val}; } // clang-format on @@ -251,6 +256,35 @@ namespace test { } }; + template + struct common_reference { + Ref ref_; + + common_reference(Ref r) : ref_{static_cast(r)} {} + + // clang-format off + template + requires convertible_to + common_reference(proxy_reference pref) : ref_{pref.peek()} {} + // clang-format on + }; +} // namespace test + +// clang-format off +template class TQuals, template class UQuals> + requires std::common_reference_with> +struct std::basic_common_reference<::test::proxy_reference, U, TQuals, UQuals> { + using type = common_reference_t>; +}; + +template class TQuals, template class UQuals> + requires std::common_reference_with, Elem&> +struct std::basic_common_reference, TQuals, UQuals> { + using type = common_reference_t, Elem&>; +}; +// clang-format on + +namespace test { // clang-format off template using BinaryPredicateFor = boolish (*)(std::iter_common_reference_t, std::iter_common_reference_t); template -struct with_writable_iterators { +struct with_output_iterators { template static constexpr void call() { using namespace test; @@ -604,10 +638,6 @@ struct with_writable_iterators { iterator>(); Continuation::template call>(); - Continuation::template call>(); - Continuation::template call>(); // For forward and bidi, Eq is necessarily true but Diff and Proxy may vary. Continuation::template call>(); @@ -636,6 +666,23 @@ struct with_writable_iterators { } }; +template +struct with_writable_iterators { + template + static constexpr void call() { + using namespace test; + using test::iterator; + + // Diff and Eq are not significant for "lone" single-pass iterators, so we can ignore them here. + Continuation::template call>(); + Continuation::template call>(); + + with_output_iterators::template call(); + } +}; + template struct with_contiguous_ranges { template @@ -936,6 +983,11 @@ constexpr void test_contiguous() { with_contiguous_ranges::call(); } +template +constexpr void input_range_output_iterator_permutations() { + with_input_ranges, Element1>::call(); +} + template constexpr void test_in_in() { with_input_ranges, Element1>::call(); @@ -975,11 +1027,11 @@ struct get_nth_fn { { return get(std::forward(t)); } template - [[nodiscard]] constexpr decltype(auto) operator()(test::proxy_reference ref) const noexcept + [[nodiscard]] constexpr decltype(auto) operator()(test::proxy_reference r) const noexcept requires requires { - (*this)(ref.peek()); + (*this)(r.peek()); } - { return (*this)(ref.peek()); } + { return (*this)(r.peek()); } }; inline constexpr get_nth_fn<0> get_first; inline constexpr get_nth_fn<1> get_second; diff --git a/tests/std/test.lst b/tests/std/test.lst index 98930beaa8b..4c9d6bf510c 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -254,6 +254,8 @@ tests\P0896R4_ranges_alg_find_if tests\P0896R4_ranges_alg_find_if_not tests\P0896R4_ranges_alg_for_each tests\P0896R4_ranges_alg_for_each_n +tests\P0896R4_ranges_alg_generate +tests\P0896R4_ranges_alg_generate_n tests\P0896R4_ranges_alg_heap tests\P0896R4_ranges_alg_is_permutation tests\P0896R4_ranges_alg_is_sorted @@ -261,6 +263,12 @@ tests\P0896R4_ranges_alg_minmax tests\P0896R4_ranges_alg_mismatch tests\P0896R4_ranges_alg_move tests\P0896R4_ranges_alg_none_of +tests\P0896R4_ranges_alg_partition +tests\P0896R4_ranges_alg_partition_copy +tests\P0896R4_ranges_alg_partition_point +tests\P0896R4_ranges_alg_replace +tests\P0896R4_ranges_alg_replace_copy +tests\P0896R4_ranges_alg_replace_copy_if tests\P0896R4_ranges_alg_replace_if tests\P0896R4_ranges_alg_search tests\P0896R4_ranges_alg_search_n diff --git a/tests/std/tests/P0896R4_ranges_alg_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_copy/test.cpp index cb900599857..6fd9130e399 100644 --- a/tests/std/tests/P0896R4_ranges_alg_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_copy/test.cpp @@ -9,51 +9,47 @@ #include -constexpr void smoke_test() { - using ranges::copy, ranges::copy_result, ranges::iterator_t; - using std::same_as; - - // Validate that copy_result aliases in_out_result - STATIC_ASSERT(same_as, ranges::in_out_result>); - - // Validate dangling story - STATIC_ASSERT( - same_as{}, static_cast(nullptr))), copy_result>); - STATIC_ASSERT(same_as{}, static_cast(nullptr))), copy_result>); - - int const input[] = {13, 42, 1729}; - { // Validate range overload - int output[] = {-1, -1, -1}; - auto result = copy(basic_borrowed_range{input}, basic_borrowed_range{output}.begin()); - STATIC_ASSERT(same_as>, iterator_t>>>); - assert(result.in == basic_borrowed_range{input}.end()); - assert(result.out == basic_borrowed_range{output}.end()); - assert(ranges::equal(output, input)); - } - { // Validate iterator + sentinel overload - int output[] = {-1, -1, -1}; - basic_borrowed_range wrapped_input{input}; - auto result = copy(wrapped_input.begin(), wrapped_input.end(), basic_borrowed_range{output}.begin()); - STATIC_ASSERT(same_as>, iterator_t>>>); - assert(result.in == wrapped_input.end()); - assert(result.out == basic_borrowed_range{output}.end()); - assert(ranges::equal(output, input)); - } -} +using namespace std; -int main() { - STATIC_ASSERT((smoke_test(), true)); - smoke_test(); -} +// Validate that copy_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, static_cast(nullptr))), + ranges::copy_result>); +STATIC_ASSERT( + same_as{}, static_cast(nullptr))), ranges::copy_result>); struct instantiator { - template - static void call(In&& in = {}, Out out = {}) { - (void) ranges::copy(in, std::move(out)); - (void) ranges::copy(ranges::begin(in), ranges::end(in), std::move(out)); + static constexpr int input[3] = {13, 42, 1729}; + + template > Write> + static constexpr void call() { + using ranges::copy, ranges::copy_result, ranges::iterator_t; + { // Validate iterator + sentinel overload + int output[3] = {-1, -1, -1}; + Read wrapped_input{input}; + + auto result = copy(wrapped_input.begin(), wrapped_input.end(), Write{output}); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(ranges::equal(output, input)); + } + { // Validate range overload + int output[3] = {-1, -1, -1}; + Read wrapped_input{input}; + + auto result = copy(wrapped_input, Write{output}); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(ranges::equal(output, input)); + } } }; -template void test_in_write(); +int main() { + STATIC_ASSERT((test_in_write(), true)); + test_in_write(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_copy_if/test.cpp b/tests/std/tests/P0896R4_ranges_alg_copy_if/test.cpp index 7a594989014..aa257403649 100644 --- a/tests/std/tests/P0896R4_ranges_alg_copy_if/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_copy_if/test.cpp @@ -11,14 +11,15 @@ #include +using namespace std; template struct not_pair { T first; U second; - auto operator<=>(const not_pair&) const = default; + auto operator<=>(not_pair const&) const = default; - template + template constexpr friend auto&& get(not_pair& np) noexcept { if constexpr (I == 0) { return np.first; @@ -27,7 +28,7 @@ struct not_pair { return np.second; } } - template + template constexpr friend auto&& get(not_pair const& np) noexcept { if constexpr (I == 0) { return np.first; @@ -36,84 +37,70 @@ struct not_pair { return np.second; } } - template + template constexpr friend auto&& get(not_pair&& np) noexcept { if constexpr (I == 0) { - return std::move(np).first; + return move(np).first; } else { STATIC_ASSERT(I == 1); - return std::move(np).second; + return move(np).second; } } - template + template constexpr friend auto&& get(not_pair const&& np) noexcept { if constexpr (I == 0) { - return std::move(np).first; + return move(np).first; } else { STATIC_ASSERT(I == 1); - return std::move(np).second; + return move(np).second; } } }; -constexpr void smoke_test() { - using ranges::copy_if, ranges::copy_if_result, ranges::iterator_t; - using std::same_as; - using P = not_pair; +using P = not_pair; - constexpr auto is_odd = [](int x) { return x % 2 != 0; }; +constexpr auto is_odd = [](int const x) { return x % 2 != 0; }; - // Validate that copy_if_result aliases in_out_result - STATIC_ASSERT(same_as, ranges::in_out_result>); +// Validate that copy_if_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); - // Validate dangling story - STATIC_ASSERT(same_as{}, static_cast(nullptr), is_odd)), - copy_if_result>); - STATIC_ASSERT( - same_as{}, static_cast(nullptr), is_odd)), copy_if_result>); - - std::array const input = {{{1, 99}, {4, 98}, {5, 97}}}; - std::array const expected = {{{1, 99}, {5, 97}}}; - using I = iterator_t>; - using O = iterator_t>; - { // Validate range overload - std::array output = {}; - auto result = copy_if(basic_borrowed_range{input}, basic_borrowed_range{output}.begin(), is_odd, get_first); - STATIC_ASSERT(same_as>); - assert(result.in == basic_borrowed_range{input}.end()); - assert(result.out == basic_borrowed_range{output}.end()); - assert(ranges::equal(output, expected)); - } - { // Validate iterator + sentinel overload - std::array output = {}; - basic_borrowed_range wrapped_input{input}; - auto result = copy_if( - wrapped_input.begin(), wrapped_input.end(), basic_borrowed_range{output}.begin(), is_odd, get_first); - STATIC_ASSERT(same_as>); - assert(result.in == wrapped_input.end()); - assert(result.out == basic_borrowed_range{output}.end()); - assert(ranges::equal(output, expected)); - } -} - -int main() { - STATIC_ASSERT((smoke_test(), true)); - smoke_test(); -} +// Validate dangling story +STATIC_ASSERT(same_as{}, static_cast(nullptr), is_odd)), + ranges::copy_if_result>); +STATIC_ASSERT(same_as{}, static_cast(nullptr), is_odd)), + ranges::copy_if_result>); struct instantiator { - template - static void call(In&& in = {}, Out out = {}) { - using ranges::begin, ranges::copy_if, ranges::end, ranges::iterator_t; + static constexpr P input[3] = {{1, 99}, {4, 98}, {5, 97}}; + static constexpr P expected[2] = {{1, 99}, {5, 97}}; + + template > Write> + static constexpr void call() { + using ranges::copy_if, ranges::copy_if_result, ranges::iterator_t; + { // Validate range overload + array output = {{{-1, -1}, {-1, -1}}}; + Read wrapped_input{input}; - constexpr UnaryPredicateFor> pred{}; - constexpr ProjectionFor> proj{}; + auto result = copy_if(wrapped_input, Write{output.data()}, is_odd, get_first); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output.data() + 2); + assert(ranges::equal(output, expected)); + } + { // Validate iterator + sentinel overload + array output = {{{-1, -1}, {-1, -1}}}; + Read wrapped_input{input}; - copy_if(in, std::move(out), pred); - copy_if(begin(in), end(in), std::move(out), pred); - copy_if(in, std::move(out), ProjectedUnaryPredicate<>{}, proj); - copy_if(begin(in), end(in), std::move(out), ProjectedUnaryPredicate<>{}, proj); + auto result = copy_if(wrapped_input.begin(), wrapped_input.end(), Write{output.data()}, is_odd, get_first); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output.data() + 2); + assert(ranges::equal(output, expected)); + } } }; -template void test_in_write(); +int main() { + STATIC_ASSERT((test_in_write(), true)); + test_in_write(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_copy_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_copy_n/test.cpp index 590df780886..b3c512888e2 100644 --- a/tests/std/tests/P0896R4_ranges_alg_copy_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_copy_n/test.cpp @@ -9,34 +9,29 @@ #include -constexpr void smoke_test() { - using ranges::copy_n, ranges::copy_n_result, ranges::iterator_t; - using std::same_as; - - // Validate that copy_n_result aliases in_out_result - STATIC_ASSERT(same_as, ranges::in_out_result>); - - int const input[] = {13, 42, 1729}; - int output[] = {-1, -1, -1}; - basic_borrowed_range wrapped_input{input}; - auto result = copy_n(wrapped_input.begin(), ranges::distance(input), basic_borrowed_range{output}.begin()); - STATIC_ASSERT(same_as>, iterator_t>>>); - assert(result.in == wrapped_input.end()); - assert(result.out == basic_borrowed_range{output}.end()); - assert(ranges::equal(output, input)); -} +using namespace std; -int main() { - STATIC_ASSERT((smoke_test(), true)); - smoke_test(); -} +// Validate that copy_n_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); struct instantiator { - template - static void call(In in = {}, std::iter_difference_t const count = 42, Out out = {}) { - (void) ranges::copy_n(std::move(in), count, std::move(out)); + static constexpr int input[3] = {13, 42, 1729}; + + template > Write> + static constexpr void call() { + using ranges::copy_n, ranges::copy_n_result, ranges::iterator_t; + int output[3] = {-1, -1, -1}; + Read wrapped_input{input}; + + auto result = copy_n(wrapped_input.begin(), 3, Write{output}); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(ranges::equal(output, input)); } }; -template void test_read_write(); +int main() { + STATIC_ASSERT((test_in_write(), true)); + test_in_write(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_count/test.cpp b/tests/std/tests/P0896R4_ranges_alg_count/test.cpp index 14912670975..05145d1e87c 100644 --- a/tests/std/tests/P0896R4_ranges_alg_count/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_count/test.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include -#include #include #include #include @@ -10,44 +9,33 @@ #include -constexpr void smoke_test() { - using ranges::count; - using P = std::pair; - std::array const x = {{{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}}; - using D = ranges::range_difference_t>; - - { - // Validate range overload - auto result = count(basic_borrowed_range{x}, 99, get_second); - STATIC_ASSERT(std::same_as); - assert(result == 3); - } - { - // Validate iterator + sentinel overload - basic_borrowed_range wrapped_x{x}; - auto result = count(wrapped_x.begin(), wrapped_x.end(), 47, get_second); - STATIC_ASSERT(std::same_as); - assert(result == 2); - } -} - -int main() { - STATIC_ASSERT((smoke_test(), true)); - smoke_test(); -} +using namespace std; +using P = pair; struct instantiator { - template - static void call(In&& in = {}) { - ranges::range_value_t const value{}; - (void) ranges::count(in, value); - - struct type { - bool operator==(type const&) const = default; - }; - using Projection = type (*)(std::iter_common_reference_t>); - (void) ranges::count(in, type{}, Projection{}); + static constexpr P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + + template + static constexpr void call() { + using ranges::count; + { // Validate iterator + sentinel overload + Read wrapped_input{input}; + + auto result = count(wrapped_input.begin(), wrapped_input.end(), 47, get_second); + STATIC_ASSERT(same_as>); + assert(result == 2); + } + { // Validate range overload + Read wrapped_input{input}; + + auto result = count(wrapped_input, 99, get_second); + STATIC_ASSERT(same_as>); + assert(result == 3); + } } }; -template void test_in(); +int main() { + STATIC_ASSERT((test_in(), true)); + test_in(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_count_if/test.cpp b/tests/std/tests/P0896R4_ranges_alg_count_if/test.cpp index 70d0e51f36e..33e3ff26708 100644 --- a/tests/std/tests/P0896R4_ranges_alg_count_if/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_count_if/test.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include -#include #include #include #include @@ -13,41 +12,33 @@ constexpr auto is_even = [](auto const& x) { return x % 2 == 0; }; constexpr auto is_odd = [](auto const& x) { return x % 2 != 0; }; -constexpr void smoke_test() { - using ranges::count_if; - using P = std::pair; - std::array const x = {{{0, 47}, {1, 99}, {2, 99}, {3, 47}, {4, 99}}}; - using D = ranges::range_difference_t>; - - { - // Validate range overload - auto result = count_if(basic_borrowed_range{x}, is_even, get_first); - STATIC_ASSERT(std::same_as); - assert(result == 3); - } - { - // Validate iterator + sentinel overload - basic_borrowed_range wrapped_x{x}; - auto result = count_if(wrapped_x.begin(), wrapped_x.end(), is_odd, get_first); - STATIC_ASSERT(std::same_as); - assert(result == 2); - } -} - -int main() { - STATIC_ASSERT((smoke_test(), true)); - smoke_test(); -} +using namespace std; +using P = pair; struct instantiator { - template - static void call(In&& in = {}) { - using ranges::iterator_t; - using I = iterator_t; - - (void) ranges::count_if(in, UnaryPredicateFor{}); - (void) ranges::count_if(in, ProjectedUnaryPredicate<>{}, ProjectionFor{}); + static constexpr P input[5] = {{0, 47}, {1, 99}, {2, 99}, {3, 47}, {4, 99}}; + + template + static constexpr void call() { + using ranges::count_if; + { // Validate iterator + sentinel overload + Read wrapped_input{input}; + + auto result = count_if(wrapped_input.begin(), wrapped_input.end(), is_odd, get_first); + STATIC_ASSERT(same_as>); + assert(result == 2); + } + { // Validate range overload + Read wrapped_input{input}; + + auto result = count_if(wrapped_input, is_even, get_first); + STATIC_ASSERT(same_as>); + assert(result == 3); + } } }; -template void test_in(); +int main() { + STATIC_ASSERT((test_in(), true)); + test_in(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_generate/env.lst b/tests/std/tests/P0896R4_ranges_alg_generate/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_generate/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_alg_generate/test.cpp b/tests/std/tests/P0896R4_ranges_alg_generate/test.cpp new file mode 100644 index 00000000000..6d9cb19528a --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_generate/test.cpp @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include + +using namespace std; + +constexpr auto iota_gen = [val = 0]() mutable { return val++; }; + +// Validate dangling story +STATIC_ASSERT(same_as{}, iota_gen)), ranges::dangling>); +STATIC_ASSERT(same_as{}, iota_gen)), int*>); + +struct instantiator { + template Out> + static constexpr void call() { + using ranges::generate, ranges::iterator_t; + + { + int output[] = {13, 42, 1367}; + Out out_wrapper{output}; + auto result = generate(out_wrapper, iota_gen); + STATIC_ASSERT(same_as>); + assert(result == out_wrapper.end()); + for (int i = 0; i < 3; ++i) { + assert(i == output[i]); + } + } + { + int output[] = {13, 42, 1367}; + Out out_wrapper{output}; + auto result = generate(out_wrapper.begin(), out_wrapper.end(), iota_gen); + STATIC_ASSERT(same_as>); + assert(result == out_wrapper.end()); + for (int i = 0; i < 3; ++i) { + assert(i == output[i]); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_out(), true)); + test_out(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_generate_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_generate_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_generate_n/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_alg_generate_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_generate_n/test.cpp new file mode 100644 index 00000000000..f08ba74d46d --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_generate_n/test.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include + +using namespace std; + +struct instantiator { + template Out> + static constexpr void call() { + using ranges::generate_n, ranges::equal, ranges::iterator_t; + + const auto iota_gen = [val = 0]() mutable { return val++; }; + + { + int output[] = {13, 42, 1367}; + Out out_wrapper{output}; + auto result = generate_n(out_wrapper.begin(), ranges::distance(output), iota_gen); + STATIC_ASSERT(same_as>); + assert(result == out_wrapper.end()); + for (int i = 0; i < 3; ++i) { + assert(i == output[i]); + } + } + + constexpr int expected_output[] = {13, 42, 1367}; + int output[] = {13, 42, 1367}; + { + Out out_wrapper{output}; + auto result = generate_n(out_wrapper.begin(), 0, iota_gen); + STATIC_ASSERT(same_as>); + assert(result.peek() == output); + assert(equal(output, expected_output)); + } + { + Out out_wrapper{output}; + auto result = generate_n(out_wrapper.begin(), -1, iota_gen); + STATIC_ASSERT(same_as>); + assert(result.peek() == output); + assert(equal(output, expected_output)); + } + } +}; + +int main() { + STATIC_ASSERT((test_out(), true)); + test_out(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_move/test.cpp index 8b1141e7065..c97f016e4bc 100644 --- a/tests/std/tests/P0896R4_ranges_alg_move/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_move/test.cpp @@ -9,75 +9,67 @@ #include +using namespace std; + struct int_wrapper { int val = 10; constexpr int_wrapper() = default; constexpr int_wrapper(int x) : val{x} {} - constexpr int_wrapper(int_wrapper&& that) : val{std::exchange(that.val, -1)} {} + constexpr int_wrapper(int_wrapper&& that) : val{exchange(that.val, -1)} {} constexpr int_wrapper& operator=(int_wrapper&& that) { - val = std::exchange(that.val, -1); + val = exchange(that.val, -1); return *this; } + auto operator<=>(const int_wrapper&) const = default; }; -constexpr void smoke_test() { - using ranges::move, ranges::move_result, ranges::iterator_t; - using std::same_as; +// Validate that move_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); - // Validate that move_result aliases in_out_result - STATIC_ASSERT(same_as, ranges::in_out_result>); +// Validate dangling story +STATIC_ASSERT(same_as{}, static_cast(nullptr))), + ranges::move_result>); +STATIC_ASSERT( + same_as{}, static_cast(nullptr))), ranges::move_result>); - // Validate dangling story - STATIC_ASSERT( - same_as{}, static_cast(nullptr))), move_result>); - STATIC_ASSERT(same_as{}, static_cast(nullptr))), move_result>); +struct instantiator { + static constexpr int_wrapper expected_output[3] = {13, 55, 12345}; + static constexpr int_wrapper expected_input[3] = {-1, -1, -1}; - int const input[] = {13, 53, 12435}; - { - int output[] = {-2, -2, -2}; - auto result = move(basic_borrowed_range{input}, basic_borrowed_range{output}.begin()); - STATIC_ASSERT(same_as>, iterator_t>>>); - assert(result.in == basic_borrowed_range{input}.end()); - assert(result.out == basic_borrowed_range{output}.end()); - assert(ranges::equal(output, input)); + static constexpr void eq(int_wrapper const (&output)[3], int_wrapper const (&input)[3]) { + // Extracted into a separate function to keep /analyze from exhausting the compiler heap + assert(ranges::equal(output, expected_output)); + assert(ranges::equal(input, expected_input)); } - { - int output[] = {-2, -2, -2}; - basic_borrowed_range wrapped_input{input}; - auto result = move(wrapped_input.begin(), wrapped_input.end(), basic_borrowed_range{output}.begin()); - STATIC_ASSERT(same_as>, iterator_t>>>); - assert(result.in == wrapped_input.end()); - assert(result.out == basic_borrowed_range{output}.end()); - assert(ranges::equal(output, input)); - } - { - int_wrapper input1[3] = {13, 55, 1234}; - int const expected_output[3] = {13, 55, 1234}; - int_wrapper actual_output[3] = {-2, -2, -2}; - basic_borrowed_range wrapped_input{input1}; - auto result = move(wrapped_input.begin(), wrapped_input.end(), basic_borrowed_range{actual_output}.begin()); - assert(result.in == wrapped_input.end()); - assert(result.out == basic_borrowed_range{actual_output}.end()); - for (int i = 0; i < 3; ++i) { - assert(input1[i].val == -1); - assert(actual_output[i].val == expected_output[i]); - } - } -} -int main() { - STATIC_ASSERT((smoke_test(), true)); - smoke_test(); -} + template > Write> + static constexpr void call() { + using ranges::move, ranges::move_result, ranges::iterator_t; + { + int_wrapper input[3] = {13, 55, 12345}; + int_wrapper output[3] = {-2, -2, -2}; + Read wrapped_input{input}; -struct instantiator { - template - static void call(In&& in = {}, Out out = {}) { - (void) ranges::move(in, std::move(out)); - (void) ranges::move(ranges::begin(in), ranges::end(in), std::move(out)); + auto result = move(wrapped_input, Write{output}); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + eq(output, input); + } + { + int_wrapper input[3] = {13, 55, 12345}; + int_wrapper output[3] = {-2, -2, -2}; + Read wrapped_input{input}; + + auto result = move(wrapped_input.begin(), wrapped_input.end(), Write{output}); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + eq(output, input); + } } }; -template void test_in_write(); +int main() { + STATIC_ASSERT((test_in_write(), true)); + test_in_write(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_partition/env.lst b/tests/std/tests/P0896R4_ranges_alg_partition/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_partition/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_alg_partition/test.cpp b/tests/std/tests/P0896R4_ranges_alg_partition/test.cpp new file mode 100644 index 00000000000..785d6ef20d8 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_partition/test.cpp @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Covers ranges::is_partitioned and ranges::partition (and bits of ranges::partition_point) + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +#define ASSERT(...) assert((__VA_ARGS__)) + +using P = pair; + +constexpr auto is_even = [](int i) { return i % 2 == 0; }; + +// Validate dangling story +STATIC_ASSERT(same_as{}, is_even)), ranges::dangling>); +STATIC_ASSERT(same_as{}, is_even)), ranges::subrange>); + +struct empty_test { + template + static constexpr void call() { + // Validate empty ranges + using ranges::is_partitioned, ranges::partition, ranges::partition_point; + { + Range range{}; + ASSERT(is_partitioned(range, is_even, get_first)); + } + { + Range range{}; + ASSERT(is_partitioned(range.begin(), range.end(), is_even, get_first)); + } + + if constexpr (ranges::forward_range) { + const Range range{}; + { + const auto result = partition(range, is_even, get_first); + ASSERT(result.begin() == range.end()); + ASSERT(result.end() == range.end()); + } + { + const auto result = partition(range.begin(), range.end(), is_even, get_first); + ASSERT(result.begin() == range.end()); + ASSERT(result.end() == range.end()); + } + } + } +}; + +struct partition_test { + static constexpr array elements = {P{0, 42}, P{1, 42}, P{2, 42}, P{3, 42}, P{4, 42}, P{5, 42}, P{6, 42}, P{7, 42}}; + + template + static constexpr void call() { + using ranges::is_partitioned, ranges::partition, ranges::partition_point, ranges::is_permutation, + ranges::subrange; + + auto pairs = elements; + + { + Range range{pairs}; + ASSERT(!is_partitioned(range, is_even, get_first)); + } + { + Range range{pairs}; + ASSERT(!is_partitioned(range.begin(), range.end(), is_even, get_first)); + } + +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 + if (!is_constant_evaluated()) +#endif // TRANSITION, VSO-938163 + { + if constexpr (ranges::forward_range) { + const Range range{pairs}; + const auto mid = ranges::next(range.begin(), 4); + + { + auto result = partition(range, is_even, get_first); + ASSERT(result.begin() == mid); + ASSERT(result.end() == range.end()); + } + ASSERT(is_permutation(subrange{range.begin(), mid}, array{0, 2, 4, 6}, ranges::equal_to{}, get_first)); + ASSERT(is_partitioned(range, is_even, get_first)); + ASSERT(partition_point(range, is_even, get_first) == mid); + + pairs = elements; + + { + auto result = partition(range.begin(), range.end(), is_even, get_first); + ASSERT(result.begin() == mid); + ASSERT(result.end() == range.end()); + } + ASSERT(is_permutation(subrange{range.begin(), mid}, array{0, 2, 4, 6}, ranges::equal_to{}, get_first)); + ASSERT(is_partitioned(range.begin(), range.end(), is_even, get_first)); + ASSERT(partition_point(range.begin(), range.end(), is_even, get_first) == mid); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_in(), true)); + test_in(); + + STATIC_ASSERT((test_in(), true)); + test_in(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_partition_copy/env.lst b/tests/std/tests/P0896R4_ranges_alg_partition_copy/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_partition_copy/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_alg_partition_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_partition_copy/test.cpp new file mode 100644 index 00000000000..12d3d4cbd86 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_partition_copy/test.cpp @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +#define ASSERT(...) assert((__VA_ARGS__)) + +using P = pair; + +constexpr auto is_even = [](int i) { return i % 2 == 0; }; + +// Validate that partition_copy_result aliases in_out_out_result +STATIC_ASSERT( + same_as, ranges::in_out_out_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, nullptr_to, nullptr_to, is_even)), + ranges::partition_copy_result>); +STATIC_ASSERT(same_as{}, nullptr_to, nullptr_to, is_even)), + ranges::partition_copy_result>); + +struct empty_test { + template > Out1, + indirectly_writable> Out2> + static constexpr void call() { + // Validate empty ranges + using ranges::partition_copy, ranges::partition_copy_result, ranges::iterator_t; + + { + Range range{}; + auto result = partition_copy(range, Out1{}, Out2{}, is_even, get_first); + STATIC_ASSERT(same_as, Out1, Out2>>); + ASSERT(result.in == range.end()); + ASSERT(result.out1.peek() == nullptr); + ASSERT(result.out2.peek() == nullptr); + } + { + Range range{}; + auto result = partition_copy(range.begin(), range.end(), Out1{}, Out2{}, is_even, get_first); + STATIC_ASSERT( + same_as, Out1, Out2>>); + ASSERT(result.in == range.end()); + ASSERT(result.out1.peek() == nullptr); + ASSERT(result.out2.peek() == nullptr); + } + } +}; + +struct partition_copy_test { + static constexpr int N = 32; + + template > O1, + indirectly_writable> O2> + static constexpr void call() { + using ranges::partition_copy; + + P source[N]; + for (int i = 0; i < N; ++i) { + source[i] = {i, 42}; + } + + for (int i = 0; i < N; ++i) { + P dest[N]; + ranges::fill(dest, P{-1, 13}); + + const R range{source}; + auto result = partition_copy( + range, O1{dest}, O2{dest + i}, [i](int x) { return x < i; }, get_first); + assert(result.in == range.end()); + assert(result.out1.peek() == dest + i); + assert(result.out2.peek() == dest + N); + assert(ranges::equal(source, dest)); + } + } +}; + +template +constexpr void run_tests() { + // Call Instantiator::template call() with a range whose element type is Elem, and two iterators to + // which Elem is writable, whose properties are "interesting" for ranges::partition_copy. What combinations of + // properties are "interesting"? + + // For the input range, the algorithm simply unwraps iterators and chugs through looking for the end. It doesn't + // * take advantage of any capabilities provided by stronger-than-input categories, + // * care if the sentinel and iterator have the same type, + // * care if it can difference iterators with sentinels or each other, or + // * care about the size of the input range at all. (It can't even use size info to check the outputs, because we + // don't how many of the input elements will be written through each output.) + // TLDR: One input range with a proxy reference type and no other notable properties (the so-called "weakest" input + // range) suffices. + + // For the outputs, both of which are treated equivalently, the algorithm is similarly oblivious to properties other + // than reference type and the ability to unwrap/rewrap. These could simply be the "weakest" writable iterator type + // in with_writable_iterators. + + // Out of simple paranoia, let's permute ProxyRef; seven extra pointless tests won't hurt. + + using test::range, test::iterator, test::input, test::output, test::CanCompare, test::CanDifference, test::Common, + test::ProxyRef, test::Sized; + + using proxy_range = range; + using non_proxy_range = range; + using proxy_iterator = iterator, CanDifference::no, CanCompare::no, ProxyRef::yes>; + using non_proxy_iterator = iterator, CanDifference::no, CanCompare::no, ProxyRef::no>; + + Instantiator::template call(); + Instantiator::template call(); + Instantiator::template call(); + Instantiator::template call(); + Instantiator::template call(); + Instantiator::template call(); + Instantiator::template call(); + Instantiator::template call(); +} + +int main() { + STATIC_ASSERT((run_tests(), true)); + run_tests(); + + STATIC_ASSERT((run_tests(), true)); + run_tests(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_partition_point/env.lst b/tests/std/tests/P0896R4_ranges_alg_partition_point/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_partition_point/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_alg_partition_point/test.cpp b/tests/std/tests/P0896R4_ranges_alg_partition_point/test.cpp new file mode 100644 index 00000000000..bfd99511fae --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_partition_point/test.cpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +#define ASSERT(...) assert((__VA_ARGS__)) + +using P = pair; + +constexpr auto is_even = [](int i) { return i % 2 == 0; }; + +// Validate dangling story +STATIC_ASSERT(same_as{}, is_even)), ranges::dangling>); +STATIC_ASSERT(same_as{}, is_even)), int*>); + +struct empty_test { + template + static constexpr void call() { + // Validate empty ranges + using ranges::partition_point; + + const Range range{}; + ASSERT(partition_point(range, is_even, get_first) == range.end()); + ASSERT(partition_point(range.begin(), range.end(), is_even, get_first) == range.end()); + } +}; + +struct partition_point_test { + template + static constexpr void call() { + using ranges::partition_point; + int elements[200]; + iota(ranges::begin(elements), ranges::end(elements), 0); + + // to avoid constant expression step limits + const size_t bound = elements[0] + (is_constant_evaluated() ? 10 : ranges::size(elements)); + + for (size_t i = 0; i < bound; ++i) { + const R range{span{elements}.first(i)}; + for (size_t j = 0; j < i; ++j) { + assert(partition_point(range, [j](int x) { return x < static_cast(j); }).peek() == elements + j); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_fwd(), true)); + test_fwd(); + + STATIC_ASSERT((test_fwd(), true)); + test_fwd(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_replace/env.lst b/tests/std/tests/P0896R4_ranges_alg_replace/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace/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_alg_replace/test.cpp b/tests/std/tests/P0896R4_ranges_alg_replace/test.cpp new file mode 100644 index 00000000000..3e116dda73f --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace/test.cpp @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include +using namespace std; +using P = pair; + +// Validate dangling story +STATIC_ASSERT(same_as{}, 42, 5)), ranges::dangling>); +STATIC_ASSERT(same_as{}, 42, 5)), int*>); + +struct instantiator { + static constexpr P output[5] = {{0, 99}, {47, 1}, {2, 99}, {47, 1}, {4, 99}}; + + template + static constexpr void call() { + using ranges::replace, ranges::iterator_t; + { // Validate iterator + sentinel overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; + + auto result = replace(wrapped_input.begin(), wrapped_input.end(), 47, P{47, 1}, get_second); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(ranges::equal(output, input)); + } + { // Validate range overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; + + auto result = replace(wrapped_input, 47, P{47, 1}, get_second); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(ranges::equal(output, input)); + } + } +}; + +int main() { + STATIC_ASSERT((test_in(), true)); + test_in(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_replace_copy/env.lst b/tests/std/tests/P0896R4_ranges_alg_replace_copy/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_copy/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_alg_replace_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_replace_copy/test.cpp new file mode 100644 index 00000000000..965c5ecd5ac --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_copy/test.cpp @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include +using namespace std; +using P = pair; + +// Validate that replace_copy_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, static_cast(nullptr), 42, 5)), + ranges::replace_copy_result>); +STATIC_ASSERT(same_as{}, static_cast(nullptr), 42, 5)), + ranges::replace_copy_result>); + +struct instantiator { + static constexpr P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + static constexpr P expected[5] = {{0, 99}, {47, 1}, {2, 99}, {47, 1}, {4, 99}}; + + static constexpr void eq(P const (&output)[5]) { + // Extracted into a separate function to keep /analyze from exhausting the compiler heap + assert(ranges::equal(output, expected)); + } + + template > Write> + static constexpr void call() { + using ranges::replace_copy, ranges::replace_copy_result, ranges::iterator_t; + { // Validate iterator + sentinel overload + P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + + auto result = + replace_copy(wrapped_input.begin(), wrapped_input.end(), Write{output}, 47, P{47, 1}, get_second); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 5); + eq(output); + } + { // Validate range overload + P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + + auto result = replace_copy(wrapped_input, Write{output}, 47, P{47, 1}, get_second); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 5); + eq(output); + } + } +}; + +int main() { + STATIC_ASSERT((input_range_output_iterator_permutations(), true)); + input_range_output_iterator_permutations(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/env.lst b/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/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_alg_replace_copy_if/test.cpp b/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/test.cpp new file mode 100644 index 00000000000..0048304155c --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/test.cpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include +using namespace std; +using P = pair; + +constexpr auto matches = [](int const val) { return val == 47; }; + +// Validate that replace_copy_if_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, static_cast(nullptr), matches, 5)), + ranges::replace_copy_if_result>); +STATIC_ASSERT(same_as{}, static_cast(nullptr), matches, 5)), + ranges::replace_copy_if_result>); + +struct instantiator { + static constexpr P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + static constexpr P expected[5] = {{0, 99}, {47, 1}, {2, 99}, {47, 1}, {4, 99}}; + + static constexpr void eq(P const (&output)[5]) { + // Extracted into a separate function to keep /analyze from exhausting the compiler heap + assert(ranges::equal(output, expected)); + } + + template > Write> + static constexpr void call() { + using ranges::replace_copy_if, ranges::replace_copy_if_result, ranges::iterator_t; + { // Validate iterator + sentinel overload + P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + + auto result = replace_copy_if( + wrapped_input.begin(), wrapped_input.end(), Write{output}, matches, P{47, 1}, get_second); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 5); + eq(output); + } + { // Validate range overload + P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + + auto result = replace_copy_if(wrapped_input, Write{output}, matches, P{47, 1}, get_second); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 5); + eq(output); + } + } +}; + +int main() { + STATIC_ASSERT((input_range_output_iterator_permutations(), true)); + input_range_output_iterator_permutations(); +} diff --git a/tests/std/tests/concepts_matrix.lst b/tests/std/tests/concepts_matrix.lst index 8414e31b200..37b0a2358be 100644 --- a/tests/std/tests/concepts_matrix.lst +++ b/tests/std/tests/concepts_matrix.lst @@ -12,12 +12,12 @@ PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /Zc:wchar_t-" PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=1" PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /fp:except /Zc:preprocessor" PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /await" -PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /analyze:only" +# PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /analyze:only" # TRANSITION, GH-1030 PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=1" PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=0 /fp:strict" PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=1" PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /await" -PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /analyze:only" +# PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /analyze:only" # TRANSITION, GH-1030 PM_CL="/Za /MD /permissive-" PM_CL="/Za /MDd /permissive-" # PM_CL="/BE /c /MD"