From ebf06f932f967c0b1fcfd9439db48257b64f8990 Mon Sep 17 00:00:00 2001 From: Raphael Robatsch Date: Fri, 29 Oct 2021 20:03:26 +0200 Subject: [PATCH] line buffer: cleanup --- src/line_buffer.hpp | 97 +++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/src/line_buffer.hpp b/src/line_buffer.hpp index 37f4e3f..64c6053 100644 --- a/src/line_buffer.hpp +++ b/src/line_buffer.hpp @@ -3,58 +3,69 @@ #pragma once #include -#include +#include +#include -// reads data from Reader, and passes complete lines to Handler. -template +// reads data from Reader, and passes complete lines to Consumer. +template class LineBuffer { - std::array _buffer; - size_t _bytesBuffered {0}; - size_t _bytesConsumed {0}; - bool _discardLine {0}; + using Iterator = typename std::array::iterator; + std::array _buffer; + Iterator _bufferedTo; + Iterator _consumedTo; + bool _discardLine {false}; public: - template - size_t readLines(const Reader& reader, const Handler& handler) + LineBuffer() + : _bufferedTo {_buffer.begin()} + , _consumedTo {_buffer.begin()} + { + } + + template + ssize_t readLines(const Reader& reader, const Consumer& consumer) { - auto d = _buffer.data(); while (true) { - auto bytesRead = reader(d + _bytesBuffered, _buffer.size() - _bytesBuffered); + auto bytesRead = reader(_bufferedTo, _buffer.end() - _bufferedTo); if (bytesRead <= 0) { return bytesRead; } - - _bytesBuffered += bytesRead; - char* linePosition = nullptr; - do { - char* lineStart = d + _bytesConsumed; - linePosition = static_cast(memchr( - lineStart, - '\n', - _bytesBuffered - _bytesConsumed)); - - if (linePosition) { - int lineLength = linePosition - lineStart; - if (!_discardLine) { - handler(lineStart, lineLength); - } - _bytesConsumed += lineLength + 1; - _discardLine = false; - } - } while (linePosition); - - size_t bytesRemaining = _bytesBuffered - _bytesConsumed; - if (bytesRemaining == _buffer.size()) { - // line too long - _discardLine = true; - _bytesBuffered = 0; - _bytesConsumed = 0; - } else if (bytesRemaining > 0 && _bytesConsumed > 0) { - // move the last partial message to the front of the buffer, so a full-sized - // message will fit - memmove(d, d+_bytesConsumed, bytesRemaining); - _bytesBuffered = bytesRemaining; - _bytesConsumed = 0; + _bufferedTo += bytesRead; + dispatchLines(consumer); + resetBuffer(); + } + } +private: + template + 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 if (bytesRemaining > 0 && _consumedTo > _buffer.begin()) { + // 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; } } };