2021-10-27 18:20:14 +02:00
|
|
|
// somebar - dwl bar
|
|
|
|
// See LICENSE file for copyright and license details.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
2021-10-29 20:03:26 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <sys/types.h>
|
2021-10-27 18:20:14 +02:00
|
|
|
|
2021-10-29 20:03:26 +02:00
|
|
|
// reads data from Reader, and passes complete lines to Consumer.
|
|
|
|
template<size_t BufSize>
|
2021-10-27 18:20:14 +02:00
|
|
|
class LineBuffer {
|
2021-10-29 20:33:27 +02:00
|
|
|
using Iterator = typename std::array<char, BufSize>::iterator;
|
|
|
|
std::array<char, BufSize> _buffer;
|
|
|
|
Iterator _bufferedTo;
|
|
|
|
Iterator _consumedTo;
|
|
|
|
bool _discardLine {false};
|
2021-10-27 18:20:14 +02:00
|
|
|
public:
|
2021-10-29 20:33:27 +02:00
|
|
|
LineBuffer()
|
|
|
|
: _bufferedTo {_buffer.begin()}
|
|
|
|
, _consumedTo {_buffer.begin()}
|
|
|
|
{
|
|
|
|
}
|
2021-10-29 20:03:26 +02:00
|
|
|
|
2021-10-29 20:33:27 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
2021-10-29 23:23:35 +02:00
|
|
|
private:
|
2021-10-29 20:33:27 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2021-10-29 20:03:26 +02:00
|
|
|
|
2021-10-29 20:33:27 +02:00
|
|
|
void resetBuffer()
|
|
|
|
{
|
|
|
|
size_t bytesRemaining = _bufferedTo - _consumedTo;
|
|
|
|
if (bytesRemaining == _buffer.size()) {
|
|
|
|
// line too long
|
|
|
|
_discardLine = true;
|
|
|
|
_consumedTo = _buffer.begin();
|
|
|
|
_bufferedTo = _buffer.begin();
|
2021-10-30 11:21:30 +02:00
|
|
|
} else {
|
2021-10-29 20:33:27 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2021-10-27 18:20:14 +02:00
|
|
|
};
|