CXXIter 0.2
Loading...
Searching...
No Matches
Generator.h
1#pragma once
2
3#ifdef CXXITER_HAS_COROUTINE
4
5#include <coroutine>
6
7#include "Common.h"
8
9namespace CXXIter {
10
11 // ################################################################################################
12 // GENERATOR
13 // ################################################################################################
14
20 template<typename T>
21 class Generator {
22 public:
23 using value_type = T;
24 struct promise_type;
25 using Handle = std::coroutine_handle<promise_type>;
26
27 struct promise_type {
28 IterValue<T> currentItem;
29 std::exception_ptr exceptionPtr;
30
31 Generator<T> get_return_object() {
32 return Generator{Handle::from_promise(*this)};
33 }
34 static std::suspend_always initial_suspend() noexcept { return {}; }
35 static std::suspend_always final_suspend() noexcept { return {}; }
36 std::suspend_always yield_value(T value) noexcept {
37 currentItem = value;
38 return {};
39 }
40
41 void unhandled_exception() {
42 exceptionPtr = std::current_exception();
43 }
44 };
45
46 explicit Generator(const Handle coroutine) : m_coroutine{coroutine} {}
47 Generator() = default;
48 ~Generator() {
49 if (m_coroutine) {
50 m_coroutine.destroy();
51 }
52 }
53
54 Generator(const Generator&) = delete;
55 Generator& operator=(const Generator&) = delete;
56
57 Generator(Generator&& other) noexcept : m_coroutine{other.m_coroutine} {
58 other.m_coroutine = {};
59 }
60 Generator& operator=(Generator&& other) noexcept {
61 m_coroutine = other;
62 other.m_coroutine = {};
63 return *this;
64 }
65
66 IterValue<T> next() {
67 if(m_coroutine && !m_coroutine.promise().currentItem.has_value()) {
68 m_coroutine.resume();
69 if(m_coroutine.promise().exceptionPtr) {
70 std::rethrow_exception(m_coroutine.promise().exceptionPtr);
71 }
72 }
73 if(m_coroutine.done()) {
74 m_coroutine.destroy();
75 m_coroutine = {};
76 return {};
77 }
78 // Depends on IterValue<T>'s guarantee, to clear the moved-out-of IterValue
79 // irrespecting on the type of T. (std::optional<T> doesn't!)
80 //TODO: unit-test for IterValue?
81 return std::move(m_coroutine.promise().currentItem);
82 }
83
84 private:
85 Handle m_coroutine;
86 };
87
88 template<typename T>
89 concept GeneratorFunction = (std::invocable<T> && util::is_template_instance_v<std::invoke_result_t<T>, Generator>);
90}
91
92#endif
Generator that C++20 coroutines passed to CXXIter::IterApi::generateFrom() have to return....
Definition: Generator.h:21
Container that is used to pass elements through CXXIter's iterator pipelines.
Definition: IterValue.h:19
CXXIter.
Definition: CXXIter.h:48