Creating the std :: iostream adapter

I would like to create an iostream adapter class that allows me to modify data written to or read from a stream on the fly. The adapter itself must be iostream to provide true transparency regarding third-party code.

Example for the StreamEncoder class derived from std::ostream :

 // External algorithm, creates large amounts of log data int foo(int bar, std::ostream& logOutput); int main() { // The target file std::ofstream file("logfile.lzma"); // A StreamEncoder compressing the output via LZMA StreamEncoder lzmaEncoder(file, &encodeLzma); // A StreamEncoder converting the UTF-8 log data to UTF-16 StreamEncoder utf16Encoder(lzmaEncoder, &utf8ToUtf16); // Call foo(), but write the log data to an LZMA-compressed UTF-16 file cout << foo(42, utf16Encoder); } 

As far as I know, I need to create a new basic_streambuf derivation and paste it into a subclass of basic_ostream , but that seems pretty complicated.

Is there an easier way to do this?

+4
source share
1 answer

Oddly enough, at least since everything is really designed to work, none of this should directly include iostreams and / or streambufs.

I would think of iostream as a match-maker class. Iostream has streambuf, which provides a buffer interface for some external data source / receiver. It also has a locale that handles all formatting. Iostream is a little more than the leader of a playground that keeps these two playing together beautifully (so to speak). Since you are dealing with data formatting, all of this (or should be) handled locally.

The locale is not monolithic, although it consists of several facet s, each of which is devoted to one specific part of data formatting. In this case, the part that you probably care about is the codecvt facet, which is used (almost exclusively) to translate between the external and internal representations of data read from / to iostreams.

However, better or worse, however, a language can only contain one piece of codecvt at a time, and not a chain of them, as you contemplate. Thus, what you really need / need is a wrapper class that provides the codec as an external interface, but allows you to bind an arbitrary set of transformations to data during I / O.

For utf-to-utf conversion, Boost.locale provides the utf_to_utf function and the codecvt wrapper code, so this part of the conversion is simple and straightforward.

So that someone would not assume that such things will be done using the ICU, I will add that Boost.Locale is pretty much a wrapper around the ICU, so this is more or less the same answer, but in a more C + friendly form + (whereas the ICU itself is quite similar to Java, and that's all, except for being openly hostile to C ++).

The other side is that writing a codecvt grant adds more complexity to a fairly simple task. Filtering streambuf (for one example) is usually much easier to write. It is still not as simple as we would like, but not as bad as the face of codecvt. As mentioned in @Flexo, the Boost iostreams library already includes a streambuf filter that performs ZIP compression. Doing something similar with lzma (or lzh, arithmetic, etc.) is relatively easy, at least assuming you have compression functions that are easy to use (you basically just supply them with an input buffer and they provide a buffer results).

+4
source

All Articles