Ceci est simpliste, et du haut de mes doigts, mais je pense que quelque chose le long de ces lignes fonctionnerait:
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);
}
};
Dans un commentaire, vous avez mentionné que vous vouliez éviter de créer un grand char buffer. Lorsque vous utilisez l'appel système read
, il est généralement plus efficace d'effectuer quelques lectures importantes plutôt que de nombreuses petites. Ainsi, la plupart des implémentations vont opter pour de grands tampons d'entrée pour gagner cette efficacité. Vous pouvez mettre en œuvre quelque chose comme:
std::vector<char> input;
char in;
int r;
while ((r = read(fd, &in, 1)) == 1) input.push_back(in);
Mais cela impliquerait un appel système et au moins un octet copié pour chaque octet d'entrée. En revanche, le code que j'ai mis en avant évite les copies de données supplémentaires.
Je ne m'attends pas vraiment à ce que le code que j'utilise soit la solution que vous adopteriez. Je voulais juste vous fournir une illustration de la façon de créer un objet auto-extensible qui soit assez efficace dans le temps et l'espace. Selon vos objectifs, vous pouvez l'étendre ou écrire le vôtre. Du haut de ma tête, certaines améliorations peuvent être: au lieu
- utilisation
std::list
, pour éviter vecteur redimensionnement
- API permettent à un paramètre pour spécifier le nombre d'octets à lire
- utilisation
readv
pour permettre toujours au moins BUF_SIZE
octets (ou plus de BUF_SIZE
octets) à lire à la fois
Oui. Plusieurs personnes ont écrit des tampons de flux qui se connectent aux sockets. Bien qu'ils semblent initialement cool, au moins de ce que j'ai vu, ils travaillent rarement très bien dans la pratique. Vous (presque) devez ajouter une sorte d'opération asynchrone (par exemple, comme ASIO) pour que cela fonctionne bien. http://socketstream.sourceforge.net/, http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html, etc. –