Discussion:
[asio-users] How to remove dependence on boost::asio?
Vinnie Falco
2014-06-29 15:53:00 UTC
Permalink
I'm wrapping a C based HTTP parser up in a class interface and I want
to support parsing from ConstBufferSequence and ConstBuffers. But
there's nothing about this that technical "needs" asio. Except that I
am stuck bringing in asio just for buffer_cast and buffer_size. How
can I remove the dependence on asio? Here's the code in question:

https://github.com/ripple/rippled/blob/develop/src/beast/beast/http/message_parser.h#L120

Here's an excerpt of the relevant sections.

class parser
{
//...
/** Write data to the parser.
The return value includes the error code if any,
and the number of bytes consumed in the input sequence.
*/
std::pair <error_code, std::size_t>
write_one (void const* in, std::size_t bytes);

template <class ConstBuffer>
std::pair <error_code, std::size_t>
write_one (ConstBuffer const& buffer)
{
return write_one (boost::asio::buffer_cast <void const*> (buffer),
boost::asio::buffer_size (buffer));
}

template <class ConstBufferSequence>
std::pair <error_code, std::size_t>
write (ConstBufferSequence const& buffers)
{
std::pair <error_code, std::size_t> result (error_code(), 0);
for (auto const& buffer : buffers)
{
std::size_t bytes_consumed;
std::tie (result.first, bytes_consumed) = write_one (buffer);
if (result.first)
break;
result.second += bytes_consumed;
}
return result;
}
//...
};
--
Follow me on Github: https://github.com/vinniefalco
Vinnie Falco
2014-06-30 04:19:43 UTC
Permalink
If a user passes in a boost.asio buffer, argument dependent lookup will
find the appropriate functions for those types. Just make sure to not
prevent argument dependent lookup by fully qualifying the namespace those
functions are called from.
...
if you just remove boost::asio:: from those two calls, you enable ADL and
it probably would just work.
...
Arvid Norberg
I wish this was true but when the namespace qualifiers are removed,
the result no longer compiles. And the asio documentation makes no
mention of buffer, buffer_copy, or buffer_size being called via
argument dependent lookup. Furthermore, boost::asio places these
functions in the boost::asio namespace which would prevent the
compiler from finding overloads in other namespaces.
--
Follow me on Github: https://github.com/vinniefalco
Niklas Angare
2014-06-30 23:47:00 UTC
Permalink
Post by Vinnie Falco
if you just remove boost::asio:: from those two calls, you enable ADL and
it probably would just work.
I wish this was true but when the namespace qualifiers are removed,
the result no longer compiles.
ADL apparently needs some help to work with function templates such as
buffer_cast:
http://stackoverflow.com/questions/2953684/why-doesnt-adl-find-function-templates

The following code compiles with GCC and Clang:

#include <utility>
#include <tuple>

class error_code
{
};

namespace dummy
{
template<typename T> T buffer_cast();
}

class parser
{
//...
public:
/** Write data to the parser.
The return value includes the error code if any,
and the number of bytes consumed in the input sequence.
*/
std::pair <error_code, std::size_t>
write_one (void const* in, std::size_t bytes);

template <class ConstBuffer>
std::pair <error_code, std::size_t>
write_one (ConstBuffer const& buffer)
{
using dummy::buffer_cast;
return write_one (buffer_cast <void const*> (buffer),
buffer_size (buffer));
}

template <class ConstBufferSequence>
std::pair <error_code, std::size_t>
write (ConstBufferSequence const& buffers)
{
std::pair <error_code, std::size_t> result (error_code(), 0);
for (auto const& buffer : buffers)
{
std::size_t bytes_consumed;
std::tie (result.first, bytes_consumed) = write_one (buffer);
if (result.first)
break;
result.second += bytes_consumed;
}
return result;
}
//...
};
Vinnie Falco
2014-07-01 15:18:40 UTC
Permalink
Post by Niklas Angare
ADL apparently needs some help to work with function templates such as
http://stackoverflow.com/questions/2953684/why-doesnt-adl-find-function-templates
...

That did the trick, thanks!
Vinnie Falco
2014-07-05 19:32:16 UTC
Permalink
Post by Niklas Angare
if you just remove boost::asio:: from those two calls, you enable ADL and
it probably would just work.
...
ADL apparently needs some help to work with function templates such as
...
The code you provided works when the argument to buffer_cast is an
asio type like const_buffer (or the return value of
boost::asio::streambuff::data()). But it fails when the argument is
something like std::string.
Niklas Angare
2014-07-06 13:22:20 UTC
Permalink
Post by Vinnie Falco
Post by Niklas Angare
if you just remove boost::asio:: from those two calls, you enable ADL and
it probably would just work.
...
ADL apparently needs some help to work with function templates such as
...
The code you provided works when the argument to buffer_cast is an
asio type like const_buffer (or the return value of
boost::asio::streambuff::data()). But it fails when the argument is
something like std::string.
Ok. Two more suggestions:

a)

Add this to the top of the file:
namespace boost { namespace asio { } }

Add this to write_one():
using namespace boost::asio;

Require that users that want to use Asio buffers include the appropriate
Asio header before yours.

b)

Make the functions that take Asio buffers free functions and move them to a
separate header file. Asio itself has a mix of member functions and free
functions so it wouldn't be terribly out of place.

Regards,

Niklas Angare

Loading...