1//===----------------------------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03, c++11, c++14, c++17
10
11// See https://llvm.org/PR33271
12// UNSUPPORTED: ubsan
13
14#include <coroutine>
15#include <vector>
16#include <cassert>
17
18#include "test_macros.h"
19
20template <typename Ty> struct generator {
21 struct promise_type {
22 Ty current_value;
23 std::suspend_always yield_value(Ty value) {
24 this->current_value = value;
25 return {};
26 }
27 std::suspend_always initial_suspend() { return {}; }
28 std::suspend_always final_suspend() noexcept { return {}; }
29 generator get_return_object() { return generator{this}; };
30 void return_void() {}
31 void unhandled_exception() {}
32 };
33
34 struct iterator {
35 std::coroutine_handle<promise_type> Coro_;
36 bool Done_;
37
38 iterator(std::coroutine_handle<promise_type> Coro, bool Done)
39 : Coro_(Coro), Done_(Done) {}
40
41 iterator &operator++() {
42 Coro_.resume();
43 Done_ = Coro_.done();
44 return *this;
45 }
46
47 bool operator==(iterator const &_Right) const {
48 return Done_ == _Right.Done_;
49 }
50
51 bool operator!=(iterator const &_Right) const { return !(*this == _Right); }
52
53 Ty const &operator*() const { return Coro_.promise().current_value; }
54
55 Ty const *operator->() const { return &(operator*()); }
56 };
57
58 iterator begin() {
59 p.resume();
60 return {p, p.done()};
61 }
62
63 iterator end() { return {p, true}; }
64
65 generator(generator &&rhs) : p(rhs.p) { rhs.p = nullptr; }
66
67 ~generator() {
68 if (p)
69 p.destroy();
70 }
71
72private:
73 explicit generator(promise_type *promise)
74 : p(std::coroutine_handle<promise_type>::from_promise(*promise)) {}
75
76 std::coroutine_handle<promise_type> p;
77};
78
79struct minig {
80 struct promise_type {
81 int current_value;
82 std::suspend_always yield_value(int value) {
83 this->current_value = value;
84 return {};
85 }
86 std::suspend_always initial_suspend() { return {}; }
87 std::suspend_always final_suspend() noexcept { return {}; }
88 minig get_return_object() { return minig{this}; };
89 void return_void() {}
90 void unhandled_exception() {}
91 };
92
93 bool move_next() {
94 p.resume();
95 return !p.done();
96 }
97 int current_value() { return p.promise().current_value; }
98
99 minig(minig &&rhs) : p(rhs.p) { rhs.p = nullptr; }
100
101 ~minig() {
102 if (p)
103 p.destroy();
104 }
105
106private:
107 explicit minig(promise_type *promise)
108 : p(std::coroutine_handle<promise_type>::from_promise(*promise)) {}
109
110 std::coroutine_handle<promise_type> p;
111};
112
113
114minig mini_count(int n) {
115 for (int i = 0; i < n; i++) {
116 co_yield i;
117 }
118}
119
120generator<int> count(int n) {
121 for (int i = 0; i < n; ++i)
122 co_yield i;
123}
124
125generator<int> range(int from, int n) {
126 for (int i = from; i < n; ++i)
127 co_yield i;
128}
129
130void test_count() {
131 const std::vector<int> expect = {0, 1, 2, 3, 4};
132 std::vector<int> got;
133 for (auto x : count(5))
134 got.push_back(x);
135 assert(expect == got);
136}
137
138void test_range() {
139 int sum = 0;
140 for (auto v: range(1, 20))
141 sum += v;
142 assert(sum == 190);
143}
144
145void test_mini_generator() {
146 int sum = 0;
147 auto g = mini_count(n: 5);
148 while (g.move_next()) {
149 sum += g.current_value();
150 }
151 assert(sum == 10);
152}
153
154int main(int, char**) {
155 test_count();
156 test_range();
157 test_mini_generator();
158
159 return 0;
160}
161

source code of libcxx/test/std/language.support/support.coroutines/end.to.end/generator.pass.cpp