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
1173ebcabfSKonstantin Varlamov // <algorithm>
1273ebcabfSKonstantin Varlamov
1373ebcabfSKonstantin Varlamov // template<input_or_output_iterator O, sentinel_for<O> S, copy_constructible F>
1473ebcabfSKonstantin Varlamov // requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
1573ebcabfSKonstantin Varlamov // constexpr O generate(O first, S last, F gen); // Since C++20
1673ebcabfSKonstantin Varlamov //
1773ebcabfSKonstantin Varlamov // template<class R, copy_constructible F>
1873ebcabfSKonstantin Varlamov // requires invocable<F&> && output_range<R, invoke_result_t<F&>>
1973ebcabfSKonstantin Varlamov // constexpr borrowed_iterator_t<R> generate(R&& r, F gen); // Since C++20
2073ebcabfSKonstantin Varlamov
2173ebcabfSKonstantin Varlamov #include <algorithm>
2273ebcabfSKonstantin Varlamov #include <array>
2373ebcabfSKonstantin Varlamov #include <concepts>
2473ebcabfSKonstantin Varlamov #include <functional>
2573ebcabfSKonstantin Varlamov #include <ranges>
26ead7302bSKonstantin Varlamov #include <utility>
2773ebcabfSKonstantin Varlamov
2873ebcabfSKonstantin Varlamov #include "almost_satisfies_types.h"
2973ebcabfSKonstantin Varlamov #include "test_iterators.h"
3073ebcabfSKonstantin Varlamov
31ead7302bSKonstantin Varlamov struct IntGen {
32ead7302bSKonstantin Varlamov int operator()() const;
33ead7302bSKonstantin Varlamov };
34ead7302bSKonstantin Varlamov
35ead7302bSKonstantin Varlamov struct UncopyableGen {
36ead7302bSKonstantin Varlamov UncopyableGen(const UncopyableGen&) = delete;
37ead7302bSKonstantin Varlamov int operator()() const;
38ead7302bSKonstantin Varlamov };
39ead7302bSKonstantin Varlamov static_assert(!std::copy_constructible<UncopyableGen>);
40ead7302bSKonstantin Varlamov static_assert(std::invocable<UncopyableGen>);
41ead7302bSKonstantin Varlamov
42ead7302bSKonstantin Varlamov struct UninvocableGen {
43ead7302bSKonstantin Varlamov };
44ead7302bSKonstantin Varlamov static_assert(std::copy_constructible<UninvocableGen>);
45ead7302bSKonstantin Varlamov static_assert(!std::invocable<UninvocableGen>);
46ead7302bSKonstantin Varlamov
47ead7302bSKonstantin Varlamov struct IntPtrGen {
48ead7302bSKonstantin Varlamov int* operator()() const;
49ead7302bSKonstantin Varlamov };
50ead7302bSKonstantin Varlamov
51ead7302bSKonstantin Varlamov // Test constraints of the (iterator, sentinel) overload.
52ead7302bSKonstantin Varlamov // ======================================================
53ead7302bSKonstantin Varlamov
54ead7302bSKonstantin Varlamov template <class Iter = int*, class Sent = int*, class Gen = IntGen>
55ead7302bSKonstantin Varlamov concept HasGenerateIter =
56ead7302bSKonstantin Varlamov requires(Iter&& iter, Sent&& sent, Gen&& gen) {
57ead7302bSKonstantin Varlamov std::ranges::generate(std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Gen>(gen));
58ead7302bSKonstantin Varlamov };
59ead7302bSKonstantin Varlamov
60ead7302bSKonstantin Varlamov static_assert(HasGenerateIter<int*, int*, IntGen>);
61ead7302bSKonstantin Varlamov
62ead7302bSKonstantin Varlamov // !input_or_output_iterator<O>
63ead7302bSKonstantin Varlamov static_assert(!HasGenerateIter<InputIteratorNotInputOrOutputIterator>);
64ead7302bSKonstantin Varlamov
65ead7302bSKonstantin Varlamov // !sentinel_for<S, O>
66ead7302bSKonstantin Varlamov static_assert(!HasGenerateIter<int*, SentinelForNotSemiregular>);
67ead7302bSKonstantin Varlamov static_assert(!HasGenerateIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
68ead7302bSKonstantin Varlamov
69ead7302bSKonstantin Varlamov // !copy_constructible<F>
70ead7302bSKonstantin Varlamov static_assert(!HasGenerateIter<int*, int*, UncopyableGen>);
71ead7302bSKonstantin Varlamov
72ead7302bSKonstantin Varlamov // !invocable<F&>
73ead7302bSKonstantin Varlamov static_assert(!HasGenerateIter<int*, int*, UninvocableGen>);
74ead7302bSKonstantin Varlamov
75ead7302bSKonstantin Varlamov // !indirectly_writable<O, invoke_result_t<F&>>
76ead7302bSKonstantin Varlamov static_assert(!HasGenerateIter<int*, int*, IntPtrGen>);
77ead7302bSKonstantin Varlamov
78ead7302bSKonstantin Varlamov // Test constraints of the (range) overload.
79ead7302bSKonstantin Varlamov // =========================================
80ead7302bSKonstantin Varlamov
81ead7302bSKonstantin Varlamov template <class Range, class Gen = IntGen>
82ead7302bSKonstantin Varlamov concept HasGenerateRange =
83ead7302bSKonstantin Varlamov requires(Range&& range, Gen&& gen) {
84ead7302bSKonstantin Varlamov std::ranges::generate(std::forward<Range>(range), std::forward<Gen>(gen));
85ead7302bSKonstantin Varlamov };
86ead7302bSKonstantin Varlamov
87ead7302bSKonstantin Varlamov template <class T>
88ead7302bSKonstantin Varlamov using R = UncheckedRange<T>;
89ead7302bSKonstantin Varlamov
90ead7302bSKonstantin Varlamov static_assert(HasGenerateRange<R<int*>, IntGen>);
91ead7302bSKonstantin Varlamov
92ead7302bSKonstantin Varlamov // !copy_constructible<F>
93ead7302bSKonstantin Varlamov static_assert(!HasGenerateRange<R<int*>, UncopyableGen>);
94ead7302bSKonstantin Varlamov
95ead7302bSKonstantin Varlamov // !invocable<F&>
96ead7302bSKonstantin Varlamov static_assert(!HasGenerateRange<R<int*>, UninvocableGen>);
97ead7302bSKonstantin Varlamov
98ead7302bSKonstantin Varlamov // !output_range<R, invoke_result_t<F&>>
99ead7302bSKonstantin Varlamov static_assert(!HasGenerateRange<InputRangeNotInputOrOutputIterator>);
100ead7302bSKonstantin Varlamov static_assert(!HasGenerateRange<R<int*>, IntPtrGen>);
101ead7302bSKonstantin Varlamov
102*fb855eb9SMark de Wever template <class Iter, class Sent, std::size_t N, class Gen>
test_one(const std::array<int,N> input,Gen gen,std::array<int,N> expected)103ead7302bSKonstantin Varlamov constexpr void test_one(const std::array<int, N> input, Gen gen, std::array<int, N> expected) {
104ead7302bSKonstantin Varlamov { // (iterator, sentinel) overload.
105ead7302bSKonstantin Varlamov auto in = input;
106ead7302bSKonstantin Varlamov auto begin = Iter(in.data());
107ead7302bSKonstantin Varlamov auto end = Sent(Iter(in.data() + in.size()));
108ead7302bSKonstantin Varlamov
109ead7302bSKonstantin Varlamov std::same_as<Iter> decltype(auto) result = std::ranges::generate(std::move(begin), std::move(end), gen);
110ead7302bSKonstantin Varlamov assert(base(result) == in.data() + in.size());
111ead7302bSKonstantin Varlamov assert(in == expected);
112ead7302bSKonstantin Varlamov }
113ead7302bSKonstantin Varlamov
114ead7302bSKonstantin Varlamov { // (range) overload.
115ead7302bSKonstantin Varlamov auto in = input;
116ead7302bSKonstantin Varlamov auto begin = Iter(in.data());
117ead7302bSKonstantin Varlamov auto end = Sent(Iter(in.data() + in.size()));
118ead7302bSKonstantin Varlamov auto range = std::ranges::subrange(std::move(begin), std::move(end));
119ead7302bSKonstantin Varlamov
120ead7302bSKonstantin Varlamov // For some reason `ranges::generate` accepts both input and output iterators but only output (not input) ranges.
121ead7302bSKonstantin Varlamov if constexpr (std::ranges::output_range<decltype(range), std::invoke_result_t<Gen&>>) {
122ead7302bSKonstantin Varlamov std::same_as<Iter> decltype(auto) result = std::ranges::generate(std::move(range), gen);
123ead7302bSKonstantin Varlamov assert(base(result) == in.data() + in.size());
124ead7302bSKonstantin Varlamov assert(in == expected);
125ead7302bSKonstantin Varlamov }
126ead7302bSKonstantin Varlamov }
127ead7302bSKonstantin Varlamov }
128ead7302bSKonstantin Varlamov
129ead7302bSKonstantin Varlamov template <class Iter, class Sent>
test_iter_sent()130ead7302bSKonstantin Varlamov constexpr void test_iter_sent() {
131ead7302bSKonstantin Varlamov auto gen = [ctr = 1] () mutable { return ctr++; };
132ead7302bSKonstantin Varlamov
133ead7302bSKonstantin Varlamov // Empty sequence.
134ead7302bSKonstantin Varlamov test_one<Iter, Sent, 0>({}, gen, {});
135ead7302bSKonstantin Varlamov // 1-element sequence.
136ead7302bSKonstantin Varlamov test_one<Iter, Sent>(std::array{-10}, gen, {1});
137ead7302bSKonstantin Varlamov // Longer sequence.
138ead7302bSKonstantin Varlamov test_one<Iter, Sent>(std::array<int, 5>{}, gen, {1, 2, 3, 4, 5});
139ead7302bSKonstantin Varlamov }
140ead7302bSKonstantin Varlamov
141ead7302bSKonstantin Varlamov template <class Iter>
test_iter()142ead7302bSKonstantin Varlamov constexpr void test_iter() {
143ead7302bSKonstantin Varlamov if constexpr (std::sentinel_for<Iter, Iter>) {
144ead7302bSKonstantin Varlamov test_iter_sent<Iter, Iter>();
145ead7302bSKonstantin Varlamov }
146ead7302bSKonstantin Varlamov test_iter_sent<Iter, sentinel_wrapper<Iter>>();
147ead7302bSKonstantin Varlamov }
148ead7302bSKonstantin Varlamov
test_iterators()149ead7302bSKonstantin Varlamov constexpr void test_iterators() {
150ead7302bSKonstantin Varlamov test_iter<cpp17_input_iterator<int*>>();
151ead7302bSKonstantin Varlamov test_iter<cpp20_input_iterator<int*>>();
152ead7302bSKonstantin Varlamov test_iter<cpp17_output_iterator<int*>>();
153ead7302bSKonstantin Varlamov test_iter<cpp20_output_iterator<int*>>();
154ead7302bSKonstantin Varlamov test_iter<forward_iterator<int*>>();
155ead7302bSKonstantin Varlamov test_iter<bidirectional_iterator<int*>>();
156ead7302bSKonstantin Varlamov test_iter<random_access_iterator<int*>>();
157ead7302bSKonstantin Varlamov test_iter<contiguous_iterator<int*>>();
158ead7302bSKonstantin Varlamov test_iter<int*>();
159ead7302bSKonstantin Varlamov }
16073ebcabfSKonstantin Varlamov
test()16173ebcabfSKonstantin Varlamov constexpr bool test() {
162ead7302bSKonstantin Varlamov test_iterators();
163ead7302bSKonstantin Varlamov
164ead7302bSKonstantin Varlamov { // Complexity: exactly N evaluations of `gen()` and assignments.
165ead7302bSKonstantin Varlamov struct AssignedOnce {
166ead7302bSKonstantin Varlamov bool assigned = false;
167ead7302bSKonstantin Varlamov constexpr AssignedOnce& operator=(const AssignedOnce&) {
168ead7302bSKonstantin Varlamov assert(!assigned);
169ead7302bSKonstantin Varlamov assigned = true;
170ead7302bSKonstantin Varlamov return *this;
171ead7302bSKonstantin Varlamov }
172ead7302bSKonstantin Varlamov };
173ead7302bSKonstantin Varlamov
174ead7302bSKonstantin Varlamov { // (iterator, sentinel) overload.
175ead7302bSKonstantin Varlamov int gen_invocations = 0;
176ead7302bSKonstantin Varlamov auto gen = [&gen_invocations] { ++gen_invocations; return AssignedOnce(); };
177*fb855eb9SMark de Wever constexpr std::size_t N = 10;
178ead7302bSKonstantin Varlamov std::array<AssignedOnce, N> in;
179ead7302bSKonstantin Varlamov
180ead7302bSKonstantin Varlamov std::ranges::generate(in.begin(), in.end(), gen);
181ead7302bSKonstantin Varlamov assert(std::ranges::all_of(in, &AssignedOnce::assigned));
182ead7302bSKonstantin Varlamov assert(gen_invocations == N);
183ead7302bSKonstantin Varlamov }
184ead7302bSKonstantin Varlamov
185ead7302bSKonstantin Varlamov { // (range) overload.
186ead7302bSKonstantin Varlamov int gen_invocations = 0;
187ead7302bSKonstantin Varlamov auto gen = [&gen_invocations] { ++gen_invocations; return AssignedOnce(); };
188*fb855eb9SMark de Wever constexpr std::size_t N = 10;
189ead7302bSKonstantin Varlamov std::array<AssignedOnce, N> in;
190ead7302bSKonstantin Varlamov
191ead7302bSKonstantin Varlamov std::ranges::generate(in, gen);
192ead7302bSKonstantin Varlamov assert(std::ranges::all_of(in, &AssignedOnce::assigned));
193ead7302bSKonstantin Varlamov assert(gen_invocations == N);
194ead7302bSKonstantin Varlamov }
195ead7302bSKonstantin Varlamov }
19673ebcabfSKonstantin Varlamov
19773ebcabfSKonstantin Varlamov return true;
19873ebcabfSKonstantin Varlamov }
19973ebcabfSKonstantin Varlamov
main(int,char **)20073ebcabfSKonstantin Varlamov int main(int, char**) {
20173ebcabfSKonstantin Varlamov test();
20273ebcabfSKonstantin Varlamov static_assert(test());
20373ebcabfSKonstantin Varlamov
20473ebcabfSKonstantin Varlamov return 0;
20573ebcabfSKonstantin Varlamov }
206