summaryrefslogtreecommitdiff
path: root/boost/beast/core/detail/impl/read.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/core/detail/impl/read.hpp')
-rw-r--r--boost/beast/core/detail/impl/read.hpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/boost/beast/core/detail/impl/read.hpp b/boost/beast/core/detail/impl/read.hpp
new file mode 100644
index 0000000000..137384aa40
--- /dev/null
+++ b/boost/beast/core/detail/impl/read.hpp
@@ -0,0 +1,260 @@
+//
+// Copyright (c) 2016-2019 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_DETAIL_IMPL_READ_HPP
+#define BOOST_BEAST_DETAIL_IMPL_READ_HPP
+
+#include <boost/beast/core/bind_handler.hpp>
+#include <boost/beast/core/async_base.hpp>
+#include <boost/beast/core/flat_static_buffer.hpp>
+#include <boost/asio/basic_stream_socket.hpp>
+#include <boost/asio/coroutine.hpp>
+#include <boost/throw_exception.hpp>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+// The number of bytes in the stack buffer when using non-blocking.
+static std::size_t constexpr default_max_stack_buffer = 16384;
+
+//------------------------------------------------------------------------------
+
+struct dynamic_read_ops
+{
+
+// read into a dynamic buffer until the
+// condition is met or an error occurs
+template<
+ class Stream,
+ class DynamicBuffer,
+ class Condition,
+ class Handler>
+class read_op
+ : public net::coroutine
+ , public async_base<
+ Handler, beast::executor_type<Stream>>
+{
+ Stream& s_;
+ DynamicBuffer& b_;
+ Condition cond_;
+ error_code ec_;
+ std::size_t total_ = 0;
+
+public:
+ read_op(read_op&&) = default;
+
+ template<class Handler_, class Condition_>
+ read_op(
+ Handler_&& h,
+ Stream& s,
+ DynamicBuffer& b,
+ Condition_&& cond)
+ : async_base<Handler,
+ beast::executor_type<Stream>>(
+ std::forward<Handler_>(h),
+ s.get_executor())
+ , s_(s)
+ , b_(b)
+ , cond_(std::forward<Condition_>(cond))
+ {
+ (*this)({}, 0, false);
+ }
+
+ void
+ operator()(
+ error_code ec,
+ std::size_t bytes_transferred,
+ bool cont = true)
+ {
+ std::size_t max_size;
+ std::size_t max_prepare;
+ BOOST_ASIO_CORO_REENTER(*this)
+ {
+ for(;;)
+ {
+ max_size = cond_(ec, total_, b_);
+ max_prepare = std::min<std::size_t>(
+ std::max<std::size_t>(
+ 512, b_.capacity() - b_.size()),
+ std::min<std::size_t>(
+ max_size, b_.max_size() - b_.size()));
+ if(max_prepare == 0)
+ break;
+ BOOST_ASIO_CORO_YIELD
+ s_.async_read_some(
+ b_.prepare(max_prepare), std::move(*this));
+ b_.commit(bytes_transferred);
+ total_ += bytes_transferred;
+ }
+ if(! cont)
+ {
+ // run this handler "as-if" using net::post
+ // to reduce template instantiations
+ ec_ = ec;
+ BOOST_ASIO_CORO_YIELD
+ s_.async_read_some(
+ b_.prepare(0), std::move(*this));
+ ec = ec_;
+ }
+ this->complete_now(ec, total_);
+ }
+ }
+};
+
+//------------------------------------------------------------------------------
+
+struct run_read_op
+{
+ template<
+ class AsyncReadStream,
+ class DynamicBuffer,
+ class Condition,
+ class ReadHandler>
+ void
+ operator()(
+ ReadHandler&& h,
+ AsyncReadStream* s,
+ DynamicBuffer* b,
+ Condition&& c)
+ {
+ // If you get an error on the following line it means
+ // that your handler does not meet the documented type
+ // requirements for the handler.
+
+ static_assert(
+ beast::detail::is_invocable<ReadHandler,
+ void(error_code, std::size_t)>::value,
+ "ReadHandler type requirements not met");
+
+ read_op<
+ AsyncReadStream,
+ DynamicBuffer,
+ typename std::decay<Condition>::type,
+ typename std::decay<ReadHandler>::type>(
+ std::forward<ReadHandler>(h),
+ *s,
+ *b,
+ std::forward<Condition>(c));
+ }
+
+};
+
+};
+
+//------------------------------------------------------------------------------
+
+template<
+ class SyncReadStream,
+ class DynamicBuffer,
+ class CompletionCondition,
+ class>
+std::size_t
+read(
+ SyncReadStream& stream,
+ DynamicBuffer& buffer,
+ CompletionCondition cond)
+{
+ static_assert(is_sync_read_stream<SyncReadStream>::value,
+ "SyncReadStream type requirements not met");
+ static_assert(
+ net::is_dynamic_buffer<DynamicBuffer>::value,
+ "DynamicBuffer type requirements not met");
+ static_assert(
+ detail::is_invocable<CompletionCondition,
+ void(error_code&, std::size_t, DynamicBuffer&)>::value,
+ "CompletionCondition type requirements not met");
+ error_code ec;
+ auto const bytes_transferred = detail::read(
+ stream, buffer, std::move(cond), ec);
+ if(ec)
+ BOOST_THROW_EXCEPTION(system_error{ec});
+ return bytes_transferred;
+}
+
+template<
+ class SyncReadStream,
+ class DynamicBuffer,
+ class CompletionCondition,
+ class>
+std::size_t
+read(
+ SyncReadStream& stream,
+ DynamicBuffer& buffer,
+ CompletionCondition cond,
+ error_code& ec)
+{
+ static_assert(is_sync_read_stream<SyncReadStream>::value,
+ "SyncReadStream type requirements not met");
+ static_assert(
+ net::is_dynamic_buffer<DynamicBuffer>::value,
+ "DynamicBuffer type requirements not met");
+ static_assert(
+ detail::is_invocable<CompletionCondition,
+ void(error_code&, std::size_t, DynamicBuffer&)>::value,
+ "CompletionCondition type requirements not met");
+ ec = {};
+ std::size_t total = 0;
+ std::size_t max_size;
+ std::size_t max_prepare;
+ for(;;)
+ {
+ max_size = cond(ec, total, buffer);
+ max_prepare = std::min<std::size_t>(
+ std::max<std::size_t>(
+ 512, buffer.capacity() - buffer.size()),
+ std::min<std::size_t>(
+ max_size, buffer.max_size() - buffer.size()));
+ if(max_prepare == 0)
+ break;
+ std::size_t const bytes_transferred =
+ stream.read_some(buffer.prepare(max_prepare), ec);
+ buffer.commit(bytes_transferred);
+ total += bytes_transferred;
+ }
+ return total;
+}
+
+template<
+ class AsyncReadStream,
+ class DynamicBuffer,
+ class CompletionCondition,
+ class ReadHandler,
+ class>
+BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
+async_read(
+ AsyncReadStream& stream,
+ DynamicBuffer& buffer,
+ CompletionCondition&& cond,
+ ReadHandler&& handler)
+{
+ static_assert(is_async_read_stream<AsyncReadStream>::value,
+ "AsyncReadStream type requirements not met");
+ static_assert(
+ net::is_dynamic_buffer<DynamicBuffer>::value,
+ "DynamicBuffer type requirements not met");
+ static_assert(
+ detail::is_invocable<CompletionCondition,
+ void(error_code&, std::size_t, DynamicBuffer&)>::value,
+ "CompletionCondition type requirements not met");
+ return net::async_initiate<
+ ReadHandler,
+ void(error_code, std::size_t)>(
+ typename dynamic_read_ops::run_read_op{},
+ handler,
+ &stream,
+ &buffer,
+ std::forward<CompletionCondition>(cond));
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif