I have a buffer of chars of a fixed length and I'd like to feed it to a function that takes a std::istream&. How can I do that without copying the buffer?
If it means deriving a custom streambuf, I think I'll live with the copy. I'm just wondering if I'm missing something straightforward.
Here's what I'm doing now (which does the unwanted copy):
void loadFromBuffer(const char* buff, size_t len) {
std::istringstream is(std::string(buff, len)); // BUFFER COPIED HERE :(
load(is);
}
Edit:
For the record, here's the straightforward solution using boost.Iostreams:
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
void loadFromBuffer2(char* buff, size_t len) {
typedef boost::iostreams::stream<boost::iostreams::array_source> array_stream;
array_stream is(buff, len);
load(is);
}
I accepted the Boost.Iostreams answer because it seems to be the "right" solution, however it doesn't compile on my platform (Android NDK), so I ended up using the deprecated std::istrstream solution. Thanks everyone.
I've been in a similar situation myself, and instead of creating everything myself I used Boost.Iostreams, creating a read-only source device.
Untested, but this may work:
class ConstBufferDevice
{
public:
typedef char char_type;
struct category :
virtual boost::iostreams::device_tag,
virtual boost::iostreams::input_seekable
{
};
ConstBufferDevice(const char_type* buffer, size_t buffersize)
: buffer_(buffer)
, buffersize_(buffersize)
, pos_(0)
{
}
std::streamsize read(char_type* buffer, std::streamsize buffersize)
{
const std::streamsize amount = static_cast<std::streamsize>(buffersize_ - pos_);
const std::streamsize result = (std::min)(buffersize, amount);
if (result != 0)
{
std::copy(buffer_ + pos_, buffer_ + pos_ + result, buffer);
pos_ += result;
return result;
}
else
{
return buffersize ? -1 : 0; // EOF
}
}
std::streampos seek(boost::iostreams::stream_offset offset,
std::ios_base::seekdir seekdir)
{
// Determine new value of pos_
boost::iostreams::stream_offset newpos;
if (seekdir == std::ios_base::beg)
{
newpos = offset;
}
else if (seekdir == std::ios_base::cur)
{
newpos = pos_ + offset;
}
else if (seekdir == std::ios_base::end)
{
newpos = buffersize_ + offset;
}
else
{
throw std::ios_base::failure("bad seek direction");
}
// Check for errors
if (newpos < 0 || newpos > buffersize_)
{
throw std::ios_base::failure("bad seek offset");
}
pos_ = static_cast<size_t>(newpos);
return boost::iostreams::offset_to_position(newpos);
}
private:
const char_type* buffer_;
size_t buffersize_;
size_t pos_;
};
typedef boost::iostreams::stream<ConstBufferDevice> ConstBufferStream;
One option would be to provide a custom implementation of std::streambuf
that references an external (rather than internal) buffer. Once you have this, you could subclass off of std::istream
and provide a constructor that sets up the istream
's stream buffer to be an instance of your custom streambuf
type that points to your buffer. This immediately gives you the full capabilities of an istream
that would be backed by your external buffer. IIRC, most of the complexity of implementing streambuf
involves the complexities of refilling the buffer when it runs out of data, but in your case that should be trivial since you can just report that you're out of data.
Hope this helps!
I doubt this is possible. The STL containers/streams etc. always want to own the buffer, thus they copy it. There's no simple way I am aware of.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With