2

I need to do async_read_until, after which I want to call async_read_some using the same boost::asio::streambuf that was used for async_read_until.

The reason why I want to use the same boost::asio::streambuf is that after async_read_until there might be some data left in the buffer. When reading via async_read_some I want to get not only the new data that is available but also the data that might have been left after async_read_until.

However, async_read_some does not have an overload for boost::asio::streambuf. How can I solve this problem?

Here is an example of the code I need to execute. Note that read_some can be called multiple times.

class io
{
    //...
public:

    void read_until()
    {
        boost::asio::async_read_until(m_socket, m_buffer, "\n", 
            [this](const boost::system::error_code& ec, std::size_t bytes_transferred)
        {
            read_some();
        });
    }

    void read_some()
    {
        // I need use async_read_some here into m_buffer
        // ...
        // read_some() can be called again from completion handler
    }

private:
    boost::asio::streambuf m_buffer;
    boost::asio::ip::tcp::socket m_socket;
};

I read that you can use prepare/commit/consume, but I don't fully understand how to use these methods correctly. Can someone give an example and explain what exactly these methods do and how to use them correctly?


UPDATE

Please answer the following questions:

  1. Is it true that boost::asio::streambuf consists of at least two buffers? A read buffer and a write buffer?
  2. If so, is it true that boost::asio::streambuf::prepare allocates space in the write buffer?
  3. If so, is it true that boost::asio::streambuf::commit copies data from the write buffer to the read buffer?
  4. Is it true that boost::asio::streambuf::consume removes data from the read buffer?
  5. Is it true that if the read buffer contained data [my_data], and then prepare(n), async_read_some and commit is called, then after commit the read buffer will contain [my_data]+[new_data_from_async_read_some]?
4

1 Answer 1

2
  1. Q. Is it true that asio::streambuf consists of at least two buffers? A read buffer and a write buffer?

    Not necessarily. It might be, or it might not be. asio::streambuf bridges two worls:

    • the Asio concept DynamicBuffer (v1) which defines the prepare, commit, and consume interface in terms of single buffers.

    • the iostreams std::streambuf which similarly describes an interface like¹

      enter image description here

      Note, here too there's a logical "input" and "output area" which can be from the same buffer (as in e.g. std::basic_stringbuf or std::basic_spanbuf

    That said, currently Asio's streambuf happens to always keep a single buffer in the storage model: is it safe to use boost::asio::streambuf as both an istream and an array as string_view?


  2. Q. If so, is it true that prepare allocates space in the write buffer?

    It reserves enough space for the output area. If necessary, it will (re)allocate.


  3. Q. If so, is it true that commit copies data from the write buffer to the read buffer?

    No. It merely manipulates some pointers to indicate the new extents of available input/output areas.


  4. Q. *Is it true that consume removes data from the read buffer?

    It will typically again just update some pointers, though implementations might shrink the allocated storage to fit. You can infer that implementations have this leeway from the invalidation specifications in the concept:

    expression assertion/note
    pre/post conditions
    x.consume(n) Removes n bytes from beginning of the input sequence. If n is greater than the size of the input sequence, the entire input sequence is removed. All constant or mutable buffer sequences previously obtained using data() or prepare() are invalidated.

  5. Q. Is it true that if the read buffer contained data "my_data", and then prepare(n), async_read_some and commit are called, then after commit the read buffer will contain "my_data"+[new_data_from_async_read_some]?

    Logically, yes. To be more precisely, you might refer to "get area" instead of "read buffer", matching the iostreams jargon, and avoiding the implication that data is copied during commit.


¹ image originally from https://cppreference.com/w/cpp/io/basic_streambuf.html where it is currently broken for some reason?

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you! 2) Enough for what? When does reallocate become necessary? Does this mean that if I call prepare(1024) and pass the result to async_read_some, then when reading it is possible that I will read more than 1024 bytes due to reallocation? 3) Anyway, this operation makes the data that was written to the buffer available for reading, is that correct?
@JoeJ The specification could not be more clear on that. Your question bullet 2. is about prepare. So obviously it is prepare that might allocate. NOT read_some. You KNOW that because read_some takes a MutableBuffer, not a DynamicBuffer. Wasn't that the reason you were having this question in the first place?
3). Yes. I was hoping that my answering "Logically, yes." was enough to make clear that "yes" was the answer. It's just that specifics of the implementation are less rigid (and suboptimal) than your imagined implementation from the question text.
If for some reason you worry how much prepare() actually allocates and when, why don't just implement the concept yourself? It's not actually that hard. There's plenty examples (dynamic_vector_buffer, dynamic_string_buf, beast::flat_buffer etc.)
You can just look at the documentation for flat_buffer to see what logic you should apply: "A dynamic buffer providing buffer sequences of length one.". Of course, if you're paranoid, just double check: coliru.stacked-crooked.com/a/ebce4710086ccca2
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.