|
|
- #pragma once
-
- #include "gp/containers/vector.hpp"
- #include "gp/functional/optional.hpp"
- #include "gp/ipc/bottleneck.hpp"
- #include "gp/utils/allocators/allocator.hpp"
- #include "gp/utils/allocators/buddy.hpp"
- #include "gp/utils/pointers.hpp"
-
- namespace gp {
- /*class abstract_sender_erasor {
- virtual ~abstract_sender_erasor() = 0;
- virtual bool try_send(const gp::buffer<char> message) = 0;
- };
-
- class abstract_sender_erasor_c : abstract_sender_erasor {
- virtual abstract_sender_erasor_c* clone(gp::allocator&) = 0;
- virtual ~abstract_sender_erasor_c() = 0;
- };
-
- template<typename predicate>
- class abstract_receiver_erasor {
- [[no_unique_address]] predicate v;
- virtual abstract_receiver_erasor* clone(abstract_receiver_erasor&, gp::allocator&) = 0;
- virtual ~abstract_receiver_erasor() = 0;
- virtual gp::optional<gp::vector<char>> try_receive(allocator& allocate) = 0;
- };
-
- class abstract_receiver_erasor_c : abstract_sender_erasor {
- virtual abstract_receiver_erasor_c* clone(gp::allocator&) = 0;
- virtual ~abstract_receiver_erasor_c() = 0;
- };
-
- template<std::copyable T>
- class impl_channel_sender : abstract_sender_erasor_c {
- T& value;
-
- impl_channel_sender(T& cpy)
- : value(cpy)
- {};
-
- impl_channel_sender(T&& cpy)
- requires std::movable<T>
- : value(gp::forward<T>(cpy))
- {};
-
- virtual abstract_sender_erasor_c* clone(gp::allocator& allocator) {
-
- }
- };*/
-
-
-
- /**
- * @brief
- */
- class basic_channel {
- allocator& self_allocator; //< This is from whatever created the channel and MUST outlive the channel
- gp::unique_ptr<allocator> local_allocator_impl; //< The allocator used here
- gp::vector<gp::vector<char>> data;
- gp::fast_bottleneck lock;
-
- public:
- /**
- * @brief Construct a new channel object
- *
- * @param memory_source Where do we allocate from for this channel
- * @param memory_available The amount of memory to allocate, default specified in the configuration
- */
- basic_channel(allocator& memory_source, size_t memory_available = gp_config::limits::channel_default_size)
- : self_allocator(memory_source)
- , local_allocator_impl(
- gp::unique_ptr<gp::buddy<gp_config::limits::channel_max_size/16,16>>
- ::make(self_allocator, memory_available, self_allocator)
- .cast<allocator>()
- )
- , data(*local_allocator_impl)
- {}
-
- /**
- * @brief Sends a message on the channel
- *
- * @param message The message to transmit through the channel, this implies two copies. Empty messages are invalid and hence not transmitted.
- * @return true if the message was successfully sent
- * @return false if the message was not sent
- */
- bool try_send(const gp::buffer<char> message) {
- if(message.size() == 0) return false;
- auto guard = lock_guard(lock);
- auto v = gp::vector<char>(*local_allocator_impl);
- if(not v.reserve(message.size())) return false;
- for(char c : message) {
- v.push_back(c);
- }
- if(not data.push_back(v)) return false;
- if((*data.rbegin()).size() == 0) return false;
- return true;
- }
-
- /**
- * @brief Tries to receive a message that matches a certain predicate
- *
- * @tparam predicate represents the predicate type, you will probably never specify that by hand
- * @param allocate The allocator to allocate the response from
- * @param pred The predicate
- * @return gp::optional<gp::vector<char>> if the receive failed, this will be empty, else it will contain the message
- */
- template<typename predicate>
- gp::optional<gp::vector<char>> try_receive(
- allocator& allocate,
- predicate pred = [](gp::buffer<char>){return true;}
- ) {
- for(auto it = data.begin(); it != data.end(); ++it) {
- auto& elem = *it;
- if(predicate(elem.as_buffer())) {
- auto v = gp::vector<char>(allocate);
- if(not v.reserve(elem.size())) return nullopt;
- for(char c : elem) {
- v.push_back(c);
- }
- data.remove(it);
- return gp::move(v);
- }
- }
- return nullopt;
- }
- };
- }
|