diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 59db8eb1959..798dddaf741 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3029,6 +3029,63 @@ template _Se, class _Ty, class _Pj = identity, + indirect_unary_predicate> _Pr> + requires indirectly_writable<_It, const _Ty&> + constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) const { + _Adl_verify_range(_First, _Last); + auto _UResult = _Replace_if_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), + _Pass_fn(_Pred), _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + + template , _Pj>> _Pr> + requires indirectly_writable, const _Ty&> + constexpr borrowed_iterator_t<_Rng> operator()( + _Rng&& _Range, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) const { + auto _First = _RANGES begin(_Range); + auto _UResult = _Replace_if_unchecked( + _Get_unwrapped(_STD move(_First)), _Uend(_Range), _Pass_fn(_Pred), _Newval, _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult)); + return _First; + } + // clang-format on + private: + template + _NODISCARD static constexpr _It _Replace_if_unchecked( + _It _First, const _Se _Last, _Pr _Pred, const _Ty& _Newval, _Pj _Proj) { + // replace projected _Oldval that fulfills _Pred with _Newval in [_First, _Last) + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_writable<_It, const _Ty&>); + _STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>); + + for (; _First != _Last; ++_First) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) { + *_First = _Newval; + } + } + + return _First; + } + }; + + inline constexpr _Replace_if_fn replace_if{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE replace_copy template _CONSTEXPR20 _OutIt replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Oldval, const _Ty& _Newval) { diff --git a/tests/std/test.lst b/tests/std/test.lst index 6358d0afa94..98930beaa8b 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_if 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_if/env.lst b/tests/std/tests/P0896R4_ranges_alg_replace_if/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_if/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_replace_if/test.cpp b/tests/std/tests/P0896R4_ranges_alg_replace_if/test.cpp new file mode 100644 index 00000000000..3f0f41cd48c --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_if/test.cpp @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include +using namespace std; +using P = pair; + +constexpr auto matches = [](int const val) { return val == 47; }; + +// Validate dangling story +STATIC_ASSERT(same_as{}, matches, 5)), ranges::dangling>); +STATIC_ASSERT(same_as{}, matches, 5)), int*>); + +struct instantiator { + static constexpr P output[5] = {{0, 99}, {47, 1}, {2, 99}, {47, 1}, {4, 99}}; + + template + static constexpr void call() { + using ranges::replace_if; + { // Validate iterator + sentinel overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; + + auto result = replace_if(wrapped_input.begin(), wrapped_input.end(), matches, P{47, 1}, get_second); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(ranges::equal(output, input)); + } + { // Validate range overload + P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}}; + Read wrapped_input{input}; + + auto result = replace_if(wrapped_input, matches, P{47, 1}, get_second); + STATIC_ASSERT(same_as>); + assert(result == wrapped_input.end()); + assert(ranges::equal(output, input)); + } + } +}; + +int main() { + STATIC_ASSERT((test_in(), true)); + test_in(); +}