General Purpose library for Freestanding C++ and POSIX systems
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

128 řádky
4.5 KiB

před 3 roky
  1. #pragma once
  2. #include "gp/containers/vector.hpp"
  3. #include "gp/functional/optional.hpp"
  4. #include "gp/ipc/bottleneck.hpp"
  5. #include "gp/utils/allocators/allocator.hpp"
  6. #include "gp/utils/allocators/buddy.hpp"
  7. #include "gp/utils/pointers.hpp"
  8. namespace gp {
  9. /*class abstract_sender_erasor {
  10. virtual ~abstract_sender_erasor() = 0;
  11. virtual bool try_send(const gp::buffer<char> message) = 0;
  12. };
  13. class abstract_sender_erasor_c : abstract_sender_erasor {
  14. virtual abstract_sender_erasor_c* clone(gp::allocator&) = 0;
  15. virtual ~abstract_sender_erasor_c() = 0;
  16. };
  17. template<typename predicate>
  18. class abstract_receiver_erasor {
  19. [[no_unique_address]] predicate v;
  20. virtual abstract_receiver_erasor* clone(abstract_receiver_erasor&, gp::allocator&) = 0;
  21. virtual ~abstract_receiver_erasor() = 0;
  22. virtual gp::optional<gp::vector<char>> try_receive(allocator& allocate) = 0;
  23. };
  24. class abstract_receiver_erasor_c : abstract_sender_erasor {
  25. virtual abstract_receiver_erasor_c* clone(gp::allocator&) = 0;
  26. virtual ~abstract_receiver_erasor_c() = 0;
  27. };
  28. template<std::copyable T>
  29. class impl_channel_sender : abstract_sender_erasor_c {
  30. T& value;
  31. impl_channel_sender(T& cpy)
  32. : value(cpy)
  33. {};
  34. impl_channel_sender(T&& cpy)
  35. requires std::movable<T>
  36. : value(gp::forward<T>(cpy))
  37. {};
  38. virtual abstract_sender_erasor_c* clone(gp::allocator& allocator) {
  39. }
  40. };*/
  41. /**
  42. * @brief
  43. */
  44. class basic_channel {
  45. allocator& self_allocator; //< This is from whatever created the channel and MUST outlive the channel
  46. gp::unique_ptr<allocator> local_allocator_impl; //< The allocator used here
  47. gp::vector<gp::vector<char>> data;
  48. gp::fast_bottleneck lock;
  49. public:
  50. /**
  51. * @brief Construct a new channel object
  52. *
  53. * @param memory_source Where do we allocate from for this channel
  54. * @param memory_available The amount of memory to allocate, default specified in the configuration
  55. */
  56. basic_channel(allocator& memory_source, size_t memory_available = gp_config::limits::channel_default_size)
  57. : self_allocator(memory_source)
  58. , local_allocator_impl(
  59. gp::unique_ptr<gp::buddy<math::log2(gp_config::limits::channel_max_size/16),16>>
  60. ::make(self_allocator, memory_available, self_allocator)
  61. .cast<allocator>()
  62. )
  63. , data(*local_allocator_impl)
  64. {}
  65. /**
  66. * @brief Sends a message on the channel
  67. *
  68. * @param message The message to transmit through the channel, this implies two copies. Empty messages are invalid and hence not transmitted.
  69. * @return true if the message was successfully sent
  70. * @return false if the message was not sent
  71. */
  72. bool try_send(const gp::buffer<char> message) {
  73. if(message.size() == 0) return false;
  74. auto guard = lock_guard(lock);
  75. auto v = gp::vector<char>(*local_allocator_impl);
  76. if(not v.reserve(message.size())) return false;
  77. for(char c : message) {
  78. v.push_back(c);
  79. }
  80. if(not data.push_back(v)) return false;
  81. if((*data.rbegin()).size() == 0) return false;
  82. return true;
  83. }
  84. /**
  85. * @brief Tries to receive a message that matches a certain predicate
  86. *
  87. * @tparam predicate represents the predicate type, you will probably never specify that by hand
  88. * @param allocate The allocator to allocate the response from
  89. * @param pred The predicate
  90. * @return gp::optional<gp::vector<char>> if the receive failed, this will be empty, else it will contain the message
  91. */
  92. template<typename predicate>
  93. gp::optional<gp::vector<char>> try_receive(
  94. allocator& allocate,
  95. predicate pred = [](gp::buffer<char>){return true;}
  96. ) {
  97. for(auto it = data.begin(); it != data.end(); ++it) {
  98. auto& elem = *it;
  99. if(predicate(elem.as_buffer())) {
  100. auto v = gp::vector<char>(allocate);
  101. if(not v.reserve(elem.size())) return nullopt;
  102. for(char c : elem) {
  103. v.push_back(c);
  104. }
  105. data.remove(it);
  106. return gp::move(v);
  107. }
  108. }
  109. return nullopt;
  110. }
  111. };
  112. }