开发者

how to use boost::asio::async_read_until with an external memory address as a buffer

开发者 https://www.devze.com 2023-04-11 17:40 出处:网络
async_read_until expects a basic_streambuf into which the data will be read. I don\'t want to allocate additional memory, but using a memory address (from a specified interface that I\'m not allowed t

async_read_until expects a basic_streambuf into which the data will be read. I don't want to allocate additional memory, but using a memory address (from a specified interface that I'm not allowed to change) as 开发者_运维问答the target buffer.

Is it possible to create a streambuf with an external memory address or do I need to write a wrapper-class?


Finally solved the issue by writing my own async_read_until_delim class which expects a memory-pointer and a maximum value of bytes to read. It's as close as possible to the original boost implementation, but has a few adjustments which should lead to a more performant execution.

namespace {

template<typename read_handler>
class async_read_until_delim
{
public:
    async_read_until_delim(tcp::socket& socket, void* buffer, std::size_t max_read_size_in_bytes,
        char delim, read_handler& handler)
            : m_socket(socket), m_cur(static_cast<char*>(buffer)),
              m_end(static_cast<char*>(buffer) + max_read_size_in_bytes), m_delim(delim),
              m_handler(handler), m_pos(0)
        {
            read_some();
        }
    async_read_until_delim(async_read_until_delim const& other)
        : m_socket(other.m_socket), m_cur(other.m_cur), m_end(other.m_end), m_delim(other.m_delim),
          m_handler(other.m_handler), m_pos(other.m_pos)
        {
        }

    void operator()(boost::system::error_code const& error, std::size_t bytes_transferred)
        {
            if (!error)
            {    
                if (std::find(m_cur, m_end, m_delim) != m_end)
                {
                    m_handler(error, m_pos + bytes_transferred);
                    return;
                }
                else if (m_cur == m_end)
                {
                    m_handler(boost::asio::error::not_found, -1);
                    return;
                }

                m_cur += bytes_transferred;
                m_pos += bytes_transferred;

                read_some();
            }
            else
                m_handler(error, m_pos);
        }

private:
    void read_some()
        {
            m_socket.async_read_some(
                boost::asio::buffer(m_cur, m_end - m_cur), async_read_until_delim(*this));
        }

    tcp::socket&  m_socket;
    char         *m_cur,
                 *m_end;
    char          m_delim;
    read_handler  m_handler;
    std::size_t   m_pos;
};

template<typename read_handler>
inline void do_async_read_until_delim(tcp::socket& socket, void* buffer, std::size_t max_read_size_in_bytes,
    char delim, read_handler& handler)
{
    async_read_until_delim<read_handler>(socket, buffer, max_read_size_in_bytes, delim, handler);
}

} /* anonymous namespace */

So, I hope it will be usefull for someone too.

0

精彩评论

暂无评论...
验证码 换一张
取 消