Esto es simplista, y la parte superior de los dedos, pero creo que algo como lo siguiente funcionaría:
template <unsigned BUF_SIZE>
struct Buffer {
char buf_[BUF_SIZE];
int len_;
Buffer() : buf_(), len_(0) {}
int read (int fd) {
int r = read(fd, buf_ + len_, BUF_SIZE - len_);
if (r > 0) len_ += r;
return r;
}
int capacity() const { return BUF_SIZE - len_; }
}
template <unsigned BUF_SIZE>
struct BufferStream {
typedef std::unique_ptr< Buffer<BUF_SIZE> > BufferPtr;
std::vector<BufferPtr> stream_;
BufferStream() : stream_(1, BufferPtr(new Buffer<BUF_SIZE>)) {}
int read (int fd) {
if ((*stream_.rbegin())->capacity() == 0)
stream_.push_back(BufferPtr(new Buffer<BUF_SIZE>));
return (*stream_.rbegin())->read(fd);
}
};
En un comentario, usted ha mencionado que quería evitar la creación de un gran char buffer. Cuando se usa la llamada al sistema read
, generalmente es más eficiente realizar algunas lecturas grandes que muchas pequeñas. Entonces, la mayoría de las implementaciones optarán por grandes búferes de entrada para obtener esa eficiencia. Se podría implementar algo como:
std::vector<char> input;
char in;
int r;
while ((r = read(fd, &in, 1)) == 1) input.push_back(in);
Pero eso implicaría una llamada al sistema y al menos un byte copiado por cada byte de entrada. Por el contrario, el código que presento evita copias de datos adicionales.
Realmente no espero que el código que propongo sea la solución que usted adoptaría. Solo quería ofrecerle una ilustración de cómo crear un objeto autoextendido que sea bastante eficiente en espacio y tiempo. Dependiendo de sus propósitos, puede extenderlo o escribir uno propio. De la parte superior de mi cabeza, algunas mejoras pueden ser:
- uso
std::list
lugar, para evitar vector de cambio de tamaño
- permiten API un parámetro para especificar el número de bytes a leer
- uso
readv
para permitir siempre por lo menos BUF_SIZE
bytes (o más de BUF_SIZE
bytes) para leer en un momento
Sí. Muy pocas personas han escrito buffers de flujo que se conectan a sockets. Si bien inicialmente parecen geniales, al menos por lo que he visto, rara vez funcionan tan bien en la práctica. Usted (casi) necesita agregar algún tipo de operación asincrónica (por ejemplo, como lo hace ASIO) para que funcione bien. http://socketstream.sourceforge.net/, http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html, etc. –