Getting istream to work off a byte array
18 Aug 2014Introduction
The C++ Standard Library provides an extensive library for working with streams. These are abstract classes designed to work with data that is in a stream format. There are comprehensive concrete implementations for working with files and strings, however I’m still yet to find an implementation that will take a plain old c-array and allow you to treat it as a stream.
In today’s post, I’ll present a small std::istream
implementation that will consume these plain old c-arrays so that you can keep the rest of your APIs uniform to using stream objects.
A brief explanation
We’ll actually be developing two classes here. We’ll need a class to derive from std::istream
which is what we’ll pass around to other parts of our program, but internally this std::istream
derived object will manage a std::basic_streambuf<char>
derivative.
Looking at the definition of a std::basic_streambuf
we can see the following:
The class basic_streambuf controls input and output to a character sequence.
It would appear that most of the work here has been done for us. basic_streambuf
will take care of the I/O from our character sequence, we just need to supply it (the character sequence, that is). I did say byte
array in the title of this post, so the actual data type will be uint8_t*
as opposed to char*
.
Implementation
Our implementation of basic_streambuf
must abide by the char_traits type definition, so we get as close to our byte definition as possible with char
. You can see that the constructor has a little bit of cast work going on to get setg
to operate correctly.
Finally, we just create an istream
derivative that uses this membuf
object under the covers:
We set the internal buffer that memstream
will use by making a call to rdbuf
. The constructor performs some initialisation of the stream itself (to use a membuf
) implementation.
In Use
You can now treat your plain old c-arrays just like an input stream now. Something simple:
That’s all there is to it. From the snippet above, you can pass s
around just like any other input stream, because, well, it is just any other input stream.