rotor_light
real-time C++ actor micro-framework for embedded systems, supervisable
queue.hpp
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: 2022 Ivan Baidakou
3
4#pragma once
5
6#include "message.hpp"
7#include <cassert>
8#include <cstddef>
9#include <limits>
10#include <tuple>
11#include <type_traits>
12#include <utility>
13
14namespace rotor_light {
15
16struct ItemQueueBase;
17
21struct ItemGuard {
22 ItemGuard() : message{nullptr} {}
23
25 ItemGuard(Message *message_, ItemQueueBase *item_queue_)
26 : message{message_}, item_queue{item_queue_} {}
27 ItemGuard(const ItemGuard &) = delete;
28 ItemGuard(ItemGuard &&) = delete;
29
31 ItemGuard &operator=(const ItemGuard &) = default;
32
34 inline operator bool() { return message; }
35
37 inline Message &operator*() { return *message; }
38
41
44};
45
53 ItemQueueBase(size_t item_size, size_t items_count);
54 ItemQueueBase(const ItemQueueBase &) = delete;
55 ItemQueueBase(ItemQueueBase &&) = delete;
56
60
67 template <typename MessageType, typename... Args>
68 MessageType *put(Args... args) {
69 static_assert(std::is_base_of<Message, MessageType>::value,
70 "type should be inherited from Message");
71 assert((sizeof(MessageType) <= item_size) &&
72 "no storage for the message, increase ItemSize");
73 if (items_size == items_count) {
74 return nullptr;
75 }
76 auto ptr = buff_ptr + item_size * free_index;
77 if (free_index == items_size - 1) {
78 free_index = 0;
79 } else {
80 ++free_index;
81 }
82 auto message = new (ptr) MessageType(std::forward<Args>(args)...);
83 message->type = MessageType::type_id;
84 ++items_count;
85 return message;
86 }
87
89 void release();
90
91protected:
92 friend struct Message;
94 void post_constructor(char *buff);
95
96private:
97 char *buff_ptr;
98 Index item_size;
99 Index items_size;
100 volatile Index items_count;
101 volatile Index free_index;
102 volatile Index occupied_index;
103};
104
108template <typename Storage, size_t ItemsCount>
110 static_assert(Storage::item_size > 0, "queue size have to be positive");
111
112 ItemQueue() : ItemQueueBase(Storage::item_size, ItemsCount) {
113 post_constructor(reinterpret_cast<char *>(&storage));
114 }
115
116private:
117 using Item = typename Storage::Item;
118 Item storage[ItemsCount];
119};
120
124struct QueueBase {
126 QueueBase(ItemQueueBase **queues, size_t queue_count);
127 QueueBase(const QueueBase &) = delete;
128 QueueBase(QueueBase &&) = delete;
129
135 template <typename MessageType, typename... Args>
136 bool put(size_t queue_index, Args... args) {
137 assert((queue_index < queue_count) && "valid queue/priority");
138 return queues[queue_index]->put<MessageType>(std::forward<Args>(args)...);
139 }
140
144
145private:
146 ItemQueueBase **queues;
147 uint8_t queue_count;
148};
149
154template <typename Storage, size_t... Counts> struct Queue : QueueBase {
155 static_assert(Storage::item_size > sizeof(Message),
156 "not enough storage for a message");
158 using Queues = std::tuple<ItemQueue<Storage, Counts>...>;
159
161 static constexpr size_t Size = std::tuple_size<Queues>::value;
162 static_assert(Size > 0, "there should be at least one queue");
163
164 Queue() : QueueBase(queues, Size) { fill_queue<0>(); }
165
166private:
167 template <size_t Index> void fill_queue() {
168 auto &queue = std::get<Index>(queues_storage);
169 queues[Index] = &queue;
170 if constexpr (Index + 1 < Size) {
171 fill_queue<Index + 1>();
172 }
173 }
174
175 Queues queues_storage;
176 ItemQueueBase *queues[Size];
177};
178
179} // namespace rotor_light
Message removal helper after message delivery.
Definition: queue.hpp:21
ItemGuard(Message *message_, ItemQueueBase *item_queue_)
Definition: queue.hpp:25
Message & operator*()
Definition: queue.hpp:37
ItemGuard & operator=(const ItemGuard &)=default
Message * message
Definition: queue.hpp:40
ItemQueueBase * item_queue
Definition: queue.hpp:43
base class for queues.
Definition: queue.hpp:51
MessageType * put(Args... args)
Definition: queue.hpp:68
ItemQueueBase(size_t item_size, size_t items_count)
void post_constructor(char *buff)
convenient helper for storing fixed amount of messages
Definition: queue.hpp:109
base class for all rotor-light messages
Definition: message.hpp:22
base class for meta-queue (list of queues, ordered by priorities))
Definition: queue.hpp:124
QueueBase(ItemQueueBase **queues, size_t queue_count)
bool put(size_t queue_index, Args... args)
Definition: queue.hpp:136
conveninent helper for meta-queue (list of queues, ordered by priorities)
Definition: queue.hpp:154
static constexpr size_t Size
Definition: queue.hpp:161
std::tuple< ItemQueue< Storage, Counts >... > Queues
Definition: queue.hpp:158