173ebcabfSKonstantin Varlamov //===----------------------------------------------------------------------===//
273ebcabfSKonstantin Varlamov //
373ebcabfSKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
473ebcabfSKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information.
573ebcabfSKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
673ebcabfSKonstantin Varlamov //
773ebcabfSKonstantin Varlamov //===----------------------------------------------------------------------===//
873ebcabfSKonstantin Varlamov 
973ebcabfSKonstantin Varlamov // UNSUPPORTED: c++03, c++11, c++14, c++17
1073ebcabfSKonstantin Varlamov // UNSUPPORTED: libcpp-has-no-incomplete-ranges
1173ebcabfSKonstantin Varlamov 
1273ebcabfSKonstantin Varlamov // template<input_iterator I, sentinel_for<I> S, class T1, class T2,
1373ebcabfSKonstantin Varlamov //          output_iterator<const T2&> O, class Proj = identity>
1473ebcabfSKonstantin Varlamov //   requires indirectly_copyable<I, O> &&
1573ebcabfSKonstantin Varlamov //            indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
1673ebcabfSKonstantin Varlamov //   constexpr replace_copy_result<I, O>
1773ebcabfSKonstantin Varlamov //     replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value,
1873ebcabfSKonstantin Varlamov //                  Proj proj = {});                                                                // Since C++20
1973ebcabfSKonstantin Varlamov //
2073ebcabfSKonstantin Varlamov // template<input_range R, class T1, class T2, output_iterator<const T2&> O,
2173ebcabfSKonstantin Varlamov //          class Proj = identity>
2273ebcabfSKonstantin Varlamov //   requires indirectly_copyable<iterator_t<R>, O> &&
2373ebcabfSKonstantin Varlamov //            indirect_binary_predicate<ranges::equal_to,
2473ebcabfSKonstantin Varlamov //                                      projected<iterator_t<R>, Proj>, const T1*>
2573ebcabfSKonstantin Varlamov //   constexpr replace_copy_result<borrowed_iterator_t<R>, O>
2673ebcabfSKonstantin Varlamov //     replace_copy(R&& r, O result, const T1& old_value, const T2& new_value,
2773ebcabfSKonstantin Varlamov //                  Proj proj = {});                                                                // Since C++20
2873ebcabfSKonstantin Varlamov 
2973ebcabfSKonstantin Varlamov #include <algorithm>
3073ebcabfSKonstantin Varlamov #include <array>
3173ebcabfSKonstantin Varlamov #include <concepts>
3273ebcabfSKonstantin Varlamov #include <functional>
3373ebcabfSKonstantin Varlamov #include <ranges>
34*40c79a4dSNikolas Klauser #include <utility>
3573ebcabfSKonstantin Varlamov 
3673ebcabfSKonstantin Varlamov #include "almost_satisfies_types.h"
37*40c79a4dSNikolas Klauser #include "counting_projection.h"
3873ebcabfSKonstantin Varlamov #include "test_iterators.h"
3973ebcabfSKonstantin Varlamov 
40*40c79a4dSNikolas Klauser template <class Iter, class Sent = sentinel_wrapper<Iter>, class OutIter = int*>
41*40c79a4dSNikolas Klauser concept HasReplaceCopyIter =
42*40c79a4dSNikolas Klauser   requires(Iter&& first, Sent&& last, OutIter&& result) {
43*40c79a4dSNikolas Klauser     std::ranges::replace_copy(
44*40c79a4dSNikolas Klauser         std::forward<Iter>(first), std::forward<Sent>(last), std::forward<OutIter>(result), 0, 0);
45*40c79a4dSNikolas Klauser };
46*40c79a4dSNikolas Klauser 
47*40c79a4dSNikolas Klauser static_assert(HasReplaceCopyIter<int*>);
48*40c79a4dSNikolas Klauser 
49*40c79a4dSNikolas Klauser // !input_iterator<I>
50*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyIter<InputIteratorNotDerivedFrom>);
51*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyIter<InputIteratorNotIndirectlyReadable>);
52*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyIter<InputIteratorNotInputOrOutputIterator>);
53*40c79a4dSNikolas Klauser 
54*40c79a4dSNikolas Klauser // !sentinel_for<S, I>
55*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyIter<int*, SentinelForNotSemiregular>);
56*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
57*40c79a4dSNikolas Klauser 
58*40c79a4dSNikolas Klauser // !output_iterator<O, const T2&>
59*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyIter<int*, int*, OutputIteratorNotIndirectlyWritable>);
60*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyIter<int*, int*, OutputIteratorNotInputOrOutputIterator>);
61*40c79a4dSNikolas Klauser 
62*40c79a4dSNikolas Klauser // !indirectly_copyable<I, O>
63*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyIter<int*, int*, int**>);
64*40c79a4dSNikolas Klauser 
65*40c79a4dSNikolas Klauser // !indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
66*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyIter<IndirectBinaryPredicateNotIndirectlyReadable>);
67*40c79a4dSNikolas Klauser 
68*40c79a4dSNikolas Klauser template <class Range, class OutIter = int*>
69*40c79a4dSNikolas Klauser concept HasReplaceCopyRange = requires(Range&& range, OutIter&& result) {
70*40c79a4dSNikolas Klauser   std::ranges::replace_copy(std::forward<Range>(range), std::forward<OutIter>(result), 0, 0);
71*40c79a4dSNikolas Klauser };
72*40c79a4dSNikolas Klauser 
73*40c79a4dSNikolas Klauser template <class T>
74*40c79a4dSNikolas Klauser using R = UncheckedRange<T>;
75*40c79a4dSNikolas Klauser 
76*40c79a4dSNikolas Klauser static_assert(HasReplaceCopyRange<R<int*>>);
77*40c79a4dSNikolas Klauser 
78*40c79a4dSNikolas Klauser // !input_range<R>
79*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyRange<InputRangeNotDerivedFrom>);
80*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyRange<InputRangeNotIndirectlyReadable>);
81*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyRange<InputRangeNotInputOrOutputIterator>);
82*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyRange<InputRangeNotSentinelSemiregular>);
83*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyRange<InputRangeNotSentinelEqualityComparableWith>);
84*40c79a4dSNikolas Klauser 
85*40c79a4dSNikolas Klauser // !output_iterator<O, const T2&>
86*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyRange<R<int*>, OutputIteratorNotIndirectlyWritable>);
87*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyRange<R<int*>, OutputIteratorNotInputOrOutputIterator>);
88*40c79a4dSNikolas Klauser 
89*40c79a4dSNikolas Klauser // !indirectly_copyable<iterator_t<R>, O>
90*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyRange<R<int*>, R<int**>>);
91*40c79a4dSNikolas Klauser 
92*40c79a4dSNikolas Klauser // !indirect_binary_predicate<ranges::equal_to, projected<iterator_t<T>, Proj>, const T1*>
93*40c79a4dSNikolas Klauser static_assert(!HasReplaceCopyRange<R<IndirectBinaryPredicateNotIndirectlyReadable>>);
94*40c79a4dSNikolas Klauser 
95*40c79a4dSNikolas Klauser template <int N>
96*40c79a4dSNikolas Klauser struct Data {
97*40c79a4dSNikolas Klauser   std::array<int, N> input;
98*40c79a4dSNikolas Klauser   int old_value;
99*40c79a4dSNikolas Klauser   int new_value;
100*40c79a4dSNikolas Klauser   std::array<int, N> expected;
101*40c79a4dSNikolas Klauser };
102*40c79a4dSNikolas Klauser 
103*40c79a4dSNikolas Klauser template <class InIter, class Sent, class OutIter, int N>
test(Data<N> d)104*40c79a4dSNikolas Klauser constexpr void test(Data<N> d) {
105*40c79a4dSNikolas Klauser   { // iterator overload
106*40c79a4dSNikolas Klauser     std::array<int, N> output;
107*40c79a4dSNikolas Klauser 
108*40c79a4dSNikolas Klauser     auto first  = InIter(d.input.data());
109*40c79a4dSNikolas Klauser     auto last   = Sent(InIter(d.input.data() + d.input.size()));
110*40c79a4dSNikolas Klauser     auto result = OutIter(output.data());
111*40c79a4dSNikolas Klauser 
112*40c79a4dSNikolas Klauser     std::same_as<std::ranges::replace_copy_result<InIter, OutIter>> decltype(auto) ret =
113*40c79a4dSNikolas Klauser         std::ranges::replace_copy(std::move(first), std::move(last), std::move(result), d.old_value, d.new_value);
114*40c79a4dSNikolas Klauser     assert(base(ret.in) == d.input.data() + d.input.size());
115*40c79a4dSNikolas Klauser     assert(base(ret.out) == output.data() + output.size());
116*40c79a4dSNikolas Klauser     assert(d.expected == output);
117*40c79a4dSNikolas Klauser   }
118*40c79a4dSNikolas Klauser 
119*40c79a4dSNikolas Klauser   { // range overload
120*40c79a4dSNikolas Klauser     std::array<int, N> output;
121*40c79a4dSNikolas Klauser 
122*40c79a4dSNikolas Klauser     auto range  = std::ranges::subrange(InIter(d.input.data()), Sent(InIter(d.input.data() + d.input.size())));
123*40c79a4dSNikolas Klauser     auto result = OutIter(output.data());
124*40c79a4dSNikolas Klauser 
125*40c79a4dSNikolas Klauser     std::same_as<std::ranges::replace_copy_result<InIter, OutIter>> decltype(auto) ret =
126*40c79a4dSNikolas Klauser         std::ranges::replace_copy(range, result, d.old_value, d.new_value);
127*40c79a4dSNikolas Klauser     assert(base(ret.in) == d.input.data() + d.input.size());
128*40c79a4dSNikolas Klauser     assert(base(ret.out) == output.data() + output.size());
129*40c79a4dSNikolas Klauser     assert(d.expected == output);
130*40c79a4dSNikolas Klauser   }
131*40c79a4dSNikolas Klauser }
132*40c79a4dSNikolas Klauser 
133*40c79a4dSNikolas Klauser template <class InIter, class Sent, class OutIter>
tests()134*40c79a4dSNikolas Klauser constexpr void tests() {
135*40c79a4dSNikolas Klauser   // simple test
136*40c79a4dSNikolas Klauser   test<InIter, Sent, OutIter, 4>({.input = {1, 2, 3, 4}, .old_value = 2, .new_value = 5, .expected = {1, 5, 3, 4}});
137*40c79a4dSNikolas Klauser   // empty range
138*40c79a4dSNikolas Klauser   test<InIter, Sent, OutIter, 0>({.input = {}, .old_value = 2, .new_value = 5, .expected = {}});
139*40c79a4dSNikolas Klauser   // all elements match
140*40c79a4dSNikolas Klauser   test<InIter, Sent, OutIter, 4>({.input = {1, 1, 1, 1}, .old_value = 1, .new_value = 2, .expected = {2, 2, 2, 2}});
141*40c79a4dSNikolas Klauser   // no element matches
142*40c79a4dSNikolas Klauser   test<InIter, Sent, OutIter, 4>({.input = {1, 1, 1, 1}, .old_value = 2, .new_value = 3, .expected = {1, 1, 1, 1}});
143*40c79a4dSNikolas Klauser   // old_value and new_value are identical - match
144*40c79a4dSNikolas Klauser   test<InIter, Sent, OutIter, 4>({.input = {1, 1, 1, 1}, .old_value = 1, .new_value = 1, .expected = {1, 1, 1, 1}});
145*40c79a4dSNikolas Klauser   // old_value and new_value are identical - no match
146*40c79a4dSNikolas Klauser   test<InIter, Sent, OutIter, 4>({.input = {1, 1, 1, 1}, .old_value = 2, .new_value = 2, .expected = {1, 1, 1, 1}});
147*40c79a4dSNikolas Klauser   // more elements
148*40c79a4dSNikolas Klauser   test<InIter, Sent, OutIter, 7>(
149*40c79a4dSNikolas Klauser       {.input = {1, 2, 3, 4, 5, 6, 7}, .old_value = 2, .new_value = 3, .expected = {1, 3, 3, 4, 5, 6, 7}});
150*40c79a4dSNikolas Klauser   // single element - match
151*40c79a4dSNikolas Klauser   test<InIter, Sent, OutIter, 1>({.input = {1}, .old_value = 1, .new_value = 5, .expected = {5}});
152*40c79a4dSNikolas Klauser   // single element - no match
153*40c79a4dSNikolas Klauser   test<InIter, Sent, OutIter, 1>({.input = {2}, .old_value = 1, .new_value = 5, .expected = {2}});
154*40c79a4dSNikolas Klauser }
155*40c79a4dSNikolas Klauser 
156*40c79a4dSNikolas Klauser template <class InIter, class Sent>
test_output_iterators()157*40c79a4dSNikolas Klauser constexpr void test_output_iterators() {
158*40c79a4dSNikolas Klauser   tests<InIter, Sent, cpp17_output_iterator<int*>>();
159*40c79a4dSNikolas Klauser   tests<InIter, Sent, forward_iterator<int*>>();
160*40c79a4dSNikolas Klauser   tests<InIter, Sent, bidirectional_iterator<int*>>();
161*40c79a4dSNikolas Klauser   tests<InIter, Sent, random_access_iterator<int*>>();
162*40c79a4dSNikolas Klauser   tests<InIter, Sent, contiguous_iterator<int*>>();
163*40c79a4dSNikolas Klauser   tests<InIter, Sent, int*>();
164*40c79a4dSNikolas Klauser }
165*40c79a4dSNikolas Klauser 
166*40c79a4dSNikolas Klauser template <class InIter>
test_sentinels()167*40c79a4dSNikolas Klauser constexpr void test_sentinels() {
168*40c79a4dSNikolas Klauser   test_output_iterators<InIter, InIter>();
169*40c79a4dSNikolas Klauser   test_output_iterators<InIter, sentinel_wrapper<InIter>>();
170*40c79a4dSNikolas Klauser   test_output_iterators<InIter, sized_sentinel<InIter>>();
171*40c79a4dSNikolas Klauser }
17273ebcabfSKonstantin Varlamov 
test()17373ebcabfSKonstantin Varlamov constexpr bool test() {
174*40c79a4dSNikolas Klauser   test_output_iterators<cpp17_input_iterator<int*>, sentinel_wrapper<cpp17_input_iterator<int*>>>();
175*40c79a4dSNikolas Klauser   test_output_iterators<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>>();
176*40c79a4dSNikolas Klauser   test_sentinels<forward_iterator<int*>>();
177*40c79a4dSNikolas Klauser   test_sentinels<bidirectional_iterator<int*>>();
178*40c79a4dSNikolas Klauser   test_sentinels<random_access_iterator<int*>>();
179*40c79a4dSNikolas Klauser   test_sentinels<contiguous_iterator<int*>>();
180*40c79a4dSNikolas Klauser   test_sentinels<int*>();
181*40c79a4dSNikolas Klauser   test_sentinels<const int*>();
182*40c79a4dSNikolas Klauser 
183*40c79a4dSNikolas Klauser   { // check that a custom projection works
184*40c79a4dSNikolas Klauser     struct S {
185*40c79a4dSNikolas Klauser       int i;
186*40c79a4dSNikolas Klauser     };
187*40c79a4dSNikolas Klauser 
188*40c79a4dSNikolas Klauser     { // iterator overload
189*40c79a4dSNikolas Klauser       S a[] = {{1}, {2}, {3}, {4}};
190*40c79a4dSNikolas Klauser       S b[4];
191*40c79a4dSNikolas Klauser       auto ret = std::ranges::replace_copy(std::begin(a), std::end(a), std::begin(b), 1, S{2}, &S::i);
192*40c79a4dSNikolas Klauser       assert(ret.in == std::end(a));
193*40c79a4dSNikolas Klauser       assert(ret.out == std::end(b));
194*40c79a4dSNikolas Klauser     }
195*40c79a4dSNikolas Klauser 
196*40c79a4dSNikolas Klauser     { // range overload
197*40c79a4dSNikolas Klauser       S a[] = {{1}, {2}, {3}, {4}};
198*40c79a4dSNikolas Klauser       S b[4];
199*40c79a4dSNikolas Klauser       auto ret = std::ranges::replace_copy(a, std::begin(b), 1, S{2}, &S::i);
200*40c79a4dSNikolas Klauser       assert(ret.in == std::end(a));
201*40c79a4dSNikolas Klauser       assert(ret.out == std::end(b));
202*40c79a4dSNikolas Klauser     }
203*40c79a4dSNikolas Klauser   }
204*40c79a4dSNikolas Klauser 
205*40c79a4dSNikolas Klauser   {   // Complexity: exactly `last - first` applications of the corresponding predicate and any projection.
206*40c79a4dSNikolas Klauser     { // iterator overload
207*40c79a4dSNikolas Klauser       int proj_count = 0;
208*40c79a4dSNikolas Klauser       int a[] = {1, 2, 3, 4};
209*40c79a4dSNikolas Klauser       int b[4];
210*40c79a4dSNikolas Klauser       std::ranges::replace_copy(
211*40c79a4dSNikolas Klauser           std::begin(a), std::end(a), std::begin(b), 0, 0, counting_projection(proj_count));
212*40c79a4dSNikolas Klauser       assert(proj_count == 4);
213*40c79a4dSNikolas Klauser     }
214*40c79a4dSNikolas Klauser 
215*40c79a4dSNikolas Klauser     { // range overload
216*40c79a4dSNikolas Klauser       int proj_count = 0;
217*40c79a4dSNikolas Klauser       int a[] = {1, 2, 3, 4};
218*40c79a4dSNikolas Klauser       int b[4];
219*40c79a4dSNikolas Klauser       std::ranges::replace_copy(a, std::begin(b), 0, 0, counting_projection(proj_count));
220*40c79a4dSNikolas Klauser       assert(proj_count == 4);
221*40c79a4dSNikolas Klauser     }
222*40c79a4dSNikolas Klauser   }
223*40c79a4dSNikolas Klauser 
224*40c79a4dSNikolas Klauser   { // using different types for the old and new values works
225*40c79a4dSNikolas Klauser     struct S {
226*40c79a4dSNikolas Klauser       constexpr operator int() const { return 0; }
227*40c79a4dSNikolas Klauser       constexpr bool operator==(const S&) const = default;
228*40c79a4dSNikolas Klauser       constexpr bool operator==(int i) const { return i == 0; }
229*40c79a4dSNikolas Klauser     };
230*40c79a4dSNikolas Klauser     struct T {
231*40c79a4dSNikolas Klauser       constexpr operator int() const { return 1; }
232*40c79a4dSNikolas Klauser     };
233*40c79a4dSNikolas Klauser     {
234*40c79a4dSNikolas Klauser       int a[] = {0, 1, 2, 3};
235*40c79a4dSNikolas Klauser       int b[4];
236*40c79a4dSNikolas Klauser       std::ranges::replace_copy(std::begin(a), std::end(a), std::begin(b), S{}, T{});
237*40c79a4dSNikolas Klauser       assert(std::ranges::equal(b, std::array{1, 1, 2, 3}));
238*40c79a4dSNikolas Klauser     }
239*40c79a4dSNikolas Klauser     {
240*40c79a4dSNikolas Klauser       int a[] = {0, 1, 2, 3};
241*40c79a4dSNikolas Klauser       int b[4];
242*40c79a4dSNikolas Klauser       std::ranges::replace_copy(a, std::begin(b), S{}, T{});
243*40c79a4dSNikolas Klauser       assert(std::ranges::equal(b, std::array{1, 1, 2, 3}));
244*40c79a4dSNikolas Klauser     }
245*40c79a4dSNikolas Klauser   }
24673ebcabfSKonstantin Varlamov 
24773ebcabfSKonstantin Varlamov   return true;
24873ebcabfSKonstantin Varlamov }
24973ebcabfSKonstantin Varlamov 
main(int,char **)25073ebcabfSKonstantin Varlamov int main(int, char**) {
25173ebcabfSKonstantin Varlamov   test();
25273ebcabfSKonstantin Varlamov   static_assert(test());
25373ebcabfSKonstantin Varlamov 
25473ebcabfSKonstantin Varlamov   return 0;
25573ebcabfSKonstantin Varlamov }
256