HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
coroutine.hpp
1// Copyright Take Vos 2020-2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include <ranges>
8#include <concepts>
9#include <coroutine>
10#include <optional>
11
12namespace tt {
13
24template<typename T>
25class generator {
26public:
27 using value_type = T;
28
30 public:
31 generator<value_type> get_return_object()
32 {
33 return generator{handle_type::from_promise(*this)};
34 }
35
36 value_type const &value() {
37 return *_value;
38 }
39
40 static std::suspend_always initial_suspend() noexcept
41 {
42 return {};
43 }
44
45 static std::suspend_always final_suspend() noexcept
46 {
47 return {};
48 }
49
50 std::suspend_always yield_value(value_type const &value) noexcept
51 {
52 _value = value;
53 return {};
54 }
55
56 std::suspend_always yield_value(value_type &&value) noexcept
57 {
58 _value = std::move(value);
59 return {};
60 }
61
62 void return_void() noexcept {}
63
64 // Disallow co_await in generator coroutines.
65 void await_transform() = delete;
66
67 [[noreturn]] static void unhandled_exception()
68 {
69 throw;
70 }
71
72 private:
73 std::optional<value_type> _value;
74 };
75
76 using handle_type = std::coroutine_handle<promise_type>;
77
78 explicit generator(handle_type coroutine) : _coroutine(coroutine) {}
79
80 generator() = default;
82 {
83 if (_coroutine) {
84 _coroutine.destroy();
85 }
86 }
87
88 generator(const generator &) = delete;
89 generator &operator=(const generator &) = delete;
90
91 generator(generator &&other) noexcept : _coroutine{other._coroutine}
92 {
93 tt_axiom(&other != this);
94 other._coroutine = {};
95 }
96
97 generator &operator=(generator &&other) noexcept
98 {
99 tt_return_on_self_assignment(other);
100 if (_coroutine) {
101 _coroutine.destroy();
102 }
103 _coroutine = other._coroutine;
104 other._coroutine = {};
105 return *this;
106 }
107
110 class iterator {
111 public:
112 explicit iterator(handle_type coroutine) : _coroutine{coroutine} {}
113
117 {
118 _coroutine.resume();
119 return *this;
120 }
121
124 value_type const &operator*() const
125 {
126 return _coroutine.promise().value();
127 }
128
131 [[nodiscard]] bool operator==(std::default_sentinel_t) const
132 {
133 return !_coroutine || _coroutine.done();
134 }
135
136
137 private:
138 handle_type _coroutine;
139 };
140
144 {
145 if (_coroutine) {
146 _coroutine.resume();
147 }
148 return iterator{_coroutine};
149 }
150
153 std::default_sentinel_t end()
154 {
155 return {};
156 }
157
158private:
159 handle_type _coroutine;
160};
161
162} // namespace tt
163
A return value for a generator-function.
Definition coroutine.hpp:25
std::default_sentinel_t end()
Return a sentinal for the iterator.
Definition coroutine.hpp:153
iterator begin()
Start the generator-function and return an iterator.
Definition coroutine.hpp:143
Definition coroutine.hpp:29
A forward iterator which iterates through values co_yieled by the generator-function.
Definition coroutine.hpp:110
bool operator==(std::default_sentinel_t) const
Check if the generator-function has finished.
Definition coroutine.hpp:131
iterator & operator++()
Resume the generator-function.
Definition coroutine.hpp:116
value_type const & operator*() const
Retrieve the value co_yielded by the generator-function.
Definition coroutine.hpp:124
T move(T... args)