-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCompromise.h
133 lines (99 loc) · 2.89 KB
/
Compromise.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#ifndef COMPROMISE_H
#define COMPROMISE_H
// Simple C++ coroutine helper library
// https://github.com/cyanide-burnout/Compromise
// Artem Prilutskiy, 2022-2025
#include <any>
#include <utility>
#include <coroutine>
#include <exception>
#include <functional>
namespace Compromise
{
struct Promise;
class Future;
enum Status
{
Idle,
Await,
Yield,
Return
};
typedef std::function<bool (Future*, Status)> Hook;
typedef std::coroutine_handle<Promise> Handle;
using Task = Future;
// In this implementation it is allowed to pass value back to caller by co_yield only
struct Suspender
{
bool await_ready() noexcept;
void await_suspend(Handle) noexcept;
void await_resume() const noexcept;
Future* future;
Handle entry;
int status;
};
template<typename Actor, typename Type> struct Awaiter
{
constexpr bool await_ready() const { return false; };
bool await_suspend(Handle handle) { return actor.wait(handle); };
Type await_resume() { return actor.value(); };
Actor& actor;
};
struct Promise
{
Promise();
Future get_return_object();
std::suspend_never initial_suspend() noexcept;
Suspender final_suspend() noexcept;
Suspender yield_value(std::any value);
void unhandled_exception();
void return_void();
Handle entry;
Status status;
Future* future;
std::any data;
std::exception_ptr exception;
};
class Future
{
public:
using promise_type = Promise;
Future(const Future& future) = delete;
explicit Future(Promise* promise);
Future(Handle&& handle);
Future(Future&& future);
~Future();
bool done();
void resume();
void rethrow();
void release();
Handle& handle() &;
std::any& value() &;
bool wait(Handle& handle);
operator bool();
std::any& operator ()();
Awaiter<Future, std::any&> operator co_await() noexcept;
Hook hook;
private:
Handle routine;
};
template<typename Type> class Emitter
{
public:
const Type& value() & { return data; };
bool wait(Handle& handle) { routine = handle; routine.promise().status = Await; return !update(data); };
void wake(const Type& event) { if (routine) { data = event; std::exchange(routine, nullptr)(); } };
Awaiter<Emitter, const Type&> operator co_await() noexcept { return { *this }; };
private:
Handle routine;
Type data;
protected:
virtual bool update(Type&)
{
// In case of synchronous processing, update() can update the data and return true to avoid coroutine from suspension
// Otherwise update() has to return false and following callback must call wake() to resume coroutine
return false;
};
};
};
#endif