123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- // SPDX-License-Identifier: MIT
- // SPDX-FileCopyrightText: 2022 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 {
- ItemGuard() : message{nullptr} {}
- ItemGuard(Message *message_, ItemQueueBase *item_queue_)
- : message{message_}, item_queue{item_queue_} {}
- ItemGuard(const ItemGuard &) = delete;
- ItemGuard(ItemGuard &&) = delete;
- ~ItemGuard();
- ItemGuard &operator=(ItemGuard &&);
- inline operator bool() { return message; }
- inline Message &operator*() { return *message; }
- void reset();
- private:
- Message *message;
- ItemQueueBase *item_queue;
- };
- struct ItemQueueBase {
- ItemQueueBase(size_t item_size, size_t items_count);
- ItemQueueBase(const ItemQueueBase &) = delete;
- ItemQueueBase(ItemQueueBase &&) = delete;
- Message *next();
- template <typename MessageType, typename... Args>
- MessageType *put(Args... args) {
- static_assert(std::is_base_of<Message, MessageType>::value,
- "type should be inherited from Message");
- if (free_index == occupied_index) {
- return nullptr;
- }
- assert(free_index != undef);
- auto ptr = buff_ptr + item_size * free_index;
- if (occupied_index == undef) {
- occupied_index = free_index;
- }
- free_index = (free_index + 1) % items_count;
- return new (ptr) MessageType(std::forward<Args>(args)...);
- }
- void release(Message *);
- protected:
- static constexpr auto undef = std::numeric_limits<uint8_t>::max();
- friend struct Message;
- void post_constructor(char *buff);
- char *buff_ptr;
- index_t item_size;
- index_t items_count;
- index_t free_index;
- volatile index_t occupied_index;
- };
- 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 {
- QueueBase(ItemQueueBase **queues, size_t queue_count);
- QueueBase(const QueueBase &) = delete;
- QueueBase(QueueBase &&) = delete;
- template <typename MessageType, typename... Args>
- bool put(size_t queue_index, Args... args) {
- assert((queue_index < queue_count) && "valid queue/priority");
- assert((sizeof(MessageType) <= item_size) &&
- "no storage for the message, increase ItemSize");
- return queues[queue_index]->put<MessageType>(std::forward<Args>(args)...);
- }
- ItemGuard next();
- private:
- ItemQueueBase **queues;
- uint8_t queue_count;
- };
- template <typename Storage, size_t... Counts> struct Queue : QueueBase {
- static_assert(Storage::item_size > sizeof(Message),
- "not enough storage for a message");
- using Queues = std::tuple<ItemQueue<Storage, Counts>...>;
- 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 <size_t 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
|