diff options
| author | stkhan <personal@slickd.xyz> | 2023-03-31 19:42:29 -0500 |
|---|---|---|
| committer | stkhan <personal@slickd.xyz> | 2023-03-31 19:42:29 -0500 |
| commit | 0e71af11a27631e45c0160842e4498507420eff0 (patch) | |
| tree | 4eed4eba5b0273f26bc55243cce36a2670ac0fef /wm/somebar/src/line_buffer.hpp | |
| parent | 07afc07ffff324f3a355f2437bd643b616fe0af4 (diff) | |
bar and blocks
Diffstat (limited to 'wm/somebar/src/line_buffer.hpp')
| -rw-r--r-- | wm/somebar/src/line_buffer.hpp | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/wm/somebar/src/line_buffer.hpp b/wm/somebar/src/line_buffer.hpp new file mode 100644 index 0000000..a5497bf --- /dev/null +++ b/wm/somebar/src/line_buffer.hpp @@ -0,0 +1,71 @@ +// somebar - dwl bar +// See LICENSE file for copyright and license details. + +#pragma once +#include <array> +#include <algorithm> +#include <sys/types.h> + +// reads data from Reader, and passes complete lines to Consumer. +template<size_t BufSize> +class LineBuffer { + using Iterator = typename std::array<char, BufSize>::iterator; + std::array<char, BufSize> _buffer; + Iterator _bufferedTo; + Iterator _consumedTo; + bool _discardLine {false}; +public: + LineBuffer() + : _bufferedTo {_buffer.begin()} + , _consumedTo {_buffer.begin()} + { + } + + template<typename Reader, typename Consumer> + ssize_t readLines(const Reader& reader, const Consumer& consumer) + { + while (true) { + auto bytesRead = reader(_bufferedTo, _buffer.end() - _bufferedTo); + if (bytesRead <= 0) { + return bytesRead; + } + _bufferedTo += bytesRead; + dispatchLines(consumer); + resetBuffer(); + } + } +private: + template<typename Consumer> + void dispatchLines(const Consumer& consumer) + { + while (true) { + auto separator = std::find(_consumedTo, _bufferedTo, '\n'); + if (separator == _bufferedTo) { + break; + } + size_t lineLength = separator - _consumedTo; + if (!_discardLine) { + consumer(_consumedTo, lineLength); + } + _consumedTo = separator + 1; + _discardLine = false; + } + } + + void resetBuffer() + { + size_t bytesRemaining = _bufferedTo - _consumedTo; + if (bytesRemaining == _buffer.size()) { + // line too long + _discardLine = true; + _consumedTo = _buffer.begin(); + _bufferedTo = _buffer.begin(); + } else { + // move the last partial message to the front of the buffer, so a full-sized + // message will fit + std::copy(_consumedTo, _bufferedTo, _buffer.begin()); + _consumedTo = _buffer.begin(); + _bufferedTo = _consumedTo + bytesRemaining; + } + } +}; |