Fenix @develop
 
Loading...
Searching...
No Matches
promise.hpp
1#ifndef FENIX_TASKS_PROMISE_HPP
2#define FENIX_TASKS_PROMISE_HPP
3
4#include <coroutine>
5#include <exception>
6#include "subtask.hpp"
7#include "awaiter.hpp"
8#include "request.hpp"
9
10#include <cstdio>
11
12namespace fenix::tasks {
13
14namespace impl {
15template <typename T>
17 T val;
18 void return_value(const T& v) { val = v; }
19 T result() { return val; }
20};
21template <>
22struct ReturnHolder<void> {
23 void return_void() {};
24};
25}
26
27template <typename T, bool eager>
28class Task;
29
30template <typename T, bool eager = true>
31class Promise : public impl::ReturnHolder<T> {
32 public:
34 using TaskT = Task<T, eager>;
35 using HandleT = std::coroutine_handle<PromiseT>;
36
37 TaskT get_return_object() noexcept {
38 assert(!handle);
39 handle = HandleT::from_promise(*this);
40 return {this};
41 }
42
43 // Eagerly start tasks
44 auto initial_suspend() noexcept {
45 if constexpr (eager) return std::suspend_never{};
46 if constexpr (!eager) return std::suspend_always{};
47 }
48 // Don't destroy coroutine until object is destroyed
49 auto final_suspend() noexcept {
50 subtask.reset();
51 coro_done = true;
52 return std::suspend_always{};
53 }
54 // Rethrow exceptions immediately
55 void unhandled_exception() {
56 coro_done = true;
57 throw;
58 }
59
60 // Fixes some wonkiness in the standard and in the compiler implementations
61 // of coroutine cleanup w/ exceptions.
62 void register_owning_ptr(PromiseT** ptr) { owning_ptr = ptr; }
63 ~Promise() {
64 if (owning_ptr) *owning_ptr = nullptr;
65 }
66
67 void destroy() { handle.destroy(); }
68 bool done() { return coro_done; }
69
70 void resume() {
71 if (done()) return;
72 if (subtask) {
73 if (await_mode == AwaitMode::Blocking) subtask->wait();
74 else subtask->resume();
75 if (subtask->done()) subtask.reset();
76 }
77 if (!subtask) handle.resume();
78 }
79 void wait() {
80 await_mode = AwaitMode::Blocking;
81 while (!done()) resume();
82 }
83
84 template <Subtaskable U>
85 Awaiter<U> await_transform(U&& u) {
86 if constexpr (std::is_base_of_v<SubtaskBase, U>) {
87 subtask = std::make_shared<U>(std::forward<U>(u));
88 } else {
89 subtask = std::make_shared<Subtask<U>>(std::forward<U>(u));
90 }
91 return subtask.get();
92 }
93 Awaiter<Request> await_transform(MPI_Request*& r) {
94 return await_transform(Request(r));
95 }
96 Awaiter<Request> await_transform(MPI_Request& r) {
97 return await_transform(Request(&r));
98 }
99 auto await_transform(const std::suspend_always& s) {
100 subtask.reset();
101 return std::suspend_always{};
102 }
103
104 HandleT handle;
105 bool coro_done = false;
106 AwaitMode await_mode = AwaitMode::NonBlocking;
107 std::shared_ptr<SubtaskBase> subtask;
108 PromiseT** owning_ptr = nullptr;
109};
110
111} // namespace fenix::tasks
112
113#endif //FENIX_TASKS_PROMISE_HPP
Definition awaiter.hpp:14
Definition promise.hpp:31
Definition request.hpp:20
Definition task.hpp:16
Definition promise.hpp:16