Erki acbdbf4f7f
Some checks failed
CI & Unit Tests / Unit-Tests (push) Failing after 8s
CI & Unit Tests / Docs (push) Successful in 10s
WIP9: some improvements
2025-02-28 08:51:05 +02:00

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