Last active
December 5, 2019 22:58
-
-
Save qookei/146c1c36457d6fe444fc60cf536dceb8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <queue> | |
#include <utility> | |
#include <tuple> | |
#include <algorithm> | |
#include <type_traits> | |
namespace async { | |
template <typename AwaitFn, typename... AwaitArgs> | |
struct awaitor { | |
awaitor(AwaitFn await_fn, AwaitArgs... args) | |
:_await_fn{await_fn}, _args{args...} { | |
} | |
AwaitFn _await_fn; | |
std::tuple<AwaitArgs...> _args; | |
bool is_done() { | |
return std::apply(_await_fn, _args); | |
} | |
}; | |
template <typename CompleteFn, typename... CompleteArgs> | |
struct completor { | |
completor(CompleteFn complete_fn, CompleteArgs... args) | |
:_complete_fn{complete_fn}, _args{args...} { | |
} | |
CompleteFn _complete_fn; | |
std::tuple<CompleteArgs...> _args; | |
using completor_type = CompleteFn; | |
using invoke_type = std::invoke_result_t<CompleteFn, CompleteArgs...>; | |
void invoke_complete() { | |
std::apply(_complete_fn, _args); | |
} | |
}; | |
template <typename Awaitor, typename Completor> | |
struct async_thing { | |
async_thing(Awaitor awaitor, Completor completor) | |
: _awaitor{awaitor}, _completor{completor} { | |
} | |
Awaitor _awaitor; | |
Completor _completor; | |
bool try_complete() { | |
if (!_awaitor.is_done()) | |
return false; | |
else | |
_completer.invoke_complete(); | |
return true; | |
} | |
}; | |
struct scheduled_element_base { | |
virtual ~scheduled_element_base() {} | |
virtual bool try_complete() = 0; | |
}; | |
template <typename AsyncThing> | |
struct scheduled_element : public scheduled_element_base { | |
scheduled_element(AsyncThing thing) :_thing{thing} {} | |
bool try_complete() override { return _thing.try_complete(); } | |
private: | |
AsyncThing _thing; | |
}; | |
struct scheduler { | |
std::vector<scheduled_element_base *> _scheduled; | |
std::queue<scheduled_element_base *> _queued; | |
void run_schedule() { | |
if (!_queued.size()) | |
reset_schedule(); | |
if (!_queued.size()) | |
std::cerr << "empty schedule" << std::endl; | |
while (_queued.size()) { | |
auto e = _queued.front(); | |
if(e->try_complete()) | |
remove_from_schedule(e); | |
_queued.pop(); | |
} | |
reset_schedule(); | |
} | |
void run_until_empty() { | |
while(_scheduled.size()) | |
run_schedule(); | |
} | |
template <typename AsyncThing> | |
void schedule(AsyncThing t) { | |
auto *e = new scheduled_element{t}; | |
schedule_thing(e); | |
} | |
private: | |
void reset_schedule() { | |
for (auto e : _scheduled) | |
_queued.push(e); | |
} | |
void schedule_thing(scheduled_element_base *e) { | |
_scheduled.push_back(e); | |
} | |
void remove_from_schedule(scheduled_element_base *e) { | |
_scheduled.erase(std::find(_scheduled.begin(), _scheduled.end(), e)); | |
delete e; | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment