libcopp 2.3.2
Loading...
Searching...
No Matches
sample_readme_14.cpp
Go to the documentation of this file.
1// Copyright 2026 owent
2// Sample code for C++20 coroutine channel/receiver model
3
6
7#include <cstdio>
8#include <iostream>
9#include <memory>
10#include <vector>
11
12#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
13
14template <class TReceiver>
15static inline void reset_channel_value(TReceiver& receiver) {
16 auto ctx = receiver.get_context();
17 if (ctx) {
18 ctx->reset_value();
19 }
20}
21
22// ===============================================
23// Example 1: Basic Channel Usage with C++20 Coroutine
24// ===============================================
25
26copp::callable_future<int> basic_consumer(copp::generator_channel_receiver<int> receiver) {
27 std::cout << "[Consumer] Waiting for first value..." << std::endl;
28
29 // Use co_await to receive value from channel
30 int value1 = co_await receiver;
31 std::cout << "[Consumer] Received first value: " << value1 << std::endl;
32
33 // Must reset to receive next value
34 reset_channel_value(receiver);
35
36 std::cout << "[Consumer] Waiting for second value..." << std::endl;
37 int value2 = co_await receiver;
38 std::cout << "[Consumer] Received second value: " << value2 << std::endl;
39
40 reset_channel_value(receiver);
41
42 std::cout << "[Consumer] Waiting for third value..." << std::endl;
43 int value3 = co_await receiver;
44 std::cout << "[Consumer] Received third value: " << value3 << std::endl;
45
46 co_return value1 + value2 + value3;
47}
48
50 std::cout << "\n========== Example 1: Basic C++20 Channel Usage ==========\n" << std::endl;
51
52 // Create a channel for int communication
53 auto [receiver, sender] = copp::make_channel<int>();
54
55 // Start consumer coroutine
56 std::cout << "Starting consumer coroutine..." << std::endl;
57 auto consumer_future = basic_consumer(std::move(receiver));
58
59 std::cout << "\nConsumer is now waiting for values..." << std::endl;
60 std::cout << "Is consumer ready? " << (consumer_future.is_ready() ? "Yes" : "No") << std::endl;
61
62 // Send values through sender
63 std::cout << "\nSending first value: 10" << std::endl;
64 sender->set_value(10);
65
66 std::cout << "\nSending second value: 20" << std::endl;
67 sender->set_value(20);
68
69 std::cout << "\nSending third value: 30" << std::endl;
70 sender->set_value(30);
71
72 std::cout << "\nConsumer completed with sum: " << consumer_future.get_internal_promise().data() << std::endl;
73}
74
75// ===============================================
76// Example 2: Producer/Consumer Pattern
77// ===============================================
78
79copp::callable_future<void> producer_coroutine(copp::generator_channel_sender<int> sender, int count) {
80 std::cout << "[Producer] Starting to produce " << count << " values..." << std::endl;
81
82 for (int i = 1; i <= count; ++i) {
83 int value = i * 100;
84 std::cout << "[Producer] Producing value " << i << ": " << value << std::endl;
85
86 // Send value to channel
87 sender->set_value(value);
88
89 // Yield to let consumer process
90 auto current_status = co_yield copp::callable_future<void>::yield_status();
91 (void)current_status;
92 }
93
94 std::cout << "[Producer] Production complete!" << std::endl;
95 co_return;
96}
97
98copp::callable_future<int> consumer_coroutine(copp::generator_channel_receiver<int> receiver, int count) {
99 std::cout << "[Consumer] Starting to consume " << count << " values..." << std::endl;
100
101 int sum = 0;
102 for (int i = 1; i <= count; ++i) {
103 std::cout << "[Consumer] Waiting for value " << i << "..." << std::endl;
104
105 int value = co_await receiver;
106 std::cout << "[Consumer] Received value " << i << ": " << value << std::endl;
107
108 sum += value;
109 reset_channel_value(receiver);
110 }
111
112 std::cout << "[Consumer] Consumption complete! Total sum: " << sum << std::endl;
113 co_return sum;
114}
115
116void example_producer_consumer() {
117 std::cout << "\n========== Example 2: Producer/Consumer Pattern ==========\n" << std::endl;
118
119 auto [receiver, sender] = copp::make_channel<int>();
120
121 // Start both producer and consumer
122 auto consumer = consumer_coroutine(std::move(receiver), 5);
123 auto producer = producer_coroutine(sender, 5);
124
125 std::cout << "\nBoth coroutines completed!" << std::endl;
126 std::cout << "Final sum: " << consumer.get_internal_promise().data() << std::endl;
127}
128
129// ===============================================
130// Example 3: Error Handling
131// ===============================================
132
133struct custom_error_transform {
134 int operator()(copp::promise_status status) const {
135 if (status == copp::promise_status::kKilled) {
136 std::cout << "[Error Transform] Coroutine was killed, returning -999" << std::endl;
137 return -999;
138 } else if (status == copp::promise_status::kTimeout) {
139 std::cout << "[Error Transform] Timeout occurred, returning -888" << std::endl;
140 return -888;
141 }
142 std::cout << "[Error Transform] Other error: " << static_cast<int>(status) << ", returning -1" << std::endl;
143 return -1;
144 }
145};
146
147copp::callable_future<int> consumer_with_error_handling(
148 copp::generator_channel_receiver<int, custom_error_transform> receiver) {
149 std::cout << "[Consumer] Waiting for value (with custom error handling)..." << std::endl;
150
151 // This will use custom_error_transform if an error occurs
152 int value = co_await receiver;
153
154 std::cout << "[Consumer] Received value or error default: " << value << std::endl;
155 co_return value;
156}
157
159 std::cout << "\n========== Example 3: Error Handling with Custom Transform ==========\n" << std::endl;
160
161 auto [receiver, sender] = copp::make_channel<int, custom_error_transform>();
162
163 auto consumer = consumer_with_error_handling(std::move(receiver));
164
165 std::cout << "\nKilling consumer to demonstrate error handling..." << std::endl;
166 consumer.kill(copp::promise_status::kKilled, true);
167
168 std::cout << "Consumer result after kill: " << consumer.get_internal_promise().data() << std::endl;
169}
170
171// ===============================================
172// Example 4: Void Channel
173// ===============================================
174
175copp::callable_future<void> void_channel_consumer(copp::generator_channel_receiver<void> receiver) {
176 std::cout << "[Consumer] Waiting for signal 1..." << std::endl;
177 co_await receiver;
178 std::cout << "[Consumer] Received signal 1!" << std::endl;
179
180 reset_channel_value(receiver);
181
182 std::cout << "[Consumer] Waiting for signal 2..." << std::endl;
183 co_await receiver;
184 std::cout << "[Consumer] Received signal 2!" << std::endl;
185
186 reset_channel_value(receiver);
187
188 std::cout << "[Consumer] Waiting for signal 3..." << std::endl;
189 co_await receiver;
190 std::cout << "[Consumer] Received signal 3!" << std::endl;
191
192 co_return;
193}
194
195void example_void_channel() {
196 std::cout << "\n========== Example 4: Void Channel (Signaling) ==========\n" << std::endl;
197
198 auto [receiver, sender] = copp::make_channel<void>();
199
200 auto consumer = void_channel_consumer(std::move(receiver));
201
202 std::cout << "\nSending signal 1..." << std::endl;
203 sender->set_value();
204
205 std::cout << "\nSending signal 2..." << std::endl;
206 sender->set_value();
207
208 std::cout << "\nSending signal 3..." << std::endl;
209 sender->set_value();
210
211 std::cout << "\nConsumer completed!" << std::endl;
212}
213
214// ===============================================
215// Example 5: Comparison of Generator Future Types
216// ===============================================
217
218void example_vtable_types() {
219 std::cout << "\n========== Example 5: Generator VTable Types ==========\n" << std::endl;
220
221 std::cout << "libcopp provides three generator vtable types:\n" << std::endl;
222
223 std::cout << "1. generator_vtable_type::kDefault" << std::endl;
224 std::cout << " - Uses std::function for callbacks (most flexible)" << std::endl;
225 std::cout << " - Can capture complex state in lambdas" << std::endl;
226 std::cout << " - Type: copp::generator_future<T>" << std::endl;
227 std::cout << " - Best for: Complex scenarios with stateful callbacks\n" << std::endl;
228
229 std::cout << "2. generator_vtable_type::kLightWeight" << std::endl;
230 std::cout << " - Uses function pointers instead of std::function" << std::endl;
231 std::cout << " - Lower overhead, faster performance" << std::endl;
232 std::cout << " - Type: copp::generator_lightweight_future<T>" << std::endl;
233 std::cout << " - Best for: Performance-critical code with simple callbacks\n" << std::endl;
234
235 std::cout << "3. generator_vtable_type::kNone" << std::endl;
236 std::cout << " - No callbacks, designed for channel/receiver pattern" << std::endl;
237 std::cout << " - Minimal overhead, most efficient" << std::endl;
238 std::cout << " - Type: copp::generator_channel_future<T> (used by make_channel)" << std::endl;
239 std::cout << " - Best for: Channel-based communication between coroutines\n" << std::endl;
240
241 std::cout << "Recommendation:" << std::endl;
242 std::cout << " - For channels: Use make_channel() (kNone vtable)" << std::endl;
243 std::cout << " - For simple futures: Use generator_lightweight_future (kLightWeight)" << std::endl;
244 std::cout << " - For complex futures: Use generator_future (kDefault)\n" << std::endl;
245}
246
247// ===============================================
248// Main
249// ===============================================
250
251int main() {
253 example_producer_consumer();
255 example_void_channel();
256 example_vtable_types();
257
258 std::cout << "\n========== All C++20 Channel Examples Completed! ==========\n" << std::endl;
259 return 0;
260}
261
262#else
263
264int main() {
265 std::cerr << "C++20 coroutine is not enabled, sample is disabled" << std::endl;
266 return 0;
267}
268
269#endif
void example_basic_channel()
void example_error_handling()
int main()