|
|
- #pragma once
- #include "gp/array.hpp"
- #include "gp/algorithm/move.hpp"
- #include "gp/vfs/fs_types.hpp"
- #include "gp/allocator/aggregator.hpp"
-
- namespace gp {
- template<typename error_function, typename pop_function>
- class self_filling_channel{
- error_function on_error;
- pop_function filler;
- public:
- gp::buffer<char>::associated_iterator push(gp::buffer<char> input) {
- on_error();
- return input.begin();
- }
- gp::buffer<char>::associated_iterator pop(gp::buffer<char> dest) {
- return filler(dest);
- }
- };
-
- template<size_t size, size_t count = 1, bool whole_messages = true, bool zero_out = true>
- class channel {
- gp::array<size_t, count> message_sizes;
- gp::array<
- gp::array<char, size>,
- count
- > messages;
- size_t r_offset = 0;
- size_t w_offset = 0;
- [[nodiscard]] size_t write_one(size_t loc, gp::buffer<char> message) {
- auto cond = message.size();
- size_t idx = 0;
- for(; idx < cond; ++idx) {
- messages[loc][idx] = message[idx];
- }
- message_sizes[loc] = message.size();
- w_offset += 1;
- if constexpr (count != 1) w_offset %= size;
- if constexpr (zero_out) {
- auto ret = idx;
- for(; idx < messages[loc].size(); ++idx) {
- messages[loc] = 0;
- }
- return ret;
- }
- return idx;
- }
- [[nodiscard]] size_t read_one(size_t loc, gp::buffer<char> message) {
- size_t ret;
- size_t idx = 0;
- size_t trailer = 0;
- if(message_sizes[loc] < message.size())
- {
- for(; idx < message_sizes[loc]; ++idx) {
- message[idx] = messages[loc][idx];
- }
- r_offset += 1;
- if constexpr (count != 1) w_offset %= size;
- ret = idx;
- } else {
- for(; idx < message.size(); ++idx) {
- message[idx] = messages[loc][idx];
- }
- ret = idx;
- for(; idx < message_sizes[loc]; ++idx, ++trailer)
- {
- message[trailer] = message[idx];
- }
- message_sizes[loc] = trailer;
- }
-
- if constexpr (zero_out) {
- if(trailer == 0) {
- message_sizes[loc] = 0;
- }
- for(; trailer < messages[loc].size(); ++trailer)
- {
- messages[loc][trailer] = 0;
- }
- }
-
- return ret;
- }
- public:
- channel() {}
- gp::buffer<char>::associated_iterator push(gp::buffer<char> input) {
- if constexpr (whole_messages) {
- if(input.size() > size) {
- return input.begin();
- }
- }
- if constexpr (count == 1) {
- if(w_offset == r_offset) {
- auto to_write = gp::min(input.size(), size);
- write_one(
- 0,
- gp::buffer<char>(input.begin().data, to_write)
- );
- return input.begin()+to_write;
- } else {
- return input.begin();
- }
- } else {
- auto next_w = (w_offset+1)%count;
- auto to_consume = input;
- while(to_consume.size() && (next_w == r_offset)) {
- auto to_write = gp::min(to_consume.size(), size);
- to_write = write_one(
- w_offset,
- to_consume.trim_start(to_write)
- );
- to_consume = to_consume.trim_start(to_write);
- next_w = (w_offset+1)%count;
- }
- return to_consume.begin();
- }
- }
- gp::buffer<char>::associated_iterator pop(gp::buffer<char> dest) {
- if(r_offset == w_offset) {
- return dest.begin();
- }
- size_t idx;
- if constexpr (count == 1) {
- idx = 0;
- } else {
- idx = r_offset;
- }
- if constexpr (whole_messages) {
- if(message_sizes[idx] > dest.size()) {
- return dest.begin();
- }
- auto sz = gp::min(message_sizes[idx], dest.size());
- read_one(idx, gp::buffer<char>(dest.begin(), sz));
- return dest.begin()+sz;
- }
- auto to_fill = dest;
- do{
- auto to_read = gp::min(to_fill.size(), size);
- to_read = read_one(
- r_offset,
- to_fill.trim_start(to_read)
- );
- to_fill = to_fill.trim_start(to_read);
- }while(r_offset != w_offset && to_fill.size());
- return to_fill.begin();
- }
- };
- }
|