When I updated my LZW reference code to use the latest C++ features, I abstracted my input and output functions using templates. Data was read and written using the iostreams paradigm, which requires simple classes that implement just a few functions. Would I have been better off using the iterator paradigm instead? The C++ algorithms library favors that method of processing data, and it can be both elegant and powerful. Which of the two paradigms is the right one for data compression?
The Conflict
General purpose data compression routines tend to be used on binary streams of data, either from files or in-memory objects. So what is the best general paradigm for input and output when compressing data?
You might analyze this problem by imagining that you need to write a binary copy routine.
template<class INPUT_ITERATOR, class OUTPUT_ITERATOR>
void bcopy( INPUT_ITERATOR input, INPUT_ITERATOR eof, OUTPUT_ITERATOR output )
{
while ( input != eof )
*output++ = *input++;
}
This routine is particularly nice when you are performing a simple copy using pointers to memory – the generated code should be really efficient.
However, the iterator paradigm doesn’t work quite as well when you want to perform a binary copy of data in a file. I can make use of iterators that almost do the job:
std::ifstream in( "input.txt", std::ios_base::binary );
std::ofstream out("output.txt", std::ios_base::binary );
bcopy( std::istream_iterator(in),
std::istream_iterator(),
std::ostream_iterator(out) );
But the bad news is that both istream_iterator and ostream_iterator use the insertion and extraction operators, which are really meant for whitespace-delimited textual data, not binary data. The copy routine shown here will not make a binary byte-for-byte copy of the input file.
So when using files, the stream approach seems to be the way to go:
template<class INPUT_STREAM, class OUTPUT_STREAM>
void bcopy( INPUT_STREAM in, OUTPUT_STREAM out )
{
char c;
while ( in.get(c) )
out.put(c);
}
If my files have been opened using the iostream classes, you can use this binary copy function without having to write any glue code – they already support the get and put methods, so this works right out of the box.
My Choice
If I’ve made up my mind that my data compression routine is going to use one of these two paradigms, it means I am going to have to write some glue code. If I choose the iterator-based approach, I need the equivalent of istream_iterator and ostream_iterator for binary files – and these aren’t in the standard library. If I choose the stream-based approach, I need efficient put() and get() members for blocks of memory. In some cases basic_stringstream might do the job, but not in all cases.
After dithering around with various solutions, I tentatively opted for the stream paradigm. I found the implementation for various sources of data to be fairly simple, and the interface is easy to understand. I don’t know if it’s the perfect choice, and I’ll keep experimenting, but for now it works for me. My abstraction of the LZW code still needs a lot of work, so it’s always possible I could rethink this at a later date.
I’d like to hear your thoughts – is there an obvious right answer to this question?
3 users commented in " Streams or Iterators? "
Follow-up comment rss or Leave a TrackbackHi,
Isn’t istreambuf_iterator the iterator you’re looking for ?
http://cplusplus.com/reference/std/iterator/istreambuf_iterator/
It directly reads from the inner streambuf without using the extraction operator.
The opposite iterator exists: ostreambuf_iterator.
Fred
@Fred,
When I was writing this post I was kind of worried that there was a solution in the standard library that I just didn’t know about. I’m not much of am expert on iostreams (but who is, really), so I viewed it as a strong possibility. I’m limited to a smartphone for the mext few days, but I’ll post an update when I’m connected to a computer again.
Reader comments like yours are awesome because it automatically generates a new blog post. Many thanks!
[...] = 'wpp-261'; var addthis_config = {"data_track_clickback":true};A few weeks back I was looking at the choice of whether to use iterators or streaming operations for I/O on my data compression code. I was [...]
Leave A Reply
You can insert source code in your comment without fear of too much mangling by tagging it to use the iG:Syntax Hiliter plugin. A typical usage of this plugin will look like this:[c]
Note that tags are enclosed in square brackets, not angle brackets. Tags currently supported by this plugin are: as (ActionScript), asp, c, cpp, csharp, css, delphi, html, java, js, mysql, perl, python, ruby, smarty, sql, vb, vbnet, xml, code (Generic). If you post your comment and you aren't happy with the way it looks, I will do everything I can to edit it to your satisfaction.int main()
{
printf( "Hello, world!\n" );
return 1;
}
[/c]