Hi Adam,

I suspect you could write a wrapper class around ArrayPtr<const
ArrayPtr<const word>> that implements ConstBufferSequence while adding
minimal overhead. The class would have one data member of type
ArrayPtr<...> and would implement the necessary methods to make it a
ConstBufferSequence. You might need to similarly wrap each segment, if
asio::buffer() would otherwise create a copy.

BTW, careful about `asio::buffer(a.begin(), a.size())` -- I think you need
to multiply the size by `sizeof(capnp::word)`, since asio::buffer seems to
be byte-based.

-Kenton

On Sat, Feb 11, 2017 at 4:03 AM, <[email protected]> wrote:

> Hi,
>
> I'm trying to send Cap'n Proto messages over boost::asio streams,
> specifically ZeroMQ sockets.
>
> I'm currently using capnp::messageToFlatArray(…) combined with
> boost::asio::buffer(…) like so:
>
> auto data = capnp::messageToFlatArray(message);
> socket.async_send(boost::asio::buffer(data.begin(), data.size()), [](const
> boost::system::error_code& ec, std::size_t bytes_transferred){…});
>
> While this works, the call to messageToFlatArray creates a copy of the
> message contents.
>
> I found the following Stack Overflow reply from Kenton that briefly
> outlined the idea of using MessageBuilder::getSegmentsForOutput()
> combined with ZeroMQ multipart messages to avoid the overhead of a copy:
>
> Send the message as a ZeroMQ multi-part message, with the parts being the
>> message's segments. capnp::MessageBuilder::getSegmentsForOutput()
>> returns an array of arrays pointing into the raw message segments. 
>> capnp::SegmentArrayMessageReader
>> takes such an array of arrays as input. If you can send the array of arrays
>> as a multipart message, then you can skip using capnp/serialize.h at all,
>> since its only purpose is to combine the segments into a single message
>> with a segment table. In your case, ZeroMQ would be in charge of
>> remembering where each segment starts and ends.
>>
>
> -- Kenton Varda - http://stackoverflow.com/a/32042234
>
> All of asio's stream write functions take a ConstBufferSequence that
> allows the caller to pass multiple buffers to be written in a single call.
> For the ZeroMQ-asio binding (zmqp), passing multiple buffers to a write
> call sends a multipart message.
>
> The result of MessageBuilder::getSegmentsForOutput() isn't
> directly convertible to a ConstBufferSequence as the outer ArrayPtr
> doesn't provide ::value_type or ::const_iterator and the inner ArrayPtr's
> aren't convertible to asio::const_buffers.
>
> I've come up with the following code to do the conversion:
>
> auto raw_segments = message.getSegmentsForOutput();
>
> std::vector<asio::const_buffer> segments(raw_segments.size());
> std::transform(raw_segments.begin(), raw_segments.end(), segments.begin(),
> [](const kj::ArrayPtr<const capnp::word> a) {
>       return asio::buffer(a.begin(), a.size());
> });
>
> socket.async_send(segments, [](const boost::system::error_code& ec, 
> std::size_t
> bytes_transferred){});
>
> While this works, I do ask:
> Is there an easier (or more "correct") way to convert the output of
> MessageBuilder::getSegmentsForOutput() to a ConstBufferSequence?
> Is there a more efficient method? Is it possible to forgo the conversion
> of the outer array to a vector and the inner arrays to buffers? A
> ConstBufferSequence is basically a "array of arrays" anyway.
>
>
> Regards,
> Adam
>
> --
> You received this message because you are subscribed to the Google Groups
> "Cap'n Proto" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> Visit this group at https://groups.google.com/group/capnproto.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
Visit this group at https://groups.google.com/group/capnproto.

Reply via email to