buffer.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #pragma once
  2. #include <memory>
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. #include <types/allocator.hpp>
  6. namespace types {
  7. template <typename Allocator>
  8. class basic_buffer {
  9. public:
  10. using alloc_traits = std::allocator_traits<Allocator>;
  11. private:
  12. char* const start;
  13. char* const end;
  14. char* base;
  15. char* head;
  16. size_t count;
  17. Allocator alloc{};
  18. private:
  19. constexpr char _get_char(char* ptr) {
  20. --count;
  21. return *ptr;
  22. }
  23. constexpr void _put_char(char c) {
  24. *head = c;
  25. ++count;
  26. }
  27. constexpr char* _forward(char* ptr) {
  28. if (ptr == end)
  29. return start;
  30. else
  31. return ptr + 1;
  32. }
  33. constexpr char* _backward(char* ptr) {
  34. if (ptr == start)
  35. return end;
  36. else
  37. return ptr - 1;
  38. }
  39. public:
  40. constexpr basic_buffer(size_t size)
  41. : start{alloc_traits::allocate(alloc, size)}
  42. , end{start + size - 1}
  43. , base{start}
  44. , head{start}
  45. , count{0} {}
  46. constexpr basic_buffer(const basic_buffer& buf)
  47. : start{alloc_traits::allocate(alloc, buf.end + 1 - buf.start)}
  48. , end{(uint32_t)start + (uint32_t)buf.end - (uint32_t)buf.start}
  49. , base{(uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start}
  50. , head{(uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start}
  51. , count{buf.count} {}
  52. constexpr basic_buffer(basic_buffer&& buf)
  53. : start{buf.start}
  54. , end{buf.end}
  55. , base{buf.base}
  56. , head{buf.head}
  57. , count{buf.count} {}
  58. constexpr ~basic_buffer() {
  59. if (start)
  60. alloc_traits::deallocate(alloc, start, end - start);
  61. }
  62. constexpr bool empty(void) const { return count == 0; }
  63. constexpr bool full(void) const {
  64. return count == static_cast<size_t>(end - start + 1);
  65. }
  66. constexpr int front(void) {
  67. if (empty())
  68. return EOF;
  69. return *base;
  70. }
  71. constexpr int back(void) {
  72. if (empty())
  73. return EOF;
  74. return *_backward(head);
  75. }
  76. constexpr int get(void) {
  77. if (empty())
  78. return EOF;
  79. char c = _get_char(base);
  80. base = _forward(base);
  81. return c;
  82. }
  83. constexpr int pop(void) {
  84. if (empty())
  85. return EOF;
  86. char c = _get_char(_backward(head));
  87. head = _backward(head);
  88. return c;
  89. }
  90. constexpr int put(char c) {
  91. if (full())
  92. return EOF;
  93. _put_char(c);
  94. head = _forward(head);
  95. return c;
  96. }
  97. constexpr size_t size(void) const { return count; }
  98. constexpr size_t avail(void) const { return end - start + 1 - count; }
  99. constexpr void clear(void) {
  100. count = 0;
  101. head = base;
  102. }
  103. };
  104. using buffer = basic_buffer<std::allocator<char>>;
  105. } // namespace types