summaryrefslogtreecommitdiff
path: root/boost/beast/experimental/core/impl/flat_stream.ipp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/experimental/core/impl/flat_stream.ipp')
-rw-r--r--boost/beast/experimental/core/impl/flat_stream.ipp309
1 files changed, 309 insertions, 0 deletions
diff --git a/boost/beast/experimental/core/impl/flat_stream.ipp b/boost/beast/experimental/core/impl/flat_stream.ipp
new file mode 100644
index 0000000000..a94622f7cc
--- /dev/null
+++ b/boost/beast/experimental/core/impl/flat_stream.ipp
@@ -0,0 +1,309 @@
+//
+// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail 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)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_CORE_IMPL_FLAT_STREAM_IPP
+#define BOOST_BEAST_CORE_IMPL_FLAT_STREAM_IPP
+
+#include <boost/beast/core/buffers_prefix.hpp>
+#include <boost/beast/websocket/teardown.hpp>
+#include <boost/asio/associated_allocator.hpp>
+#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/coroutine.hpp>
+#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
+
+namespace boost {
+namespace beast {
+
+template<class NextLayer>
+template<class ConstBufferSequence, class Handler>
+class flat_stream<NextLayer>::write_op
+ : public boost::asio::coroutine
+{
+ using alloc_type = typename
+#if defined(BOOST_NO_CXX11_ALLOCATOR)
+ boost::asio::associated_allocator_t<Handler>::template
+ rebind<char>::other;
+#else
+ std::allocator_traits<boost::asio::associated_allocator_t<Handler>>
+ ::template rebind_alloc<char>;
+#endif
+
+ struct deleter
+ {
+ alloc_type alloc;
+ std::size_t size = 0;
+
+ explicit
+ deleter(alloc_type const& alloc_)
+ : alloc(alloc_)
+ {
+ }
+
+ void
+ operator()(char* p)
+ {
+ alloc.deallocate(p, size);
+ }
+ };
+
+ flat_stream<NextLayer>& s_;
+ ConstBufferSequence b_;
+ std::unique_ptr<char, deleter> p_;
+ Handler h_;
+
+public:
+ template<class DeducedHandler>
+ write_op(
+ flat_stream<NextLayer>& s,
+ ConstBufferSequence const& b,
+ DeducedHandler&& h)
+ : s_(s)
+ , b_(b)
+ , p_(nullptr, deleter{
+ (boost::asio::get_associated_allocator)(h)})
+ , h_(std::forward<DeducedHandler>(h))
+ {
+ }
+
+ using allocator_type =
+ boost::asio::associated_allocator_t<Handler>;
+
+ allocator_type
+ get_allocator() const noexcept
+ {
+ return (boost::asio::get_associated_allocator)(h_);
+ }
+
+ using executor_type = boost::asio::associated_executor_t<
+ Handler, decltype(std::declval<NextLayer&>().get_executor())>;
+
+ executor_type
+ get_executor() const noexcept
+ {
+ return (boost::asio::get_associated_executor)(
+ h_, s_.get_executor());
+ }
+
+ void
+ operator()(
+ boost::system::error_code ec,
+ std::size_t bytes_transferred);
+
+ friend
+ bool asio_handler_is_continuation(write_op* op)
+ {
+ using boost::asio::asio_handler_is_continuation;
+ return asio_handler_is_continuation(
+ std::addressof(op->h_));
+ }
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, write_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
+};
+
+template<class NextLayer>
+template<class ConstBufferSequence, class Handler>
+void
+flat_stream<NextLayer>::
+write_op<ConstBufferSequence, Handler>::
+operator()(
+ error_code ec,
+ std::size_t bytes_transferred)
+{
+ BOOST_ASIO_CORO_REENTER(*this)
+ {
+ BOOST_ASIO_CORO_YIELD
+ {
+ auto const result = coalesce(b_, coalesce_limit);
+ if(result.second)
+ {
+ p_.get_deleter().size = result.first;
+ p_.reset(p_.get_deleter().alloc.allocate(
+ p_.get_deleter().size));
+ boost::asio::buffer_copy(
+ boost::asio::buffer(
+ p_.get(), p_.get_deleter().size),
+ b_, result.first);
+ s_.stream_.async_write_some(
+ boost::asio::buffer(
+ p_.get(), p_.get_deleter().size),
+ std::move(*this));
+ }
+ else
+ {
+ s_.stream_.async_write_some(
+ boost::beast::buffers_prefix(result.first, b_),
+ std::move(*this));
+ }
+ }
+ p_.reset();
+ h_(ec, bytes_transferred);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+template<class NextLayer>
+template<class... Args>
+flat_stream<NextLayer>::
+flat_stream(Args&&... args)
+ : stream_(std::forward<Args>(args)...)
+{
+}
+
+template<class NextLayer>
+template<class MutableBufferSequence>
+std::size_t
+flat_stream<NextLayer>::
+read_some(MutableBufferSequence const& buffers)
+{
+ static_assert(boost::beast::is_sync_read_stream<next_layer_type>::value,
+ "SyncReadStream requirements not met");
+ static_assert(boost::asio::is_mutable_buffer_sequence<
+ MutableBufferSequence>::value,
+ "MutableBufferSequence requirements not met");
+ error_code ec;
+ auto n = read_some(buffers, ec);
+ if(ec)
+ BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
+ return n;
+}
+
+template<class NextLayer>
+template<class MutableBufferSequence>
+std::size_t
+flat_stream<NextLayer>::
+read_some(MutableBufferSequence const& buffers, error_code& ec)
+{
+ return stream_.read_some(buffers, ec);
+}
+
+template<class NextLayer>
+template<
+ class MutableBufferSequence,
+ class ReadHandler>
+BOOST_ASIO_INITFN_RESULT_TYPE(
+ ReadHandler, void(error_code, std::size_t))
+flat_stream<NextLayer>::
+async_read_some(
+ MutableBufferSequence const& buffers,
+ ReadHandler&& handler)
+{
+ static_assert(boost::beast::is_async_read_stream<next_layer_type>::value,
+ "AsyncReadStream requirements not met");
+ static_assert(boost::asio::is_mutable_buffer_sequence<
+ MutableBufferSequence >::value,
+ "MutableBufferSequence requirements not met");
+ return stream_.async_read_some(
+ buffers, std::forward<ReadHandler>(handler));
+}
+
+template<class NextLayer>
+template<class ConstBufferSequence>
+std::size_t
+flat_stream<NextLayer>::
+write_some(ConstBufferSequence const& buffers)
+{
+ static_assert(boost::beast::is_sync_write_stream<next_layer_type>::value,
+ "SyncWriteStream requirements not met");
+ static_assert(boost::asio::is_const_buffer_sequence<
+ ConstBufferSequence>::value,
+ "ConstBufferSequence requirements not met");
+ auto const result = coalesce(buffers, coalesce_limit);
+ if(result.second)
+ {
+ std::unique_ptr<char[]> p{new char[result.first]};
+ auto const b = boost::asio::buffer(p.get(), result.first);
+ boost::asio::buffer_copy(b, buffers);
+ return stream_.write_some(b);
+ }
+ return stream_.write_some(
+ boost::beast::buffers_prefix(result.first, buffers));
+}
+
+template<class NextLayer>
+template<class ConstBufferSequence>
+std::size_t
+flat_stream<NextLayer>::
+write_some(ConstBufferSequence const& buffers, error_code& ec)
+{
+ static_assert(boost::beast::is_sync_write_stream<next_layer_type>::value,
+ "SyncWriteStream requirements not met");
+ static_assert(boost::asio::is_const_buffer_sequence<
+ ConstBufferSequence>::value,
+ "ConstBufferSequence requirements not met");
+ auto const result = coalesce(buffers, coalesce_limit);
+ if(result.second)
+ {
+ std::unique_ptr<char[]> p{new char[result.first]};
+ auto const b = boost::asio::buffer(p.get(), result.first);
+ boost::asio::buffer_copy(b, buffers);
+ return stream_.write_some(b, ec);
+ }
+ return stream_.write_some(
+ boost::beast::buffers_prefix(result.first, buffers), ec);
+}
+
+template<class NextLayer>
+template<
+ class ConstBufferSequence,
+ class WriteHandler>
+BOOST_ASIO_INITFN_RESULT_TYPE(
+ WriteHandler, void(error_code, std::size_t))
+flat_stream<NextLayer>::
+async_write_some(
+ ConstBufferSequence const& buffers,
+ WriteHandler&& handler)
+{
+ static_assert(boost::beast::is_async_write_stream<next_layer_type>::value,
+ "AsyncWriteStream requirements not met");
+ static_assert(boost::asio::is_const_buffer_sequence<
+ ConstBufferSequence>::value,
+ "ConstBufferSequence requirements not met");
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code, std::size_t));
+ write_op<ConstBufferSequence, BOOST_ASIO_HANDLER_TYPE(
+ WriteHandler, void(error_code, std::size_t))>{
+ *this, buffers, std::move(init.completion_handler)}({}, 0);
+ return init.result.get();
+}
+
+template<class NextLayer>
+void
+teardown(
+ boost::beast::websocket::role_type role,
+ flat_stream<NextLayer>& s,
+ error_code& ec)
+{
+ using boost::beast::websocket::teardown;
+ teardown(role, s.next_layer(), ec);
+}
+
+template<class NextLayer, class TeardownHandler>
+void
+async_teardown(
+ boost::beast::websocket::role_type role,
+ flat_stream<NextLayer>& s,
+ TeardownHandler&& handler)
+{
+ using boost::beast::websocket::async_teardown;
+ async_teardown(role, s.next_layer(), std::move(handler));
+}
+
+} // beast
+} // boost
+
+#endif