Skip to content

File command_queue.h

File List > command_queue.h

Go to the documentation of this file

#pragma once

#include <memory>
#include <mutex>
#include <queue>
#include <vector>

#include "command.h"
#include "utilities.h"
#ifndef ARDUINO
    #include "tests/mocks.h"
#endif

class SystemState;
class Command;
const inline auto CommandPointerComparator = [](const std::shared_ptr<Command>& left,
                                                const std::shared_ptr<Command>& right) -> bool {
    // A null command is "greater" than any valid command, so it will sink to the
    // bottom of the priority queue.
    if (!left) {
        return true;
    }
    if (!right) {
        return false;
    }
    return left->run_after > right->run_after;
};

class CommandQueue {
public:
    CommandQueue();
    void process(SystemState* state);

    template <typename T, typename... Args>
    void addCommand(Args&&... args) {
        auto newCommand = std::make_shared<T>(std::forward<Args>(args)...);
        max_run_after = std::max(max_run_after, newCommand->run_after);
        std::lock_guard<std::mutex> lock(xMutex);
        commandQueue.push(std::move(newCommand));
    }

    template <typename T, typename... Args>
    void addCommandAfter(Args&&... args) {
        auto run_time = max_run_after + 1;
        auto newCommand = std::make_shared<T>(std::forward<Args>(args)..., 0);
        newCommand->run_after = run_time;
        std::lock_guard<std::mutex> lock(xMutex);
        max_run_after = run_time;
        commandQueue.push(std::move(newCommand));
    }

    template <typename T, typename... Args>
    void runCommandIn(uint64_t duration, Args&&... args) {
        addCommand<T>(std::forward<Args>(args)..., duration);
    }

    std::string serialize();

private:
    uint64_t max_run_after = 0;
    std::priority_queue<
        std::shared_ptr<Command>,
        std::vector<std::shared_ptr<Command>>,
        decltype(CommandPointerComparator)>
                       commandQueue;
    mutable std::mutex xMutex;
};