2016-05-06 16 views
10

Ich möchte Daten effizient zwischen std::streambuf Instanzen kopieren. Das heißt, ich möchte Blöcke von Daten zwischen ihnen schaufeln, im Gegensatz zu zeichenweisem Kopieren. Zum Beispiel ist dies nicht was ich suche:Block-Level-Kopieren von Daten zwischen streambuffers

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

Hier ist ein Ausschnitt aus der Umsetzung von operator<<(basic_streambuf<..>*):

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

Es hierfür mit etwas mehr Fehlerprüfung syntaktischen Zucker vorhanden ist in meiner Standard-Bibliothek (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; 
       } 

Unterm Strich: Das ist nach wie vor pro-Charakter Kopieren. Ich hatte gehofft, dass die Standard-Bibliothek einen Algorithmus verwendet, der auf den Block-Level-Member-Funktionen der Stream-Puffer, sputn und sgetn, im Gegensatz zu pro-Zeichen-Transport beruht. Bietet die Standardbibliothek einen solchen Algorithmus oder muss ich meinen eigenen erstellen?

+3

Das Problem fehlschlagen ist, dass diese auf einer Schnittstelle mit virtuellen Funktionen basieren. Sie wissen nie, wann '* __ o = * __ i' nicht ausgegeben werden kann, Sie können also nicht vorauslesen und riskieren, diese Zeichen zu verlieren. –

+0

Haben Sie die Methode gefunden? – barney

Antwort

1

Ich fürchte, dass die Antwort ist: es ist nicht möglich mit dem aktuellen Design der Standard-Bibliothek. Der Grund dafür ist, dass Streambuffer die von ihnen verwaltete Zeichenfolge vollständig ausblenden. Dies macht es unmöglich, Bytes aus dem Get-Bereich eines Stream-Puffers direkt in den Put-Bereich eines anderen zu kopieren.

Wenn der "Eingabe" -Strombuffer seinen internen Puffer freigibt, könnte der "Ausgabe" -Strombuffer einfach sputn(in.data(), in.size()) verwenden. Oder noch offensichtlicher: Wenn der Ausgabepuffer auch seinen internen Puffer freigibt, könnte man einfach memcpy verwenden, um Bytes zwischen den beiden zu verschieben. Andere I/O-Bibliotheken arbeiten auf diese Weise: Beispielsweise die stream implementation von Google's Protocol Buffers. Boost IOStreams hat eine optimized implementation to copy between streams. In beiden Fällen ist ein effizientes Kopieren auf Blockebene möglich, da das Gleichstrompuffer-Äquivalent Zugriff auf seinen Zwischenpuffer bereitstellt.

In der Tat brauchen streambuffers ironischerweise nicht einmal einen Puffer: Im ungepufferten Zustand geht jedes Lesen/Schreiben direkt zum darunterliegenden Gerät. Vermutlich ist dies ein Grund, warum die Standardbibliothek Introspektion nicht unterstützt. Die unglückliche Folge ist, dass kein effizientes Kopieren zwischen Eingabe- und Ausgabestrompuffer möglich ist. Block-Kopier erfordert einen Zwischenpuffer und ein Kopieralgorithmus würde arbeiten wie folgt:

  1. Lese aus dem Eingang streambuffer über sgetn in die Zwischenpuffer.
  2. Schreiben aus dem Zwischenpuffer in den Ausgangsstrompuffer über sputn.
  3. Zum 1. bis Eingang erschöpft ist oder schreibt an den Ausgang streambuffer