From 182ba2115d76916bcd302603d530d66d47649a2b Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Sun, 5 Jul 2020 13:48:16 +0200 Subject: [PATCH 1/2] Implement ranges::replace_copy_if --- stl/inc/algorithm | 61 +++++++++++++++++++ tests/std/test.lst | 1 + .../env.lst | 4 ++ .../test.cpp | 57 +++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 tests/std/tests/P0896R4_ranges_alg_replace_copy_if/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_replace_copy_if/test.cpp diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 59db8eb1959..985a1110a02 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3095,6 +3095,67 @@ _FwdIt2 replace_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _ #ifdef __cpp_lib_concepts namespace ranges { + // ALIAS TEMPLATE replace_copy_result + template + 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 _Se, class _Ty1, output_iterator _Out, + class _Pj = identity, indirect_unary_predicate> _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 _Out, class _Pj = identity, + indirect_unary_predicate> _Pr> + requires indirectly_copyable, _Out> + constexpr replace_copy_if_result, _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 + _NODISCARD 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) const { + // 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: diff --git a/tests/std/test.lst b/tests/std/test.lst index 6358d0afa94..20bd268742f 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_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_copy_if/env.lst b/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_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_replace_copy_if/test.cpp b/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/test.cpp new file mode 100644 index 00000000000..322ccbe306c --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_replace_copy_if/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; + +constexpr auto matches = [](int const val) { return val == 47; }; + +// Validate that replace_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, 5)), + ranges::replace_copy_if_result>); +STATIC_ASSERT(same_as{}, static_cast(nullptr), 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}}; + + template + static constexpr void call() { + using ranges::replace_copy_if; + { // Validate iterator + sentinel overload + Read wrapped_input{input}; + + auto result = replace_copy_if( + wrapped_input.begin(), wrapped_input.end(), Write{output}, matches, 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 + Read wrapped_input{input}; + + auto result = replace_copy_if(wrapped_input, Write{output}, matches, 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(); +} From 4615afe629d14d2f5deffea65b8af2390a652476 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Sun, 5 Jul 2020 19:24:19 +0200 Subject: [PATCH 2/2] Assress review comments --- stl/inc/algorithm | 12 ++++++------ .../P0896R4_ranges_alg_replace_copy_if/test.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 985a1110a02..2153b254800 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3095,7 +3095,7 @@ _FwdIt2 replace_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _ #ifdef __cpp_lib_concepts namespace ranges { - // ALIAS TEMPLATE replace_copy_result + // ALIAS TEMPLATE replace_copy_if_result template using replace_copy_if_result = in_out_result<_In, _Out>; @@ -3105,7 +3105,7 @@ namespace ranges { using _Not_quite_object::_Not_quite_object; // clang-format off - template _Se, class _Ty1, output_iterator _Out, + template _Se, class _Ty, output_iterator _Out, class _Pj = identity, indirect_unary_predicate> _Pr> requires indirectly_copyable<_It, _Out> constexpr replace_copy_if_result<_It, _Out> operator()( @@ -3118,8 +3118,8 @@ namespace ranges { return {_STD move(_First), _STD move(_UResult.out)}; } - template _Out, class _Pj = identity, - indirect_unary_predicate> _Pr> + template _Out, class _Pj = identity, + indirect_unary_predicate, _Pj>> _Pr> requires indirectly_copyable, _Out> constexpr replace_copy_if_result, _Out> operator()( _Rng&& _Range, _Out _Result, _Pr _Pred, const _Ty& _Newval, _Pj _Proj = {}) const { @@ -3133,8 +3133,8 @@ namespace ranges { // clang-format on private: template - _NODISCARD 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) const { + _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>); 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 322ccbe306c..ad72b5be064 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 @@ -26,11 +26,12 @@ 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 + template > Write> static constexpr void call() { - using ranges::replace_copy_if; + 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); @@ -41,6 +42,7 @@ struct instantiator { } { // 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, Write>>);