cortex 0.0.1
Loading...
Searching...
No Matches
generator.hpp
Go to the documentation of this file.
1#pragma once
2
6
7#include <function2/function2.hpp>
8
9#include <cassert>
10#include <memory>
11#include <optional>
12#include <stdexcept>
13#include <utility>
14
20namespace cortex {
21
26template <typename T>
27class Generator final {
28public:
29private:
30 struct State;
31
32public:
38 public:
39 YieldContext(const YieldContext&) = delete;
43
44 template <typename U>
45 void operator()(U&& value) {
46 assert(state_);
47 assert(ctx_);
48 assert(!state_->current.has_value());
49 state_->current.emplace(std::forward<U>(value));
50 ctx_->Suspend();
51 }
52
53 private:
54 friend class Generator;
55
56 YieldContext(State* state, CoroutineSuspendContext* ctx) noexcept
57 : state_(state)
58 , ctx_(ctx) {}
59
60 State* state_ {nullptr};
61 CoroutineSuspendContext* ctx_ {nullptr};
62 };
63
64 using Body = fu2::unique_function<void(YieldContext&)>;
65
76 static Generator Make(Body body,
77 std::size_t stack_size_bytes = 262144,
79 if (!static_cast<bool>(body)) {
80 throw std::invalid_argument("generator body is null.");
81 }
82
83 auto state = std::make_shared<State>();
84 auto coroutine = Coroutine::Make(
85 [state, body = std::move(body)](CoroutineSuspendContext& ctx) mutable {
86 YieldContext yield_ctx(state.get(), &ctx);
87 body(yield_ctx);
88 },
89 stack_size_bytes,
90 std::move(resource));
91
92 return Generator(std::move(coroutine), std::move(state));
93 }
94
99 struct Builder {
100 public:
102 : stack_size_bytes_(262144)
103 , memory_resource_(GetDefaultMemoryResource()) {}
104
106 return Generator::Make(std::move(body), stack_size_bytes_, std::move(memory_resource_));
107 }
108
109 Builder SetStackSizeInBytes(std::size_t stack_size_bytes) && noexcept {
110 stack_size_bytes_ = stack_size_bytes;
111 return std::move(*this);
112 }
113
115 memory_resource_ = std::move(resource);
116 return std::move(*this);
117 }
118
119 private:
120 std::size_t stack_size_bytes_ {0};
121 MemoryResourceSharedPtr memory_resource_ {nullptr};
122 };
123
124 Generator(const Generator&) = delete;
125 Generator(Generator&&) noexcept = default;
126 Generator& operator=(const Generator&) = delete;
127 Generator& operator=(Generator&&) noexcept = default;
128 ~Generator() = default;
129
134 [[nodiscard]] bool IsDone() const noexcept {
135 return coroutine_.IsDone();
136 }
137
142 bool Next() {
143 assert(state_);
144 if (coroutine_.IsDone()) {
145 return false;
146 }
147
148 state_->current.reset();
149
150 coroutine_.Resume();
151 return state_->current.has_value();
152 }
153
160 assert(state_);
161 if (!state_->current.has_value()) {
162 throw std::logic_error("generator has no value.");
163 }
164
165 T value = std::move(*state_->current);
166 state_->current.reset();
167 return value;
168 }
169
170private:
171 struct State {
172 std::optional<T> current;
173 };
174
175 explicit Generator(Coroutine coroutine, std::shared_ptr<State> state)
176 : state_(std::move(state))
177 , coroutine_(std::move(coroutine)) {}
178
179 std::shared_ptr<State> state_;
180 Coroutine coroutine_;
181};
182
183} // namespace cortex
Provides a mechanism for a coroutine to suspend itself.
Definition coroutine_suspend_context.hpp:17
virtual void Suspend()=0
Suspends the current coroutine's execution.
static Coroutine Make(CoroutineBody body, std::size_t stack_size_bytes=kDefaultStackSizeBytes, MemoryResourceSharedPtr resource=GetDefaultMemoryResource())
Creates a new coroutine with the specified body and stack size.
void Resume()
Resumes the execution of the coroutine.
bool IsDone() const noexcept
Checks if the coroutine has finished its execution.
Context provided to the generator body to yield values.
Definition generator.hpp:37
YieldContext(const YieldContext &)=delete
YieldContext(YieldContext &&)=delete
YieldContext & operator=(const YieldContext &)=delete
YieldContext & operator=(YieldContext &&)=delete
void operator()(U &&value)
Definition generator.hpp:45
A stackful generator that yields values of type T.
Definition generator.hpp:27
bool IsDone() const noexcept
Checks if the generator has finished its execution.
Definition generator.hpp:134
Generator(Generator &&) noexcept=default
bool Next()
Resumes execution until a value is yielded or the generator completes.
Definition generator.hpp:142
fu2::unique_function< void(YieldContext &)> Body
Definition generator.hpp:64
static Generator Make(Body body, std::size_t stack_size_bytes=262144, MemoryResourceSharedPtr resource=GetDefaultMemoryResource())
Creates a new generator with the specified body and stack size.
Definition generator.hpp:76
Generator(const Generator &)=delete
T DetachValue()
Moves out the current value and clears it.
Definition generator.hpp:159
Main entry point for the cortex coroutine library.
Context for suspending coroutine execution.
Definition base_coroutine.hpp:14
MemoryResourceSharedPtr GetDefaultMemoryResource()
std::shared_ptr< MemoryResource > MemoryResourceSharedPtr
Definition memory_resource.hpp:30
A builder class for creating Generator instances with custom configuration.
Definition generator.hpp:99
Builder()
Definition generator.hpp:101
Builder SetMemoryResource(MemoryResourceSharedPtr resource) &&noexcept
Definition generator.hpp:114
Builder SetStackSizeInBytes(std::size_t stack_size_bytes) &&noexcept
Definition generator.hpp:109
Generator Build(Body body) &&
Definition generator.hpp:105