#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<typename error_function, typename pop_function>
|
|
class self_filling_channel{
|
|
error_function on_error;
|
|
pop_function filler;
|
|
|
|
gp::buffer<char>::associated_iterator push(gp::buffer<char> input) {
|
|
return filler(input);
|
|
}
|
|
gp::buffer<char>::associated_iterator pop(gp::buffer<char> dest) {
|
|
on_error();
|
|
return dest.begin();
|
|
}
|
|
};
|
|
|
|
template<typename error_function, typename push_function>
|
|
class input_channel{
|
|
error_function on_error;
|
|
push_function filler;
|
|
|
|
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();
|
|
}
|
|
};
|
|
}
|