0

I'm trying to set the internal buffer of an input stream, but my implementation in C++17 doesn't implement pubsetbuf() for istringstream.

I've tried some other techniques, but they are slow or copy the original buffer. I'm looking for a fast method that doesn't do any copying.

It's closely related to this question about an output stream: Setting the internal buffer used by a standard stream (pubsetbuf)

I've followed it closely, but the buffer for the input stream remains uninitialised/empty.

// Modified template from the other question about an output stream.
// This is for an input stream, but I can't get it to work.
template <typename char_type>
struct istreambuf : public std::basic_streambuf<char_type, std::char_traits<char_type> >
{
    istreambuf(char_type* buffer, std::streamsize buffer_length)
    {
        // Set the "put" pointer to the start of the buffer and record its length.
        this->setp(buffer, buffer + buffer_length);
    }
};

int main()
{
    ifstream infile(FILENAME, std::ifstream::binary);
    if (!infile.is_open())
    {
        cerr << endl << "Failed to open file " << FILENAME << endl;
        return 0;
    }

    // Works, but slow.
    //istringstream local_stream;
    //local_stream << infile.rdbuf();

    // Works, but creates a copy.
    //istringstream local_stream(&buffer[0]);  

    // Works, but creates a copy.
    //local_stream.str(&buffer[0]);

    // Read entire file into buffer.
    infile.seekg(0, std::ios::end);
    streampos length = infile.tellg();
    infile.seekg(0, std::ios::beg);
    vector<char> buffer(length);
    //char* buffer = new char[length];
    infile.read(&buffer[0], length);

    // Doesn't work, but should point to original.
    // It returns "this" (does nothing).
    //local_stream.rdbuf()->pubsetbuf(&buffer[0], length);  

    // Works, but deprecated in C++98.
    //std::istrstream local_stream(&buffer[0]);  
    //local_stream.rdbuf()->pubsetbuf(&buffer[0], length);

    // I followed the example in the other question about an output stream,
    // but I modified for an input stream. I can't get it to work. Any ideas?
    istreambuf<char> istream_buffer(&buffer[0], length);
    istream local_stream(&istream_buffer);

    string str1, str2;
    while (local_stream >> str1 && local_stream >> str2)
    {
        . . .
    }
}
tim
  • 482
  • 3
  • 12
  • This question does not explain what the problem is. Descriptions like "not having much success" and "can't get it to work" are vague and not helpful. It is unlikely that this question in its current form will help someone in the future. I'd ask for clarification, but it looks like the issue is no longer a problem. – JaMiT May 24 '19 at 00:26
  • Thanks for your advice. I've edited it for clarity. – tim May 24 '19 at 01:08

1 Answers1

0

I've solved it! Spot the difference.

template <typename char_type>
struct istreambuf : public std::basic_streambuf<char_type, std::char_traits<char_type> >
{
    istreambuf(char_type* buffer, std::streamsize buffer_length)
    {
        // Set the "put" pointer to the start of the buffer and record its length.
        //this->setp(buffer, buffer + buffer_length);

        // Set the "get" pointer to the start of the buffer, the next item, and record its length.
        this->setg(buffer, buffer, buffer + buffer_length);
    }
};

I needed to set the "get" pointer, not the "put" pointer. It works well now.

tim
  • 482
  • 3
  • 12