#pragma once #include #include #include #include namespace types { template class basic_buffer { public: using alloc_traits = std::allocator_traits; private: char* const start; char* const end; char* base; char* head; size_t count; Allocator alloc{}; private: constexpr char _get_char(char* ptr) { --count; return *ptr; } constexpr void _put_char(char c) { *head = c; ++count; } constexpr char* _forward(char* ptr) { if (ptr == end) return start; else return ptr + 1; } constexpr char* _backward(char* ptr) { if (ptr == start) return end; else return ptr - 1; } public: constexpr basic_buffer(size_t size) : start{alloc_traits::allocate(alloc, size)} , end{start + size - 1} , base{start} , head{start} , count{0} {} constexpr basic_buffer(const basic_buffer& buf) : start{alloc_traits::allocate(alloc, buf.end + 1 - buf.start)} , end{(uint32_t)start + (uint32_t)buf.end - (uint32_t)buf.start} , base{(uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start} , head{(uint32_t)start + (uint32_t)buf.base - (uint32_t)buf.start} , count{buf.count} {} constexpr basic_buffer(basic_buffer&& buf) : start{buf.start} , end{buf.end} , base{buf.base} , head{buf.head} , count{buf.count} {} constexpr ~basic_buffer() { if (start) alloc_traits::deallocate(alloc, start, end - start); } constexpr bool empty(void) const { return count == 0; } constexpr bool full(void) const { return count == static_cast(end - start + 1); } constexpr int front(void) { if (empty()) return EOF; return *base; } constexpr int back(void) { if (empty()) return EOF; return *_backward(head); } constexpr int get(void) { if (empty()) return EOF; char c = _get_char(base); base = _forward(base); return c; } constexpr int pop(void) { if (empty()) return EOF; char c = _get_char(_backward(head)); head = _backward(head); return c; } constexpr int put(char c) { if (full()) return EOF; _put_char(c); head = _forward(head); return c; } constexpr size_t size(void) const { return count; } constexpr size_t avail(void) const { return end - start + 1 - count; } constexpr void clear(void) { count = 0; head = base; } }; using buffer = basic_buffer>; } // namespace types