Internal buffer used by standard input stream (pubsetbuf)
Asked Answered
K

1

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)
    {
        . . .
    }
}
Kick answered 23/5, 2019 at 21:49 Comment(2)
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.Uncinus
Thanks for your advice. I've edited it for clarity.Kick
K
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.

Kick answered 23/5, 2019 at 22:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.