// // detail/buffer_sequence_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP #define ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/buffer.hpp" #include "asio/detail/array_fwd.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class buffer_sequence_adapter_base { #if defined(ASIO_WINDOWS_RUNTIME) public: // The maximum number of buffers to support in a single operation. enum { max_buffers = 1 }; protected: typedef Windows::Storage::Streams::IBuffer^ native_buffer_type; ASIO_DECL static void init_native_buffer( native_buffer_type& buf, const asio::mutable_buffer& buffer); ASIO_DECL static void init_native_buffer( native_buffer_type& buf, const asio::const_buffer& buffer); #elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) public: // The maximum number of buffers to support in a single operation. enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; protected: typedef WSABUF native_buffer_type; static void init_native_buffer(WSABUF& buf, const asio::mutable_buffer& buffer) { buf.buf = static_cast(buffer.data()); buf.len = static_cast(buffer.size()); } static void init_native_buffer(WSABUF& buf, const asio::const_buffer& buffer) { buf.buf = const_cast(static_cast(buffer.data())); buf.len = static_cast(buffer.size()); } #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) public: // The maximum number of buffers to support in a single operation. enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; protected: typedef iovec native_buffer_type; static void init_iov_base(void*& base, void* addr) { base = addr; } template static void init_iov_base(T& base, void* addr) { base = static_cast(addr); } static void init_native_buffer(iovec& iov, const asio::mutable_buffer& buffer) { init_iov_base(iov.iov_base, buffer.data()); iov.iov_len = buffer.size(); } static void init_native_buffer(iovec& iov, const asio::const_buffer& buffer) { init_iov_base(iov.iov_base, const_cast(buffer.data())); iov.iov_len = buffer.size(); } #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) }; // Helper class to translate buffers into the native buffer representation. template class buffer_sequence_adapter : buffer_sequence_adapter_base { public: enum { is_single_buffer = false }; explicit buffer_sequence_adapter(const Buffers& buffer_sequence) : count_(0), total_buffer_size_(0) { buffer_sequence_adapter::init( asio::buffer_sequence_begin(buffer_sequence), asio::buffer_sequence_end(buffer_sequence)); } native_buffer_type* buffers() { return buffers_; } std::size_t count() const { return count_; } std::size_t total_size() const { return total_buffer_size_; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const Buffers& buffer_sequence) { return buffer_sequence_adapter::all_empty( asio::buffer_sequence_begin(buffer_sequence), asio::buffer_sequence_end(buffer_sequence)); } static void validate(const Buffers& buffer_sequence) { buffer_sequence_adapter::validate( asio::buffer_sequence_begin(buffer_sequence), asio::buffer_sequence_end(buffer_sequence)); } static Buffer first(const Buffers& buffer_sequence) { return buffer_sequence_adapter::first( asio::buffer_sequence_begin(buffer_sequence), asio::buffer_sequence_end(buffer_sequence)); } enum { linearisation_storage_size = 8192 }; static Buffer linearise(const Buffers& buffer_sequence, const asio::mutable_buffer& storage) { return buffer_sequence_adapter::linearise( asio::buffer_sequence_begin(buffer_sequence), asio::buffer_sequence_end(buffer_sequence), storage); } private: template void init(Iterator begin, Iterator end) { Iterator iter = begin; for (; iter != end && count_ < max_buffers; ++iter, ++count_) { Buffer buffer(*iter); init_native_buffer(buffers_[count_], buffer); total_buffer_size_ += buffer.size(); } } template static bool all_empty(Iterator begin, Iterator end) { Iterator iter = begin; std::size_t i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) if (Buffer(*iter).size() > 0) return false; return true; } template static void validate(Iterator begin, Iterator end) { Iterator iter = begin; for (; iter != end; ++iter) { Buffer buffer(*iter); buffer.data(); } } template static Buffer first(Iterator begin, Iterator end) { Iterator iter = begin; for (; iter != end; ++iter) { Buffer buffer(*iter); if (buffer.size() != 0) return buffer; } return Buffer(); } template static Buffer linearise(Iterator begin, Iterator end, const asio::mutable_buffer& storage) { asio::mutable_buffer unused_storage = storage; Iterator iter = begin; while (iter != end && unused_storage.size() != 0) { Buffer buffer(*iter); ++iter; if (buffer.size() == 0) continue; if (unused_storage.size() == storage.size()) { if (iter == end) return buffer; if (buffer.size() >= unused_storage.size()) return buffer; } unused_storage += asio::buffer_copy(unused_storage, buffer); } return Buffer(storage.data(), storage.size() - unused_storage.size()); } native_buffer_type buffers_[max_buffers]; std::size_t count_; std::size_t total_buffer_size_; }; template class buffer_sequence_adapter : buffer_sequence_adapter_base { public: enum { is_single_buffer = true }; explicit buffer_sequence_adapter( const asio::mutable_buffer& buffer_sequence) { init_native_buffer(buffer_, Buffer(buffer_sequence)); total_buffer_size_ = buffer_sequence.size(); } native_buffer_type* buffers() { return &buffer_; } std::size_t count() const { return 1; } std::size_t total_size() const { return total_buffer_size_; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const asio::mutable_buffer& buffer_sequence) { return buffer_sequence.size() == 0; } static void validate(const asio::mutable_buffer& buffer_sequence) { buffer_sequence.data(); } static Buffer first(const asio::mutable_buffer& buffer_sequence) { return Buffer(buffer_sequence); } enum { linearisation_storage_size = 1 }; static Buffer linearise(const asio::mutable_buffer& buffer_sequence, const Buffer&) { return Buffer(buffer_sequence); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; template class buffer_sequence_adapter : buffer_sequence_adapter_base { public: enum { is_single_buffer = true }; explicit buffer_sequence_adapter( const asio::const_buffer& buffer_sequence) { init_native_buffer(buffer_, Buffer(buffer_sequence)); total_buffer_size_ = buffer_sequence.size(); } native_buffer_type* buffers() { return &buffer_; } std::size_t count() const { return 1; } std::size_t total_size() const { return total_buffer_size_; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const asio::const_buffer& buffer_sequence) { return buffer_sequence.size() == 0; } static void validate(const asio::const_buffer& buffer_sequence) { buffer_sequence.data(); } static Buffer first(const asio::const_buffer& buffer_sequence) { return Buffer(buffer_sequence); } enum { linearisation_storage_size = 1 }; static Buffer linearise(const asio::const_buffer& buffer_sequence, const Buffer&) { return Buffer(buffer_sequence); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; #if !defined(ASIO_NO_DEPRECATED) template class buffer_sequence_adapter : buffer_sequence_adapter_base { public: enum { is_single_buffer = true }; explicit buffer_sequence_adapter( const asio::mutable_buffers_1& buffer_sequence) { init_native_buffer(buffer_, Buffer(buffer_sequence)); total_buffer_size_ = buffer_sequence.size(); } native_buffer_type* buffers() { return &buffer_; } std::size_t count() const { return 1; } std::size_t total_size() const { return total_buffer_size_; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const asio::mutable_buffers_1& buffer_sequence) { return buffer_sequence.size() == 0; } static void validate(const asio::mutable_buffers_1& buffer_sequence) { buffer_sequence.data(); } static Buffer first(const asio::mutable_buffers_1& buffer_sequence) { return Buffer(buffer_sequence); } enum { linearisation_storage_size = 1 }; static Buffer linearise(const asio::mutable_buffers_1& buffer_sequence, const Buffer&) { return Buffer(buffer_sequence); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; template class buffer_sequence_adapter : buffer_sequence_adapter_base { public: enum { is_single_buffer = true }; explicit buffer_sequence_adapter( const asio::const_buffers_1& buffer_sequence) { init_native_buffer(buffer_, Buffer(buffer_sequence)); total_buffer_size_ = buffer_sequence.size(); } native_buffer_type* buffers() { return &buffer_; } std::size_t count() const { return 1; } std::size_t total_size() const { return total_buffer_size_; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const asio::const_buffers_1& buffer_sequence) { return buffer_sequence.size() == 0; } static void validate(const asio::const_buffers_1& buffer_sequence) { buffer_sequence.data(); } static Buffer first(const asio::const_buffers_1& buffer_sequence) { return Buffer(buffer_sequence); } enum { linearisation_storage_size = 1 }; static Buffer linearise(const asio::const_buffers_1& buffer_sequence, const Buffer&) { return Buffer(buffer_sequence); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; #endif // !defined(ASIO_NO_DEPRECATED) template class buffer_sequence_adapter > : buffer_sequence_adapter_base { public: enum { is_single_buffer = false }; explicit buffer_sequence_adapter( const boost::array& buffer_sequence) { init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); } native_buffer_type* buffers() { return buffers_; } std::size_t count() const { return 2; } std::size_t total_size() const { return total_buffer_size_; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const boost::array& buffer_sequence) { return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; } static void validate(const boost::array& buffer_sequence) { buffer_sequence[0].data(); buffer_sequence[1].data(); } static Buffer first(const boost::array& buffer_sequence) { return Buffer(buffer_sequence[0].size() != 0 ? buffer_sequence[0] : buffer_sequence[1]); } enum { linearisation_storage_size = 8192 }; static Buffer linearise(const boost::array& buffer_sequence, const asio::mutable_buffer& storage) { if (buffer_sequence[0].size() == 0) return Buffer(buffer_sequence[1]); if (buffer_sequence[1].size() == 0) return Buffer(buffer_sequence[0]); return Buffer(storage.data(), asio::buffer_copy(storage, buffer_sequence)); } private: native_buffer_type buffers_[2]; std::size_t total_buffer_size_; }; #if defined(ASIO_HAS_STD_ARRAY) template class buffer_sequence_adapter > : buffer_sequence_adapter_base { public: enum { is_single_buffer = false }; explicit buffer_sequence_adapter( const std::array& buffer_sequence) { init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); } native_buffer_type* buffers() { return buffers_; } std::size_t count() const { return 2; } std::size_t total_size() const { return total_buffer_size_; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const std::array& buffer_sequence) { return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; } static void validate(const std::array& buffer_sequence) { buffer_sequence[0].data(); buffer_sequence[1].data(); } static Buffer first(const std::array& buffer_sequence) { return Buffer(buffer_sequence[0].size() != 0 ? buffer_sequence[0] : buffer_sequence[1]); } enum { linearisation_storage_size = 8192 }; static Buffer linearise(const std::array& buffer_sequence, const asio::mutable_buffer& storage) { if (buffer_sequence[0].size() == 0) return Buffer(buffer_sequence[1]); if (buffer_sequence[1].size() == 0) return Buffer(buffer_sequence[0]); return Buffer(storage.data(), asio::buffer_copy(storage, buffer_sequence)); } private: native_buffer_type buffers_[2]; std::size_t total_buffer_size_; }; #endif // defined(ASIO_HAS_STD_ARRAY) } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/buffer_sequence_adapter.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP