зеркало из https://github.com/microsoft/STL.git
Implement ranges::replace, ranges::replace_copy, ranges::replace_copy_if (#983)
Co-authored-by: Casey Carter <Casey@Carter.net> Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
This commit is contained in:
Родитель
294355d4fa
Коммит
f357e2c3cb
|
@ -3286,6 +3286,64 @@ void replace(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty&
|
|||
const _Ty& _Newval) noexcept; // terminates
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::replace
|
||||
class _Replace_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 _Ty1, class _Ty2, class _Pj = identity>
|
||||
requires indirectly_writable<_It, const _Ty2&>
|
||||
&& indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty1*>
|
||||
constexpr _It operator()(
|
||||
_It _First, _Se _Last, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UResult = _Replace_unchecked(
|
||||
_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Oldval, _Newval, _Pass_fn(_Proj));
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UResult));
|
||||
return _First;
|
||||
}
|
||||
|
||||
template <input_range _Rng, class _Ty1, class _Ty2, class _Pj = identity>
|
||||
requires indirectly_writable<iterator_t<_Rng>, const _Ty2&>
|
||||
&& indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Rng>, _Pj>, const _Ty1*>
|
||||
constexpr borrowed_iterator_t<_Rng> operator()(
|
||||
_Rng&& _Range, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj = {}) const {
|
||||
auto _First = _RANGES begin(_Range);
|
||||
auto _UResult = _Replace_unchecked(
|
||||
_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Oldval, _Newval, _Pass_fn(_Proj));
|
||||
|
||||
_Seek_wrapped(_First, _STD move(_UResult));
|
||||
return _First;
|
||||
}
|
||||
// clang-format on
|
||||
private:
|
||||
template <class _It, class _Se, class _Ty1, class _Ty2, class _Pj>
|
||||
_NODISCARD static constexpr _It _Replace_unchecked(
|
||||
_It _First, const _Se _Last, const _Ty1& _Oldval, const _Ty2& _Newval, _Pj _Proj) {
|
||||
// replace projected _Oldval 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 _Ty2&>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty1*>);
|
||||
|
||||
for (; _First != _Last; ++_First) {
|
||||
if (_STD invoke(_Proj, *_First) == _Oldval) {
|
||||
*_First = _Newval;
|
||||
}
|
||||
}
|
||||
|
||||
return _First;
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _Replace_fn replace{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE replace_if
|
||||
template <class _FwdIt, class _Pr, class _Ty>
|
||||
_CONSTEXPR20 void replace_if(const _FwdIt _First, const _FwdIt _Last, _Pr _Pred, const _Ty& _Val) {
|
||||
|
@ -3394,6 +3452,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 <class _In, class _Out>
|
||||
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 <input_iterator _It, sentinel_for<_It> _Se, class _Ty1, class _Ty2, output_iterator<const _Ty2&> _Out,
|
||||
class _Pj = identity>
|
||||
requires indirectly_copyable<_It, _Out>
|
||||
&& indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, 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 <input_range _Rng, class _Ty1, class _Ty2, output_iterator<const _Ty2&> _Out, class _Pj = identity>
|
||||
requires indirectly_copyable<iterator_t<_Rng>, _Out>
|
||||
&& indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Rng>, _Pj>, const _Ty1*>
|
||||
constexpr replace_copy_result<borrowed_iterator_t<_Rng>, _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 <class _It, class _Se, class _Ty1, class _Ty2, class _Out, class _Pj>
|
||||
_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 _Result 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<equal_to, projected<_It, _Pj>, 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 <class _InIt, class _OutIt, class _Pr, class _Ty>
|
||||
_CONSTEXPR20 _OutIt replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, const _Ty& _Val) {
|
||||
|
@ -3428,6 +3552,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 _Result while replacing _Oldval with _Newval if projected _Oldval fulfills _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:
|
||||
|
|
|
@ -627,7 +627,7 @@ template <class I1, class I2>
|
|||
using BinaryPredicateFor = boolish (*)(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>);
|
||||
|
||||
template <class Continuation, class Element>
|
||||
struct with_writable_iterators {
|
||||
struct with_output_iterators {
|
||||
template <class... Args>
|
||||
static constexpr void call() {
|
||||
using namespace test;
|
||||
|
@ -638,10 +638,6 @@ struct with_writable_iterators {
|
|||
iterator<output, Element, CanDifference::no, CanCompare::no, ProxyRef::no>>();
|
||||
Continuation::template call<Args...,
|
||||
iterator<output, Element, CanDifference::no, CanCompare::no, ProxyRef::yes>>();
|
||||
Continuation::template call<Args...,
|
||||
iterator<input, Element, CanDifference::no, CanCompare::no, ProxyRef::no>>();
|
||||
Continuation::template call<Args...,
|
||||
iterator<input, Element, CanDifference::no, CanCompare::no, ProxyRef::yes>>();
|
||||
// For forward and bidi, Eq is necessarily true but Diff and Proxy may vary.
|
||||
Continuation::template call<Args...,
|
||||
iterator<fwd, Element, CanDifference::no, CanCompare::yes, ProxyRef::no>>();
|
||||
|
@ -670,6 +666,23 @@ struct with_writable_iterators {
|
|||
}
|
||||
};
|
||||
|
||||
template <class Continuation, class Element>
|
||||
struct with_writable_iterators {
|
||||
template <class... Args>
|
||||
static constexpr void call() {
|
||||
using namespace test;
|
||||
using test::iterator;
|
||||
|
||||
// Diff and Eq are not significant for "lone" single-pass iterators, so we can ignore them here.
|
||||
Continuation::template call<Args...,
|
||||
iterator<input, Element, CanDifference::no, CanCompare::no, ProxyRef::no>>();
|
||||
Continuation::template call<Args...,
|
||||
iterator<input, Element, CanDifference::no, CanCompare::no, ProxyRef::yes>>();
|
||||
|
||||
with_output_iterators<Continuation, Element>::template call<Args...>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Continuation, class Element>
|
||||
struct with_contiguous_ranges {
|
||||
template <class... Args>
|
||||
|
@ -970,6 +983,11 @@ constexpr void test_contiguous() {
|
|||
with_contiguous_ranges<Instantiator, Element>::call();
|
||||
}
|
||||
|
||||
template <class Instantiator, class Element1, class Element2>
|
||||
constexpr void input_range_output_iterator_permutations() {
|
||||
with_input_ranges<with_output_iterators<Instantiator, Element2>, Element1>::call();
|
||||
}
|
||||
|
||||
template <class Instantiator, class Element1, class Element2>
|
||||
constexpr void test_in_in() {
|
||||
with_input_ranges<with_input_ranges<Instantiator, Element2>, Element1>::call();
|
||||
|
|
|
@ -266,6 +266,9 @@ tests\P0896R4_ranges_alg_none_of
|
|||
tests\P0896R4_ranges_alg_partition
|
||||
tests\P0896R4_ranges_alg_partition_copy
|
||||
tests\P0896R4_ranges_alg_partition_point
|
||||
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
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,48 @@
|
|||
// 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>;
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(same_as<decltype(ranges::replace(borrowed<false>{}, 42, 5)), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::replace(borrowed<true>{}, 42, 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, ranges::iterator_t;
|
||||
{ // Validate iterator + sentinel overload
|
||||
P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}};
|
||||
Read wrapped_input{input};
|
||||
|
||||
auto result = replace(wrapped_input.begin(), wrapped_input.end(), 47, P{47, 1}, get_second);
|
||||
STATIC_ASSERT(same_as<decltype(result), 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(wrapped_input, 47, P{47, 1}, get_second);
|
||||
STATIC_ASSERT(same_as<decltype(result), 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>();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,62 @@
|
|||
// 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>;
|
||||
|
||||
// Validate that replace_copy_result aliases in_out_result
|
||||
STATIC_ASSERT(same_as<ranges::replace_copy_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), 42, 5)),
|
||||
ranges::replace_copy_result<ranges::dangling, int*>>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::replace_copy(borrowed<true>{}, static_cast<int*>(nullptr), 42, 5)),
|
||||
ranges::replace_copy_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}};
|
||||
|
||||
static constexpr void eq(P const (&output)[5]) {
|
||||
// Extracted into a separate function to keep /analyze from exhausting the compiler heap
|
||||
assert(ranges::equal(output, expected));
|
||||
}
|
||||
|
||||
template <ranges::input_range Read, indirectly_writable<ranges::range_reference_t<Read>> 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<decltype(result), replace_copy_result<iterator_t<Read>, Write>>);
|
||||
assert(result.in == wrapped_input.end());
|
||||
assert(result.out.peek() == output + 5);
|
||||
eq(output);
|
||||
}
|
||||
{ // 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<decltype(result), replace_copy_result<iterator_t<Read>, Write>>);
|
||||
assert(result.in == wrapped_input.end());
|
||||
assert(result.out.peek() == output + 5);
|
||||
eq(output);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((input_range_output_iterator_permutations<instantiator, P const, P>(), true));
|
||||
input_range_output_iterator_permutations<instantiator, P const, P>();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,64 @@
|
|||
// 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_if(borrowed<false>{}, static_cast<int*>(nullptr), matches, 5)),
|
||||
ranges::replace_copy_if_result<ranges::dangling, int*>>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::replace_copy_if(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}};
|
||||
|
||||
static constexpr void eq(P const (&output)[5]) {
|
||||
// Extracted into a separate function to keep /analyze from exhausting the compiler heap
|
||||
assert(ranges::equal(output, expected));
|
||||
}
|
||||
|
||||
template <ranges::input_range Read, 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
|
||||
P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
|
||||
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<decltype(result), replace_copy_if_result<iterator_t<Read>, Write>>);
|
||||
assert(result.in == wrapped_input.end());
|
||||
assert(result.out.peek() == output + 5);
|
||||
eq(output);
|
||||
}
|
||||
{ // Validate range overload
|
||||
P output[5] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
|
||||
Read wrapped_input{input};
|
||||
|
||||
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);
|
||||
eq(output);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((input_range_output_iterator_permutations<instantiator, P const, P>(), true));
|
||||
input_range_output_iterator_permutations<instantiator, P const, P>();
|
||||
}
|
Загрузка…
Ссылка в новой задаче