diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 945936ee546..9f5ea0f97cf 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -386,6 +386,21 @@ namespace ranges { inline constexpr _For_each_n_fn for_each_n{_Not_quite_object::_Construct_tag{}}; // VARIABLE ranges::find + // clang-format off + // concept-constrained for strict enforcement as it is used by several algorithms + template _Se, class _Ty, class _Pj> + requires indirect_binary_predicate, const _Ty*> + _NODISCARD constexpr _It _Find_unchecked(_It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj) { + for (; _First != _Last; ++_First) { + if (_STD invoke(_Proj, *_First) == _Val) { + break; + } + } + + return _First; + } + // clang-format on + class _Find_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -395,16 +410,10 @@ namespace ranges { requires indirect_binary_predicate, const _Ty*> _NODISCARD constexpr _It operator()(_It _First, _Se _Last, const _Ty& _Val, _Pj _Proj = {}) const { _Adl_verify_range(_First, _Last); - // Performance note: investigate using _Find_unchecked when same_as<_Pj, identity> - auto _UFirst = _Get_unwrapped(_STD move(_First)); - const auto _ULast = _Get_unwrapped(_STD move(_Last)); - for (; _UFirst != _ULast; ++_UFirst) { - if (_STD invoke(_Proj, *_UFirst) == _Val) { - break; - } - } + auto _UResult = _RANGES _Find_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Val, _Pass_fn(_Proj)); - _Seek_wrapped(_First, _STD move(_UFirst)); + _Seek_wrapped(_First, _STD move(_UResult)); return _First; } @@ -412,7 +421,12 @@ namespace ranges { requires indirect_binary_predicate, _Pj>, const _Ty*> _NODISCARD constexpr borrowed_iterator_t<_Rng> operator()( _Rng&& _Range, const _Ty& _Val, _Pj _Proj = {}) const { - return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Val, _Pass_fn(_Proj)); + auto _First = _RANGES begin(_Range); + auto _UResult = + _RANGES _Find_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Val, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; } // clang-format on }; @@ -430,6 +444,18 @@ _NODISCARD _FwdIt find_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr #ifdef __cpp_lib_concepts namespace ranges { // VARIABLE ranges::find_if + // concept-constrained for strict enforcement as it is used by several algorithms + template _Se, class _Pj, indirect_unary_predicate> _Pr> + _NODISCARD constexpr _It _Find_if_unchecked(_It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) { + for (; _First != _Last; ++_First) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + break; + } + } + + return _First; + } + class _Find_if_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -438,22 +464,22 @@ namespace ranges { 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)); - const auto _ULast = _Get_unwrapped(_STD move(_Last)); - for (; _UFirst != _ULast; ++_UFirst) { - if (_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { - break; - } - } + auto _UResult = _RANGES _Find_if_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Pred), _Pass_fn(_Proj)); - _Seek_wrapped(_First, _STD move(_UFirst)); + _Seek_wrapped(_First, _STD move(_UResult)); return _First; } template , _Pj>> _Pr> _NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const { - return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); + auto _First = _RANGES begin(_Range); + auto _UResult = _RANGES _Find_if_unchecked( + _Get_unwrapped(_STD move(_First)), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; } }; @@ -1554,8 +1580,9 @@ namespace ranges { template requires indirectly_copyable, _Out> constexpr copy_result, _Out> operator()(_Rng&& _Range, _Out _Result) const { - auto _First = _RANGES begin(_Range); - auto _UResult = _RANGES _Copy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_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)}; } @@ -1589,6 +1616,39 @@ namespace ranges { }; inline constexpr _Copy_n_fn copy_n{_Not_quite_object::_Construct_tag{}}; + + // ALIAS TEMPLATE copy_backward_result + template + using copy_backward_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::copy_backward + class _Copy_backward_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se1, bidirectional_iterator _It2> + requires indirectly_copyable<_It1, _It2> + constexpr copy_backward_result<_It1, _It2> operator()(_It1 _First, _Se1 _Last, _It2 _Result) const { + _Adl_verify_range(_First, _Last); + auto _UFirst = _Get_unwrapped(_STD move(_First)); + auto _ULast = _Get_final_iterator_unwrapped<_It1>(_UFirst, _STD move(_Last)); + _Seek_wrapped(_First, _ULast); + _Result = _Copy_backward_unchecked(_STD move(_UFirst), _STD move(_ULast), _STD move(_Result)); + return {_STD move(_First), _STD move(_Result)}; + } + + template + requires indirectly_copyable, _It> + constexpr copy_backward_result, _It> operator()(_Rng&& _Range, _It _Result) const { + auto _ULast = _Get_final_iterator_unwrapped(_Range); + _Result = _Copy_backward_unchecked(_Ubegin(_Range), _ULast, _STD move(_Result)); + return {_Rewrap_iterator(_Range, _STD move(_ULast)), _STD move(_Result)}; + } + // clang-format on + }; + + inline constexpr _Copy_backward_fn copy_backward{_Not_quite_object::_Construct_tag{}}; } // namespace ranges #endif // __cpp_lib_concepts @@ -2573,7 +2633,8 @@ namespace ranges { if constexpr (sized_sentinel_for<_Se, _It>) { const auto _Dist = _ULast - _UFirst; - auto _UResult = _Search_n_sized(_STD move(_UFirst), _Dist, _Val, _Count, _Pass_fn(_Pred), _Pass_fn(_Proj)); + auto _UResult = + _Search_n_sized(_STD move(_UFirst), _Dist, _Val, _Count, _Pass_fn(_Pred), _Pass_fn(_Proj)); return _Rewrap_subrange>(_First, _STD move(_UResult)); } else { auto _UResult = _Search_n_unsized( @@ -2584,8 +2645,8 @@ namespace ranges { template requires indirectly_comparable, const _Ty*, _Pr, _Pj> - _NODISCARD constexpr borrowed_subrange_t<_Rng> operator()( - _Rng&& _Range, const range_difference_t<_Rng> _Count, const _Ty& _Val, _Pr _Pred = {}, _Pj _Proj = {}) const { + _NODISCARD constexpr borrowed_subrange_t<_Rng> operator()(_Rng&& _Range, const range_difference_t<_Rng> _Count, + const _Ty& _Val, _Pr _Pred = {}, _Pj _Proj = {}) const { auto _First = _RANGES begin(_Range); if (_Count <= 0) { @@ -2599,8 +2660,8 @@ namespace ranges { _Search_n_sized(_Get_unwrapped(_First), _Dist, _Val, _Count, _Pass_fn(_Pred), _Pass_fn(_Proj)); return _Rewrap_subrange>(_First, _STD move(_UResult)); } else { - auto _UResult = _Search_n_unsized(_Get_unwrapped(_First), _Uend(_Range), _Val, - _Count, _Pass_fn(_Pred), _Pass_fn(_Proj)); + auto _UResult = _Search_n_unsized( + _Get_unwrapped(_First), _Uend(_Range), _Val, _Count, _Pass_fn(_Pred), _Pass_fn(_Proj)); return _Rewrap_subrange>(_First, _STD move(_UResult)); } } @@ -3266,6 +3327,120 @@ _FwdIt3 transform(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, co _Fn _Func) noexcept; // terminates #endif // _HAS_CXX17 +#ifdef __cpp_lib_concepts +namespace ranges { + // ALIAS TEMPLATE unary_transform_result + template + using unary_transform_result = in_out_result<_In, _Out>; + + // ALIAS TEMPLATE binary_transform_result + template + using binary_transform_result = in_in_out_result<_In1, _In2, _Out>; + + // VARIABLE ranges::transform + class _Transform_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, weakly_incrementable _Out, copy_constructible _Fn, + class _Pj = identity> + requires indirectly_writable<_Out, indirect_result_t<_Fn&, projected<_It, _Pj>>> + constexpr unary_transform_result<_It, _Out> operator()( + _It _First, _Se _Last, _Out _Result, _Fn _Func, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Transform_unary_unchecked(_Get_unwrapped(_STD move(_First)), + _Get_unwrapped(_STD move(_Last)), _STD move(_Result), _Pass_fn(_Func), _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; + } + + template + requires indirectly_writable<_Out, indirect_result_t<_Fn&, projected, _Pj>>> + constexpr unary_transform_result, _Out> operator()( + _Rng&& _Range, _Out _Result, _Fn _Func, _Pj _Proj = {}) const { + auto _First = _RANGES begin(_Range); + auto _UResult = _Transform_unary_unchecked( + _Get_unwrapped(_STD move(_First)), _Uend(_Range), _STD move(_Result), _Pass_fn(_Func), _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; + } + + template _Se1, input_iterator _It2, sentinel_for<_It2> _Se2, + weakly_incrementable _Out, copy_constructible _Fn, class _Pj1 = identity, class _Pj2 = identity> + requires indirectly_writable<_Out, indirect_result_t<_Fn&, projected<_It1, _Pj1>, projected<_It2, _Pj2>>> + constexpr binary_transform_result<_It1, _It2, _Out> operator()(_It1 _First1, _Se1 _Last1, _It2 _First2, + _Se2 _Last2, _Out _Result, _Fn _Func, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const { + _Adl_verify_range(_First1, _Last1); + _Adl_verify_range(_First2, _Last2); + auto _UResult = + _Transform_binary_unchecked(_Get_unwrapped(_STD move(_First1)), _Get_unwrapped(_STD move(_Last1)), + _Get_unwrapped(_STD move(_First2)), _Get_unwrapped(_STD move(_Last2)), _STD move(_Result), + _Pass_fn(_Func), _Pass_fn(_Proj1), _Pass_fn(_Proj2)); + + _Seek_wrapped(_First1, _STD move(_UResult.in1)); + _Seek_wrapped(_First2, _STD move(_UResult.in2)); + return {_STD move(_First1), _STD move(_First2), _STD move(_UResult.out)}; + } + + template + requires indirectly_writable<_Out, indirect_result_t<_Fn&, projected, _Pj1>, + projected, _Pj2>>> + constexpr binary_transform_result, borrowed_iterator_t<_Rng2>, _Out> operator()( + _Rng1&& _Range1, _Rng2&& _Range2, _Out _Result, _Fn _Func, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const { + auto _First1 = _RANGES begin(_Range1); + auto _First2 = _RANGES begin(_Range2); + auto _UResult = _Transform_binary_unchecked(_Get_unwrapped(_STD move(_First1)), _Uend(_Range1), + _Get_unwrapped(_STD move(_First2)), _Uend(_Range2), _STD move(_Result), _Pass_fn(_Func), + _Pass_fn(_Proj1), _Pass_fn(_Proj2)); + + _Seek_wrapped(_First1, _STD move(_UResult.in1)); + _Seek_wrapped(_First2, _STD move(_UResult.in2)); + return {_STD move(_First1), _STD move(_First2), _STD move(_UResult.out)}; + } + // clang-format on + + private: + template + _NODISCARD static constexpr unary_transform_result<_It, _Out> _Transform_unary_unchecked( + _It _First, const _Se _Last, _Out _Result, _Fn _Func, _Pj _Proj) { + // transform projected [_First, _Last) with _Func + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_writable<_Out, indirect_result_t<_Fn&, projected<_It, _Pj>>>); + + for (; _First != _Last; ++_First, (void) ++_Result) { + *_Result = _STD invoke(_Func, _STD invoke(_Proj, *_First)); + } + + return {_STD move(_First), _STD move(_Result)}; + } + + template + _NODISCARD static constexpr binary_transform_result<_It1, _It2, _Out> _Transform_binary_unchecked(_It1 _First1, + const _Se1 _Last1, _It2 _First2, const _Se2 _Last2, _Out _Result, _Fn _Func, _Pj1 _Proj1, _Pj2 _Proj2) { + // transform projected [_First1, _Last1) and projected [_First2, _Last2) with _Func + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It1>); + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It2>); + _STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out>); + _STL_INTERNAL_STATIC_ASSERT( + indirectly_writable<_Out, indirect_result_t<_Fn&, projected<_It1, _Pj1>, projected<_It2, _Pj2>>>); + + for (; _First1 != _Last1 && _First2 != _Last2; ++_First1, (void) ++_First2, ++_Result) { + *_Result = _STD invoke(_Func, _STD invoke(_Proj1, *_First1), _STD invoke(_Proj2, *_First2)); + } + + return {_STD move(_First1), _STD move(_First2), _STD move(_Result)}; + } + }; + + inline constexpr _Transform_fn transform{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE replace template _CONSTEXPR20 void replace(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Oldval, const _Ty& _Newval) { @@ -3871,13 +4046,247 @@ _FwdIt2 remove_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _P template = 0> _NODISCARD _FwdIt remove( _ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) noexcept; // terminates -#endif // _HAS_CXX17 -#if _HAS_CXX17 template = 0> _NODISCARD _FwdIt remove_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates #endif // _HAS_CXX17 +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::remove + class _Remove_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, class _Ty, class _Pj = identity> + requires indirect_binary_predicate, const _Ty*> + _NODISCARD constexpr subrange<_It> operator()(_It _First, _Se _Last, const _Ty& _Val, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Remove_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Val, _Pass_fn(_Proj)); + + return _Rewrap_subrange>(_First, _STD move(_UResult)); + } + + template + requires permutable> + && indirect_binary_predicate, _Pj>, const _Ty*> + _NODISCARD constexpr borrowed_subrange_t<_Rng> operator()( + _Rng&& _Range, const _Ty& _Val, _Pj _Proj = {}) const { + auto _UResult = _Remove_unchecked(_Ubegin(_Range), _Uend(_Range), _Val, _Pass_fn(_Proj)); + + return _Rewrap_subrange>(_Range, _STD move(_UResult)); + } + // clang-format on + private: + template + _NODISCARD static constexpr subrange<_It> _Remove_unchecked( + _It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj) { + // Remove projected values equal to _Val from [_First, _Last) + _STL_INTERNAL_STATIC_ASSERT(permutable<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate, const _Ty*>); + + _First = _RANGES _Find_unchecked(_STD move(_First), _Last, _Val, _Proj); + auto _Next = _First; + if (_First == _Last) { + return {_STD move(_Next), _STD move(_First)}; + } + + while (++_First != _Last) { + if (_STD invoke(_Proj, *_First) != _Val) { + *_Next = _RANGES iter_move(_First); + ++_Next; + } + } + + return {_STD move(_Next), _STD move(_First)}; + } + }; + + inline constexpr _Remove_fn remove{_Not_quite_object::_Construct_tag{}}; + + // VARIABLE ranges::remove_if + class _Remove_if_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template _Se, class _Pj = identity, + indirect_unary_predicate> _Pr> + _NODISCARD constexpr subrange<_It> operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Remove_if_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> + _NODISCARD constexpr borrowed_subrange_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const { + auto _UResult = _Remove_if_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> _Remove_if_unchecked( + _It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) { + // Remove values whose projection satisfies _Pred from [_First, _Last) + _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>>); + + _First = _RANGES _Find_if_unchecked(_STD move(_First), _Last, _Pred, _Proj); + auto _Next = _First; + if (_First == _Last) { + return {_STD move(_Next), _STD move(_First)}; + } + + while (++_First != _Last) { + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + *_Next = _RANGES iter_move(_First); + ++_Next; + } + } + + return {_STD move(_Next), _STD move(_First)}; + } + }; + + inline constexpr _Remove_if_fn remove_if{_Not_quite_object::_Construct_tag{}}; + + // ALIAS TEMPLATE remove_copy_result + template + using remove_copy_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::remove_copy + class _Remove_copy_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, weakly_incrementable _Out, class _Ty, class _Pj = identity> + requires indirectly_copyable<_It, _Out> + && indirect_binary_predicate, const _Ty*> + constexpr remove_copy_result<_It, _Out> operator()( + _It _First, _Se _Last, _Out _Result, const _Ty& _Val, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Remove_copy_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), + _Get_unwrapped_unverified(_STD move(_Result)), _Val, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + _Seek_wrapped(_Result, _STD move(_UResult.out)); + return {_STD move(_First), _STD move(_Result)}; + } + + template + requires indirectly_copyable, _Out> + && indirect_binary_predicate, _Pj>, const _Ty*> + constexpr remove_copy_result, _Out> operator()( + _Rng&& _Range, _Out _Result, const _Ty& _Val, _Pj _Proj = {}) const { + auto _First = _RANGES begin(_Range); + auto _UResult = _Remove_copy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), + _Get_unwrapped_unverified(_STD move(_Result)), _Val, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + _Seek_wrapped(_Result, _STD move(_UResult.out)); + return {_STD move(_First), _STD move(_Result)}; + } + // clang-format on + private: + template + _NODISCARD static constexpr remove_copy_result<_It, _Out> _Remove_copy_unchecked( + _It _First, const _Se _Last, _Out _Result, const _Ty& _Val, _Pj _Proj) { + // Copy [_First, _Last) to _Result except projected values equal to _Val + _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_copyable<_It, _Out>); + _STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate, const _Ty*>); + + for (; _First != _Last; ++_First) { + if (_STD invoke(_Proj, *_First) != _Val) { + *_Result = *_First; + ++_Result; + } + } + + return {_STD move(_First), _STD move(_Result)}; + } + }; + + inline constexpr _Remove_copy_fn remove_copy{_Not_quite_object::_Construct_tag{}}; + + // ALIAS TEMPLATE remove_copy_if_result + template + using remove_copy_if_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::remove_copy_if + class _Remove_copy_if_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, weakly_incrementable _Out, class _Pj = identity, + indirect_unary_predicate> _Pr> + requires indirectly_copyable<_It, _Out> + constexpr remove_copy_if_result<_It, _Out> operator()( + _It _First, _Se _Last, _Out _Result, _Pr _Pred, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = + _Remove_copy_if_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), + _Get_unwrapped_unverified(_STD move(_Result)), _Pass_fn(_Pred), _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + _Seek_wrapped(_Result, _STD move(_UResult.out)); + return {_STD move(_First), _STD move(_Result)}; + } + + template , _Pj>> _Pr> + requires indirectly_copyable, _Out> + constexpr remove_copy_if_result, _Out> operator()( + _Rng&& _Range, _Out _Result, _Pr _Pred, _Pj _Proj = {}) const { + auto _First = _RANGES begin(_Range); + auto _UResult = _Remove_copy_if_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), + _Get_unwrapped_unverified(_STD move(_Result)), _Pass_fn(_Pred), _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + _Seek_wrapped(_Result, _STD move(_UResult.out)); + return {_STD move(_First), _STD move(_Result)}; + } + // clang-format on + private: + template + _NODISCARD static constexpr remove_copy_if_result<_It, _Out> _Remove_copy_if_unchecked( + _It _First, const _Se _Last, _Out _Result, _Pr _Pred, _Pj _Proj) { + // Copy [_First, _Last) to _Result except projected values that satisfy _Pred + _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_copyable<_It, _Out>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + + for (; _First != _Last; ++_First) { + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + *_Result = *_First; + ++_Result; + } + } + + return {_STD move(_First), _STD move(_Result)}; + } + }; + + inline constexpr _Remove_copy_if_fn remove_copy_if{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE unique template _NODISCARD _CONSTEXPR20 _FwdIt unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { @@ -4096,6 +4505,77 @@ _FwdIt2 unique_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest) noexc } #endif // _HAS_CXX17 +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::reverse + // clang-format off + // concept-constrained for strict enforcement as it is used by several algorithms + template + requires permutable<_It> + constexpr void _Reverse_common(_It _First, _It _Last) { +#if _USE_STD_VECTOR_ALGORITHMS + if constexpr (contiguous_iterator<_It>) { + using _Elem = remove_reference_t>; + constexpr size_t _Nx = sizeof(_Elem); + constexpr bool _Allow_vectorization = + conjunction_v<_Is_trivially_swappable<_Elem>, negation>>; + + if constexpr (_Allow_vectorization && _Nx <= 8 && (_Nx & (_Nx - 1)) == 0) { + if (!_STD is_constant_evaluated()) { + _Elem* const _First_addr = _STD to_address(_First); + _Elem* const _Last_addr = _STD to_address(_Last); + if constexpr (_Nx == 1) { + __std_reverse_trivially_swappable_1(_First_addr, _Last_addr); + } else if constexpr (_Nx == 2) { + __std_reverse_trivially_swappable_2(_First_addr, _Last_addr); + } else if constexpr (_Nx == 4) { + __std_reverse_trivially_swappable_4(_First_addr, _Last_addr); + } else { + __std_reverse_trivially_swappable_8(_First_addr, _Last_addr); + } + + return; + } + } + } +#endif // _USE_STD_VECTOR_ALGORITHMS + + for (; _First != _Last && _First != --_Last; ++_First) { + _RANGES iter_swap(_First, _Last); + } + } + // clang-format on + + class _Reverse_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se> + requires permutable<_It> + constexpr _It operator()(_It _First, _Se _Last) const { + _Adl_verify_range(_First, _Last); + auto _UFirst = _Get_unwrapped(_STD move(_First)); + auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last)); + _Seek_wrapped(_First, _ULast); + _RANGES _Reverse_common(_STD move(_UFirst), _STD move(_ULast)); + return _First; + } + + template + requires permutable> + constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const { + auto _ULast = _Get_final_iterator_unwrapped(_Range); + _RANGES _Reverse_common(_Ubegin(_Range), _ULast); + return _Rewrap_iterator(_Range, _STD move(_ULast)); + } + // clang-format on + }; + + inline constexpr _Reverse_fn reverse{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE reverse_copy template _CONSTEXPR20 _OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) { @@ -4562,7 +5042,8 @@ namespace ranges { } // clang-format off - template , _Pj>> _Pr> + 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)); diff --git a/stl/inc/compare b/stl/inc/compare index 389b5b58aa5..717e7b4b789 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -32,7 +32,7 @@ using _Compare_t = signed char; // These "pretty" enumerator names are safe since they reuse names of user-facing entities. enum class _Compare_eq : _Compare_t { equal = 0, equivalent = equal }; enum class _Compare_ord : _Compare_t { less = -1, greater = 1 }; -enum class _Compare_ncmp : _Compare_t { unordered = -127 }; +enum class _Compare_ncmp : _Compare_t { unordered = -128 }; // CLASS partial_ordering class partial_ordering { @@ -53,21 +53,7 @@ public: return _Val._Value == 0; } -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L - _NODISCARD friend constexpr bool operator==(const partial_ordering&, const partial_ordering&) noexcept = default; -#else // ^^^ supports <=> and P1185 / supports neither vvv - _NODISCARD friend constexpr bool operator!=(const partial_ordering _Val, _Literal_zero) noexcept { - return _Val._Value != 0; - } - - _NODISCARD friend constexpr bool operator==(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 == _Val._Value; - } - - _NODISCARD friend constexpr bool operator!=(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 != _Val._Value; - } -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L + _NODISCARD friend constexpr bool operator==(partial_ordering, partial_ordering) noexcept = default; _NODISCARD friend constexpr bool operator<(const partial_ordering _Val, _Literal_zero) noexcept { return _Val._Value == static_cast<_Compare_t>(_Compare_ord::less); @@ -78,7 +64,10 @@ public: } _NODISCARD friend constexpr bool operator<=(const partial_ordering _Val, _Literal_zero) noexcept { - return _Val._Value <= 0 && _Val._Is_ordered(); + // The stored value is either less (0xff), equivalent (0x00), greater (0x01), or unordered (0x80). + // Subtracting from 0 produces either 0x01, 0x00, 0xff, or 0x80. The result is greater than or equal to 0 + // if and only if the initial value was less or equivalent, for which we want to return true. + return static_cast(0 - static_cast(_Val._Value)) >= 0; } _NODISCARD friend constexpr bool operator>=(const partial_ordering _Val, _Literal_zero) noexcept { @@ -86,36 +75,33 @@ public: } _NODISCARD friend constexpr bool operator<(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 < _Val._Value; + return _Val > 0; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 > _Val._Value && _Val._Is_ordered(); + return _Val < 0; } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 <= _Val._Value; + return _Val >= 0; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const partial_ordering _Val) noexcept { - return 0 >= _Val._Value && _Val._Is_ordered(); + return _Val <= 0; } -#ifdef __cpp_impl_three_way_comparison _NODISCARD friend constexpr partial_ordering operator<=>(const partial_ordering _Val, _Literal_zero) noexcept { return _Val; } _NODISCARD friend constexpr partial_ordering operator<=>(_Literal_zero, const partial_ordering _Val) noexcept { - return partial_ordering{static_cast<_Compare_ord>(-_Val._Value)}; + // The stored value is either less (0xff), equivalent (0x00), greater (0x01), or unordered (0x80). + // Subtracting from 0 produces either 0x01, 0x00, 0xff, or 0x80. Note that the effect is to + // exchange less for greater (and vice versa), while leaving equivalent and unordered unchanged. + return partial_ordering{static_cast<_Compare_ord>(0 - static_cast(_Val._Value))}; } -#endif // __cpp_impl_three_way_comparison private: - _NODISCARD constexpr bool _Is_ordered() const noexcept { - return _Value != static_cast<_Compare_t>(_Compare_ncmp::unordered); - } - _Compare_t _Value; }; @@ -144,21 +130,7 @@ public: return _Val._Value == 0; } -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L - _NODISCARD friend constexpr bool operator==(const weak_ordering&, const weak_ordering&) noexcept = default; -#else // ^^^ supports <=> and P1185 / supports neither vvv - _NODISCARD friend constexpr bool operator!=(const weak_ordering _Val, _Literal_zero) noexcept { - return _Val._Value != 0; - } - - _NODISCARD friend constexpr bool operator==(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 == _Val._Value; - } - - _NODISCARD friend constexpr bool operator!=(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 != _Val._Value; - } -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L + _NODISCARD friend constexpr bool operator==(weak_ordering, weak_ordering) noexcept = default; _NODISCARD friend constexpr bool operator<(const weak_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; @@ -177,22 +149,21 @@ public: } _NODISCARD friend constexpr bool operator<(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 < _Val._Value; + return _Val > 0; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 > _Val._Value; + return _Val < 0; } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 <= _Val._Value; + return _Val >= 0; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const weak_ordering _Val) noexcept { - return 0 >= _Val._Value; + return _Val <= 0; } -#ifdef __cpp_impl_three_way_comparison _NODISCARD friend constexpr weak_ordering operator<=>(const weak_ordering _Val, _Literal_zero) noexcept { return _Val; } @@ -200,7 +171,6 @@ public: _NODISCARD friend constexpr weak_ordering operator<=>(_Literal_zero, const weak_ordering _Val) noexcept { return weak_ordering{static_cast<_Compare_ord>(-_Val._Value)}; } -#endif // __cpp_impl_three_way_comparison private: _Compare_t _Value; @@ -235,21 +205,7 @@ public: return _Val._Value == 0; } -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L - _NODISCARD friend constexpr bool operator==(const strong_ordering&, const strong_ordering&) noexcept = default; -#else // ^^^ supports <=> and P1185 / supports neither vvv - _NODISCARD friend constexpr bool operator!=(const strong_ordering _Val, _Literal_zero) noexcept { - return _Val._Value != 0; - } - - _NODISCARD friend constexpr bool operator==(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 == _Val._Value; - } - - _NODISCARD friend constexpr bool operator!=(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 != _Val._Value; - } -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L + _NODISCARD friend constexpr bool operator==(strong_ordering, strong_ordering) noexcept = default; _NODISCARD friend constexpr bool operator<(const strong_ordering _Val, _Literal_zero) noexcept { return _Val._Value < 0; @@ -268,22 +224,21 @@ public: } _NODISCARD friend constexpr bool operator<(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 < _Val._Value; + return _Val > 0; } _NODISCARD friend constexpr bool operator>(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 > _Val._Value; + return _Val < 0; } _NODISCARD friend constexpr bool operator<=(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 <= _Val._Value; + return _Val >= 0; } _NODISCARD friend constexpr bool operator>=(_Literal_zero, const strong_ordering _Val) noexcept { - return 0 >= _Val._Value; + return _Val <= 0; } -#ifdef __cpp_impl_three_way_comparison _NODISCARD friend constexpr strong_ordering operator<=>(const strong_ordering _Val, _Literal_zero) noexcept { return _Val; } @@ -291,7 +246,6 @@ public: _NODISCARD friend constexpr strong_ordering operator<=>(_Literal_zero, const strong_ordering _Val) noexcept { return strong_ordering{static_cast<_Compare_ord>(-_Val._Value)}; } -#endif // __cpp_impl_three_way_comparison private: _Compare_t _Value; @@ -364,7 +318,7 @@ struct common_comparison_category { using type = common_comparison_category_t<_Types...>; }; -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts // clang-format off template concept _Compares_as = same_as, _Cat>; @@ -409,7 +363,7 @@ struct compare_three_way { using is_transparent = int; }; // clang-format on -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts // Other components not yet implemented _STD_END diff --git a/stl/inc/filesystem b/stl/inc/filesystem index 8b93dd566d4..a2f4bd1dd09 100644 --- a/stl/inc/filesystem +++ b/stl/inc/filesystem @@ -102,6 +102,32 @@ namespace filesystem { return _Output; } + // More lenient version of _Convert_wide_to_narrow: Instead of failing on non-representable characters, + // replace them with a replacement character. + template + _NODISCARD basic_string _Convert_wide_to_narrow_replace_chars( + const __std_code_page _Code_page, const wstring_view _Input, const _Alloc& _Al) { + basic_string _Output(_Al); + + if (!_Input.empty()) { + if (_Input.size() > static_cast(INT_MAX)) { + _Throw_system_error(errc::invalid_argument); + } + + const int _Len = _Check_convert_result(__std_fs_convert_wide_to_narrow_replace_chars( + _Code_page, _Input.data(), static_cast(_Input.size()), nullptr, 0)); + + _Output.resize(static_cast(_Len)); + + const auto _Data_as_char = reinterpret_cast(_Output.data()); + + (void) _Check_convert_result(__std_fs_convert_wide_to_narrow_replace_chars( + _Code_page, _Input.data(), static_cast(_Input.size()), _Data_as_char, _Len)); + } + + return _Output; + } + _NODISCARD inline wstring _Convert_utf32_to_wide(const u32string_view _Input) { wstring _Output; @@ -1786,8 +1812,12 @@ namespace filesystem { static string _Pretty_message(const string_view _Op, const path& _Path1, const path& _Path2 = {}) { using namespace _STD string_view_literals; // TRANSITION, VSO-571749 string _Result; - const string _Path1_str = _Path1.string(); - const string _Path2_str = _Path2.string(); + // Convert the paths to narrow encoding in a way that gracefully handles non-encodable characters + const auto _Code_page = __std_fs_code_page(); + const string _Path1_str = _Convert_wide_to_narrow_replace_chars>( + _Code_page, _Path1.native(), allocator{}); + const string _Path2_str = _Convert_wide_to_narrow_replace_chars>( + _Code_page, _Path2.native(), allocator{}); _Result.reserve(_Op.size() + (_Path2_str.empty() ? 4 : 8) + _Path1_str.size() + _Path2_str.size()); _Result += _Op; _Result += R"(: ")"sv; // 3 chars diff --git a/stl/inc/span b/stl/inc/span index d61d8e375fc..8565955bfc5 100644 --- a/stl/inc/span +++ b/stl/inc/span @@ -12,13 +12,11 @@ #if !_HAS_CXX20 #pragma message("The contents of are available only with C++20 or later.") #else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv +#include #include #include #include -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L -#include -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -153,7 +151,6 @@ struct _Span_iterator { return _Myptr == _Right._Myptr; } -#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L _NODISCARD constexpr strong_ordering operator<=>(const _Span_iterator& _Right) const noexcept { #if _ITERATOR_DEBUG_LEVEL >= 1 _STL_VERIFY( @@ -161,31 +158,6 @@ struct _Span_iterator { #endif // _ITERATOR_DEBUG_LEVEL >= 1 return _Myptr <=> _Right._Myptr; } -#else // ^^^ use spaceship / no spaceship vvv - _NODISCARD constexpr bool operator!=(const _Span_iterator& _Right) const noexcept { - return !(*this == _Right); - } - - _NODISCARD constexpr bool operator<(const _Span_iterator& _Right) const noexcept { -#if _ITERATOR_DEBUG_LEVEL >= 1 - _STL_VERIFY( - _Mybegin == _Right._Mybegin && _Myend == _Right._Myend, "cannot compare incompatible span iterators"); -#endif // _ITERATOR_DEBUG_LEVEL >= 1 - return _Myptr < _Right._Myptr; - } - - _NODISCARD constexpr bool operator>(const _Span_iterator& _Right) const noexcept { - return _Right < *this; - } - - _NODISCARD constexpr bool operator<=(const _Span_iterator& _Right) const noexcept { - return !(_Right < *this); - } - - _NODISCARD constexpr bool operator>=(const _Span_iterator& _Right) const noexcept { - return !(*this < _Right); - } -#endif // defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201902L #if _ITERATOR_DEBUG_LEVEL >= 1 friend constexpr void _Verify_range(const _Span_iterator& _First, const _Span_iterator& _Last) noexcept { diff --git a/stl/inc/xfilesystem_abi.h b/stl/inc/xfilesystem_abi.h index 0d3ce7035a9..2e3fcddde59 100644 --- a/stl/inc/xfilesystem_abi.h +++ b/stl/inc/xfilesystem_abi.h @@ -276,6 +276,10 @@ _NODISCARD __std_fs_convert_result __stdcall __std_fs_convert_wide_to_narrow(_In _In_reads_(_Input_len) const wchar_t* _Input_str, _In_ int _Input_len, _Out_writes_opt_(_Output_len) char* _Output_str, _In_ int _Output_len) noexcept; +_NODISCARD __std_fs_convert_result __stdcall __std_fs_convert_wide_to_narrow_replace_chars( + _In_ __std_code_page _Code_page, _In_reads_(_Input_len) const wchar_t* _Input_str, _In_ int _Input_len, + _Out_writes_opt_(_Output_len) char* _Output_str, _In_ int _Output_len) noexcept; + _NODISCARD __std_win_error __stdcall __std_fs_get_file_id( _Out_ __std_fs_file_id* _Id, _In_z_ const wchar_t* _Path) noexcept; diff --git a/stl/inc/xutility b/stl/inc/xutility index 26299d2612e..f80ed07fa86 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2105,13 +2105,13 @@ _NODISCARD _CONSTEXPR17 bool operator>=(const reverse_iterator<_BidIt1>& _Left, #endif // __cpp_lib_concepts { return _Left._Get_current() <= _Right._Get_current(); } -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts template _BidIt2> _NODISCARD constexpr compare_three_way_result_t<_BidIt1, _BidIt2> operator<=>( const reverse_iterator<_BidIt1>& _Left, const reverse_iterator<_BidIt2>& _Right) { return _Right._Get_current() <=> _Left._Get_current(); } -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts template _NODISCARD _CONSTEXPR17 auto operator-(const reverse_iterator<_BidIt1>& _Left, const reverse_iterator<_BidIt2>& _Right) @@ -4103,12 +4103,12 @@ _NODISCARD _CONSTEXPR17 bool operator==(const move_iterator<_Iter1>& _Left, cons #endif // __cpp_lib_concepts { return _Left.base() == _Right.base(); } -#if !_HAS_CXX20 || __cpp_impl_three_way_comparison < 201902L +#if !_HAS_CXX20 template _NODISCARD _CONSTEXPR17 bool operator!=(const move_iterator<_Iter1>& _Left, const move_iterator<_Iter2>& _Right) { return !(_Left == _Right); } -#endif // !_HAS_CXX20 || __cpp_impl_three_way_comparison < 201902L +#endif // !_HAS_CXX20 template _NODISCARD _CONSTEXPR17 bool operator<(const move_iterator<_Iter1>& _Left, const move_iterator<_Iter2>& _Right) @@ -4148,13 +4148,13 @@ _NODISCARD _CONSTEXPR17 bool operator>=(const move_iterator<_Iter1>& _Left, cons #endif // __cpp_lib_concepts { return !(_Left < _Right); } -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts template _Iter2> _NODISCARD constexpr compare_three_way_result_t<_Iter1, _Iter2> operator<=>( const move_iterator<_Iter1>& _Left, const move_iterator<_Iter2>& _Right) { return _Left.base() <=> _Right.base(); } -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts template _NODISCARD _CONSTEXPR17 auto operator-(const move_iterator<_Iter1>& _Left, const move_iterator<_Iter2>& _Right) @@ -4195,21 +4195,6 @@ namespace _Unreachable_sentinel_detail { _NODISCARD friend constexpr bool operator==(const unreachable_sentinel_t&, const _Winc&) noexcept { return false; } -#if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L - template - _NODISCARD friend constexpr bool operator==(const _Winc&, const unreachable_sentinel_t&) noexcept { - return false; - } - - template - _NODISCARD friend constexpr bool operator!=(const unreachable_sentinel_t&, const _Winc&) noexcept { - return true; - } - template - _NODISCARD friend constexpr bool operator!=(const _Winc&, const unreachable_sentinel_t&) noexcept { - return true; - } -#endif // !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L }; } // namespace _Unreachable_sentinel_detail struct unreachable_sentinel_t : _Unreachable_sentinel_detail::_Base {}; // TRANSITION, /permissive- @@ -4471,27 +4456,32 @@ _BidIt2 _Copy_backward_memmove(move_iterator<_BidIt1> _First, move_iterator<_Bid #if _HAS_IF_CONSTEXPR template -_CONSTEXPR20 _BidIt2 copy_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { +_NODISCARD _CONSTEXPR20 _BidIt2 _Copy_backward_unchecked(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { // copy [_First, _Last) backwards to [..., _Dest) - _Adl_verify_range(_First, _Last); - const auto _UFirst = _Get_unwrapped(_First); - auto _ULast = _Get_unwrapped(_Last); - auto _UDest = _Get_unwrapped_n(_Dest, -_Idl_distance<_BidIt1>(_UFirst, _ULast)); - if constexpr (_Ptr_copy_cat::_Trivially_copyable) { + if constexpr (_Ptr_copy_cat<_BidIt1, _BidIt2>::_Trivially_copyable) { #ifdef __cpp_lib_is_constant_evaluated if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - _UDest = _Copy_backward_memmove(_UFirst, _ULast, _UDest); - _Seek_wrapped(_Dest, _UDest); - return _Dest; + return _Copy_backward_memmove(_First, _Last, _Dest); } } - while (_UFirst != _ULast) { - *--_UDest = *--_ULast; + while (_First != _Last) { + *--_Dest = *--_Last; } - _Seek_wrapped(_Dest, _UDest); + + return _Dest; +} + +template +_CONSTEXPR20 _BidIt2 copy_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest) { + // copy [_First, _Last) backwards to [..., _Dest) + _Adl_verify_range(_First, _Last); + const auto _UFirst = _Get_unwrapped(_First); + const auto _ULast = _Get_unwrapped(_Last); + const auto _UDest = _Get_unwrapped_n(_Dest, -_Idl_distance<_BidIt1>(_UFirst, _ULast)); + _Seek_wrapped(_Dest, _Copy_backward_unchecked(_UFirst, _ULast, _UDest)); return _Dest; } #else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv @@ -5231,7 +5221,7 @@ _NODISCARD bool lexicographical_compare( } #endif // _HAS_CXX17 -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts // FUNCTION TEMPLATE lexicographical_compare_three_way template _NODISCARD constexpr auto lexicographical_compare_three_way( @@ -5289,7 +5279,7 @@ _NODISCARD constexpr auto lexicographical_compare_three_way( _InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) { return _STD lexicographical_compare_three_way(_First1, _Last1, _First2, _Last2, compare_three_way{}); } -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts // FUNCTION TEMPLATE find template diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 860b9360d40..61292ad030b 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -346,7 +346,7 @@ #define _MSVC_KNOWN_SEMANTICS #endif -// Controls whether the STL uses "if constexpr" internally +// Controls whether the STL uses "if constexpr" internally in C++14 mode #ifndef _HAS_IF_CONSTEXPR #ifdef __CUDACC__ #define _HAS_IF_CONSTEXPR 0 diff --git a/stl/src/filesystem.cpp b/stl/src/filesystem.cpp index ca312314f04..0a1d3d5a1e8 100644 --- a/stl/src/filesystem.cpp +++ b/stl/src/filesystem.cpp @@ -421,6 +421,27 @@ void __stdcall __std_fs_directory_iterator_close(const __std_fs_dir_handle _Hand return _Result; } +[[nodiscard]] __std_fs_convert_result __stdcall __std_fs_convert_wide_to_narrow_replace_chars( + const __std_code_page _Code_page, const wchar_t* const _Input_str, const int _Input_len, char* const _Output_str, + const int _Output_len) noexcept { + __std_fs_convert_result _Result; + + _Result._Len = WideCharToMultiByte(static_cast(_Code_page), WC_NO_BEST_FIT_CHARS, _Input_str, + _Input_len, _Output_str, _Output_len, nullptr, nullptr); + + _Result._Err = _Result._Len == 0 ? __std_win_error{GetLastError()} : __std_win_error::_Success; + + // Some codepages don't support WC_NO_BEST_FIT_CHARS, fall back to default conversion. + if (_Result._Err == __std_win_error{ERROR_INVALID_FLAGS}) { + _Result._Len = WideCharToMultiByte(static_cast(_Code_page), 0, _Input_str, _Input_len, + _Output_str, _Output_len, nullptr, nullptr); + + _Result._Err = _Result._Len == 0 ? __std_win_error{GetLastError()} : __std_win_error::_Success; + } + + return _Result; +} + [[nodiscard]] __std_fs_copy_file_result __stdcall __std_fs_copy_file(const wchar_t* const _Source, const wchar_t* const _Target, __std_fs_copy_options _Options) noexcept { // copy _Source to _Target _Options &= __std_fs_copy_options::_Existing_mask; diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index d5fa87ddd08..1a6b09496eb 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -125,6 +125,26 @@ namespace test { ptr_ = s.peek(); } // clang-format on + + [[nodiscard]] friend constexpr boolish operator==(sentinel const s, Element* const ptr) noexcept { + return {s.ptr_ == ptr}; + } + [[nodiscard]] friend constexpr boolish operator==(Element* const ptr, sentinel const s) noexcept { + return {s.ptr_ == ptr}; + } + [[nodiscard]] friend constexpr boolish operator!=(sentinel const s, Element* const ptr) noexcept { + return !(s == ptr); + } + [[nodiscard]] friend constexpr boolish operator!=(Element* const ptr, sentinel const s) noexcept { + return !(s == ptr); + } + + [[nodiscard]] friend constexpr ptrdiff_t operator-(sentinel const s, Element* const ptr) noexcept { + return s.ptr_ - ptr; + } + [[nodiscard]] friend constexpr ptrdiff_t operator-(Element* const ptr, sentinel const s) noexcept { + return ptr - s.ptr_; + } }; // clang-format off @@ -188,70 +208,86 @@ namespace test { // clang-format on template - constexpr boolish operator==(proxy_reference that) const requires CanEq { + [[nodiscard]] constexpr boolish operator==(proxy_reference that) const + requires CanEq { return {ref_ == that.peek()}; } template - constexpr boolish operator!=(proxy_reference that) const requires CanNEq { + [[nodiscard]] constexpr boolish operator!=(proxy_reference that) const + requires CanNEq { return {ref_ != that.peek()}; } template - constexpr boolish operator<(proxy_reference that) const requires CanLt { + [[nodiscard]] constexpr boolish operator<(proxy_reference that) const requires CanLt { return {ref_ < that.peek()}; } template - constexpr boolish operator>(proxy_reference that) const requires CanGt { + [[nodiscard]] constexpr boolish operator>(proxy_reference that) const requires CanGt { return {ref_ > that.peek()}; } template - constexpr boolish operator<=(proxy_reference that) const requires CanLtE { + [[nodiscard]] constexpr boolish operator<=(proxy_reference that) const + requires CanLtE { return {ref_ <= that.peek()}; } template - constexpr boolish operator>=(proxy_reference that) const requires CanGtE { + [[nodiscard]] constexpr boolish operator>=(proxy_reference that) const + requires CanGtE { return {ref_ >= that.peek()}; } // clang-format off - friend constexpr boolish operator==(proxy_reference r, Value const& val) requires CanEq { + [[nodiscard]] 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 r) requires CanEq { + [[nodiscard]] friend constexpr boolish operator==(Value const& val, proxy_reference r) + requires CanEq { return {r.ref_ == val}; } - friend constexpr boolish operator!=(proxy_reference r, Value const& val) requires CanNEq { + [[nodiscard]] 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 r) requires CanNEq { + [[nodiscard]] 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 r) requires CanLt { + [[nodiscard]] friend constexpr boolish operator<(Value const& val, proxy_reference r) + requires CanLt { return {val < r.ref_}; } - friend constexpr boolish operator<(proxy_reference r, Value const& val) requires CanLt { + [[nodiscard]] 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 r) requires CanGt { + [[nodiscard]] friend constexpr boolish operator>(Value const& val, proxy_reference r) + requires CanGt { return {val > r.ref_}; } - friend constexpr boolish operator>(proxy_reference r, Value const& val) requires CanGt { + [[nodiscard]] 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 r) requires CanLtE { + [[nodiscard]] friend constexpr boolish operator<=(Value const& val, proxy_reference r) + requires CanLtE { return {val <= r.ref_}; } - friend constexpr boolish operator<=(proxy_reference r, Value const& val) requires CanLtE { + [[nodiscard]] 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 r) requires CanGtE { + [[nodiscard]] friend constexpr boolish operator>=(Value const& val, proxy_reference r) + requires CanGtE { return {val >= r.ref_}; } - friend constexpr boolish operator>=(proxy_reference r, Value const& val) requires CanGtE { + [[nodiscard]] friend constexpr boolish operator>=(proxy_reference r, Value const& val) + requires CanGtE { return {r.ref_ >= val}; } // clang-format on - constexpr Element& peek() const noexcept { + [[nodiscard]] constexpr Element& peek() const noexcept { return ref_; } }; @@ -466,7 +502,8 @@ namespace test { // iterator unwrapping operations: using _Prevent_inheriting_unwrap = iterator; - using unwrap = iterator; + using unwrap = std::conditional_t, Element*, + iterator>; [[nodiscard]] constexpr auto _Unwrapped() const& noexcept requires (to_bool(Wrapped) && to_bool(Eq)) { return unwrap{ptr_}; @@ -479,11 +516,19 @@ namespace test { static constexpr bool _Unwrap_when_unverified = true; constexpr void _Seek_to(unwrap const& i) noexcept requires (to_bool(Wrapped) && to_bool(Eq)) { - ptr_ = i.peek(); + if constexpr (at_least) { + ptr_ = i; + } else { + ptr_ = i.peek(); + } } constexpr void _Seek_to(unwrap&& i) noexcept requires (to_bool(Wrapped)) { - ptr_ = i.peek(); + if constexpr (at_least) { + ptr_ = i; + } else { + ptr_ = i.peek(); + } } }; // clang-format on @@ -570,8 +615,8 @@ namespace test { return elements_.data(); } - using UI = iterator; - using US = conditional_t>; + using UI = typename I::unwrap; + using US = conditional_t>; [[nodiscard]] constexpr UI _Unchecked_begin() const noexcept { if constexpr (!derived_from) { @@ -1003,11 +1048,21 @@ constexpr void test_fwd_fwd() { with_forward_ranges, Element1>::call(); } +template +constexpr void test_bidi_bidi() { + with_bidirectional_ranges, Element1>::call(); +} + template constexpr void test_in_write() { with_input_ranges, Element1>::call(); } +template +constexpr void test_fwd_write() { + with_forward_ranges, Element1>::call(); +} + template constexpr void test_read() { with_input_iterators::call(); @@ -1018,6 +1073,11 @@ constexpr void test_read_write() { with_input_iterators, Element1>::call(); } +template +constexpr void test_in_in_write() { + with_input_ranges, Element2>, Element1>::call(); +} + template struct get_nth_fn { template diff --git a/tests/std/test.lst b/tests/std/test.lst index 4c9d6bf510c..8b46ac33bfa 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -160,6 +160,7 @@ tests\GH_000545_include_compare tests\GH_000685_condition_variable_any tests\GH_000690_overaligned_function tests\GH_000890_pow_template +tests\GH_001010_filesystem_error_encoding tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function tests\P0024R2_parallel_algorithms_adjacent_difference @@ -240,6 +241,7 @@ tests\P0896R4_ranges_alg_all_of tests\P0896R4_ranges_alg_any_of tests\P0896R4_ranges_alg_binary_search tests\P0896R4_ranges_alg_copy +tests\P0896R4_ranges_alg_copy_backward tests\P0896R4_ranges_alg_copy_if tests\P0896R4_ranges_alg_copy_n tests\P0896R4_ranges_alg_count @@ -266,13 +268,20 @@ 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_remove +tests\P0896R4_ranges_alg_remove_copy +tests\P0896R4_ranges_alg_remove_copy_if +tests\P0896R4_ranges_alg_remove_if 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_reverse tests\P0896R4_ranges_alg_search tests\P0896R4_ranges_alg_search_n tests\P0896R4_ranges_alg_swap_ranges +tests\P0896R4_ranges_alg_transform_binary +tests\P0896R4_ranges_alg_transform_unary tests\P0896R4_ranges_iterator_machinery tests\P0896R4_ranges_range_machinery tests\P0896R4_ranges_subrange diff --git a/tests/std/tests/GH_001010_filesystem_error_encoding/env.lst b/tests/std/tests/GH_001010_filesystem_error_encoding/env.lst new file mode 100644 index 00000000000..2de7aab2959 --- /dev/null +++ b/tests/std/tests/GH_001010_filesystem_error_encoding/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_17_matrix.lst diff --git a/tests/std/tests/GH_001010_filesystem_error_encoding/test.cpp b/tests/std/tests/GH_001010_filesystem_error_encoding/test.cpp new file mode 100644 index 00000000000..a823c2599a2 --- /dev/null +++ b/tests/std/tests/GH_001010_filesystem_error_encoding/test.cpp @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; +namespace fs = std::filesystem; + +void test_filesystem_error_with_bad_codepage_characters() { + fs::path problem_path{L"problematic\xD83Dtestpath"}; // path containing lone high surrogate + + // Make sure the path is not encodable in our current locale, otherwise the test tests nothing + bool exception_caught = false; + try { + (void) problem_path.string(); + } catch (const exception&) { + exception_caught = true; + } + assert(exception_caught); + + // filesystem_error should handle the non-encodable character gracefully when building its message + fs::filesystem_error err{"testexception", problem_path, error_code{}}; + assert(string_view{err.what()}.find("problematic") != string_view::npos); + assert(string_view{err.what()}.find("testpath") != string_view::npos); +} + +int main() { + test_filesystem_error_with_bad_codepage_characters(); +} diff --git a/tests/std/tests/P0768R1_spaceship_operator/test.cpp b/tests/std/tests/P0768R1_spaceship_operator/test.cpp index 09a23f15d6b..33a1218f7d6 100644 --- a/tests/std/tests/P0768R1_spaceship_operator/test.cpp +++ b/tests/std/tests/P0768R1_spaceship_operator/test.cpp @@ -7,64 +7,89 @@ #include #include -enum class comp { equal, nonequal, less, greater, unordered }; +enum class comp { equal, less, greater, unordered }; template -constexpr bool test_ord(T val) { +constexpr bool test_order(const T val) { + // Validate that val is ordered relative to literal zero according to Z assert((val == 0) == (Z == comp::equal)); assert((0 == val) == (Z == comp::equal)); + assert((val != 0) == (Z != comp::equal)); assert((0 != val) == (Z != comp::equal)); -#ifdef __cpp_impl_three_way_comparison - assert(((val <=> 0) == 0) == (Z == comp::equal)); - assert(((0 <=> val) == 0) == (Z == comp::equal)); - -#if __cpp_impl_three_way_comparison >= 201907L - assert(val == val); - assert(!(val != val)); -#endif // __cpp_impl_three_way_comparison >= 201907L -#endif // __cpp_impl_three_way_comparison - assert(std::is_eq(val) == (Z == comp::equal)); - assert(std::is_neq(val) == (Z != comp::equal)); assert((val < 0) == (Z == comp::less)); assert((0 > val) == (Z == comp::less)); + assert((val > 0) == (Z == comp::greater)); assert((0 < val) == (Z == comp::greater)); + assert((val <= 0) == (Z != comp::greater && Z != comp::unordered)); assert((0 >= val) == (Z != comp::greater && Z != comp::unordered)); + assert((val >= 0) == (Z != comp::less && Z != comp::unordered)); assert((0 <= val) == (Z != comp::less && Z != comp::unordered)); -#ifdef __cpp_impl_three_way_comparison - assert(((val <=> 0) < 0) == (Z == comp::less)); - assert(((0 <=> val) < 0) == (Z == comp::greater)); -#if __cpp_impl_three_way_comparison >= 201907L - assert(val == val); - assert(!(val != val)); -#endif // __cpp_impl_three_way_comparison >= 201907L -#endif // __cpp_impl_three_way_comparison + assert(std::is_eq(val) == (Z == comp::equal)); + assert(std::is_neq(val) == (Z != comp::equal)); assert(std::is_lt(val) == (Z == comp::less)); assert(std::is_lteq(val) == (Z != comp::greater && Z != comp::unordered)); assert(std::is_gt(val) == (Z == comp::greater)); assert(std::is_gteq(val) == (Z != comp::less && Z != comp::unordered)); + // Validate that equality is reflexive for comparison category types + assert(val == val); + assert(!(val != val)); + return true; } -static_assert(test_ord(std::partial_ordering::equivalent)); -static_assert(test_ord(std::partial_ordering::less)); -static_assert(test_ord(std::partial_ordering::greater)); -static_assert(test_ord(std::partial_ordering::unordered)); +constexpr bool test_orderings() { + assert(test_order(std::partial_ordering::equivalent)); + assert(test_order(std::partial_ordering::less)); + assert(test_order(std::partial_ordering::greater)); + assert(test_order(std::partial_ordering::unordered)); + + assert(test_order(std::weak_ordering::equivalent)); + assert(test_order(std::weak_ordering::less)); + assert(test_order(std::weak_ordering::greater)); + + assert(test_order(std::strong_ordering::equal)); + assert(test_order(std::strong_ordering::equivalent)); + assert(test_order(std::strong_ordering::less)); + assert(test_order(std::strong_ordering::greater)); -static_assert(test_ord(std::weak_ordering::equivalent)); -static_assert(test_ord(std::weak_ordering::less)); -static_assert(test_ord(std::weak_ordering::greater)); + return true; +} + +constexpr bool test_spaceships() { + // Exhaustively validate x <=> 0 and 0 <=> x for all values of each comparison category type. + // Guards against regression of GH-1050: "0 <=> partial_ordering::unordered returns invalid value". + assert(std::partial_ordering::less <=> 0 == std::partial_ordering::less); + assert(0 <=> std::partial_ordering::less == std::partial_ordering::greater); + assert(std::partial_ordering::equivalent <=> 0 == std::partial_ordering::equivalent); + assert(0 <=> std::partial_ordering::equivalent == std::partial_ordering::equivalent); + assert(std::partial_ordering::greater <=> 0 == std::partial_ordering::greater); + assert(0 <=> std::partial_ordering::greater == std::partial_ordering::less); + assert(std::partial_ordering::unordered <=> 0 == std::partial_ordering::unordered); + assert(0 <=> std::partial_ordering::unordered == std::partial_ordering::unordered); + + assert(std::weak_ordering::less <=> 0 == std::weak_ordering::less); + assert(0 <=> std::weak_ordering::less == std::weak_ordering::greater); + assert(std::weak_ordering::equivalent <=> 0 == std::weak_ordering::equivalent); + assert(0 <=> std::weak_ordering::equivalent == std::weak_ordering::equivalent); + assert(std::weak_ordering::greater <=> 0 == std::weak_ordering::greater); + assert(0 <=> std::weak_ordering::greater == std::weak_ordering::less); + + assert(std::strong_ordering::less <=> 0 == std::strong_ordering::less); + assert(0 <=> std::strong_ordering::less == std::strong_ordering::greater); + assert(std::strong_ordering::equal <=> 0 == std::strong_ordering::equal); + assert(0 <=> std::strong_ordering::equal == std::strong_ordering::equal); + assert(std::strong_ordering::greater <=> 0 == std::strong_ordering::greater); + assert(0 <=> std::strong_ordering::greater == std::strong_ordering::less); -static_assert(test_ord(std::strong_ordering::equal)); -static_assert(test_ord(std::strong_ordering::equivalent)); -static_assert(test_ord(std::strong_ordering::less)); -static_assert(test_ord(std::strong_ordering::greater)); + return true; +} template constexpr bool test_common_cc = std::is_same_v, Expected>; @@ -121,7 +146,7 @@ static_assert(test_common_type()); static_assert(test_common_type()); static_assert(test_common_type()); -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts constexpr auto my_cmp_three_way = [](const auto& left, const auto& right) { return left <=> right; }; template @@ -187,29 +212,21 @@ void test_algorithm() { assert((test_algorithm2())); assert((test_algorithm2())); } -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts int main() { - test_ord(std::partial_ordering::equivalent); - test_ord(std::partial_ordering::less); - test_ord(std::partial_ordering::greater); - test_ord(std::partial_ordering::unordered); - - test_ord(std::weak_ordering::equivalent); - test_ord(std::weak_ordering::less); - test_ord(std::weak_ordering::greater); + static_assert(test_orderings()); + test_orderings(); - test_ord(std::strong_ordering::equal); - test_ord(std::strong_ordering::equivalent); - test_ord(std::strong_ordering::less); - test_ord(std::strong_ordering::greater); + static_assert(test_spaceships()); + test_spaceships(); -#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#ifdef __cpp_lib_concepts test_algorithm(); test_algorithm(); test_algorithm(); test_algorithm(); test_algorithm(); test_algorithm(); -#endif // defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_concepts) +#endif // __cpp_lib_concepts } diff --git a/tests/std/tests/P0896R4_ranges_alg_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_copy/test.cpp index 6fd9130e399..da5250e5256 100644 --- a/tests/std/tests/P0896R4_ranges_alg_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_copy/test.cpp @@ -15,10 +15,9 @@ using namespace std; 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>); + same_as{}, nullptr_to)), ranges::copy_result>); +STATIC_ASSERT(same_as{}, nullptr_to)), ranges::copy_result>); struct instantiator { static constexpr int input[3] = {13, 42, 1729}; diff --git a/tests/std/tests/P0896R4_ranges_alg_copy_backward/env.lst b/tests/std/tests/P0896R4_ranges_alg_copy_backward/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_copy_backward/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_copy_backward/test.cpp b/tests/std/tests/P0896R4_ranges_alg_copy_backward/test.cpp new file mode 100644 index 00000000000..ac89778f756 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_copy_backward/test.cpp @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate that copy_backward_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_backward_result>); +STATIC_ASSERT(same_as{}, static_cast(nullptr))), + ranges::copy_backward_result>); + +static constexpr int input[] = {13, 42, 1729}; +static constexpr int expected_overlapping[] = {0, 0, 1, 2}; + +struct instantiator { + template + static constexpr void call() { + // For the second range, we need an iterator to the end; it's expedient to simply ignore ranges with differing + // iterator and sentinel types (i.e., ranges that don't satisfy common_range). + if constexpr (ranges::common_range) { + using ranges::copy_backward, ranges::copy_backward_result, ranges::equal, ranges::iterator_t; + const Bidi1 wrapped_input{input}; + + { // Validate range overload + int output[] = {-2, -2, -2}; + Bidi2 wrapped_output{output}; + auto result = copy_backward(wrapped_input, wrapped_output.end()); + STATIC_ASSERT(same_as, iterator_t>>); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.begin()); + assert(equal(output, input)); + } + { // Validate iterator + sentinel overload + int output[] = {-2, -2, -2}; + Bidi2 wrapped_output{output}; + auto result = copy_backward(wrapped_input.begin(), wrapped_input.end(), wrapped_output.end()); + STATIC_ASSERT(same_as, iterator_t>>); + assert(result.in == wrapped_input.end()); + assert(result.out == wrapped_output.begin()); + assert(equal(output, input)); + } + { // Validate overlapping ranges + int io[] = {0, 1, 2, 42}; + Bidi1 in{span{io}.first<3>()}; + Bidi2 out{span{io}.last<3>()}; + auto result = copy_backward(in, out.end()); + STATIC_ASSERT(same_as, iterator_t>>); + assert(result.in == in.end()); + assert(result.out == out.begin()); + assert(equal(io, expected_overlapping)); + } + } + } +}; + +constexpr void test_memmove() { + // Get some coverage for the memmove optimization, which we would not otherwise have since we do not currently + // unwrap output iterators. TRANSITION, GH-893 + using ranges::copy_backward, ranges::copy_backward_result, ranges::begin, ranges::end, ranges::equal; + + { // Validate range overload + int output[] = {-2, -2, -2}; + auto result = copy_backward(input, end(output)); + STATIC_ASSERT(same_as>); + assert(result.in == end(input)); + assert(result.out == begin(output)); + assert(equal(output, input)); + } + { // Validate iterator + sentinel overload + int output[] = {-2, -2, -2}; + auto result = copy_backward(begin(input), end(input), end(output)); + STATIC_ASSERT(same_as>); + assert(result.in == end(input)); + assert(result.out == begin(output)); + assert(equal(output, input)); + } + { // Validate overlapping ranges + int io[] = {0, 1, 2, 42}; + auto result = copy_backward(io + 0, io + 3, io + 4); + STATIC_ASSERT(same_as>); + assert(result.in == io + 3); + assert(result.out == io + 1); + assert(equal(io, expected_overlapping)); + } +} + +int main() { + STATIC_ASSERT((test_bidi_bidi(), true)); + test_bidi_bidi(); + + STATIC_ASSERT((test_memmove(), true)); + test_memmove(); +} 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 aa257403649..cd30e073d21 100644 --- a/tests/std/tests/P0896R4_ranges_alg_copy_if/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_copy_if/test.cpp @@ -65,10 +65,10 @@ constexpr auto is_odd = [](int const x) { return x % 2 != 0; }; STATIC_ASSERT(same_as, ranges::in_out_result>); // Validate dangling story -STATIC_ASSERT(same_as{}, static_cast(nullptr), is_odd)), +STATIC_ASSERT(same_as{}, nullptr_to, is_odd)), ranges::copy_if_result>); -STATIC_ASSERT(same_as{}, static_cast(nullptr), is_odd)), - ranges::copy_if_result>); +STATIC_ASSERT( + same_as{}, nullptr_to, is_odd)), ranges::copy_if_result>); struct instantiator { static constexpr P input[3] = {{1, 99}, {4, 98}, {5, 97}}; @@ -101,6 +101,8 @@ struct instantiator { }; int main() { +#ifndef _PREFAST_ // TRANSITION, GH-1030 STATIC_ASSERT((test_in_write(), true)); +#endif // TRANSITION, GH-1030 test_in_write(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_heap/test.cpp b/tests/std/tests/P0896R4_ranges_alg_heap/test.cpp index ac24c5645f2..d938ff02434 100644 --- a/tests/std/tests/P0896R4_ranges_alg_heap/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_heap/test.cpp @@ -108,11 +108,16 @@ struct make_and_sort_heap_test { ASSERT(!is_heap(wrapped, less{}, get_first)); - make_heap(wrapped, less{}, get_first); - ASSERT(is_heap(wrapped, less{}, get_first)); - - sort_heap(wrapped, less{}, get_first); - ASSERT(is_sorted(wrapped, less{}, get_first)); +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 + if constexpr (!ranges::contiguous_range) +#endif // TRANSITION, VSO-938163 + { + make_heap(wrapped, less{}, get_first); + ASSERT(is_heap(wrapped, less{}, get_first)); + + sort_heap(wrapped, less{}, get_first); + ASSERT(is_sorted(wrapped, less{}, get_first)); + } } { @@ -121,11 +126,16 @@ struct make_and_sort_heap_test { ASSERT(!is_heap(wrapped.begin(), wrapped.end(), less{}, get_first)); - make_heap(wrapped.begin(), wrapped.end(), less{}, get_first); - ASSERT(is_heap(wrapped.begin(), wrapped.end(), less{}, get_first)); +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 + if constexpr (!ranges::contiguous_range) +#endif // TRANSITION, VSO-938163 + { + make_heap(wrapped.begin(), wrapped.end(), less{}, get_first); + ASSERT(is_heap(wrapped.begin(), wrapped.end(), less{}, get_first)); - sort_heap(wrapped.begin(), wrapped.end(), less{}, get_first); - ASSERT(is_sorted(wrapped.begin(), wrapped.end(), less{}, get_first)); + sort_heap(wrapped.begin(), wrapped.end(), less{}, get_first); + ASSERT(is_sorted(wrapped.begin(), wrapped.end(), less{}, get_first)); + } } } }; @@ -182,24 +192,34 @@ struct push_and_pop_heap_test { auto buff = initial_values; const Range wrapped{buff}; - pop_heap(wrapped, less{}, get_first); - ASSERT(equal(wrapped, expectedPopped)); +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 + if constexpr (!ranges::contiguous_range) +#endif // TRANSITION, VSO-938163 + { + pop_heap(wrapped, less{}, get_first); + ASSERT(equal(wrapped, expectedPopped)); - push_heap(wrapped, less{}, get_first); - ASSERT(equal(wrapped, expectedPushed)); + push_heap(wrapped, less{}, get_first); + ASSERT(equal(wrapped, expectedPushed)); + } } { auto buff = initial_values; const Range wrapped{buff}; - pop_heap(wrapped.begin(), wrapped.end(), less{}, get_first); - ASSERT(is_heap(expectedPopped.begin(), expectedPopped.end() - 1, less{}, get_first)); - ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPopped.begin(), expectedPopped.end())); - - push_heap(wrapped.begin(), wrapped.end(), less{}, get_first); - ASSERT(is_heap(expectedPushed, less{}, get_first)); - ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPushed.begin(), expectedPushed.end())); +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 + if constexpr (!ranges::contiguous_range) +#endif // TRANSITION, VSO-938163 + { + pop_heap(wrapped.begin(), wrapped.end(), less{}, get_first); + ASSERT(is_heap(expectedPopped.begin(), expectedPopped.end() - 1, less{}, get_first)); + ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPopped.begin(), expectedPopped.end())); + + push_heap(wrapped.begin(), wrapped.end(), less{}, get_first); + ASSERT(is_heap(expectedPushed, less{}, get_first)); + ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPushed.begin(), expectedPushed.end())); + } } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_mismatch/test.cpp b/tests/std/tests/P0896R4_ranges_alg_mismatch/test.cpp index 30f7c5e8394..51a0b864436 100644 --- a/tests/std/tests/P0896R4_ranges_alg_mismatch/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_mismatch/test.cpp @@ -71,7 +71,9 @@ constexpr void smoke_test() { } int main() { +#ifndef _PREFAST_ // TRANSITION, GH-1030 STATIC_ASSERT((smoke_test(), true)); +#endif // TRANSITION, GH-1030 smoke_test(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_move/test.cpp index c97f016e4bc..dbd4e70a55f 100644 --- a/tests/std/tests/P0896R4_ranges_alg_move/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_move/test.cpp @@ -27,49 +27,53 @@ struct int_wrapper { 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>); + same_as{}, nullptr_to)), ranges::move_result>); +STATIC_ASSERT(same_as{}, nullptr_to)), ranges::move_result>); struct instantiator { static constexpr int_wrapper expected_output[3] = {13, 55, 12345}; static constexpr int_wrapper expected_input[3] = {-1, -1, -1}; - 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)); - } - template > Write> static constexpr void call() { - using ranges::move, ranges::move_result, ranges::iterator_t; +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 +#pragma warning(suppress : 4127) // conditional expression is constant + if (!ranges::contiguous_range || !is_constant_evaluated()) +#endif // TRANSITION, VSO-938163 { - int_wrapper input[3] = {13, 55, 12345}; - int_wrapper output[3] = {-2, -2, -2}; - Read wrapped_input{input}; + using ranges::move, ranges::move_result, ranges::equal, ranges::iterator_t; + { + int_wrapper input[3] = {13, 55, 12345}; + int_wrapper output[3] = {-2, -2, -2}; + Read wrapped_input{input}; - 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, Write{output}); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(equal(output, expected_output)); + assert(equal(input, expected_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); + auto result = move(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(equal(output, expected_output)); + assert(equal(input, expected_input)); + } } } }; int main() { +#ifndef _PREFAST_ // TRANSITION, GH-1030 STATIC_ASSERT((test_in_write(), true)); +#endif // TRANSITION, GH-1030 test_in_write(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_remove/env.lst b/tests/std/tests/P0896R4_ranges_alg_remove/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_remove/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_remove/test.cpp b/tests/std/tests/P0896R4_ranges_alg_remove/test.cpp new file mode 100644 index 00000000000..3ddb3c33703 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_remove/test.cpp @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include +using namespace std; +using P = pair; + +// Validate dangling story +STATIC_ASSERT(same_as{}, 42)), ranges::dangling>); +STATIC_ASSERT(same_as{}, 42)), ranges::subrange>); + +struct instantiator { + static constexpr P expected[3] = {{0, 99}, {2, 99}, {4, 99}}; + + template + static constexpr void call() { +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 +#pragma warning(suppress : 4127) // conditional expression is constant + if (!ranges::contiguous_range || !is_constant_evaluated()) +#endif // TRANSITION, VSO-938163 + { + using ranges::remove, ranges::subrange, ranges::equal, ranges::iterator_t; + + size_t projectionCounter = 0; + auto projection = [&projectionCounter](const P& val) { + ++projectionCounter; + return val.second; + }; + + { // Validate iterator + sentinel overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; + + auto result = remove(wrapped_input.begin(), wrapped_input.end(), 47, projection); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 3)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<3>())); + assert(projectionCounter == ranges::size(input)); + } + + projectionCounter = 0; + + { // Validate range overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; + + auto result = remove(wrapped_input, 47, projection); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 3)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<3>())); + assert(projectionCounter == ranges::size(input)); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_fwd(), true)); + test_fwd(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_remove_copy/env.lst b/tests/std/tests/P0896R4_ranges_alg_remove_copy/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_remove_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_remove_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_remove_copy/test.cpp new file mode 100644 index 00000000000..e5228540ed6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_remove_copy/test.cpp @@ -0,0 +1,76 @@ +// 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 remove_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)), + ranges::remove_copy_result>); +STATIC_ASSERT(same_as{}, static_cast(nullptr), 42)), + ranges::remove_copy_result>); + +struct instantiator { + static constexpr P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + static constexpr P expected[3] = {{0, 99}, {2, 99}, {4, 99}}; + + template > Write> + static constexpr void call() { + // Fails checking the indirect_binary_predicate requirement in C1XX's permissive mode with proxy iterators + // (probably related to VSO-566808) + constexpr bool non_proxy = + is_reference_v> && is_reference_v>; + if constexpr (non_proxy || !is_permissive) { + using ranges::remove_copy, ranges::remove_copy_result, ranges::equal, ranges::iterator_t; + + size_t projectionCounter = 0; + auto projection = [&projectionCounter](const P& val) { + ++projectionCounter; + return val.second; + }; + + { // Validate iterator + sentinel overload + P output[3] = {{-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + + auto result = remove_copy(wrapped_input.begin(), wrapped_input.end(), Write{output}, 47, projection); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(equal(output, expected)); + assert(projectionCounter == ranges::size(input)); + } + + projectionCounter = 0; + + { // Validate range overload + P output[3] = {{-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + + auto result = remove_copy(wrapped_input, Write{output}, 47, projection); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(equal(output, expected)); + assert(projectionCounter == ranges::size(input)); + } + } + } +}; + +int main() { +#ifndef _PREFAST_ // TRANSITION, GH-1030 + STATIC_ASSERT((test_in_write(), true)); +#endif // TRANSITION, GH-1030 + test_in_write(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_remove_copy_if/env.lst b/tests/std/tests/P0896R4_ranges_alg_remove_copy_if/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_remove_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_remove_copy_if/test.cpp b/tests/std/tests/P0896R4_ranges_alg_remove_copy_if/test.cpp new file mode 100644 index 00000000000..23453dccd76 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_remove_copy_if/test.cpp @@ -0,0 +1,77 @@ +// 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 = [](const int val) { return val == 47; }; + +// Validate that remove_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)), + ranges::remove_copy_if_result>); +STATIC_ASSERT(same_as{}, static_cast(nullptr), matches)), + ranges::remove_copy_if_result>); + +struct instantiator { + static constexpr P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + static constexpr P expected[3] = {{0, 99}, {2, 99}, {4, 99}}; + + template > Write> + static constexpr void call() { + // Fails checking the indirect_binary_predicate requirement in C1XX's permissive mode with proxy iterators + // (probably related to VSO-566808) + constexpr bool non_proxy = + is_reference_v> && is_reference_v>; + if constexpr (non_proxy || !is_permissive) { + using ranges::remove_copy_if, ranges::remove_copy_if_result, ranges::equal, ranges::iterator_t; + + size_t projectionCounter = 0; + auto projection = [&projectionCounter](const P& val) { + ++projectionCounter; + return val.second; + }; + + { // Validate iterator + sentinel overload + P output[3] = {{-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + auto result = + remove_copy_if(wrapped_input.begin(), wrapped_input.end(), Write{output}, matches, projection); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(equal(output, expected)); + assert(projectionCounter == ranges::size(input)); + } + + projectionCounter = 0; + + { // Validate range overload + P output[3] = {{-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + auto result = remove_copy_if(wrapped_input, Write{output}, matches, projection); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 3); + assert(equal(output, expected)); + assert(projectionCounter == ranges::size(input)); + } + } + } +}; + +int main() { +#ifndef _PREFAST_ // TRANSITION, GH-1030 + STATIC_ASSERT((test_in_write(), true)); +#endif // TRANSITION, GH-1030 + test_in_write(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_remove_if/env.lst b/tests/std/tests/P0896R4_ranges_alg_remove_if/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_remove_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_remove_if/test.cpp b/tests/std/tests/P0896R4_ranges_alg_remove_if/test.cpp new file mode 100644 index 00000000000..863a0e28917 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_remove_if/test.cpp @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include +using namespace std; +using P = pair; + +constexpr auto matches = [](const int val) { return val == 47; }; + +// Validate dangling story +STATIC_ASSERT(same_as{}, matches)), ranges::dangling>); +STATIC_ASSERT(same_as{}, matches)), ranges::subrange>); + +struct instantiator { + static constexpr P expected[3] = {{0, 99}, {2, 99}, {4, 99}}; + + template + static constexpr void call() { +#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163 +#pragma warning(suppress : 4127) // conditional expression is constant + if (!ranges::contiguous_range || !is_constant_evaluated()) +#endif // TRANSITION, VSO-938163 + { + using ranges::remove_if, ranges::subrange, ranges::equal, ranges::iterator_t; + + size_t projectionCounter = 0; + auto projection = [&projectionCounter](const P& val) { + ++projectionCounter; + return val.second; + }; + + { // Validate iterator + sentinel overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; + + auto result = remove_if(wrapped_input.begin(), wrapped_input.end(), matches, projection); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 3)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<3>())); + assert(projectionCounter == ranges::size(input)); + } + + projectionCounter = 0; + + { // Validate range overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; + + auto result = remove_if(wrapped_input, matches, projection); + STATIC_ASSERT(same_as>>); + assert(result.begin() == next(wrapped_input.begin(), 3)); + assert(result.end() == wrapped_input.end()); + assert(equal(expected, span{input}.first<3>())); + assert(projectionCounter == ranges::size(input)); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_fwd(), true)); + test_fwd(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_replace_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_replace_copy/test.cpp index 965c5ecd5ac..6d07fb598f1 100644 --- a/tests/std/tests/P0896R4_ranges_alg_replace_copy/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_replace_copy/test.cpp @@ -15,23 +15,18 @@ using P = pair; STATIC_ASSERT(same_as, ranges::in_out_result>); // Validate dangling story -STATIC_ASSERT(same_as{}, static_cast(nullptr), 42, 5)), +STATIC_ASSERT(same_as{}, nullptr_to, 42, 5)), ranges::replace_copy_result>); -STATIC_ASSERT(same_as{}, static_cast(nullptr), 42, 5)), +STATIC_ASSERT(same_as{}, nullptr_to, 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; + using ranges::replace_copy, ranges::replace_copy_result, ranges::equal, ranges::iterator_t; { // Validate iterator + sentinel overload P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; Read wrapped_input{input}; @@ -41,7 +36,7 @@ struct instantiator { STATIC_ASSERT(same_as, Write>>); assert(result.in == wrapped_input.end()); assert(result.out.peek() == output + 5); - eq(output); + assert(equal(output, expected)); } { // Validate range overload P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; @@ -51,12 +46,14 @@ struct instantiator { STATIC_ASSERT(same_as, Write>>); assert(result.in == wrapped_input.end()); assert(result.out.peek() == output + 5); - eq(output); + assert(equal(output, expected)); } } }; int main() { +#ifndef _PREFAST_ // TRANSITION, GH-1030 STATIC_ASSERT((input_range_output_iterator_permutations(), true)); +#endif // TRANSITION, GH-1030 input_range_output_iterator_permutations(); } 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 index 0048304155c..76eba760270 100644 --- a/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/test.cpp @@ -17,23 +17,18 @@ constexpr auto matches = [](int const val) { return val == 47; }; STATIC_ASSERT(same_as, ranges::in_out_result>); // Validate dangling story -STATIC_ASSERT(same_as{}, static_cast(nullptr), matches, 5)), +STATIC_ASSERT(same_as{}, nullptr_to, matches, 5)), ranges::replace_copy_if_result>); -STATIC_ASSERT(same_as{}, static_cast(nullptr), matches, 5)), +STATIC_ASSERT(same_as{}, nullptr_to, 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; + using ranges::replace_copy_if, ranges::replace_copy_if_result, ranges::equal, ranges::iterator_t; { // Validate iterator + sentinel overload P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; Read wrapped_input{input}; @@ -43,7 +38,7 @@ struct instantiator { STATIC_ASSERT(same_as, Write>>); assert(result.in == wrapped_input.end()); assert(result.out.peek() == output + 5); - eq(output); + assert(equal(output, expected)); } { // Validate range overload P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; @@ -53,12 +48,14 @@ struct instantiator { STATIC_ASSERT(same_as, Write>>); assert(result.in == wrapped_input.end()); assert(result.out.peek() == output + 5); - eq(output); + assert(equal(output, expected)); } } }; int main() { +#ifndef _PREFAST_ // TRANSITION, GH-1030 STATIC_ASSERT((input_range_output_iterator_permutations(), true)); +#endif // TRANSITION, GH-1030 input_range_output_iterator_permutations(); } diff --git a/tests/std/tests/P0896R4_ranges_alg_reverse/env.lst b/tests/std/tests/P0896R4_ranges_alg_reverse/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_reverse/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_reverse/test.cpp b/tests/std/tests/P0896R4_ranges_alg_reverse/test.cpp new file mode 100644 index 00000000000..53d0251a472 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_reverse/test.cpp @@ -0,0 +1,183 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// Validate dangling story +STATIC_ASSERT(same_as{})), ranges::dangling>); +STATIC_ASSERT(same_as{})), int*>); + +struct nontrivial_int { + int val; + + constexpr nontrivial_int(int i) noexcept : val{i} {} + constexpr nontrivial_int(const nontrivial_int& that) noexcept : val{that.val} {} + constexpr nontrivial_int& operator=(const nontrivial_int& that) noexcept { + val = that.val; + return *this; + } + + auto operator<=>(const nontrivial_int&) const = default; +}; + +struct instantiator { + static constexpr nontrivial_int expected_odd[] = {1367, 42, 13}; + static constexpr nontrivial_int expected_even[] = {1729, 1367, 42, 13}; + + template + static constexpr void call() { + using ranges::reverse, ranges::equal, ranges::iterator_t; + + { // Validate iterator + sentinel overload, odd length + nontrivial_int input[] = {13, 42, 1367}; + R wrapped_input{input}; + auto result = reverse(wrapped_input.begin(), wrapped_input.end()); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(equal(input, expected_odd)); + } + { // Validate range overload, odd length + nontrivial_int input[] = {13, 42, 1367}; + R wrapped_input{input}; + auto result = reverse(wrapped_input); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(equal(input, expected_odd)); + } + { // Validate iterator + sentinel overload, even length + nontrivial_int input[] = {13, 42, 1367, 1729}; + R wrapped_input{input}; + auto result = reverse(wrapped_input.begin(), wrapped_input.end()); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(equal(input, expected_even)); + } + { // Validate range overload, even length + nontrivial_int input[] = {13, 42, 1367, 1729}; + R wrapped_input{input}; + auto result = reverse(wrapped_input); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(equal(input, expected_even)); + } + { // Validate iterator + sentinel overload, empty range + R wrapped_input{}; + auto result = reverse(wrapped_input.begin(), wrapped_input.end()); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + } + { // Validate range overload, empty range + R wrapped_input{}; + auto result = reverse(wrapped_input); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + } + } +}; + +template +struct bytes { + unsigned char storage[N]; + + constexpr bytes(unsigned char base) { + iota(storage, storage + N, base); + } + + bool operator==(const bytes&) const = default; +}; + +struct test_vector { + template + static constexpr void call() { + using ranges::reverse, ranges::equal, ranges::iterator_t; + + { // Validate iterator + sentinel overload, vectorizable odd length + ranges::range_value_t input[]{0x10, 0x20, 0x30}; + R wrapped_input{input}; + auto result = reverse(wrapped_input.begin(), wrapped_input.end()); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(equal(input, initializer_list>{0x30, 0x20, 0x10})); + } + { // Validate range overload, vectorizable odd length + ranges::range_value_t input[]{0x10, 0x20, 0x30}; + R wrapped_input{input}; + auto result = reverse(wrapped_input); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(equal(input, initializer_list>{0x30, 0x20, 0x10})); + } + + { // Validate iterator + sentinel overload, vectorizable even length + ranges::range_value_t input[]{0x10, 0x20, 0x30, 0x40}; + R wrapped_input{input}; + auto result = reverse(wrapped_input.begin(), wrapped_input.end()); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(equal(input, initializer_list>{0x40, 0x30, 0x20, 0x10})); + } + { // Validate range overload, vectorizable even length + ranges::range_value_t input[]{0x10, 0x20, 0x30, 0x40}; + R wrapped_input{input}; + auto result = reverse(wrapped_input); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(equal(input, initializer_list>{0x40, 0x30, 0x20, 0x10})); + } + + { // Validate iterator + sentinel overload, vectorizable empty + R wrapped_input{}; + auto result = reverse(wrapped_input.begin(), wrapped_input.end()); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + } + { // Validate range overload, vectorizable empty + R wrapped_input{}; + auto result = reverse(wrapped_input); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + } + } +}; + +int main() { +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 + STATIC_ASSERT((test_bidi(), true)); +#endif // TRANSITION, VSO-938163 + test_bidi(); + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 + STATIC_ASSERT((test_contiguous>(), true)); +#endif // TRANSITION, VSO-938163 + test_contiguous>(); + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 + STATIC_ASSERT((test_contiguous>(), true)); +#endif // TRANSITION, VSO-938163 + test_contiguous>(); + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 + STATIC_ASSERT((test_contiguous>(), true)); +#endif // TRANSITION, VSO-938163 + test_contiguous>(); + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 + STATIC_ASSERT((test_contiguous>(), true)); +#endif // TRANSITION, VSO-938163 + test_contiguous>(); + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 + STATIC_ASSERT((test_contiguous>(), true)); +#endif // TRANSITION, VSO-938163 + test_contiguous>(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_transform_binary/env.lst b/tests/std/tests/P0896R4_ranges_alg_transform_binary/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_transform_binary/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_transform_binary/test.cpp b/tests/std/tests/P0896R4_ranges_alg_transform_binary/test.cpp new file mode 100644 index 00000000000..11c31b21f0c --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_transform_binary/test.cpp @@ -0,0 +1,128 @@ +// 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 binary_transform_result aliases in_in_out_result +STATIC_ASSERT(same_as, ranges::in_in_out_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, borrowed{}, nullptr_to, plus{})), + ranges::binary_transform_result>); +STATIC_ASSERT(same_as{}, borrowed{}, nullptr_to, plus{})), + ranges::binary_transform_result>); +STATIC_ASSERT(same_as{}, borrowed{}, nullptr_to, plus{})), + ranges::binary_transform_result>); +STATIC_ASSERT(same_as{}, borrowed{}, nullptr_to, plus{})), + ranges::binary_transform_result>); + +struct instantiator { + static constexpr P input1[3] = {{1, 99}, {4, 98}, {5, 97}}; + static constexpr P input2[3] = {{99, 6}, {98, 7}, {97, 8}}; + static constexpr int expected[3] = {7, 11, 13}; + + static constexpr P shortInput1[2] = {{1, 99}, {4, 98}}; + static constexpr P shortInput2[2] = {{99, 6}, {98, 7}}; + static constexpr int shortExpected[2] = {7, 11}; + + template + static constexpr void call() { + using ranges::transform, ranges::binary_transform_result, ranges::iterator_t; + { // Validate iterator + sentinel overload, first range shorter + int output[2] = {-1, -1}; + Read1 wrapped_in1{shortInput1}; + Read2 wrapped_in2{input2}; + + auto result = transform(wrapped_in1.begin(), wrapped_in1.end(), wrapped_in2.begin(), wrapped_in2.end(), + Write{output}, plus{}, get_first, get_second); + STATIC_ASSERT( + same_as, iterator_t, Write>>); + assert(result.in1 == wrapped_in1.end()); + assert(next(result.in2) == wrapped_in2.end()); + assert(result.out.peek() == output + 2); + assert(ranges::equal(output, shortExpected)); + } + { // Validate iterator + sentinel overload, second range shorter + int output[2] = {-1, -1}; + Read1 wrapped_in1{input1}; + Read2 wrapped_in2{shortInput2}; + + auto result = transform(wrapped_in1.begin(), wrapped_in1.end(), wrapped_in2.begin(), wrapped_in2.end(), + Write{output}, plus{}, get_first, get_second); + STATIC_ASSERT( + same_as, iterator_t, Write>>); + assert(next(result.in1) == wrapped_in1.end()); + assert(result.in2 == wrapped_in2.end()); + assert(result.out.peek() == output + 2); + assert(ranges::equal(output, shortExpected)); + } + { // Validate range overload, first range shorter + int output[2] = {-1, -1}; + Read1 wrapped_in1{shortInput1}; + Read2 wrapped_in2{input2}; + + auto result = transform(wrapped_in1, wrapped_in2, Write{output}, plus{}, get_first, get_second); + STATIC_ASSERT( + same_as, iterator_t, Write>>); + assert(result.in1 == wrapped_in1.end()); + assert(next(result.in2) == wrapped_in2.end()); + assert(result.out.peek() == output + 2); + assert(ranges::equal(output, shortExpected)); + } + { // Validate range overload, second range shorter + int output[2] = {-1, -1}; + Read1 wrapped_in1{input1}; + Read2 wrapped_in2{shortInput2}; + + auto result = transform(wrapped_in1, wrapped_in2, Write{output}, plus{}, get_first, get_second); + STATIC_ASSERT( + same_as, iterator_t, Write>>); + assert(next(result.in1) == wrapped_in1.end()); + assert(result.in2 == wrapped_in2.end()); + assert(result.out.peek() == output + 2); + assert(ranges::equal(output, shortExpected)); + } + } +}; + +using Elem1 = const P; +using Elem2 = const P; +using Elem3 = int; + +#ifdef TEST_EVERYTHING +int main() { + // No constexpr test here; the test_in_in_write call exceeds the maximum number of steps in a constexpr computation. + test_in_in_write(); +} +#else // ^^^ test all range combinations // test only interesting range combos vvv +template +using in_test_range = test::range; +template +using out_test_iterator = + test::iterator; + +constexpr bool run_tests() { + // All (except contiguous) proxy reference types, since the algorithm doesn't really care. + using test::Common, test::Sized; + + // both input, non-common, and sized or unsized + instantiator::call, in_test_range, out_test_iterator>(); + instantiator::call, in_test_range, out_test_iterator>(); + return true; +} + +int main() { + STATIC_ASSERT(run_tests()); + run_tests(); +} +#endif // TEST_EVERYTHING diff --git a/tests/std/tests/P0896R4_ranges_alg_transform_unary/env.lst b/tests/std/tests/P0896R4_ranges_alg_transform_unary/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_transform_unary/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_transform_unary/test.cpp b/tests/std/tests/P0896R4_ranges_alg_transform_unary/test.cpp new file mode 100644 index 00000000000..3d65ceb8996 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_transform_unary/test.cpp @@ -0,0 +1,59 @@ +// 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 unary_transform_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +constexpr auto minus_one = [](const int x) { return x - 1; }; + +// Validate dangling story +STATIC_ASSERT(same_as{}, nullptr_to, minus_one)), + ranges::unary_transform_result>); +STATIC_ASSERT(same_as{}, nullptr_to, minus_one)), + ranges::unary_transform_result>); + +struct instantiator { + static constexpr P input[3] = {{1, 99}, {4, 98}, {5, 97}}; + static constexpr int expected[3] = {0, 3, 4}; + + template + static constexpr void call() { + using ranges::transform, ranges::unary_transform_result, ranges::iterator_t; + { // Validate iterator + sentinel overload + int output[3] = {-1, -1, -1}; + Read wrapped_in{input}; + + auto result = transform(wrapped_in.begin(), wrapped_in.end(), Write{output}, minus_one, get_first); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_in.end()); + assert(result.out.peek() == output + 3); + assert(ranges::equal(output, expected)); + } + { // Validate range overload + int output[3] = {-1, -1, -1}; + Read wrapped_in{input}; + + auto result = transform(wrapped_in, Write{output}, minus_one, get_first); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_in.end()); + assert(result.out.peek() == output + 3); + assert(ranges::equal(output, expected)); + } + } +}; + +int main() { + STATIC_ASSERT((test_in_write(), true)); + test_in_write(); +} diff --git a/tests/std/tests/P0896R4_ranges_test_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_test_machinery/test.cpp index 29235e1ecaa..ce114438a6f 100644 --- a/tests/std/tests/P0896R4_ranges_test_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_test_machinery/test.cpp @@ -26,9 +26,8 @@ constexpr bool iter_test() { STATIC_ASSERT(!movable || indirectly_writable); - constexpr bool can_write = - derived_from || (derived_from && assignable_from); + constexpr bool can_write = derived_from // + || (derived_from && assignable_from); STATIC_ASSERT(!can_write || output_iterator); STATIC_ASSERT(!derived_from || input_iterator); @@ -44,7 +43,11 @@ constexpr bool iter_test() { STATIC_ASSERT(!to_bool(Eq) || !to_bool(Diff) || sized_sentinel_for); if constexpr (to_bool(Wrapped)) { - STATIC_ASSERT(same_as<_Unwrapped_t, iterator>); + if constexpr (derived_from) { + STATIC_ASSERT(same_as<_Unwrapped_t, Element*>); + } else { + STATIC_ASSERT(same_as<_Unwrapped_t, iterator>); + } STATIC_ASSERT(same_as<_Unwrapped_t, sentinel>); } diff --git a/tests/std/tests/P0898R3_concepts/test.cpp b/tests/std/tests/P0898R3_concepts/test.cpp index 890f0381d2b..80c224e7df3 100644 --- a/tests/std/tests/P0898R3_concepts/test.cpp +++ b/tests/std/tests/P0898R3_concepts/test.cpp @@ -2407,7 +2407,8 @@ namespace test_boolean_testable { struct Archetype { // clang-format off operator bool() const requires (Select != 0); // Archetype<0> is not implicitly convertible to bool - explicit operator bool() const requires (Select < 2); // Archetype<1> is not explicitly convertible to bool (ambiguity) + explicit operator bool() const requires (Select < 2); // Archetype<1> is not explicitly convertible + // to bool (ambiguity) void operator!() const requires (Select == 2); // !Archetype<2> does not model _Boolean_testable_impl // clang-format on }; diff --git a/tests/std/tests/concepts_matrix.lst b/tests/std/tests/concepts_matrix.lst index 37b0a2358be..8414e31b200 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" # TRANSITION, GH-1030 +PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /analyze:only" 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" # TRANSITION, GH-1030 +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /analyze:only" PM_CL="/Za /MD /permissive-" PM_CL="/Za /MDd /permissive-" # PM_CL="/BE /c /MD" diff --git a/tests/tr1/include/tspec_random.h b/tests/tr1/include/tspec_random.h index 64c6e6c4b6b..9580a50b323 100644 --- a/tests/tr1/include/tspec_random.h +++ b/tests/tr1/include/tspec_random.h @@ -8,11 +8,12 @@ using namespace std; // COMMON TYPES #define FLIT(x) x -#define TESTR(fun) do_random_test::gen_data(fun##_dist, fun##_vals, fun##_smaller_ok, fun##_larger_ok) #define BINSIZE 100 #define SAMPLESIZE 100000 #define CHI_SQUARED_FAIL_LIMIT 125.0 +#define TESTR(fun) do_random_test::gen_data(fun##_dist, fun##_vals, fun##_smaller_ok, fun##_larger_ok) + typedef struct One_arg { // argument plus return value Float_type arg1; Float_type ans;