123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- // SPDX-License-Identifier: MIT
- // SPDX-FileCopyrightText: 2022-2024 Ivan Baidakou
- #pragma once
- #include "message.hpp"
- #include <cassert>
- #include <cstddef>
- #include <limits>
- #include <tuple>
- #include <type_traits>
- #include <utility>
- namespace rotor_light {
- struct ItemQueueBase;
- /** \struct ItemGuard
- * \brief Message removal helper after message delivery
- */
- struct ItemGuard {
- ItemGuard() : message{nullptr} {}
- /** records message for removal */
- ItemGuard(Message *message_, ItemQueueBase *item_queue_)
- : message{message_}, item_queue{item_queue_} {}
- ItemGuard(const ItemGuard &) = delete;
- ItemGuard(ItemGuard &&) = delete;
- /** copy-assignment operator */
- ItemGuard &operator=(const ItemGuard &) = default;
- /** returns true if the guard holds a message */
- inline operator bool() { return message; }
- /** derefers to a message */
- inline Message &operator*() { return *message; }
- /** guarded message */
- Message *message;
- /** message origin/queue */
- ItemQueueBase *item_queue;
- };
- /** \struct ItemQueueBase
- * \brief base class for queues.
- *
- * Item = Message
- */
- struct ItemQueueBase {
- /** initializes queue with the message size and maximum amount of messsages */
- ItemQueueBase(size_t item_size, size_t items_count);
- ItemQueueBase(const ItemQueueBase &) = delete;
- ItemQueueBase(ItemQueueBase &&) = delete;
- /** returns the next stored message if there is one; otherwise nullptr
- * is returned */
- Message *next();
- /** constructs in-place new message by forwarding args into
- * message ctor.
- *
- * returns true if message was successfully inserted
- */
- template <typename MessageType, bool force, typename... Args>
- bool put(Args &&...args) {
- static_assert(std::is_base_of<Message, MessageType>::value,
- "type should be inherited from Message");
- assert((sizeof(MessageType) <= item_size) &&
- "no storage for the message, increase ItemSize");
- bool full = (items_size == items_count);
- bool r;
- if constexpr (!force) {
- if (full) {
- return false;
- }
- auto ptr = buff_ptr + item_size * free_index;
- if (free_index == items_size - 1) {
- free_index = 0;
- } else {
- ++free_index;
- }
- auto message = new (ptr) MessageType(std::forward<Args>(args)...);
- message->type = MessageType::type_id;
- ++items_count;
- r = true;
- } else {
- auto ptr = buff_ptr + item_size * free_index;
- if (!full) {
- ++items_count;
- if (free_index == items_size - 1) {
- free_index = 0;
- } else {
- ++free_index;
- }
- } else {
- ++free_index;
- if (occupied_index + 1 == items_size) {
- occupied_index = 0;
- } else {
- ++occupied_index;
- }
- }
- auto message = new (ptr) MessageType(std::forward<Args>(args)...);
- message->type = MessageType::type_id;
- r = full;
- }
- #ifdef ROTOR_LIGHT_QUEUE_SZ
- if (items_count_maxinum < items_count) {
- items_count_maxinum = items_count;
- }
- #endif
- return r;
- }
- #ifdef ROTOR_LIGHT_QUEUE_SZ
- /** returns maximum items count during queue lifetime */
- Index max_items() const;
- #endif
- /** deletes the last message from the queue */
- void release();
- /** \brief generic non-public fields accessor */
- template <typename T> auto &access() noexcept;
- protected:
- friend struct Message;
- /** records buffer pointer */
- void post_constructor(char *buff);
- private:
- char *buff_ptr;
- Index item_size;
- Index items_size;
- Index items_count;
- Index free_index;
- Index occupied_index;
- #ifdef ROTOR_LIGHT_QUEUE_SZ
- Index items_count_maxinum;
- #endif
- };
- /** \struct ItemQueue
- * \brief convenient helper for storing fixed amount of messages
- */
- template <typename Storage, size_t ItemsCount>
- struct ItemQueue : ItemQueueBase {
- static_assert(Storage::item_size > 0, "queue size have to be positive");
- ItemQueue() : ItemQueueBase(Storage::item_size, ItemsCount) {
- post_constructor(reinterpret_cast<char *>(&storage));
- }
- private:
- using Item = typename Storage::Item;
- Item storage[ItemsCount];
- };
- /** \struct QueueBase
- * \brief base class for meta-queue (list of queues, ordered by priorities))
- */
- struct QueueBase {
- /** records storage of all sub-queues and their amount */
- QueueBase(ItemQueueBase **queues, size_t queue_count);
- QueueBase(const QueueBase &) = delete;
- QueueBase(QueueBase &&) = delete;
- /** constructs in-place new message by forwarding args into
- * message ctor.
- *
- * returns `true` if message is successfully created
- **/
- template <typename MessageType, bool force, typename... Args>
- bool put(Index queue_index, Args &&...args) {
- assert((queue_index < queue_count) && "valid queue/priority");
- auto &queue = queues[queue_index];
- return queue->put<MessageType, force>(std::forward<Args>(args)...);
- }
- #ifdef ROTOR_LIGHT_QUEUE_SZ
- /** returns maximum items count during queue lifetime */
- Index max_items(Index queue_index) const;
- #endif
- /** returns item-guard for the next message. Queues priorities are taken
- * into the account */
- ItemGuard next();
- /** \brief generic non-public fields accessor */
- template <typename T> auto &access() noexcept;
- private:
- ItemQueueBase **queues;
- uint8_t queue_count;
- };
- /** \struct Queue
- * \brief conveninent helper for meta-queue (list of queues, ordered by
- * priorities)
- */
- template <typename Storage, size_t... Counts> struct Queue : QueueBase {
- static_assert(Storage::item_size > sizeof(Message),
- "not enough storage for a message");
- /** tuple alias to store different queues */
- using Queues = std::tuple<ItemQueue<Storage, Counts>...>;
- /** the total amount of sub-queues */
- static constexpr size_t Size = std::tuple_size<Queues>::value;
- static_assert(Size > 0, "there should be at least one queue");
- Queue() : QueueBase(queues, Size) { fill_queue<0>(); }
- private:
- template <Index Index> void fill_queue() {
- auto &queue = std::get<Index>(queues_storage);
- queues[Index] = &queue;
- if constexpr (Index + 1 < Size) {
- fill_queue<Index + 1>();
- }
- }
- Queues queues_storage;
- ItemQueueBase *queues[Size];
- };
- } // namespace rotor_light
|