-
Notifications
You must be signed in to change notification settings - Fork 4
/
CoFiber.h
54 lines (45 loc) · 1.37 KB
/
CoFiber.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
#pragma once
#include "UniqueCoroutineHandle.h"
template<class T>
class ScopedExchange {
T &m_actual;
T m_old = {};
public:
constexpr ScopedExchange(T &target, const T &value)
: m_actual(target)
, m_old(std::move(m_actual)) {
m_actual = value;
}
constexpr ~ScopedExchange() noexcept { m_actual = std::move(m_old); }
};
template<class T, class V>
ScopedExchange(T &, const V &) -> ScopedExchange<T>;
class CoFiber {
struct Data {
UniqueCoroutineHandle<> coroutine{};
};
using DataPtr = std::shared_ptr<Data>;
DataPtr m{};
public:
static thread_local CoFiber current;
CoFiber() = default;
explicit CoFiber(std::shared_ptr<Data> &&ptr)
: m(ptr) {}
auto run(auto lambda) noexcept -> decltype(auto) {
auto scoped = ScopedExchange(CoFiber::current, *this);
return lambda();
}
template<class Functor, class... Args>
static auto launch(Functor functor, Args &&... args) {
static_assert(std::is_empty_v<Functor>, "Captures don't work here!");
auto fiber = CoFiber{std::make_shared<Data>()};
fiber.run([=, &args...] {
auto task = functor((Args &&) args...);
auto handle = task.extractHandle();
fiber.m->coroutine = UniqueCoroutineHandle<>{handle};
handle.resume();
});
return fiber;
}
};
inline thread_local CoFiber CoFiber::current;