Skip to content

Commit

Permalink
Implement ranges::replace_copy_if
Browse files Browse the repository at this point in the history
  • Loading branch information
miscco committed Jul 8, 2020
1 parent d275944 commit fe6d75c
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 0 deletions.
61 changes: 61 additions & 0 deletions stl/inc/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -3276,6 +3276,67 @@ _FwdIt2 replace_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _

#ifdef __cpp_lib_concepts
namespace ranges {
// ALIAS TEMPLATE replace_copy_if_result
template <class _In, class _Out>
using replace_copy_if_result = in_out_result<_In, _Out>;

// VARIABLE ranges::replace_copy_if
class _Replace_copy_if_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;

// clang-format off
template <input_iterator _It, sentinel_for<_It> _Se, class _Ty, output_iterator<const _Ty&> _Out,
class _Pj = identity, indirect_unary_predicate<projected<_It, _Pj>> _Pr>
requires indirectly_copyable<_It, _Out>
constexpr replace_copy_if_result<_It, _Out> operator()(
_It _First, _Se _Last, _Out _Result, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) const {
_Adl_verify_range(_First, _Last);
auto _UResult = _Replace_copy_if_unchecked(_Get_unwrapped(_STD move(_First)),
_Get_unwrapped(_STD move(_Last)), _STD move(_Result), _Pass_fn(_Pred), _Newval, _Pass_fn(_Proj));

_Seek_wrapped(_First, _STD move(_UResult.in));
return {_STD move(_First), _STD move(_UResult.out)};
}

template <input_range _Rng, class _Ty, output_iterator<const _Ty&> _Out, class _Pj = identity,
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
requires indirectly_copyable<iterator_t<_Rng>, _Out>
constexpr replace_copy_if_result<borrowed_iterator_t<_Rng>, _Out> operator()(
_Rng&& _Range, _Out _Result, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) const {
auto _First = _RANGES begin(_Range);
auto _UResult = _Replace_copy_if_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range),
_STD move(_Result), _Pass_fn(_Pred), _Newval, _Pass_fn(_Proj));

_Seek_wrapped(_First, _STD move(_UResult.in));
return {_STD move(_First), _STD move(_UResult.out)};
}
// clang-format on
private:
template <class _It, class _Se, class _Ty, class _Out, class _Pj, class _Pr>
_NODISCARD static constexpr replace_copy_if_result<_It, _Out> _Replace_copy_if_unchecked(
_It _First, const _Se _Last, _Out _Result, _Pr _Pred, const _Ty& _Newval, _Pj _Proj) {
// copy [_First, _Last) to _Out while replacing _Oldval with _Newval if projected _Oldval fulfuills _Pred
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>);
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>);
_STL_INTERNAL_STATIC_ASSERT(output_iterator<_Out, const _Ty&>);
_STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>);
_STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>);

for (; _First != _Last; ++_First, (void) ++_Result) {
if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) {
*_Result = _Newval;
} else {
*_Result = *_First;
}
}

return {_STD move(_First), _STD move(_Result)};
}
};

inline constexpr _Replace_copy_if_fn replace_copy_if{_Not_quite_object::_Construct_tag{}};

// VARIABLE ranges::fill
class _Fill_fn : private _Not_quite_object {
public:
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ tests\P0896R4_ranges_alg_move
tests\P0896R4_ranges_alg_none_of
tests\P0896R4_ranges_alg_replace
tests\P0896R4_ranges_alg_replace_copy
tests\P0896R4_ranges_alg_replace_copy_if
tests\P0896R4_ranges_alg_replace_if
tests\P0896R4_ranges_alg_search
tests\P0896R4_ranges_alg_search_n
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_replace_copy_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
59 changes: 59 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_replace_copy_if/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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 that replace_copy_if_result aliases in_out_result
STATIC_ASSERT(same_as<ranges::replace_copy_if_result<int, double>, ranges::in_out_result<int, double>>);

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

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 <ranges::input_range Read, ranges::indirectly_writable<ranges::range_reference_t<Read>> Write>
static constexpr void call() {
using ranges::replace_copy_if, ranges::replace_copy_if_result, ranges::iterator_t;
{ // Validate iterator + sentinel overload
Read wrapped_input{input};
P input[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};

auto result = replace_copy_if(
wrapped_input.begin(), wrapped_input.end(), Write{output}, matches, P{47, 1}, get_second);
STATIC_ASSERT(same_as<decltype(result), replace_copy_if_result<iterator_t<Read>, Write>>);
assert(result.in == wrapped_input.end());
assert(result.out.peek() == output + 5);
assert(ranges::equal(output, expected));
}
{ // Validate range overload
Read wrapped_input{input};
P input[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};

auto result = replace_copy_if(wrapped_input, Write{output}, matches, P{47, 1}, get_second);
STATIC_ASSERT(same_as<decltype(result), replace_copy_if_result<iterator_t<Read>, 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<instantiator, P const, P>(), true));
test_in_write<instantiator, P const, P>();
}

0 comments on commit fe6d75c

Please sign in to comment.