2016-05-06 13 views
10

Vorrei copiare i dati in modo efficiente tra std::streambuf istanze. Cioè, mi piacerebbe spalare blocchi di dati tra di loro, al contrario di eseguire la copia carattere per carattere. Ad esempio, questo è non quello che sto cercando:Copia a livello di blocchi di dati tra streambands

stringbuf in{ios_base::in}; 
stringbuf out{ios_base::out}; 
copy(istreambuf_iterator<char>{in}, 
    istreambuf_iterator<char>{}, 
    ostreambuf_iterator<char>{out}); 

Esiste zucchero sintattico per questo, con un po 'più di controllo degli errori:

ostream os{&out}; 
os << &in; 

Ecco un frammento della realizzazione di operator<<(basic_streambuf<..>*) nella mia libreria standard (Mac OS X, XCode 7):

   typedef istreambuf_iterator<_CharT, _Traits> _Ip; 
       typedef ostreambuf_iterator<_CharT, _Traits> _Op; 
       _Ip __i(__sb); 
       _Ip __eof; 
       _Op __o(*this); 
       size_t __c = 0; 
       for (; __i != __eof; ++__i, ++__o, ++__c) 
       { 
        *__o = *__i; 
        if (__o.failed()) 
         break; 
       } 

La linea di fondo è: questo è ancora a livello di carattere copia. Speravo che la libreria standard utilizzasse un algoritmo che si basa sulle funzioni dei membri a livello di blocco degli streambuffer, sputn e sgetn, anziché sul trasporto per carattere. La libreria standard fornisce un tale algoritmo o devo eseguire il rollover?

+3

Il problema è che questo è basato su un'interfaccia con funzioni virtuali. Non si sa mai quando '* __ o = * __ i' non verrà stampato, quindi non si può leggere avanti e rischiare di perdere quei caratteri. –

+0

hai trovato il metodo? – barney

risposta

1

Ho paura che la risposta sia: non è possibile con il design attuale della libreria standard. Il motivo è che gli streambuffer nascondono completamente la sequenza di personaggi che gestiscono. Ciò rende impossibile copiare direttamente byte dall'area get di uno streambuffer all'area put di un altro.

Se lo streambuffer di "input" esponeva il suo buffer interno, lo streambust di "output" poteva semplicemente usare sputn(in.data(), in.size()). O più ovviamente: se il buffer di output esponeva anche il suo buffer interno, allora si poteva usare il semplice memcpy per spalare i byte tra i due. Altre librerie di I/O funzionano in questo modo: ad esempio, lo stream implementation dei buffer di protocollo di Google. Boost IOStreams ha un optimized implementation to copy between streams. In entrambi i casi, una copia efficiente a livello di blocco è possibile perché l'equivalente dello streambuffer fornisce l'accesso al proprio buffer intermedio.

In effetti, gli streambuffer non hanno nemmeno bisogno di avere un buffer: quando operano senza buffer, ogni lettura/scrittura va direttamente al dispositivo sottostante. Presumibilmente questo è uno dei motivi per cui la libreria standard non supporta l'introspezione. La sfortunata conseguenza è che non è possibile una copia efficiente tra gli streambuffer di input e di output. copia block-livello richiede un buffer intermediario, e un algoritmo di copia dovrebbe operare come segue:

  1. Read dal streambuffer ingresso tramite sgetn nel buffer intermedio.
  2. Scrive dal buffer intermedio nello streambuffer di output tramite sputn.
  3. Vai a 1. finché l'ingresso è esaurita o scrive sull'output streambuffer sicuro
Problemi correlati