Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions stl/inc/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -3029,6 +3029,63 @@ template <class _ExPo, class _FwdIt, class _Pr, class _Ty, _Enable_if_execution_
void replace_if(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _Pred, const _Ty& _Val) noexcept; // terminates
#endif // _HAS_CXX17

#ifdef __cpp_lib_concepts
namespace ranges {
// VARIABLE ranges::replace_if
class _Replace_if_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;

// clang-format off
template <input_iterator _It, sentinel_for<_It> _Se, class _Ty, class _Pj = identity,
indirect_unary_predicate<projected<_It, _Pj>> _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 <input_range _Rng, class _Ty, class _Pj = identity,
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
requires indirectly_writable<iterator_t<_Rng>, 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 <class _It, class _Se, class _Ty, class _Pj, class _Pr>
_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)
Comment on lines +3068 to +3069
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I observe that there is no variable named _Oldval in this function - but this isn't confusing, so it's not worth changing to "value". No change requested.

_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 <class _InIt, class _OutIt, class _Ty>
_CONSTEXPR20 _OutIt replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Oldval, const _Ty& _Newval) {
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_replace_if/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\concepts_matrix.lst
50 changes: 50 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_replace_if/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
#include <cassert>
#include <concepts>
#include <ranges>
#include <utility>

#include <range_algorithm_support.hpp>
using namespace std;
using P = pair<int, int>;

constexpr auto matches = [](int const val) { return val == 47; };

// Validate dangling story
STATIC_ASSERT(same_as<decltype(ranges::replace_if(borrowed<false>{}, matches, 5)), ranges::dangling>);
STATIC_ASSERT(same_as<decltype(ranges::replace_if(borrowed<true>{}, matches, 5)), int*>);

struct instantiator {
static constexpr P output[5] = {{0, 99}, {47, 1}, {2, 99}, {47, 1}, {4, 99}};

template <ranges::input_range Read>
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<decltype(result), ranges::iterator_t<Read>>);
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<decltype(result), ranges::iterator_t<Read>>);
assert(result == wrapped_input.end());
assert(ranges::equal(output, input));
}
}
};

int main() {
STATIC_ASSERT((test_in<instantiator, P>(), true));
test_in<instantiator, P>();
}