Skip to content

Instantly share code, notes, and snippets.

@qookei
Last active December 5, 2019 22:58
Show Gist options
  • Save qookei/146c1c36457d6fe444fc60cf536dceb8 to your computer and use it in GitHub Desktop.
Save qookei/146c1c36457d6fe444fc60cf536dceb8 to your computer and use it in GitHub Desktop.
#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