AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
AScheduler.h
    1/*
    2 * AUI Framework - Declarative UI toolkit for modern C++20
    3 * Copyright (C) 2020-2024 Alex2772 and Contributors
    4 *
    5 * SPDX-License-Identifier: MPL-2.0
    6 *
    7 * This Source Code Form is subject to the terms of the Mozilla Public
    8 * License, v. 2.0. If a copy of the MPL was not distributed with this
    9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
   10 */
   11
   12#pragma once
   13
   14#include <chrono>
   15#include <functional>
   16#include <list>
   17#include "AUI/Reflect/AEnumerate.h"
   18#include <AUI/Thread/AMutex.h>
   19#include <AUI/Thread/AConditionVariable.h>
   20#include <AUI/Thread/IEventLoop.h>
   21#include <AUI/Util/ABitField.h>
   22
   23
   27AUI_ENUM_FLAG(ASchedulerIteration) {
   28    NONE = 0,
   29
   37    DONT_BLOCK_INFINITELY = 0b1,
   38
   46    DONT_BLOCK_TIMED = 0b10,
   47
   51    DONT_BLOCK = DONT_BLOCK_INFINITELY | DONT_BLOCK_TIMED,
   52};
   53
   58class API_AUI_CORE AScheduler: public IEventLoop {
   59private:
   60    using SchedulerDuration = std::chrono::microseconds;
   61
   62    struct Timer {
   63        std::chrono::milliseconds timeout;
   64        std::chrono::high_resolution_clock::time_point nextExecution;
   65        std::function<void()> callback;
   66    };
   67
   68    struct Task {
   69        std::chrono::high_resolution_clock::time_point executionTime;
   70        std::function<void()> callback;
   71        _weak<Timer> timer;
   72    };
   73public:
   74    using TimerHandle = _weak<Timer>;
   75
   76    AScheduler();
   77
   83    bool iteration(ABitField<ASchedulerIteration> flag = ASchedulerIteration::NONE);
   84
   85    void notifyProcessMessages() override;
   86    void loop() override;
   87
   88    template<typename Duration>
   89    void enqueue(Duration timeout, std::function<void()> callback) {
   90        std::unique_lock lock(mSync);
   91        Task asTask = {
   92                std::chrono::duration_cast<SchedulerDuration>(timeout) + currentTime(),
   93                std::move(callback)
   94        };
   95        enqueueTask(std::move(asTask));
   96        mCV.notify_all();
   97    }
   98
  107    template<typename Duration>
  108    TimerHandle timer(Duration timeout, std::function<void()> callback) {
  109        auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
  110        Timer t = {
  111                millis,
  112                millis + currentTime(),
  113                std::move(callback)
  114        };
  115        auto asTimer = _new<Timer>(std::move(t));
  116
  117        std::unique_lock lock(mSync);
  118        mTimers.push_back(asTimer);
  119        enqueueTimer(asTimer);
  120        return asTimer;
  121    }
  122
  123
  124    void removeTimer(const TimerHandle& t);
  125
  126    [[nodiscard]]
  127    bool emptyTasks() const noexcept {
  128        return mTasks.empty();
  129    }
  130
  131    void stop() {
  132        mIsRunning = false;
  133        mCV.notify_all();
  134    }
  135
  136
  137private:
  138    AMutex mSync;
  139    AConditionVariable mCV;
  140    bool mIsRunning = false;
  141
  142    std::list<Task> mTasks;
  143    std::list<_<Timer>> mTimers;
  144
  145    static std::chrono::high_resolution_clock::time_point currentTime() noexcept {
  146        return std::chrono::high_resolution_clock::now();
  147    }
  148
  149    void enqueueTimer(const _<Timer>& timer) {
  150        Task t = {
  151                timer->nextExecution,
  152                [this, timer]() {
  153                    timer->callback();
  154                    std::unique_lock lock(mSync);
  155                    enqueueTimer(timer);
  156                },
  157                timer
  158        };
  159        timer->nextExecution += timer->timeout;
  160        enqueueTask(std::move(t));
  161    }
  162
  163
  164    void enqueueTask(Task&& asTask) {
  165        auto whereToInsert = std::find_if(mTasks.begin(), mTasks.end(), [&](const Task& rhs) {
  166            return asTask.executionTime < rhs.executionTime;
  167        });
  168
  169        mTasks.insert(whereToInsert, std::move(asTask));
  170        mCV.notify_all();
  171    }
  172
  173};
Bit field implementation.
Definition ABitField.h:20
void notify_all() noexcept
Definition AConditionVariable.h:62
void notifyProcessMessages() override
Notifies this IEventLoop that its thread got a new message to process.
void loop() override
Do message processing loop.
TimerHandle timer(Duration timeout, std::function< void()> callback)
Creates a timer.
Definition AScheduler.h:108
bool iteration(ABitField< ASchedulerIteration > flag=ASchedulerIteration::NONE)
Performs an iteration.
@ NONE
Definition AFloat.h:23
type_of< T > t
Selects views that are of the specified C++ types.
Definition type_of.h:71
#define AUI_ENUM_FLAG(name)
Make a bitfield-style enum class.
Definition AEnumerate.h:227
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:51