|
@ -0,0 +1,149 @@ |
|
|
|
|
|
#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(); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
} |