2

I'm trying to implement an AsyncReadStream stream to read from std::cin and so far have the following code:

  template <class MutableBufferSequence, class ReadHandler>
  void async_read_some(const MutableBufferSequence &buf, ReadHandler handler) {

    char c[1024] = {};
    std::streamsize num = std::cin.readsome(c, 1023);
    c[num] = 0;

    boost::asio::streambuf buff(1023);
    std::ostream os(&buff);
    os << c;

    // How do I get the buff into the buf???? I've tried below:
    //boost::asio::buffered_stream<boost::asio::streambuf> buff_stream(buff);
    //boost::asio::read(buff_stream, buf);
    handler(boost::system::error_code(), boost::asio::buffer_size(buf));
  }

I'm aware that some of the code in the above is blocking, when it shouldn't really be but that's besides my problem here (I think). I've checked the documentation for MutableBufferSequence http://www.boost.org/doc/libs/1_41_0/doc/html/boost_asio/reference/MutableBufferSequence.html and there doesn't seem any obvious way to do this. Obviously I'm drastically misunderstanding something.

Jibbity jobby
  • 1,255
  • 2
  • 12
  • 26
  • Perhaps this ansewwrs my question. I will check later and delete if duplicate: https://stackoverflow.com/questions/17241770/how-to-write-to-a-boostasiomutable-buffer?rq=1 – Jibbity jobby Sep 28 '17 at 10:56
  • No it doesn't answer that. It's not about buffer sequences. – sehe Sep 28 '17 at 12:58
  • With regards to the linked answer, [`buffer_cast`](http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/buffer_cast.html) should only be used after careful consideration (e.g. consider scatter-read or gather-write buffers where the underlying memory is non-contiguous). Instead, one should often use type-safe iterators via [`buffers_begin`](http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/buffers_begin.html) and [`buffers_end`](http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/buffers_end.html). – Tanner Sansbury Sep 28 '17 at 15:10

1 Answers1

3

I'd skip the streambuf (why copy it twice?).

template <class MutableBufferSequence, class ReadHandler>
void my_read_some(MutableBufferSequence buf, ReadHandler handler) {

    char tmp[1024] = {};

    std::cin.read(tmp, sizeof(tmp));
    std::streamsize num = std::cin.gcount();

    if(std::cin || num) {
        ba::buffer_copy(buf, ba::buffer(tmp, num));

        handler({}, num);
    } else {
        handler(ba::error::eof, num);
    }
}

(where ba:: abbreviates boost::asio::).

Note also that read_some is likely not what you wanted (std::cin.readsome always reading 0 bytes).

To use it:

int main() {
    std::array<char, 512> block1{}, block2{};
    std::vector<ba::mutable_buffers_1> blocks { ba::buffer(block1), ba::buffer(block2) };

    auto handler = [&blocks](boost::system::error_code ec, size_t transferred) {
        if (ec)
            std::cout << "Error " << ec.message() << "\n";
        else {
            std::cout << "Received " << transferred << " bytes\n-------\n";

            std::copy_n(ba::buffers_begin(blocks), transferred, std::ostreambuf_iterator<char>(std::cout));
            std::cout << "\n-------\n";
        }
    };

    my_read_some(blocks, handler);
}

See it Live On Coliru

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks again Sehe. I'll accept when I get the chance to test. – Jibbity jobby Sep 28 '17 at 13:47
  • Nicely done. Consider invoking handlers via [`asio_handler_invoke()`](http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/reference/asio_handler_invoke.html) to allow for custom invocation strategies. – Tanner Sansbury Sep 28 '17 at 15:06
  • @TannerSansbury I considered doing that but couldn't find a reason to, since all we ever do is invoke the handler as passed, so I removed it again. Is there a reason to add it, in this case? (I just realized `my_read_some` is still a misnomer, but oh well for now) – sehe Sep 28 '17 at 16:11
  • 1
    I tend to always prefer the invocation hook. For example, consider the case where a handler type has invocation pre-conditions, and these pre-conditions are satisfied in either `asio_handler_invoke` or the responsibility of the caller. If one was to remove the need for pre-conditions by hoisting the setup into the handler's `operator()`, then it removes the need for a custom `asio_handler_invoke` strategy, but prevents optimizations when invoking handlers in batches. I have used this approach to minimize context switches when integrating between different languages. – Tanner Sansbury Sep 29 '17 at 03:50