Questa è semplicistico, e la parte superiore delle mie dita, ma penso che qualcosa in questo senso avrebbe funzionato:
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);
}
};
In un commento, lei ha citato si voleva evitare di creare un buffer di grande carattere. Quando si utilizza la chiamata di sistema read
, è generalmente più efficiente eseguire alcune letture di grandi dimensioni piuttosto che molte piccole. Quindi la maggior parte delle implementazioni opterà per grandi buffer di input per ottenere quell'efficienza. Si potrebbe implementare qualcosa di simile:
std::vector<char> input;
char in;
int r;
while ((r = read(fd, &in, 1)) == 1) input.push_back(in);
Ma che comporterebbe una chiamata di sistema e di almeno un byte copiati per ogni byte di ingresso. Al contrario, il codice che ho presentato evita copie di dati extra.
Non mi aspetto davvero che il codice che ho messo sia la soluzione che avresti adottato. Volevo solo fornirti un'illustrazione di come creare un oggetto autoestendente che fosse abbastanza efficiente in termini di spazio e tempo. A seconda dei tuoi scopi, potresti voler estenderlo o scrivere il tuo. Fuori della parte superiore della mia testa, alcuni miglioramenti possono essere:
- uso
std::list
invece, per evitare vettore ridimensionamento
- permettono API un parametro per specificare il numero di byte da leggere
- uso
readv
per consentire sempre almeno BUF_SIZE
byte (o più di BUF_SIZE
byte) da leggere alla volta
Sì. Molte persone hanno scritto buffer di flusso che si collegano ai socket. Sebbene inizialmente sembrino interessanti, almeno da quello che ho visto, raramente funzionano molto bene nella pratica. È (quasi) necessario aggiungere una sorta di operazione asincrona (ad esempio, come fa ASIO) per farlo funzionare correttamente. http://socketstream.sourceforge.net/, http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html, ecc. –