diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 59db8eb1959..9eb337a33d4 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3061,6 +3061,72 @@ _FwdIt2 replace_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, cons } #endif // _HAS_CXX17 +#ifdef __cpp_lib_concepts +namespace ranges { + // ALIAS TEMPLATE replace_copy_result + template + using replace_copy_result = in_out_result<_In, _Out>; + + // VARIABLE ranges::replace_copy + class _Replace_copy_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, class _Ty1, class _Ty2, output_iterator _Out, + class _Pj = identity> + requires indirectly_copyable<_It, _Out> + && indirect_binary_predicate, const _Ty1*> + constexpr replace_copy_result<_It, _Out> operator()( + _It _First, _Se _Last, _Out _Result, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Replace_copy_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), + _STD move(_Result), _Oldval, _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; + } + + template _Out, class _Pj = identity> + requires indirectly_copyable, _Out> + && indirect_binary_predicate, _Pj>, const _Ty1*> + constexpr replace_copy_result, _Out> operator()( + _Rng&& _Range, _Out _Result, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj = {}) const { + auto _First = _RANGES begin(_Range); + auto _UResult = _Replace_copy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), + _STD move(_Result), _Oldval, _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.out)}; + } + // clang-format on + private: + template + _NODISCARD static constexpr replace_copy_result<_It, _Out> _Replace_copy_unchecked( + _It _First, const _Se _Last, _Out _Result, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj) { + // copy [_First, _Last) to _Out while replacing projected _Oldval with _Newval + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(output_iterator<_Out, const _Ty2&>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>); + _STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate, const _Ty1*>); + + for (; _First != _Last; ++_First, (void) ++_Result) { + if (_STD invoke(_Proj, *_First) == _Oldval) { + *_Result = _Newval; + } else { + *_Result = *_First; + } + } + + return {_STD move(_First), _STD move(_Result)}; + } + }; + + inline constexpr _Replace_copy_fn replace_copy{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE replace_copy_if template _CONSTEXPR20 _OutIt replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, const _Ty& _Val) { diff --git a/tests/std/test.lst b/tests/std/test.lst index 6358d0afa94..0bc981730c4 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -261,6 +261,7 @@ tests\P0896R4_ranges_alg_minmax tests\P0896R4_ranges_alg_mismatch tests\P0896R4_ranges_alg_move tests\P0896R4_ranges_alg_none_of +tests\P0896R4_ranges_alg_replace_copy tests\P0896R4_ranges_alg_search tests\P0896R4_ranges_alg_search_n tests\P0896R4_ranges_alg_swap_ranges diff --git a/tests/std/tests/P0896R4_ranges_alg_replace_copy/env.lst b/tests/std/tests/P0896R4_ranges_alg_replace_copy/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_copy/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_replace_copy/test.cpp b/tests/std/tests/P0896R4_ranges_alg_replace_copy/test.cpp new file mode 100644 index 00000000000..c89f547acf7 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_copy/test.cpp @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include +using namespace std; +using P = pair; + +// Validate that replace_copy_result aliases in_out_result +STATIC_ASSERT(same_as, ranges::in_out_result>); + +// Validate dangling story +STATIC_ASSERT(same_as{}, static_cast(nullptr), 42, 5)), + ranges::replace_copy_result>); +STATIC_ASSERT(same_as{}, static_cast(nullptr), 42, 5)), + ranges::replace_copy_result>); + +struct instantiator { + static constexpr P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + static constexpr P expected[5] = {{0, 99}, {47, 1}, {2, 99}, {47, 1}, {4, 99}}; + + template > Write> + static constexpr void call() { + using ranges::replace_copy, ranges::replace_copy_result, ranges::iterator_t; + { // Validate iterator + sentinel overload + P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + + auto result = + replace_copy(wrapped_input.begin(), wrapped_input.end(), Write{output}, 47, P{47, 1}, get_second); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 5); + assert(ranges::equal(output, expected)); + } + { // Validate range overload + P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + Read wrapped_input{input}; + + auto result = replace_copy(wrapped_input, Write{output}, 47, P{47, 1}, get_second); + STATIC_ASSERT(same_as, Write>>); + assert(result.in == wrapped_input.end()); + assert(result.out.peek() == output + 5); + assert(ranges::equal(output, expected)); + } + } +}; + +int main() { + STATIC_ASSERT((test_in_write(), true)); + test_in_write(); +}