queue.hpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // SPDX-License-Identifier: MIT
  2. // SPDX-FileCopyrightText: 2022 Ivan Baidakou
  3. #pragma once
  4. #include "message.hpp"
  5. #include <cassert>
  6. #include <cstddef>
  7. #include <limits>
  8. #include <tuple>
  9. #include <type_traits>
  10. #include <utility>
  11. namespace rotor_light {
  12. struct ItemQueueBase;
  13. struct ItemGuard {
  14. ItemGuard() : message{nullptr} {}
  15. ItemGuard(Message *message_, ItemQueueBase *item_queue_)
  16. : message{message_}, item_queue{item_queue_} {}
  17. ItemGuard(const ItemGuard &) = delete;
  18. ItemGuard(ItemGuard &&) = delete;
  19. ~ItemGuard();
  20. ItemGuard &operator=(ItemGuard &&);
  21. inline operator bool() { return message; }
  22. inline Message &operator*() { return *message; }
  23. void reset();
  24. private:
  25. Message *message;
  26. ItemQueueBase *item_queue;
  27. };
  28. struct ItemQueueBase {
  29. ItemQueueBase(size_t item_size, size_t items_count);
  30. ItemQueueBase(const ItemQueueBase &) = delete;
  31. ItemQueueBase(ItemQueueBase &&) = delete;
  32. Message *next();
  33. template <typename MessageType, typename... Args>
  34. MessageType *put(Args... args) {
  35. static_assert(std::is_base_of<Message, MessageType>::value,
  36. "type should be inherited from Message");
  37. if (free_index == occupied_index) {
  38. return nullptr;
  39. }
  40. assert(free_index != undef);
  41. auto ptr = buff_ptr + item_size * free_index;
  42. if (occupied_index == undef) {
  43. occupied_index = free_index;
  44. }
  45. free_index = (free_index + 1) % items_count;
  46. return new (ptr) MessageType(std::forward<Args>(args)...);
  47. }
  48. void release(Message *);
  49. protected:
  50. static constexpr auto undef = std::numeric_limits<uint8_t>::max();
  51. friend struct Message;
  52. void post_constructor(char *buff);
  53. char *buff_ptr;
  54. index_t item_size;
  55. index_t items_count;
  56. index_t free_index;
  57. volatile index_t occupied_index;
  58. };
  59. template <typename Storage, size_t ItemsCount>
  60. struct ItemQueue : ItemQueueBase {
  61. static_assert(Storage::item_size > 0, "queue size have to be positive");
  62. ItemQueue() : ItemQueueBase(Storage::item_size, ItemsCount) {
  63. post_constructor(reinterpret_cast<char *>(&storage));
  64. }
  65. private:
  66. using Item = typename Storage::Item;
  67. Item storage[ItemsCount];
  68. };
  69. struct QueueBase {
  70. QueueBase(ItemQueueBase **queues, size_t queue_count);
  71. QueueBase(const QueueBase &) = delete;
  72. QueueBase(QueueBase &&) = delete;
  73. template <typename MessageType, typename... Args>
  74. bool put(size_t queue_index, Args... args) {
  75. assert((queue_index < queue_count) && "valid queue/priority");
  76. assert((sizeof(MessageType) <= item_size) &&
  77. "no storage for the message, increase ItemSize");
  78. return queues[queue_index]->put<MessageType>(std::forward<Args>(args)...);
  79. }
  80. ItemGuard next();
  81. private:
  82. ItemQueueBase **queues;
  83. uint8_t queue_count;
  84. };
  85. template <typename Storage, size_t... Counts> struct Queue : QueueBase {
  86. static_assert(Storage::item_size > sizeof(Message),
  87. "not enough storage for a message");
  88. using Queues = std::tuple<ItemQueue<Storage, Counts>...>;
  89. static constexpr size_t Size = std::tuple_size<Queues>::value;
  90. static_assert(Size > 0, "there should be at least one queue");
  91. Queue() : QueueBase(queues, Size) { fill_queue<0>(); }
  92. private:
  93. template <size_t Index> void fill_queue() {
  94. auto &queue = std::get<Index>(queues_storage);
  95. queues[Index] = &queue;
  96. if constexpr (Index + 1 < Size) {
  97. fill_queue<Index + 1>();
  98. }
  99. }
  100. Queues queues_storage;
  101. ItemQueueBase *queues[Size];
  102. };
  103. } // namespace rotor_light