#pragma once #include "gp/algorithm/move.hpp" #include "gp/allocator/aggregator.hpp" #include "gp/array.hpp" #include "gp/vfs/fs_types.hpp" namespace gp { template class self_filling_channel{ error_function on_error; pop_function filler; gp::buffer::associated_iterator push(gp::buffer input) { return filler(input); } gp::buffer::associated_iterator pop(gp::buffer dest) { on_error(); return dest.begin(); } }; template class input_channel{ error_function on_error; push_function filler; gp::buffer::associated_iterator push(gp::buffer input) { on_error(); return input.begin(); } gp::buffer::associated_iterator pop(gp::buffer dest) { return filler(dest); } }; template class channel { gp::array message_sizes; gp::array< gp::array, count > messages; size_t r_offset = 0; size_t w_offset = 0; [[nodiscard]] size_t write_one(size_t loc, gp::buffer 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 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::associated_iterator push(gp::buffer 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(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::associated_iterator pop(gp::buffer 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(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(); } }; }