General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.0 KiB

  1. #pragma once
  2. #include "gp/array.hpp"
  3. #include "gp/algorithm/move.hpp"
  4. #include "gp/vfs/fs_types.hpp"
  5. #include "gp/allocator/aggregator.hpp"
  6. namespace gp {
  7. template<typename error_function, typename pop_function>
  8. class self_filling_channel{
  9. error_function on_error;
  10. pop_function filler;
  11. gp::buffer<char>::associated_iterator push(gp::buffer<char> input) {
  12. return filler(input);
  13. }
  14. gp::buffer<char>::associated_iterator pop(gp::buffer<char> dest) {
  15. on_error();
  16. return dest.begin();
  17. }
  18. };
  19. template<typename error_function, typename push_function>
  20. class input_channel{
  21. error_function on_error;
  22. push_function filler;
  23. gp::buffer<char>::associated_iterator push(gp::buffer<char> input) {
  24. on_error();
  25. return input.begin();
  26. }
  27. gp::buffer<char>::associated_iterator pop(gp::buffer<char> dest) {
  28. return filler(dest);
  29. }
  30. };
  31. template<size_t size, size_t count = 1, bool whole_messages = true, bool zero_out = true>
  32. class channel {
  33. gp::array<size_t, count> message_sizes;
  34. gp::array<
  35. gp::array<char, size>,
  36. count
  37. > messages;
  38. size_t r_offset = 0;
  39. size_t w_offset = 0;
  40. [[nodiscard]] size_t write_one(size_t loc, gp::buffer<char> message) {
  41. auto cond = message.size();
  42. size_t idx = 0;
  43. for(; idx < cond; ++idx) {
  44. messages[loc][idx] = message[idx];
  45. }
  46. message_sizes[loc] = message.size();
  47. w_offset += 1;
  48. if constexpr (count != 1) w_offset %= size;
  49. if constexpr (zero_out) {
  50. auto ret = idx;
  51. for(; idx < messages[loc].size(); ++idx) {
  52. messages[loc] = 0;
  53. }
  54. return ret;
  55. }
  56. return idx;
  57. }
  58. [[nodiscard]] size_t read_one(size_t loc, gp::buffer<char> message) {
  59. size_t ret;
  60. size_t idx = 0;
  61. size_t trailer = 0;
  62. if(message_sizes[loc] < message.size())
  63. {
  64. for(; idx < message_sizes[loc]; ++idx) {
  65. message[idx] = messages[loc][idx];
  66. }
  67. r_offset += 1;
  68. if constexpr (count != 1) w_offset %= size;
  69. ret = idx;
  70. } else {
  71. for(; idx < message.size(); ++idx) {
  72. message[idx] = messages[loc][idx];
  73. }
  74. ret = idx;
  75. for(; idx < message_sizes[loc]; ++idx, ++trailer)
  76. {
  77. message[trailer] = message[idx];
  78. }
  79. message_sizes[loc] = trailer;
  80. }
  81. if constexpr (zero_out) {
  82. if(trailer == 0) {
  83. message_sizes[loc] = 0;
  84. }
  85. for(; trailer < messages[loc].size(); ++trailer)
  86. {
  87. messages[loc][trailer] = 0;
  88. }
  89. }
  90. return ret;
  91. }
  92. public:
  93. channel() {}
  94. gp::buffer<char>::associated_iterator push(gp::buffer<char> input) {
  95. if constexpr (whole_messages) {
  96. if(input.size() > size) {
  97. return input.begin();
  98. }
  99. }
  100. if constexpr (count == 1) {
  101. if(w_offset == r_offset) {
  102. auto to_write = gp::min(input.size(), size);
  103. write_one(
  104. 0,
  105. gp::buffer<char>(input.begin().data, to_write)
  106. );
  107. return input.begin()+to_write;
  108. } else {
  109. return input.begin();
  110. }
  111. } else {
  112. auto next_w = (w_offset+1)%count;
  113. auto to_consume = input;
  114. while(to_consume.size() && (next_w == r_offset)) {
  115. auto to_write = gp::min(to_consume.size(), size);
  116. to_write = write_one(
  117. w_offset,
  118. to_consume.trim_start(to_write)
  119. );
  120. to_consume = to_consume.trim_start(to_write);
  121. next_w = (w_offset+1)%count;
  122. }
  123. return to_consume.begin();
  124. }
  125. }
  126. gp::buffer<char>::associated_iterator pop(gp::buffer<char> dest) {
  127. if(r_offset == w_offset) {
  128. return dest.begin();
  129. }
  130. size_t idx;
  131. if constexpr (count == 1) {
  132. idx = 0;
  133. } else {
  134. idx = r_offset;
  135. }
  136. if constexpr (whole_messages) {
  137. if(message_sizes[idx] > dest.size()) {
  138. return dest.begin();
  139. }
  140. auto sz = gp::min(message_sizes[idx], dest.size());
  141. read_one(idx, gp::buffer<char>(dest.begin(), sz));
  142. return dest.begin()+sz;
  143. }
  144. auto to_fill = dest;
  145. do{
  146. auto to_read = gp::min(to_fill.size(), size);
  147. to_read = read_one(
  148. r_offset,
  149. to_fill.trim_start(to_read)
  150. );
  151. to_fill = to_fill.trim_start(to_read);
  152. }while(r_offset != w_offset && to_fill.size());
  153. return to_fill.begin();
  154. }
  155. };
  156. }