1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<input_or_output_iterator O, sentinel_for<O> S, copy_constructible F>
14 // requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
15 // constexpr O generate(O first, S last, F gen); // Since C++20
17 // template<class R, copy_constructible F>
18 // requires invocable<F&> && output_range<R, invoke_result_t<F&>>
19 // constexpr borrowed_iterator_t<R> generate(R&& r, F gen); // Since C++20
28 #include "almost_satisfies_types.h"
29 #include "test_iterators.h"
32 int operator()() const;
35 struct UncopyableGen
{
36 UncopyableGen(const UncopyableGen
&) = delete;
37 int operator()() const;
39 static_assert(!std::copy_constructible
<UncopyableGen
>);
40 static_assert(std::invocable
<UncopyableGen
>);
42 struct UninvocableGen
{
44 static_assert(std::copy_constructible
<UninvocableGen
>);
45 static_assert(!std::invocable
<UninvocableGen
>);
48 int* operator()() const;
51 // Test constraints of the (iterator, sentinel) overload.
52 // ======================================================
54 template <class Iter
= int*, class Sent
= int*, class Gen
= IntGen
>
55 concept HasGenerateIter
=
56 requires(Iter
&& iter
, Sent
&& sent
, Gen
&& gen
) {
57 std::ranges::generate(std::forward
<Iter
>(iter
), std::forward
<Sent
>(sent
), std::forward
<Gen
>(gen
));
60 static_assert(HasGenerateIter
<int*, int*, IntGen
>);
62 // !input_or_output_iterator<O>
63 static_assert(!HasGenerateIter
<InputIteratorNotInputOrOutputIterator
>);
65 // !sentinel_for<S, O>
66 static_assert(!HasGenerateIter
<int*, SentinelForNotSemiregular
>);
67 static_assert(!HasGenerateIter
<int*, SentinelForNotWeaklyEqualityComparableWith
>);
69 // !copy_constructible<F>
70 static_assert(!HasGenerateIter
<int*, int*, UncopyableGen
>);
73 static_assert(!HasGenerateIter
<int*, int*, UninvocableGen
>);
75 // !indirectly_writable<O, invoke_result_t<F&>>
76 static_assert(!HasGenerateIter
<int*, int*, IntPtrGen
>);
78 // Test constraints of the (range) overload.
79 // =========================================
81 template <class Range
, class Gen
= IntGen
>
82 concept HasGenerateRange
=
83 requires(Range
&& range
, Gen
&& gen
) {
84 std::ranges::generate(std::forward
<Range
>(range
), std::forward
<Gen
>(gen
));
88 using R
= UncheckedRange
<T
>;
90 static_assert(HasGenerateRange
<R
<int*>, IntGen
>);
92 // !copy_constructible<F>
93 static_assert(!HasGenerateRange
<R
<int*>, UncopyableGen
>);
96 static_assert(!HasGenerateRange
<R
<int*>, UninvocableGen
>);
98 // !output_range<R, invoke_result_t<F&>>
99 static_assert(!HasGenerateRange
<InputRangeNotInputOrOutputIterator
>);
100 static_assert(!HasGenerateRange
<R
<int*>, IntPtrGen
>);
102 template <class Iter
, class Sent
, std::size_t N
, class Gen
>
103 constexpr void test_one(const std::array
<int, N
> input
, Gen gen
, std::array
<int, N
> expected
) {
104 { // (iterator, sentinel) overload.
106 auto begin
= Iter(in
.data());
107 auto end
= Sent(Iter(in
.data() + in
.size()));
109 std::same_as
<Iter
> decltype(auto) result
= std::ranges::generate(std::move(begin
), std::move(end
), gen
);
110 assert(base(result
) == in
.data() + in
.size());
111 assert(in
== expected
);
114 { // (range) overload.
116 auto begin
= Iter(in
.data());
117 auto end
= Sent(Iter(in
.data() + in
.size()));
118 auto range
= std::ranges::subrange(std::move(begin
), std::move(end
));
120 // For some reason `ranges::generate` accepts both input and output iterators but only output (not input) ranges.
121 if constexpr (std::ranges::output_range
<decltype(range
), std::invoke_result_t
<Gen
&>>) {
122 std::same_as
<Iter
> decltype(auto) result
= std::ranges::generate(std::move(range
), gen
);
123 assert(base(result
) == in
.data() + in
.size());
124 assert(in
== expected
);
129 template <class Iter
, class Sent
>
130 constexpr void test_iter_sent() {
131 auto gen
= [ctr
= 1] () mutable { return ctr
++; };
134 test_one
<Iter
, Sent
, 0>({}, gen
, {});
135 // 1-element sequence.
136 test_one
<Iter
, Sent
>(std::array
{-10}, gen
, {1});
138 test_one
<Iter
, Sent
>(std::array
<int, 5>{}, gen
, {1, 2, 3, 4, 5});
141 template <class Iter
>
142 constexpr void test_iter() {
143 if constexpr (std::sentinel_for
<Iter
, Iter
>) {
144 test_iter_sent
<Iter
, Iter
>();
146 test_iter_sent
<Iter
, sentinel_wrapper
<Iter
>>();
149 constexpr void test_iterators() {
150 test_iter
<cpp17_input_iterator
<int*>>();
151 test_iter
<cpp20_input_iterator
<int*>>();
152 test_iter
<cpp17_output_iterator
<int*>>();
153 test_iter
<cpp20_output_iterator
<int*>>();
154 test_iter
<forward_iterator
<int*>>();
155 test_iter
<bidirectional_iterator
<int*>>();
156 test_iter
<random_access_iterator
<int*>>();
157 test_iter
<contiguous_iterator
<int*>>();
161 constexpr bool test() {
164 { // Complexity: exactly N evaluations of `gen()` and assignments.
165 struct AssignedOnce
{
166 bool assigned
= false;
167 constexpr AssignedOnce
& operator=(const AssignedOnce
&) {
174 { // (iterator, sentinel) overload.
175 int gen_invocations
= 0;
176 auto gen
= [&gen_invocations
] { ++gen_invocations
; return AssignedOnce(); };
177 constexpr std::size_t N
= 10;
178 std::array
<AssignedOnce
, N
> in
;
180 std::ranges::generate(in
.begin(), in
.end(), gen
);
181 assert(std::ranges::all_of(in
, &AssignedOnce::assigned
));
182 assert(gen_invocations
== N
);
185 { // (range) overload.
186 int gen_invocations
= 0;
187 auto gen
= [&gen_invocations
] { ++gen_invocations
; return AssignedOnce(); };
188 constexpr std::size_t N
= 10;
189 std::array
<AssignedOnce
, N
> in
;
191 std::ranges::generate(in
, gen
);
192 assert(std::ranges::all_of(in
, &AssignedOnce::assigned
));
193 assert(gen_invocations
== N
);
200 int main(int, char**) {
202 static_assert(test());