Newer
Older
mbed-os / events / tests / UNITTESTS / doubles / fakes / events / EventQueue.h
@Rajkumar Kanagaraj Rajkumar Kanagaraj on 9 Jul 2021 3 KB CMake: Move events fakes into events double dir
/* mbed Microcontroller Library
 * Copyright (c) 2020 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef EVENTQUEUE_FAKE_H
#define EVENTQUEUE_FAKE_H

#include <map>
#include <memory>
#include <functional>
#include <algorithm>
#include <vector>
#include "events/EventQueue.h"
#include <chrono>
#include <mstd_tuple>

namespace events {

typedef int handle_t;
typedef std::function<void()> function_t;
typedef unsigned tick_t;

class EventQueue {
    using duration = std::chrono::duration<int, std::milli>;

public:
    EventQueue(unsigned size = 0, unsigned char *buffer = NULL) { delete buffer; };

    ~EventQueue() { };

    /** This will advance time by given amount of milliseconds and then dispatch all events that were set to happen in that time.
     *
     * @param ms number of miliseconds to advance time
     */
    void dispatch(int milliseconds = -1) {
        if (milliseconds > 0) {
            process_events(milliseconds);
        } else {
            _now = (tick_t)-1;
            process_events();
            _now = 0;
        }
    };

    tick_t tick() {
        return _now;
    };

    bool cancel(handle_t id) {
        return cancel_handler(id);
    };

    /** Get number of events in queue.
     *
     * @return Number of events waiting in the queue.
     */
    size_t size() const {
        return _handlers.size();
    }

    template<typename F, typename ... ArgTs>
    handle_t call(F f, ArgTs... args) {
        return call_handler(
            [f, args = mstd::make_tuple(args...)]() {
                mstd::apply(f, args);
            }
        );
    }

    template<typename F, typename ... ArgTs>
    handle_t call_in(duration ms, F f, ArgTs... args) {
        return call_handler_in(
            ms.count(),
            [f, args = mstd::make_tuple(args...)]() {
                mstd::apply(f, args);
            }
        );
    }

    template <typename T, typename R, typename... ArgTs>
    int call(T *obj, R(T::*method)(ArgTs...), ArgTs... args) {
        return call_handler(
            [obj, method, args = mstd::make_tuple(args...)]() {
                mstd::apply(method, obj, args);
            }
        );
    }

    template <typename T, typename R, typename... ArgTs>
    int call_in(duration ms, T *obj, R(T::*method)(ArgTs...), ArgTs... args) {
        return call_handler_in(
            ms.count(),
            [obj, method, args = mstd::make_tuple(args...)]() {
                mstd::apply(method, obj, args);
            }
        );
    }

private:
    handle_t call_handler(function_t handler);

    handle_t call_handler_in(tick_t ms, function_t handler);

    bool cancel_handler(handle_t handle);

    void process_events(tick_t duration_ms);

    void process_events();

private:
    struct internal_event {
        std::unique_ptr<function_t> handler;
        tick_t tick;
        handle_t handle;
    };

    std::vector<internal_event> _handlers;
    tick_t _now = 0;
    handle_t _handler_id = 0;
};

}

#endif //EVENTQUEUE_FAKE_H