#ifndef BOOST_ASIO_BUFFER_REGISTRATION_HPP
#define BOOST_ASIO_BUFFER_REGISTRATION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/asio/detail/config.hpp>
#include <iterator>
#include <utility>
#include <vector>
#include <boost/asio/detail/memory.hpp>
#include <boost/asio/execution/context.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/asio/query.hpp>
#include <boost/asio/registered_buffer.hpp>
#if defined(BOOST_ASIO_HAS_IO_URING)
# include <boost/asio/detail/scheduler.hpp>
# include <boost/asio/detail/io_uring_service.hpp>
#endif
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
class buffer_registration_base
{
protected:
static mutable_registered_buffer make_buffer(const mutable_buffer& b,
const void* scope, int index) noexcept
{
return mutable_registered_buffer(b, registered_buffer_id(scope, index));
}
};
}
template <typename MutableBufferSequence,
typename Allocator = std::allocator<void>>
class buffer_registration
: detail::buffer_registration_base
{
public:
typedef Allocator allocator_type;
#if defined(GENERATING_DOCUMENTATION)
typedef unspecified iterator;
typedef unspecified const_iterator;
#else
typedef std::vector<mutable_registered_buffer>::const_iterator iterator;
typedef std::vector<mutable_registered_buffer>::const_iterator const_iterator;
#endif
template <typename Executor>
buffer_registration(const Executor& ex,
const MutableBufferSequence& buffer_sequence,
const allocator_type& alloc = allocator_type(),
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
: buffer_sequence_(buffer_sequence),
buffers_(
BOOST_ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)(alloc))
{
init_buffers(buffer_registration::get_context(ex),
boost::asio::buffer_sequence_begin(buffer_sequence_),
boost::asio::buffer_sequence_end(buffer_sequence_));
}
template <typename ExecutionContext>
buffer_registration(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence,
const allocator_type& alloc = allocator_type(),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: buffer_sequence_(buffer_sequence),
buffers_(
BOOST_ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)(alloc))
{
init_buffers(ctx,
boost::asio::buffer_sequence_begin(buffer_sequence_),
boost::asio::buffer_sequence_end(buffer_sequence_));
}
buffer_registration(buffer_registration&& other) noexcept
: buffer_sequence_(std::move(other.buffer_sequence_)),
buffers_(std::move(other.buffers_))
{
#if defined(BOOST_ASIO_HAS_IO_URING)
service_ = other.service_;
other.service_ = 0;
#endif }
~buffer_registration()
{
#if defined(BOOST_ASIO_HAS_IO_URING)
if (service_)
service_->unregister_buffers();
#endif }
buffer_registration& operator=(buffer_registration&& other) noexcept
{
if (this != &other)
{
buffer_sequence_ = std::move(other.buffer_sequence_);
buffers_ = std::move(other.buffers_);
#if defined(BOOST_ASIO_HAS_IO_URING)
if (service_)
service_->unregister_buffers();
service_ = other.service_;
other.service_ = 0;
#endif }
return *this;
}
std::size_t size() const noexcept
{
return buffers_.size();
}
const_iterator begin() const noexcept
{
return buffers_.begin();
}
const_iterator cbegin() const noexcept
{
return buffers_.cbegin();
}
const_iterator end() const noexcept
{
return buffers_.end();
}
const_iterator cend() const noexcept
{
return buffers_.cend();
}
const mutable_registered_buffer& operator[](std::size_t i) noexcept
{
return buffers_[i];
}
const mutable_registered_buffer& at(std::size_t i) noexcept
{
return buffers_.at(i);
}
private:
buffer_registration(const buffer_registration&) = delete;
buffer_registration& operator=(const buffer_registration&) = delete;
template <typename T>
static execution_context& get_context(const T& t,
enable_if_t<execution::is_executor<T>::value>* = 0)
{
return boost::asio::query(t, execution::context);
}
template <typename T>
static execution_context& get_context(const T& t,
enable_if_t<!execution::is_executor<T>::value>* = 0)
{
return t.context();
}
template <typename Iterator>
void init_buffers(execution_context& ctx, Iterator begin, Iterator end)
{
std::size_t n = std::distance(begin, end);
buffers_.resize(n);
#if defined(BOOST_ASIO_HAS_IO_URING)
service_ = &use_service<detail::io_uring_service>(ctx);
std::vector<iovec,
BOOST_ASIO_REBIND_ALLOC(allocator_type, iovec)> iovecs(n,
BOOST_ASIO_REBIND_ALLOC(allocator_type, iovec)(
buffers_.get_allocator()));
#endif
Iterator iter = begin;
for (int index = 0; iter != end; ++index, ++iter)
{
mutable_buffer b(*iter);
std::size_t i = static_cast<std::size_t>(index);
buffers_[i] = this->make_buffer(b, &ctx, index);
#if defined(BOOST_ASIO_HAS_IO_URING)
iovecs[i].iov_base = buffers_[i].data();
iovecs[i].iov_len = buffers_[i].size();
#endif }
#if defined(BOOST_ASIO_HAS_IO_URING)
if (n > 0)
{
service_->register_buffers(&iovecs[0],
static_cast<unsigned>(iovecs.size()));
}
#endif }
MutableBufferSequence buffer_sequence_;
std::vector<mutable_registered_buffer,
BOOST_ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)> buffers_;
#if defined(BOOST_ASIO_HAS_IO_URING)
detail::io_uring_service* service_;
#endif };
template <typename Executor, typename MutableBufferSequence>
BOOST_ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence>
register_buffers(const Executor& ex,
const MutableBufferSequence& buffer_sequence,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
{
return buffer_registration<MutableBufferSequence>(ex, buffer_sequence);
}
template <typename Executor, typename MutableBufferSequence, typename Allocator>
BOOST_ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence, Allocator>
register_buffers(const Executor& ex,
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
{
return buffer_registration<MutableBufferSequence, Allocator>(
ex, buffer_sequence, alloc);
}
template <typename ExecutionContext, typename MutableBufferSequence>
BOOST_ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence>
register_buffers(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
{
return buffer_registration<MutableBufferSequence>(ctx, buffer_sequence);
}
template <typename ExecutionContext,
typename MutableBufferSequence, typename Allocator>
BOOST_ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence, Allocator>
register_buffers(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
{
return buffer_registration<MutableBufferSequence, Allocator>(
ctx, buffer_sequence, alloc);
}
} }
#include <boost/asio/detail/pop_options.hpp>
#endif