// // ring_buffer.h // 2Term // // Created by Kelvin Sherlock on 1/25/2017. // // #ifndef ring_buffer_h #define ring_buffer_h #include #include template class ring_buffer { static_assert((Size & ~(Size - 1)) == Size, "Size must be power of 2"); public: void write(uint8_t x) { _buffer[_ptr] = x; _ptr = (_ptr + 1) & (Size-1); if (_capacity) --_capacity; } void write(const uint8_t *data, size_t dsize) { if (!dsize) return; // simple replace. if (dsize >= Size) { _ptr = _capacity = 0; memcpy(_buffer, data + dsize - Size, Size); assert(_redzone == 0); return; } // simple append. if (_capacity >= dsize) { memcpy(_buffer + _ptr, data, dsize); _ptr = (_ptr + dsize) & (Size - 1); _capacity -= dsize; assert(_redzone == 0); return; } // no capacity left.. overwrite. // dsize < Size. _capacity = 0; // fill up the end, then wrap around to start. if (_ptr + dsize > Size) { size_t amt = Size - _ptr; memcpy(_buffer + _ptr, data, amt); _ptr = 0; dsize -= amt; data += amt; } if (dsize) { memcpy(_buffer + _ptr, data, dsize); _ptr = (_ptr + dsize) & (Size - 1); } assert(_redzone == 0); } std::vector read() const { std::vector rv; if (_capacity) { rv.assign(_buffer, _buffer + _ptr); return rv; } // _ptr ... end, 0 .. _ptr rv.assign(_buffer + _ptr, _buffer + Size); if (_ptr) rv.insert(rv.end(), _buffer, _buffer + _ptr); return rv; } size_t max_size() const { return Size; } size_t size() const { return Size - _capacity; } bool empty() const { return _capacity == Size; } void clear() { _ptr = 0; _capacity = Size; } private: size_t _capacity = Size; size_t _ptr = 0; uint8_t _buffer[Size]; uint64_t _redzone = 0; }; #endif /* ring_buffer_h */