130 lines
3.0 KiB
C++
130 lines
3.0 KiB
C++
//
|
|
// Created by erki on 30/01/25.
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <coroutine>
|
|
#include <cstdint>
|
|
#include <utility>
|
|
|
|
#include "skullc/coro/scheduler_base.hpp"
|
|
#include "skullc/coro/task.hpp"
|
|
|
|
namespace skullc::coro
|
|
{
|
|
|
|
template<typename T>
|
|
concept TaskType = requires(T task) {
|
|
{
|
|
task.get_handle().resume()
|
|
};
|
|
};
|
|
|
|
template<template<typename X> typename C>
|
|
class Scheduler final : public SchedulerBase
|
|
{
|
|
constexpr static auto cmp = [](const auto& a, const auto& b) {
|
|
return a.first > b.first;
|
|
};
|
|
|
|
public:
|
|
using Container = C<std::pair<uint32_t, std::coroutine_handle<>>>;
|
|
using PollerContainer = C<TaskPoller*>;
|
|
|
|
Scheduler() = default;
|
|
|
|
Scheduler(const Scheduler&) = delete;
|
|
Scheduler(Scheduler&&) = delete;
|
|
Scheduler& operator=(const Scheduler&) = delete;
|
|
Scheduler& operator=(Scheduler&&) = delete;
|
|
|
|
template<TaskType... T>
|
|
void start_tasks(T... tasks)
|
|
{
|
|
start(tasks...);
|
|
}
|
|
|
|
void schedule(std::coroutine_handle<> handle, uint32_t when) override
|
|
{
|
|
scheduled_.push_back({when, handle});
|
|
std::push_heap(scheduled_.begin(), scheduled_.end(), cmp);
|
|
}
|
|
|
|
void loop(const uint32_t& current_time_ms)
|
|
{
|
|
loop(std::chrono::duration<uint32_t, std::milli>(current_time_ms));
|
|
}
|
|
|
|
void loop(const std::chrono::duration<uint32_t, std::milli>& current_time)
|
|
{
|
|
if (!scheduled_.empty())
|
|
{
|
|
auto min_time = scheduled_.front();
|
|
if (min_time.first <= current_time.count())
|
|
{
|
|
std::pop_heap(scheduled_.begin(), scheduled_.end(), cmp);
|
|
scheduled_.pop_back();
|
|
if (min_time.second)
|
|
min_time.second.resume();
|
|
}
|
|
}
|
|
|
|
bool pollers_need_updating = false;
|
|
for (auto* poller : pollers_)
|
|
{
|
|
if (poller->isReady(current_time))
|
|
{
|
|
schedule(poller->stored_coro, current_time.count());
|
|
poller->stored_coro = nullptr;
|
|
pollers_need_updating = true;
|
|
}
|
|
}
|
|
|
|
if (pollers_need_updating)
|
|
pollers_.erase(std::remove_if(pollers_.begin(), pollers_.end(),
|
|
[](const auto* poller) { return poller->stored_coro == nullptr; }));
|
|
}
|
|
|
|
void add_poller(TaskPoller* poller) override
|
|
{
|
|
pollers_.push_back(poller);
|
|
}
|
|
|
|
bool remove(std::coroutine_handle<> handle) override
|
|
{
|
|
bool found = false;
|
|
for (auto& p : scheduled_)
|
|
if (p.second == handle)
|
|
{
|
|
std::swap(p, scheduled_.back());
|
|
scheduled_.pop_back();
|
|
std::make_heap(scheduled_.begin(), scheduled_.end(), cmp);
|
|
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
if (pollers_.size() > 0)
|
|
pollers_.erase(std::remove_if(pollers_.begin(), pollers_.end(),
|
|
[handle](const auto* poller) { return poller->stored_coro == handle; }));
|
|
return found;
|
|
}
|
|
|
|
private:
|
|
Container scheduled_;
|
|
PollerContainer pollers_;
|
|
|
|
template<typename T0, typename... R>
|
|
void start(T0& t0, R&... r)
|
|
{
|
|
t0.get_handle().resume();
|
|
if constexpr (sizeof...(r) > 0)
|
|
{
|
|
start(r...);
|
|
}
|
|
}
|
|
};
|
|
|
|
}// namespace skullc::coro
|