General Purpose library for Freestanding C++ and POSIX systems
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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