В основном я реализую традиционный файловый буффер для файлового дескриптора для операций istream
. Реализация переопределяет функции sync
и underflow
, тогда как в sync
буфер будет автоматически увеличен, если необходимо (точно так же, как vector
).Настраиваемый streambuffer для C++ istream
class InputStreamBuffer : public std::basic_streambuf<char> {
private:
// small stack buffer optimization
constexpr static size_t _STACK_BUFSZ = 128;
static_assert(_STACK_BUFSZ >= 1, "Stack buffer size should be at least 1");
char_type _stk [_STACK_BUFSZ];
char_type* _buf {_stk};
size_t _size {_STACK_BUFSZ};
const int _fd {-1};
public:
InputStreamBuffer(const int);
~InputStreamBuffer();
protected:
int sync() override;
int_type underflow() override;
};
InputStreamBuffer::InputStreamBuffer(const int fd) :
_fd {fd} {
setg(_buf, _buf, _buf);
}
InputStreamBuffer::~InputStreamBuffer() {
if(_buf != _stk) {
std::free(_buf);
}
}
int InputStreamBuffer::sync() {
auto success = int {0};
while(1) {
size_t empty = gptr() - eback();
size_t avail = egptr() - gptr();
// Before we issue the read, make sure we have enough space.
if(egptr() == eback() + _size) {
// Reuse the empty region.
if(empty > _size/2) {
std::memmove(eback(), gptr(), avail);
}
// Double the array size.
else {
_size = _size * 2;
auto chunk = static_cast<char_type*>(std::malloc(_size*sizeof(char_type)));
std::memcpy(chunk, gptr(), avail);
if(_buf != _stk) std::free(_buf);
_buf = chunk;
}
setg(_buf, _buf, _buf + avail);
}
// Read the data.
issue_read:
auto ret = ::read(_fd, egptr(), _size - avail);
if(ret == -1) {
if(errno == EINTR) {
goto issue_read;
}
if(errno != EAGAIN && errno != EWOULDBLOCK) {
success = -1;
}
break;
}
else if(ret == 0) {
break;
}
setg(eback(), gptr(), egptr() + ret);
}
return success;
}
InputStreamBuffer::int_type InputStreamBuffer::underflow() {
int success = sync();
if(success == -1 || gptr() == egptr()) return traits_type::eof();
return *(gptr());
}
Идея здесь заключается в использовании этого потокового буфера с неблокирующими io. Мультиплексор ввода-вывода будет автономно вызывать sync
и вызывать зарегистрированные обратные вызовы для выполнения операций istream
. Проще говоря, вот некоторые из моих вопросов:
Входной потоковый буффер имеет определенные операции, называемые «putback». Каково потенциальное преимущество использования
putback
?::read
вернется0
при достиженииEOF
, который является очень полезным индикатором для сигнализации состояния соединения сокета на основе IO. Какова наилучшая практика для этого вsync
? Моя текущая реализация просто пропускает это.Любые комментарии, которые могут улучшить реализацию, будут очень благодарны!
Я думаю, что это относится к [обзор кода] (http://codereview.stackexchange.com/) – Jerfov2