blob: 9a0aa6ed7fb75ea71a2b4c088305e667d38e58cf [file] [log] [blame]
Neil Balchc8f41ed2018-01-20 22:06:53 -08001#ifndef _AOS_EVENTS_SIMULATED_EVENT_LOOP_H_
2#define _AOS_EVENTS_SIMULATED_EVENT_LOOP_H_
3
4#include <map>
5#include <memory>
6#include <unordered_set>
7#include <utility>
8#include <vector>
9
10#include "aos/events/event-loop.h"
11
12namespace aos {
13
14class RefCountedBuffer {
15 public:
16 RefCountedBuffer() {}
17 ~RefCountedBuffer() { clear(); }
18
19 explicit RefCountedBuffer(aos::Message *data) : data_(data) {}
20
21 explicit RefCountedBuffer(size_t size) {
22 data_ = reinterpret_cast<uint8_t *>(malloc(kRefCountSize + size)) +
23 kRefCountSize;
24 // Initialize the allocated memory with an integer
25 *GetRefCount() = 1;
26 }
27
28 RefCountedBuffer(const RefCountedBuffer &other) {
29 data_ = other.data_;
30 ++*GetRefCount();
31 }
32
33 RefCountedBuffer(RefCountedBuffer &&other) { std::swap(data_, other.data_); }
34
35 RefCountedBuffer &operator=(const RefCountedBuffer &other) {
36 if (this == &other) return *this;
37 clear();
38 data_ = other.data_;
39 ++*GetRefCount();
40 return *this;
41 }
42
43 RefCountedBuffer &operator=(RefCountedBuffer &&other) {
44 if (this == &other) return *this;
45 std::swap(data_, other.data_);
46 return *this;
47 }
48
49 aos::Message *get() const { return static_cast<aos::Message *>(data_); }
50
51 aos::Message *release() {
52 auto tmp = get();
53 data_ = nullptr;
54 return tmp;
55 }
56
57 void clear() {
58 if (data_ != nullptr) {
59 if (--*GetRefCount() == 0) {
60 // Free memory block from the start of the allocated block
61 free(GetRefCount());
62 }
63 data_ = nullptr;
64 }
65 }
66
67 private:
68 void *data_ = nullptr;
69 // Qty. memory to be allocated to the ref counter
70 static constexpr size_t kRefCountSize = sizeof(int64_t);
71
72 int64_t *GetRefCount() {
73 // Need to cast the void* to an 8 bit long object (size of void* is
74 // technically 0)
75 return reinterpret_cast<int64_t *>(static_cast<void *>(
76 reinterpret_cast<uint8_t *>(data_) - kRefCountSize));
77 }
78};
79
80class EventScheduler {
81 public:
82 using QueueType = ::std::multimap<::aos::monotonic_clock::time_point,
83 ::std::function<void()>>;
84 using Token = QueueType::iterator;
85
86 // Schedule an event with a callback function
87 // Returns an iterator to the event
88 Token Schedule(::aos::monotonic_clock::time_point time,
89 ::std::function<void()> callback);
90
91 // Deschedule an event by its iterator
92 void Deschedule(Token token);
93
94 void Run();
95
96 void Exit() { is_running_ = false; }
97
Austin Schuh7267c532019-05-19 19:55:53 -070098 ::aos::monotonic_clock::time_point monotonic_now() const { return now_; }
Neil Balchc8f41ed2018-01-20 22:06:53 -080099
100 private:
101 ::aos::monotonic_clock::time_point now_ = ::aos::monotonic_clock::epoch();
102 QueueType events_list_;
103 bool is_running_ = false;
104};
105
106class SimulatedQueue {
107 public:
Austin Schuhd681bbd2019-02-02 12:03:32 -0800108 explicit SimulatedQueue(const QueueTypeInfo &type, const ::std::string &name,
109 EventScheduler *scheduler)
110 : type_(type), name_(name), scheduler_(scheduler){};
Neil Balchc8f41ed2018-01-20 22:06:53 -0800111
Austin Schuh7267c532019-05-19 19:55:53 -0700112 ::std::unique_ptr<RawSender> MakeRawSender(EventLoop *event_loop);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800113
Austin Schuh7267c532019-05-19 19:55:53 -0700114 ::std::unique_ptr<RawFetcher> MakeRawFetcher();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800115
Austin Schuh7267c532019-05-19 19:55:53 -0700116 void MakeRawWatcher(
117 ::std::function<void(const ::aos::Message *message)> watcher);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800118
119 void Send(RefCountedBuffer message) {
120 index_++;
121 latest_message_ = message;
122 for (auto &watcher : watchers_) {
Austin Schuh7267c532019-05-19 19:55:53 -0700123 scheduler_->Schedule(scheduler_->monotonic_now(),
Neil Balchc8f41ed2018-01-20 22:06:53 -0800124 [watcher, message]() { watcher(message.get()); });
125 }
126 }
127
128 const RefCountedBuffer &latest_message() { return latest_message_; }
129
130 int64_t index() { return index_; }
131
132 size_t size() { return type_.size; }
133
Austin Schuhd681bbd2019-02-02 12:03:32 -0800134 const char *name() const { return name_.c_str(); }
135
Neil Balchc8f41ed2018-01-20 22:06:53 -0800136 private:
137 int64_t index_ = -1;
138 QueueTypeInfo type_;
Austin Schuhd681bbd2019-02-02 12:03:32 -0800139 const ::std::string name_;
Neil Balchc8f41ed2018-01-20 22:06:53 -0800140 ::std::vector<std::function<void(const aos::Message *message)>> watchers_;
141 RefCountedBuffer latest_message_;
142 EventScheduler *scheduler_;
143};
144
Neil Balchc8f41ed2018-01-20 22:06:53 -0800145class SimulatedEventLoopFactory {
146 public:
Austin Schuh7267c532019-05-19 19:55:53 -0700147 ::std::unique_ptr<EventLoop> MakeEventLoop();
148
149 void Run() { scheduler_.Run(); }
150
151 monotonic_clock::time_point monotonic_now() const {
152 return scheduler_.monotonic_now();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800153 }
154
155 private:
156 EventScheduler scheduler_;
157 ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue> queues_;
158};
Austin Schuh7267c532019-05-19 19:55:53 -0700159
Neil Balchc8f41ed2018-01-20 22:06:53 -0800160} // namespace aos
Austin Schuh7267c532019-05-19 19:55:53 -0700161
Neil Balchc8f41ed2018-01-20 22:06:53 -0800162#endif //_AOS_EVENTS_TEST_EVENT_LOOP_H_