summaryrefslogtreecommitdiff
path: root/boost/beast/core
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/core')
-rw-r--r--boost/beast/core/async_base.hpp711
-rw-r--r--boost/beast/core/basic_stream.hpp1400
-rw-r--r--boost/beast/core/bind_handler.hpp92
-rw-r--r--boost/beast/core/buffer_traits.hpp164
-rw-r--r--boost/beast/core/buffered_read_stream.hpp117
-rw-r--r--boost/beast/core/buffers_adapter.hpp173
-rw-r--r--boost/beast/core/buffers_adaptor.hpp226
-rw-r--r--boost/beast/core/buffers_cat.hpp58
-rw-r--r--boost/beast/core/buffers_prefix.hpp202
-rw-r--r--boost/beast/core/buffers_range.hpp128
-rw-r--r--boost/beast/core/buffers_suffix.hpp56
-rw-r--r--boost/beast/core/buffers_to_string.hpp18
-rw-r--r--boost/beast/core/detail/allocator.hpp2
-rw-r--r--boost/beast/core/detail/async_base.hpp46
-rw-r--r--boost/beast/core/detail/base64.hpp182
-rw-r--r--boost/beast/core/detail/base64.ipp220
-rw-r--r--boost/beast/core/detail/bind_continuation.hpp110
-rw-r--r--boost/beast/core/detail/bind_default_executor.hpp123
-rw-r--r--boost/beast/core/detail/bind_handler.hpp335
-rw-r--r--boost/beast/core/detail/buffer.hpp6
-rw-r--r--boost/beast/core/detail/buffer_traits.hpp98
-rw-r--r--boost/beast/core/detail/buffers_pair.hpp115
-rw-r--r--boost/beast/core/detail/buffers_range_adaptor.hpp142
-rw-r--r--boost/beast/core/detail/buffers_ref.hpp20
-rw-r--r--boost/beast/core/detail/chacha.hpp188
-rw-r--r--boost/beast/core/detail/clamp.hpp2
-rw-r--r--boost/beast/core/detail/config.hpp50
-rw-r--r--boost/beast/core/detail/flat_stream.hpp73
-rw-r--r--boost/beast/core/detail/get_io_context.hpp107
-rw-r--r--boost/beast/core/detail/impl/read.hpp260
-rw-r--r--boost/beast/core/detail/integer_sequence.hpp143
-rw-r--r--boost/beast/core/detail/is_invocable.hpp58
-rw-r--r--boost/beast/core/detail/ostream.hpp194
-rw-r--r--boost/beast/core/detail/pcg.hpp65
-rw-r--r--boost/beast/core/detail/read.hpp245
-rw-r--r--boost/beast/core/detail/remap_post_to_defer.hpp109
-rw-r--r--boost/beast/core/detail/service_base.hpp43
-rw-r--r--boost/beast/core/detail/sha1.hpp272
-rw-r--r--boost/beast/core/detail/sha1.ipp301
-rw-r--r--boost/beast/core/detail/static_const.hpp49
-rw-r--r--boost/beast/core/detail/static_ostream.hpp2
-rw-r--r--boost/beast/core/detail/static_string.hpp10
-rw-r--r--boost/beast/core/detail/stream_base.hpp107
-rw-r--r--boost/beast/core/detail/stream_traits.hpp111
-rw-r--r--boost/beast/core/detail/tuple.hpp116
-rw-r--r--boost/beast/core/detail/type_traits.hpp380
-rw-r--r--boost/beast/core/detail/variant.hpp280
-rw-r--r--boost/beast/core/detect_ssl.hpp651
-rw-r--r--boost/beast/core/error.hpp32
-rw-r--r--boost/beast/core/file.hpp5
-rw-r--r--boost/beast/core/file_base.hpp119
-rw-r--r--boost/beast/core/file_posix.hpp24
-rw-r--r--boost/beast/core/file_stdio.hpp15
-rw-r--r--boost/beast/core/file_win32.hpp19
-rw-r--r--boost/beast/core/flat_buffer.hpp451
-rw-r--r--boost/beast/core/flat_static_buffer.hpp237
-rw-r--r--boost/beast/core/flat_stream.hpp347
-rw-r--r--boost/beast/core/handler_ptr.hpp47
-rw-r--r--boost/beast/core/impl/async_base.hpp156
-rw-r--r--boost/beast/core/impl/basic_stream.hpp995
-rw-r--r--boost/beast/core/impl/buffered_read_stream.hpp242
-rw-r--r--boost/beast/core/impl/buffered_read_stream.ipp261
-rw-r--r--boost/beast/core/impl/buffers_adaptor.hpp (renamed from boost/beast/core/impl/buffers_adapter.ipp)363
-rw-r--r--boost/beast/core/impl/buffers_cat.hpp443
-rw-r--r--boost/beast/core/impl/buffers_cat.ipp389
-rw-r--r--boost/beast/core/impl/buffers_prefix.hpp326
-rw-r--r--boost/beast/core/impl/buffers_prefix.ipp277
-rw-r--r--boost/beast/core/impl/buffers_suffix.hpp (renamed from boost/beast/core/impl/buffers_suffix.ipp)112
-rw-r--r--boost/beast/core/impl/error.hpp44
-rw-r--r--boost/beast/core/impl/error.ipp99
-rw-r--r--boost/beast/core/impl/file_posix.ipp164
-rw-r--r--boost/beast/core/impl/file_stdio.ipp123
-rw-r--r--boost/beast/core/impl/file_win32.ipp61
-rw-r--r--boost/beast/core/impl/flat_buffer.hpp (renamed from boost/beast/core/impl/flat_buffer.ipp)303
-rw-r--r--boost/beast/core/impl/flat_static_buffer.hpp43
-rw-r--r--boost/beast/core/impl/flat_static_buffer.ipp99
-rw-r--r--boost/beast/core/impl/flat_stream.hpp276
-rw-r--r--boost/beast/core/impl/handler_ptr.hpp (renamed from boost/beast/core/impl/handler_ptr.ipp)57
-rw-r--r--boost/beast/core/impl/multi_buffer.hpp (renamed from boost/beast/core/impl/multi_buffer.ipp)748
-rw-r--r--boost/beast/core/impl/read_size.hpp (renamed from boost/beast/core/impl/read_size.ipp)18
-rw-r--r--boost/beast/core/impl/saved_handler.hpp151
-rw-r--r--boost/beast/core/impl/saved_handler.ipp76
-rw-r--r--boost/beast/core/impl/static_buffer.hpp50
-rw-r--r--boost/beast/core/impl/static_buffer.ipp156
-rw-r--r--boost/beast/core/impl/static_string.hpp (renamed from boost/beast/core/impl/static_string.ipp)36
-rw-r--r--boost/beast/core/impl/string_param.hpp (renamed from boost/beast/core/impl/string_param.ipp)6
-rw-r--r--boost/beast/core/make_printable.hpp107
-rw-r--r--boost/beast/core/multi_buffer.hpp481
-rw-r--r--boost/beast/core/ostream.hpp74
-rw-r--r--boost/beast/core/rate_policy.hpp220
-rw-r--r--boost/beast/core/read_size.hpp5
-rw-r--r--boost/beast/core/role.hpp50
-rw-r--r--boost/beast/core/saved_handler.hpp137
-rw-r--r--boost/beast/core/span.hpp2
-rw-r--r--boost/beast/core/static_buffer.hpp243
-rw-r--r--boost/beast/core/static_string.hpp19
-rw-r--r--boost/beast/core/stream_traits.hpp544
-rw-r--r--boost/beast/core/string.hpp26
-rw-r--r--boost/beast/core/string_param.hpp4
-rw-r--r--boost/beast/core/tcp_stream.hpp34
-rw-r--r--boost/beast/core/type_traits.hpp445
101 files changed, 13555 insertions, 4766 deletions
diff --git a/boost/beast/core/async_base.hpp b/boost/beast/core/async_base.hpp
new file mode 100644
index 0000000000..ee6a7d7a39
--- /dev/null
+++ b/boost/beast/core/async_base.hpp
@@ -0,0 +1,711 @@
+//
+// 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_CORE_ASYNC_BASE_HPP
+#define BOOST_BEAST_CORE_ASYNC_BASE_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/bind_handler.hpp>
+#include <boost/beast/core/detail/allocator.hpp>
+#include <boost/beast/core/detail/async_base.hpp>
+#include <boost/asio/associated_allocator.hpp>
+#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/bind_executor.hpp>
+#include <boost/asio/executor_work_guard.hpp>
+#include <boost/asio/handler_alloc_hook.hpp>
+#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
+#include <boost/asio/post.hpp>
+#include <boost/core/exchange.hpp>
+#include <boost/core/empty_value.hpp>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+/** Base class to assist writing composed operations.
+
+ A function object submitted to intermediate initiating functions during
+ a composed operation may derive from this type to inherit all of the
+ boilerplate to forward the executor, allocator, and legacy customization
+ points associated with the completion handler invoked at the end of the
+ composed operation.
+
+ The composed operation must be typical; that is, associated with one
+ executor of an I/O object, and invoking a caller-provided completion
+ handler when the operation is finished. Classes derived from
+ @ref async_base will acquire these properties:
+
+ @li Ownership of the final completion handler provided upon construction.
+
+ @li If the final handler has an associated allocator, this allocator will
+ be propagated to the composed operation subclass. Otherwise, the
+ associated allocator will be the type specified in the allocator
+ template parameter, or the default of `std::allocator<void>` if the
+ parameter is omitted.
+
+ @li If the final handler has an associated executor, then it will be used
+ as the executor associated with the composed operation. Otherwise,
+ the specified `Executor1` will be the type of executor associated
+ with the composed operation.
+
+ @li An instance of `net::executor_work_guard` for the instance of `Executor1`
+ shall be maintained until either the final handler is invoked, or the
+ operation base is destroyed, whichever comes first.
+
+ @li Calls to the legacy customization points
+ `asio_handler_invoke`,
+ `asio_handler_allocate`,
+ `asio_handler_deallocate`, and
+ `asio_handler_is_continuation`,
+ which use argument-dependent lookup, will be forwarded to the
+ legacy customization points associated with the handler.
+
+ @par Example
+
+ The following code demonstrates how @ref async_base may be be used to
+ assist authoring an asynchronous initiating function, by providing all of
+ the boilerplate to manage the final completion handler in a way that
+ maintains the allocator and executor associations:
+
+ @code
+
+ // Asynchronously read into a buffer until the buffer is full, or an error occurs
+ template<class AsyncReadStream, class ReadHandler>
+ typename net::async_result<ReadHandler, void(error_code, std::size_t)>::return_type
+ async_read(AsyncReadStream& stream, net::mutable_buffer buffer, ReadHandler&& handler)
+ {
+ using handler_type = BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t));
+ using base_type = async_base<handler_type, typename AsyncReadStream::executor_type>;
+
+ struct op : base_type
+ {
+ AsyncReadStream& stream_;
+ net::mutable_buffer buffer_;
+ std::size_t total_bytes_transferred_;
+
+ op(
+ AsyncReadStream& stream,
+ net::mutable_buffer buffer,
+ handler_type& handler)
+ : base_type(std::move(handler), stream.get_executor())
+ , stream_(stream)
+ , buffer_(buffer)
+ , total_bytes_transferred_(0)
+ {
+ (*this)({}, 0, false); // start the operation
+ }
+
+ void operator()(error_code ec, std::size_t bytes_transferred, bool is_continuation = true)
+ {
+ // Adjust the count of bytes and advance our buffer
+ total_bytes_transferred_ += bytes_transferred;
+ buffer_ = buffer_ + bytes_transferred;
+
+ // Keep reading until buffer is full or an error occurs
+ if(! ec && buffer_.size() > 0)
+ return stream_.async_read_some(buffer_, std::move(*this));
+
+ // Call the completion handler with the result. If `is_continuation` is
+ // false, which happens on the first time through this function, then
+ // `net::post` will be used to call the completion handler, otherwise
+ // the completion handler will be invoked directly.
+
+ this->invoke(is_continuation, ec, total_bytes_transferred_);
+ }
+ };
+
+ net::async_completion<ReadHandler, void(error_code, std::size_t)> init{handler};
+ op(stream, buffer, init.completion_handler);
+ return init.result.get();
+ }
+
+ @endcode
+
+ Data members of composed operations implemented as completion handlers
+ do not have stable addresses, as the composed operation object is move
+ constructed upon each call to an initiating function. For most operations
+ this is not a problem. For complex operations requiring stable temporary
+ storage, the class @ref stable_async_base is provided which offers
+ additional functionality:
+
+ @li The free function @ref allocate_stable may be used to allocate
+ one or more temporary objects associated with the composed operation.
+
+ @li Memory for stable temporary objects is allocated using the allocator
+ associated with the composed operation.
+
+ @li Stable temporary objects are automatically destroyed, and the memory
+ freed using the associated allocator, either before the final completion
+ handler is invoked (a Networking requirement) or when the composed operation
+ is destroyed, whichever occurs first.
+
+ @par Temporary Storage Example
+
+ The following example demonstrates how a composed operation may store a
+ temporary object.
+
+ @code
+
+ @endcode
+
+ @tparam Handler The type of the completion handler to store.
+ This type must meet the requirements of <em>CompletionHandler</em>.
+
+ @tparam Executor1 The type of the executor used when the handler has no
+ associated executor. An instance of this type must be provided upon
+ construction. The implementation will maintain an executor work guard
+ and a copy of this instance.
+
+ @tparam Allocator The allocator type to use if the handler does not
+ have an associated allocator. If this parameter is omitted, then
+ `std::allocator<void>` will be used. If the specified allocator is
+ not default constructible, an instance of the type must be provided
+ upon construction.
+
+ @see stable_async_base
+*/
+template<
+ class Handler,
+ class Executor1,
+ class Allocator = std::allocator<void>
+>
+class async_base
+#if ! BOOST_BEAST_DOXYGEN
+ : private boost::empty_value<Allocator>
+#endif
+{
+ static_assert(
+ net::is_executor<Executor1>::value,
+ "Executor type requirements not met");
+
+ Handler h_;
+ net::executor_work_guard<Executor1> wg1_;
+
+ virtual
+ void
+ before_invoke_hook()
+ {
+ }
+
+public:
+ /** Constructor
+
+ @param handler The final completion handler.
+ The type of this object must meet the requirements of <em>CompletionHandler</em>.
+ The implementation takes ownership of the handler by performing a decay-copy.
+
+ @param ex1 The executor associated with the implied I/O object
+ target of the operation. The implementation shall maintain an
+ executor work guard for the lifetime of the operation, or until
+ the final completion handler is invoked, whichever is shorter.
+
+ @param alloc The allocator to be associated with objects
+ derived from this class. If `Allocator` is default-constructible,
+ this parameter is optional and may be omitted.
+ */
+#if BOOST_BEAST_DOXYGEN
+ template<class Handler_>
+ async_base(
+ Handler&& handler,
+ Executor1 const& ex1,
+ Allocator const& alloc = Allocator());
+#else
+ template<
+ class Handler_,
+ class = typename std::enable_if<
+ ! std::is_same<typename
+ std::decay<Handler_>::type,
+ async_base
+ >::value>::type
+ >
+ async_base(
+ Handler_&& handler,
+ Executor1 const& ex1)
+ : h_(std::forward<Handler_>(handler))
+ , wg1_(ex1)
+ {
+ }
+
+ template<class Handler_>
+ async_base(
+ Handler_&& handler,
+ Executor1 const& ex1,
+ Allocator const& alloc)
+ : boost::empty_value<Allocator>(
+ boost::empty_init_t{}, alloc)
+ , h_(std::forward<Handler_>(handler))
+ , wg1_(ex1)
+ {
+ }
+#endif
+
+ /// Move Constructor
+ async_base(async_base&& other) = default;
+
+ /** The type of allocator associated with this object.
+
+ If a class derived from @ref async_base is a completion
+ handler, then the associated allocator of the derived class will
+ be this type.
+ */
+ using allocator_type =
+ net::associated_allocator_t<Handler, Allocator>;
+
+ /** The type of executor associated with this object.
+
+ If a class derived from @ref async_base is a completion
+ handler, then the associated executor of the derived class will
+ be this type.
+ */
+ using executor_type =
+ net::associated_executor_t<Handler, Executor1>;
+
+ /** Returns the allocator associated with this object.
+
+ If a class derived from @ref async_base is a completion
+ handler, then the object returned from this function will be used
+ as the associated allocator of the derived class.
+ */
+ allocator_type
+ get_allocator() const noexcept
+ {
+ return net::get_associated_allocator(h_,
+ boost::empty_value<Allocator>::get());
+ }
+
+ /** Returns the executor associated with this object.
+
+ If a class derived from @ref async_base is a completion
+ handler, then the object returned from this function will be used
+ as the associated executor of the derived class.
+ */
+ executor_type
+ get_executor() const noexcept
+ {
+ return net::get_associated_executor(
+ h_, wg1_.get_executor());
+ }
+
+ /// Returns the handler associated with this object
+ Handler const&
+ handler() const noexcept
+ {
+ return h_;
+ }
+
+ /** Returns ownership of the handler associated with this object
+
+ This function is used to transfer ownership of the handler to
+ the caller, by move-construction. After the move, the only
+ valid operations on the base object are move construction and
+ destruction.
+ */
+ Handler
+ release_handler()
+ {
+ return std::move(h_);
+ }
+
+ /** Invoke the final completion handler, maybe using post.
+
+ This invokes the final completion handler with the specified
+ arguments forwarded. It is undefined to call either of
+ @ref complete or @ref complete_now more than once.
+
+ Any temporary objects allocated with @ref beast::allocate_stable will
+ be automatically destroyed before the final completion handler
+ is invoked.
+
+ @param is_continuation If this value is `false`, then the
+ handler will be submitted to the executor using `net::post`.
+ Otherwise the handler will be invoked as if by calling
+ @ref complete_now.
+
+ @param args A list of optional parameters to invoke the handler
+ with. The completion handler must be invocable with the parameter
+ list, or else a compilation error will result.
+ */
+ template<class... Args>
+ void
+ complete(bool is_continuation, Args&&... args)
+ {
+ this->before_invoke_hook();
+ if(! is_continuation)
+ {
+ auto const ex = get_executor();
+ net::post(net::bind_executor(
+ ex,
+ beast::bind_front_handler(
+ std::move(h_),
+ std::forward<Args>(args)...)));
+ wg1_.reset();
+ }
+ else
+ {
+ wg1_.reset();
+ h_(std::forward<Args>(args)...);
+ }
+ }
+
+ /** Invoke the final completion handler.
+
+ This invokes the final completion handler with the specified
+ arguments forwarded. It is undefined to call either of
+ @ref complete or @ref complete_now more than once.
+
+ Any temporary objects allocated with @ref beast::allocate_stable will
+ be automatically destroyed before the final completion handler
+ is invoked.
+
+ @param args A list of optional parameters to invoke the handler
+ with. The completion handler must be invocable with the parameter
+ list, or else a compilation error will result.
+ */
+ template<class... Args>
+ void
+ complete_now(Args&&... args)
+ {
+ this->before_invoke_hook();
+ wg1_.reset();
+ h_(std::forward<Args>(args)...);
+ }
+
+#if ! BOOST_BEAST_DOXYGEN
+ Handler*
+ get_legacy_handler_pointer() noexcept
+ {
+ return std::addressof(h_);
+ }
+#endif
+};
+
+//------------------------------------------------------------------------------
+
+/** Base class to provide completion handler boilerplate for composed operations.
+
+ A function object submitted to intermediate initiating functions during
+ a composed operation may derive from this type to inherit all of the
+ boilerplate to forward the executor, allocator, and legacy customization
+ points associated with the completion handler invoked at the end of the
+ composed operation.
+
+ The composed operation must be typical; that is, associated with one
+ executor of an I/O object, and invoking a caller-provided completion
+ handler when the operation is finished. Classes derived from
+ @ref async_base will acquire these properties:
+
+ @li Ownership of the final completion handler provided upon construction.
+
+ @li If the final handler has an associated allocator, this allocator will
+ be propagated to the composed operation subclass. Otherwise, the
+ associated allocator will be the type specified in the allocator
+ template parameter, or the default of `std::allocator<void>` if the
+ parameter is omitted.
+
+ @li If the final handler has an associated executor, then it will be used
+ as the executor associated with the composed operation. Otherwise,
+ the specified `Executor1` will be the type of executor associated
+ with the composed operation.
+
+ @li An instance of `net::executor_work_guard` for the instance of `Executor1`
+ shall be maintained until either the final handler is invoked, or the
+ operation base is destroyed, whichever comes first.
+
+ @li Calls to the legacy customization points
+ `asio_handler_invoke`,
+ `asio_handler_allocate`,
+ `asio_handler_deallocate`, and
+ `asio_handler_is_continuation`,
+ which use argument-dependent lookup, will be forwarded to the
+ legacy customization points associated with the handler.
+
+ Data members of composed operations implemented as completion handlers
+ do not have stable addresses, as the composed operation object is move
+ constructed upon each call to an initiating function. For most operations
+ this is not a problem. For complex operations requiring stable temporary
+ storage, the class @ref stable_async_base is provided which offers
+ additional functionality:
+
+ @li The free function @ref beast::allocate_stable may be used to allocate
+ one or more temporary objects associated with the composed operation.
+
+ @li Memory for stable temporary objects is allocated using the allocator
+ associated with the composed operation.
+
+ @li Stable temporary objects are automatically destroyed, and the memory
+ freed using the associated allocator, either before the final completion
+ handler is invoked (a Networking requirement) or when the composed operation
+ is destroyed, whichever occurs first.
+
+ @par Example
+
+ The following code demonstrates how @ref stable_async_base may be be used to
+ assist authoring an asynchronous initiating function, by providing all of
+ the boilerplate to manage the final completion handler in a way that maintains
+ the allocator and executor associations. Furthermore, the operation shown
+ allocates temporary memory using @ref beast::allocate_stable for the timer and
+ message, whose addresses must not change between intermediate operations:
+
+ @code
+
+ // Asynchronously send a message multiple times, once per second
+ template <class AsyncWriteStream, class T, class WriteHandler>
+ auto async_write_messages(
+ AsyncWriteStream& stream,
+ T const& message,
+ std::size_t repeat_count,
+ WriteHandler&& handler) ->
+ typename net::async_result<
+ typename std::decay<WriteHandler>::type,
+ void(error_code)>::return_type
+ {
+ using handler_type = typename net::async_completion<WriteHandler, void(error_code)>::completion_handler_type;
+ using base_type = stable_async_base<handler_type, typename AsyncWriteStream::executor_type>;
+
+ struct op : base_type, boost::asio::coroutine
+ {
+ // This object must have a stable address
+ struct temporary_data
+ {
+ // Although std::string is in theory movable, most implementations
+ // use a "small buffer optimization" which means that we might
+ // be submitting a buffer to the write operation and then
+ // moving the string, invalidating the buffer. To prevent
+ // undefined behavior we store the string object itself at
+ // a stable location.
+ std::string const message;
+
+ net::steady_timer timer;
+
+ temporary_data(std::string message_, net::io_context& ctx)
+ : message(std::move(message_))
+ , timer(ctx)
+ {
+ }
+ };
+
+ AsyncWriteStream& stream_;
+ std::size_t repeats_;
+ temporary_data& data_;
+
+ op(AsyncWriteStream& stream, std::size_t repeats, std::string message, handler_type& handler)
+ : base_type(std::move(handler), stream.get_executor())
+ , stream_(stream)
+ , repeats_(repeats)
+ , data_(allocate_stable<temporary_data>(*this, std::move(message), stream.get_executor().context()))
+ {
+ (*this)(); // start the operation
+ }
+
+ // Including this file provides the keywords for macro-based coroutines
+ #include <boost/asio/yield.hpp>
+
+ void operator()(error_code ec = {}, std::size_t = 0)
+ {
+ reenter(*this)
+ {
+ // If repeats starts at 0 then we must complete immediately. But
+ // we can't call the final handler from inside the initiating
+ // function, so we post our intermediate handler first. We use
+ // net::async_write with an empty buffer instead of calling
+ // net::post to avoid an extra function template instantiation, to
+ // keep compile times lower and make the resulting executable smaller.
+ yield net::async_write(stream_, net::const_buffer{}, std::move(*this));
+ while(! ec && repeats_-- > 0)
+ {
+ // Send the string. We construct a `const_buffer` here to guarantee
+ // that we do not create an additional function template instantation
+ // of net::async_write, since we already instantiated it above for
+ // net::const_buffer.
+
+ yield net::async_write(stream_,
+ net::const_buffer(net::buffer(data_.message)), std::move(*this));
+ if(ec)
+ break;
+
+ // Set the timer and wait
+ data_.timer.expires_after(std::chrono::seconds(1));
+ yield data_.timer.async_wait(std::move(*this));
+ }
+ }
+
+ // The base class destroys the temporary data automatically,
+ // before invoking the final completion handler
+ this->complete_now(ec);
+ }
+
+ // Including this file undefines the macros for the coroutines
+ #include <boost/asio/unyield.hpp>
+ };
+
+ net::async_completion<WriteHandler, void(error_code)> completion(handler);
+ std::ostringstream os;
+ os << message;
+ op(stream, repeat_count, os.str(), completion.completion_handler);
+ return completion.result.get();
+ }
+
+ @endcode
+
+ @tparam Handler The type of the completion handler to store.
+ This type must meet the requirements of <em>CompletionHandler</em>.
+
+ @tparam Executor1 The type of the executor used when the handler has no
+ associated executor. An instance of this type must be provided upon
+ construction. The implementation will maintain an executor work guard
+ and a copy of this instance.
+
+ @tparam Allocator The allocator type to use if the handler does not
+ have an associated allocator. If this parameter is omitted, then
+ `std::allocator<void>` will be used. If the specified allocator is
+ not default constructible, an instance of the type must be provided
+ upon construction.
+
+ @see allocate_stable, async_base
+*/
+template<
+ class Handler,
+ class Executor1,
+ class Allocator = std::allocator<void>
+>
+class stable_async_base
+ : public async_base<
+ Handler, Executor1, Allocator>
+{
+ detail::stable_base* list_ = nullptr;
+
+ void
+ before_invoke_hook() override
+ {
+ detail::stable_base::destroy_list(list_);
+ }
+
+public:
+ /** Constructor
+
+ @param handler The final completion handler.
+ The type of this object must meet the requirements of <em>CompletionHandler</em>.
+ The implementation takes ownership of the handler by performing a decay-copy.
+
+ @param ex1 The executor associated with the implied I/O object
+ target of the operation. The implementation shall maintain an
+ executor work guard for the lifetime of the operation, or until
+ the final completion handler is invoked, whichever is shorter.
+
+ @param alloc The allocator to be associated with objects
+ derived from this class. If `Allocator` is default-constructible,
+ this parameter is optional and may be omitted.
+ */
+#if BOOST_BEAST_DOXYGEN
+ template<class Handler>
+ stable_async_base(
+ Handler&& handler,
+ Executor1 const& ex1,
+ Allocator const& alloc = Allocator());
+#else
+ template<
+ class Handler_,
+ class = typename std::enable_if<
+ ! std::is_same<typename
+ std::decay<Handler_>::type,
+ stable_async_base
+ >::value>::type
+ >
+ stable_async_base(
+ Handler_&& handler,
+ Executor1 const& ex1)
+ : async_base<
+ Handler, Executor1, Allocator>(
+ std::forward<Handler_>(handler), ex1)
+ {
+ }
+
+ template<class Handler_>
+ stable_async_base(
+ Handler_&& handler,
+ Executor1 const& ex1,
+ Allocator const& alloc)
+ : async_base<
+ Handler, Executor1, Allocator>(
+ std::forward<Handler_>(handler), ex1, alloc)
+ {
+ }
+#endif
+
+ /// Move Constructor
+ stable_async_base(stable_async_base&& other)
+ : async_base<Handler, Executor1, Allocator>(
+ std::move(other))
+ , list_(boost::exchange(other.list_, nullptr))
+ {
+ }
+
+ /** Destructor
+
+ If the completion handler was not invoked, then any
+ state objects allocated with @ref allocate_stable will
+ be destroyed here.
+ */
+ ~stable_async_base()
+ {
+ detail::stable_base::destroy_list(list_);
+ }
+
+ /** Allocate a temporary object to hold operation state.
+
+ The object will be destroyed just before the completion
+ handler is invoked, or when the operation base is destroyed.
+ */
+ template<
+ class State,
+ class Handler_,
+ class Executor1_,
+ class Allocator_,
+ class... Args>
+ friend
+ State&
+ allocate_stable(
+ stable_async_base<
+ Handler_, Executor1_, Allocator_>& base,
+ Args&&... args);
+};
+
+/** Allocate a temporary object to hold stable asynchronous operation state.
+
+ The object will be destroyed just before the completion
+ handler is invoked, or when the base is destroyed.
+
+ @tparam State The type of object to allocate.
+
+ @param base The helper to allocate from.
+
+ @param args An optional list of parameters to forward to the
+ constructor of the object being allocated.
+
+ @see stable_async_base
+*/
+template<
+ class State,
+ class Handler,
+ class Executor1,
+ class Allocator,
+ class... Args>
+State&
+allocate_stable(
+ stable_async_base<
+ Handler, Executor1, Allocator>& base,
+ Args&&... args);
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/async_base.hpp>
+
+#endif
diff --git a/boost/beast/core/basic_stream.hpp b/boost/beast/core/basic_stream.hpp
new file mode 100644
index 0000000000..057ab07ffd
--- /dev/null
+++ b/boost/beast/core/basic_stream.hpp
@@ -0,0 +1,1400 @@
+//
+// 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_CORE_BASIC_STREAM_HPP
+#define BOOST_BEAST_CORE_BASIC_STREAM_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/stream_base.hpp>
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/rate_policy.hpp>
+#include <boost/beast/core/role.hpp>
+#include <boost/beast/core/stream_traits.hpp>
+#include <boost/asio/async_result.hpp>
+#include <boost/asio/basic_stream_socket.hpp>
+#include <boost/asio/connect.hpp>
+#include <boost/asio/executor.hpp>
+#include <boost/asio/is_executor.hpp>
+#include <boost/core/empty_value.hpp>
+#include <boost/config/workaround.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/shared_ptr.hpp>
+#include <chrono>
+#include <limits>
+#include <memory>
+
+#if ! BOOST_BEAST_DOXYGEN
+namespace boost {
+namespace asio {
+namespace ssl {
+template<typename> class stream;
+} // ssl
+} // asio
+} // boost
+#endif
+
+namespace boost {
+namespace beast {
+
+/** A stream socket wrapper with timeouts, an executor, and a rate limit policy.
+
+ This stream wraps a `net::basic_stream_socket` to provide
+ the following features:
+
+ @li An <em>Executor</em> may be associated with the stream, which will
+ be used to invoke any completion handlers which do not already have
+ an associated executor. This achieves support for
+ <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">[P1322R0] Networking TS enhancement to enable custom I/O executors</a>.
+
+ @li Timeouts may be specified for each logical asynchronous operation
+ performing any reading, writing, or connecting.
+
+ @li A <em>RatePolicy</em> may be associated with the stream, to implement
+ rate limiting through the policy's interface.
+
+ Although the stream supports multiple concurrent outstanding asynchronous
+ operations, the stream object is not thread-safe. The caller is responsible
+ for ensuring that the stream is accessed from only one thread at a time.
+ This includes the times when the stream, and its underlying socket, are
+ accessed by the networking implementation. To meet this thread safety
+ requirement, all asynchronous operations must be performed by the stream
+ within the same implicit strand (only one thread `net::io_context::run`)
+ or within the same explicit strand, such as an instance of `net::strand`.
+
+ Completion handlers with explicit associated executors (such as those
+ arising from use of `net::bind_executor`) will be invoked by the stream
+ using the associated executor. Otherwise, the completion handler will
+ be invoked by the executor associated with the stream upon construction.
+ The type of executor used with this stream must meet the following
+ requirements:
+
+ @li Function objects submitted to the executor shall never run
+ concurrently with each other.
+
+ The executor type `net::strand` meets these requirements. Use of a
+ strand as the executor in the stream class template offers an additional
+ notational convenience: the strand does not need to be specified in
+ each individual initiating function call.
+
+ Unlike other stream wrappers, the underlying socket is accessed
+ through the @ref socket member function instead of `next_layer`.
+ This causes the @ref basic_stream to be returned in calls
+ to @ref get_lowest_layer.
+
+ @par Usage
+
+ To use this stream declare an instance of the class. Then, before
+ each logical operation for which a timeout is desired, call
+ @ref expires_after with a duration, or call @ref expires_at with a
+ time point. Alternatively, call @ref expires_never to disable the
+ timeout for subsequent logical operations. A logical operation
+ is any series of one or more direct or indirect calls to the timeout
+ stream's asynchronous read, asynchronous write, or asynchronous connect
+ functions.
+
+ When a timeout is set and a mixed operation is performed (one that
+ includes both reads and writes, for example) the timeout applies
+ to all of the intermediate asynchronous operations used in the
+ enclosing operation. This allows timeouts to be applied to stream
+ algorithms which were not written specifically to allow for timeouts,
+ when those algorithms are passed a timeout stream with a timeout set.
+
+ When a timeout occurs the socket will be closed, canceling any
+ pending I/O operations. The completion handlers for these canceled
+ operations will be invoked with the error @ref beast::error::timeout.
+
+ @par Examples
+
+ This function reads an HTTP request with a timeout, then sends the
+ HTTP response with a different timeout.
+
+ @code
+ void process_http_1 (tcp_stream& stream, net::yield_context yield)
+ {
+ flat_buffer buffer;
+ http::request<http::empty_body> req;
+
+ // Read the request, with a 15 second timeout
+ stream.expires_after(std::chrono::seconds(15));
+ http::async_read(stream, buffer, req, yield);
+
+ // Calculate the response
+ http::response<http::string_body> res = make_response(req);
+
+ // Send the response, with a 30 second timeout.
+ stream.expires_after (std::chrono::seconds(30));
+ http::async_write (stream, res, yield);
+ }
+ @endcode
+
+ The example above could be expressed using a single timeout with a
+ simple modification. The function that follows first reads an HTTP
+ request then sends the HTTP response, with a single timeout that
+ applies to the entire combined operation of reading and writing:
+
+ @code
+ void process_http_2 (tcp_stream& stream, net::yield_context yield)
+ {
+ flat_buffer buffer;
+ http::request<http::empty_body> req;
+
+ // Require that the read and write combined take no longer than 30 seconds
+ stream.expires_after(std::chrono::seconds(30));
+
+ http::async_read(stream, buffer, req, yield);
+
+ http::response<http::string_body> res = make_response(req);
+ http::async_write (stream, res, yield);
+ }
+ @endcode
+
+ Some stream algorithms, such as `ssl::stream::async_handshake` perform
+ both reads and writes. A timeout set before calling the initiating function
+ of such composite stream algorithms will apply to the entire composite
+ operation. For example, a timeout may be set on performing the SSL handshake
+ thusly:
+
+ @code
+ void do_ssl_handshake (net::ssl::stream<tcp_stream>& stream, net::yield_context yield)
+ {
+ // Require that the SSL handshake take no longer than 10 seconds
+ stream.expires_after(std::chrono::seconds(10));
+
+ stream.async_handshake(net::ssl::stream_base::client, yield);
+ }
+ @endcode
+
+ @par Blocking I/O
+
+ Synchronous functions behave identically as that of the wrapped
+ `net::basic_stream_socket`. Timeouts are not available when performing
+ blocking calls.
+
+ @tparam Protocol A type meeting the requirements of <em>Protocol</em>
+ representing the protocol the protocol to use for the basic stream socket.
+ A common choice is `net::ip::tcp`.
+
+ @tparam Executor A type meeting the requirements of <em>Executor</em> to
+ be used for submitting all completion handlers which do not already have an
+ associated executor. If this type is omitted, the default of `net::executor`
+ will be used.
+
+ @par Thread Safety
+ <em>Distinct objects</em>: Safe.@n
+ <em>Shared objects</em>: Unsafe. The application must also ensure
+ that all asynchronous operations are performed within the same
+ implicit or explicit strand.
+
+ @see
+
+ @li <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">[P1322R0] Networking TS enhancement to enable custom I/O executors</a>.
+*/
+template<
+ class Protocol,
+ class Executor = net::executor,
+ class RatePolicy = unlimited_rate_policy
+>
+class basic_stream
+#if ! BOOST_BEAST_DOXYGEN
+ : private detail::stream_base
+#endif
+{
+public:
+ /// The type of the underlying socket.
+ using socket_type =
+ net::basic_stream_socket<Protocol, Executor>;
+
+ /** The type of the executor associated with the stream.
+
+ This will be the type of executor used to invoke completion
+ handlers which do not have an explicit associated executor.
+ */
+ using executor_type = beast::executor_type<socket_type>;
+
+ /// The protocol type.
+ using protocol_type = Protocol;
+
+ /// The endpoint type.
+ using endpoint_type = typename Protocol::endpoint;
+
+private:
+ static_assert(net::is_executor<Executor>::value,
+ "Executor type requirements not met");
+
+ struct impl_type
+ : boost::enable_shared_from_this<impl_type>
+ , boost::empty_value<RatePolicy>
+ {
+ // must come first
+ net::basic_stream_socket<
+ Protocol, Executor> socket;
+
+ op_state read;
+ op_state write;
+ net::steady_timer timer; // rate timer
+ int waiting = 0;
+
+ impl_type(impl_type&&) = default;
+
+ template<class... Args>
+ explicit
+ impl_type(std::false_type, Args&&...);
+
+ template<class RatePolicy_, class... Args>
+ explicit
+ impl_type(std::true_type,
+ RatePolicy_&& policy, Args&&...);
+
+ impl_type& operator=(impl_type&&) = delete;
+
+ beast::executor_type<socket_type>
+ ex() noexcept
+ {
+ return this->socket.get_executor();
+ }
+
+ RatePolicy&
+ policy() noexcept
+ {
+ return this->boost::empty_value<RatePolicy>::get();
+ }
+
+ RatePolicy const&
+ policy() const noexcept
+ {
+ return this->boost::empty_value<RatePolicy>::get();
+ }
+
+ template<class Executor2>
+ void on_timer(Executor2 const& ex2);
+
+ void reset(); // set timeouts to never
+ void close(); // cancel everything
+ };
+
+ // We use shared ownership for the state so it can
+ // outlive the destruction of the stream_socket object,
+ // in the case where there is no outstanding read or write
+ // but the implementation is still waiting on a timer.
+ boost::shared_ptr<impl_type> impl_;
+
+ struct timeout_handler;
+
+ struct ops;
+
+#if ! BOOST_BEAST_DOXYGEN
+ // boost::asio::ssl::stream needs these
+ // DEPRECATED
+ template<class>
+ friend class boost::asio::ssl::stream;
+ // DEPRECATED
+ using lowest_layer_type = socket_type;
+ // DEPRECATED
+ lowest_layer_type&
+ lowest_layer() noexcept
+ {
+ return impl_->socket;
+ }
+ // DEPRECATED
+ lowest_layer_type const&
+ lowest_layer() const noexcept
+ {
+ return impl_->socket;
+ }
+#endif
+
+public:
+ /** Destructor
+
+ This function destroys the stream, cancelling any outstanding
+ asynchronous operations associated with the socket as if by
+ calling cancel.
+ */
+ ~basic_stream();
+
+ /** Constructor
+
+ This constructor creates the stream by forwarding all arguments
+ to the underlying socket. The socket then needs to be open and
+ connected or accepted before data can be sent or received on it.
+
+ @param args A list of parameters forwarded to the constructor of
+ the underlying socket.
+ */
+#if BOOST_BEAST_DOXYGEN
+ template<class... Args>
+ explicit
+ basic_stream(Args&&... args);
+#else
+ template<class Arg0, class... Args,
+ class = typename std::enable_if<
+ ! std::is_constructible<RatePolicy, Arg0>::value>::type>
+ explicit
+ basic_stream(Arg0&& argo, Args&&... args);
+#endif
+
+ /** Constructor
+
+ This constructor creates the stream with the specified rate
+ policy, and forwards all remaining arguments to the underlying
+ socket. The socket then needs to be open and connected or
+ accepted before data can be sent or received on it.
+
+ @param policy The rate policy object to use. The stream will
+ take ownership of this object by decay-copy.
+
+ @param args A list of parameters forwarded to the constructor of
+ the underlying socket.
+ */
+#if BOOST_BEAST_DOXYGEN
+ template<class RatePolicy_, class... Args>
+ explicit
+ basic_stream(RatePolicy_&& policy, Args&&... args);
+#else
+ template<class RatePolicy_, class Arg0, class... Args,
+ class = typename std::enable_if<
+ std::is_constructible<
+ RatePolicy, RatePolicy_>::value>::type>
+ basic_stream(
+ RatePolicy_&& policy, Arg0&& arg, Args&&... args);
+#endif
+
+ /** Move constructor
+
+ @param other The other object from which the move will occur.
+
+ @note Following the move, the moved-from object is in the
+ same state as if newly constructed.
+ */
+ basic_stream(basic_stream&& other);
+
+ /// Move assignment (deleted).
+ basic_stream& operator=(basic_stream&&) = delete;
+
+ /// Return a reference to the underlying socket
+ socket_type&
+ socket() noexcept
+ {
+ return impl_->socket;
+ }
+
+ /// Return a reference to the underlying socket
+ socket_type const&
+ socket() const noexcept
+ {
+ return impl_->socket;
+ }
+
+ /** Release ownership of the underlying socket.
+
+ This function causes all outstanding asynchronous connect,
+ read, and write operations to be canceled as if by a call
+ to @ref cancel. Ownership of the underlying socket is then
+ transferred to the caller.
+ */
+ socket_type
+ release_socket();
+
+ //--------------------------------------------------------------------------
+
+ /// Returns the rate policy associated with the object
+ RatePolicy&
+ rate_policy() noexcept
+ {
+ return impl_->policy();
+ }
+
+ /// Returns the rate policy associated with the object
+ RatePolicy const&
+ rate_policy() const noexcept
+ {
+ return impl_->policy();
+ }
+
+ /** Set the timeout for the next logical operation.
+
+ This sets either the read timer, the write timer, or
+ both timers to expire after the specified amount of time
+ has elapsed. If a timer expires when the corresponding
+ asynchronous operation is outstanding, the stream will be
+ closed and any outstanding operations will complete with the
+ error @ref beast::error::timeout. Otherwise, if the timer
+ expires while no operations are outstanding, and the expiraton
+ is not set again, the next operation will time out immediately.
+
+ The timer applies collectively to any asynchronous reads
+ or writes initiated after the expiration is set, until the
+ expiration is set again. A call to @ref async_connect
+ counts as both a read and a write.
+
+ @param expiry_time The amount of time after which a logical
+ operation should be considered timed out.
+ */
+ void
+ expires_after(
+ std::chrono::nanoseconds expiry_time);
+
+ /** Set the timeout for the next logical operation.
+
+ This sets either the read timer, the write timer, or both
+ timers to expire at the specified time point. If a timer
+ expires when the corresponding asynchronous operation is
+ outstanding, the stream will be closed and any outstanding
+ operations will complete with the error @ref beast::error::timeout.
+ Otherwise, if the timer expires while no operations are outstanding,
+ and the expiraton is not set again, the next operation will time out
+ immediately.
+
+ The timer applies collectively to any asynchronous reads
+ or writes initiated after the expiration is set, until the
+ expiration is set again. A call to @ref async_connect
+ counts as both a read and a write.
+
+ @param expiry_time The time point after which a logical
+ operation should be considered timed out.
+ */
+ void
+ expires_at(net::steady_timer::time_point expiry_time);
+
+ /// Disable the timeout for the next logical operation.
+ void
+ expires_never();
+
+ /** Cancel all asynchronous operations associated with the socket.
+
+ This function causes all outstanding asynchronous connect,
+ read, and write operations to finish immediately. Completion
+ handlers for cancelled operations will receive the error
+ `net::error::operation_aborted`. Completion handlers not
+ yet invoked whose operations have completed, will receive
+ the error corresponding to the result of the operation (which
+ may indicate success).
+ */
+ void
+ cancel();
+
+ /** Close the timed stream.
+
+ This cancels all of the outstanding asynchronous operations
+ as if by calling @ref cancel, and closes the underlying socket.
+ */
+ void
+ close();
+
+ //--------------------------------------------------------------------------
+
+ /** Get the executor associated with the object.
+
+ This function may be used to obtain the executor object that the
+ stream uses to dispatch completion handlers without an assocaited
+ executor.
+
+ @return A copy of the executor that stream will use to dispatch handlers.
+ */
+ executor_type
+ get_executor() const noexcept
+ {
+ return impl_->ex();
+ }
+
+ /** Connect the stream to the specified endpoint.
+
+ This function is used to connect the underlying socket to the
+ specified remote endpoint. The function call will block until
+ the connection is successfully made or an error occurs.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ @param ep The remote endpoint to connect to.
+
+ @throws system_error Thrown on failure.
+
+ @see connect
+ */
+ void
+ connect(endpoint_type const& ep)
+ {
+ socket().connect(ep);
+ }
+
+ /** Connect the stream to the specified endpoint.
+
+ This function is used to connect the underlying socket to the
+ specified remote endpoint. The function call will block until
+ the connection is successfully made or an error occurs.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ @param ep The remote endpoint to connect to.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @see connect
+ */
+ void
+ connect(endpoint_type const& ep, error_code& ec)
+ {
+ socket().connect(ep, ec);
+ }
+
+ /** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed operation</em>, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param endpoints A sequence of endpoints.
+
+ @returns The successfully connected endpoint.
+
+ @throws system_error Thrown on failure. If the sequence is
+ empty, the associated error code is `net::error::not_found`.
+ Otherwise, contains the error from the last connection attempt.
+ */
+ template<class EndpointSequence
+ #if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+ #endif
+ >
+ typename Protocol::endpoint
+ connect(EndpointSequence const& endpoints)
+ {
+ return net::connect(socket(), endpoints);
+ }
+
+ /** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed operation</em>, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param endpoints A sequence of endpoints.
+
+ @param ec Set to indicate what error occurred, if any. If the sequence is
+ empty, set to `net::error::not_found`. Otherwise, contains the error
+ from the last connection attempt.
+
+ @returns On success, the successfully connected endpoint. Otherwise, a
+ default-constructed endpoint.
+ */
+ template<class EndpointSequence
+ #if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+ #endif
+ >
+ typename Protocol::endpoint
+ connect(
+ EndpointSequence const& endpoints,
+ error_code& ec
+ )
+ {
+ return net::connect(socket(), endpoints, ec);
+ }
+
+ /** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed operation</em>, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param begin An iterator pointing to the start of a sequence of endpoints.
+
+ @param end An iterator pointing to the end of a sequence of endpoints.
+
+ @returns An iterator denoting the successfully connected endpoint.
+
+ @throws system_error Thrown on failure. If the sequence is
+ empty, the associated error code is `net::error::not_found`.
+ Otherwise, contains the error from the last connection attempt.
+ */
+ template<class Iterator>
+ Iterator
+ connect(
+ Iterator begin, Iterator end)
+ {
+ return net::connect(socket(), begin, end);
+ }
+
+ /** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed operation</em>, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param begin An iterator pointing to the start of a sequence of endpoints.
+
+ @param end An iterator pointing to the end of a sequence of endpoints.
+
+ @param ec Set to indicate what error occurred, if any. If the sequence is
+ empty, set to boost::asio::error::not_found. Otherwise, contains the error
+ from the last connection attempt.
+
+ @returns On success, an iterator denoting the successfully connected
+ endpoint. Otherwise, the end iterator.
+ */
+ template<class Iterator>
+ Iterator
+ connect(
+ Iterator begin, Iterator end,
+ error_code& ec)
+ {
+ return net::connect(socket(), begin, end, ec);
+ }
+
+ /** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed operation</em>, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param endpoints A sequence of endpoints.
+
+ @param connect_condition A function object that is called prior to each
+ connection attempt. The signature of the function object must be:
+ @code
+ bool connect_condition(
+ error_code const& ec,
+ typename Protocol::endpoint const& next);
+ @endcode
+ The @c ec parameter contains the result from the most recent connect
+ operation. Before the first connection attempt, @c ec is always set to
+ indicate success. The @c next parameter is the next endpoint to be tried.
+ The function object should return true if the next endpoint should be tried,
+ and false if it should be skipped.
+
+ @returns The successfully connected endpoint.
+
+ @throws boost::system::system_error Thrown on failure. If the sequence is
+ empty, the associated error code is `net::error::not_found`.
+ Otherwise, contains the error from the last connection attempt.
+ */
+ template<
+ class EndpointSequence, class ConnectCondition
+ #if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+ #endif
+ >
+ typename Protocol::endpoint
+ connect(
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition
+ )
+ {
+ return net::connect(socket(), endpoints, connect_condition);
+ }
+
+ /** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed operation</em>, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param endpoints A sequence of endpoints.
+
+ @param connect_condition A function object that is called prior to each
+ connection attempt. The signature of the function object must be:
+ @code
+ bool connect_condition(
+ error_code const& ec,
+ typename Protocol::endpoint const& next);
+ @endcode
+ The @c ec parameter contains the result from the most recent connect
+ operation. Before the first connection attempt, @c ec is always set to
+ indicate success. The @c next parameter is the next endpoint to be tried.
+ The function object should return true if the next endpoint should be tried,
+ and false if it should be skipped.
+
+ @param ec Set to indicate what error occurred, if any. If the sequence is
+ empty, set to `net::error::not_found`. Otherwise, contains the error
+ from the last connection attempt.
+
+ @returns On success, the successfully connected endpoint. Otherwise, a
+ default-constructed endpoint.
+ */
+ template<
+ class EndpointSequence, class ConnectCondition
+ #if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+ #endif
+ >
+ typename Protocol::endpoint
+ connect(
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition,
+ error_code& ec)
+ {
+ return net::connect(socket(), endpoints, connect_condition, ec);
+ }
+
+ /** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed operation</em>, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param begin An iterator pointing to the start of a sequence of endpoints.
+
+ @param end An iterator pointing to the end of a sequence of endpoints.
+
+ @param connect_condition A function object that is called prior to each
+ connection attempt. The signature of the function object must be:
+ @code
+ bool connect_condition(
+ error_code const& ec,
+ typename Protocol::endpoint const& next);
+ @endcode
+ The @c ec parameter contains the result from the most recent connect
+ operation. Before the first connection attempt, @c ec is always set to
+ indicate success. The @c next parameter is the next endpoint to be tried.
+ The function object should return true if the next endpoint should be tried,
+ and false if it should be skipped.
+
+ @returns An iterator denoting the successfully connected endpoint.
+
+ @throws boost::system::system_error Thrown on failure. If the sequence is
+ empty, the associated @c error_code is `net::error::not_found`.
+ Otherwise, contains the error from the last connection attempt.
+ */
+ template<
+ class Iterator, class ConnectCondition>
+ Iterator
+ connect(
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition)
+ {
+ return net::connect(socket(), begin, end, connect_condition);
+ }
+
+ /** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed operation</em>, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param begin An iterator pointing to the start of a sequence of endpoints.
+
+ @param end An iterator pointing to the end of a sequence of endpoints.
+
+ @param connect_condition A function object that is called prior to each
+ connection attempt. The signature of the function object must be:
+ @code
+ bool connect_condition(
+ error_code const& ec,
+ typename Protocol::endpoint const& next);
+ @endcode
+ The @c ec parameter contains the result from the most recent connect
+ operation. Before the first connection attempt, @c ec is always set to
+ indicate success. The @c next parameter is the next endpoint to be tried.
+ The function object should return true if the next endpoint should be tried,
+ and false if it should be skipped.
+
+ @param ec Set to indicate what error occurred, if any. If the sequence is
+ empty, set to `net::error::not_found`. Otherwise, contains the error
+ from the last connection attempt.
+
+ @returns On success, an iterator denoting the successfully connected
+ endpoint. Otherwise, the end iterator.
+ */
+ template<
+ class Iterator, class ConnectCondition>
+ Iterator
+ connect(
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition,
+ error_code& ec)
+ {
+ return net::connect(socket(), begin, end, connect_condition, ec);
+ }
+
+ /** Connect the stream to the specified endpoint asynchronously.
+
+ This function is used to asynchronously connect the underlying
+ socket to the specified remote endpoint. The function call always
+ returns immediately.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ If the timeout timer expires while the operation is outstanding,
+ the operation will be canceled and the completion handler will be
+ invoked with the error @ref error::timeout.
+
+ @param ep The remote endpoint to which the underlying socket will be
+ connected. Copies will be made of the endpoint object as required.
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
+ error_code ec // Result of operation
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+
+ @see async_connect
+ */
+ template<class ConnectHandler>
+ BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)
+ async_connect(
+ endpoint_type const& ep,
+ ConnectHandler&& handler);
+
+ /** Establishes a connection by trying each endpoint in a sequence asynchronously.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed asynchronous operation</em>, is
+ implemented in terms of calls to the underlying socket's `async_connect`
+ function.
+
+ If the timeout timer expires while the operation is outstanding,
+ the current connection attempt will be canceled and the completion
+ handler will be invoked with the error @ref error::timeout.
+
+ @param endpoints A sequence of endpoints. This this object must meet
+ the requirements of <em>EndpointSequence</em>.
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
+ // Result of operation. if the sequence is empty, set to
+ // net::error::not_found. Otherwise, contains the
+ // error from the last connection attempt.
+ error_code const& error,
+
+ // On success, the successfully connected endpoint.
+ // Otherwise, a default-constructed endpoint.
+ typename Protocol::endpoint const& endpoint
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+ */
+ template<
+ class EndpointSequence,
+ class RangeConnectHandler
+ #if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+ #endif
+ >
+ BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
+ async_connect(
+ EndpointSequence const& endpoints,
+ RangeConnectHandler&& handler);
+
+ /** Establishes a connection by trying each endpoint in a sequence asynchronously.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed asynchronous operation</em>, is
+ implemented in terms of calls to the underlying socket's `async_connect`
+ function.
+
+ If the timeout timer expires while the operation is outstanding,
+ the current connection attempt will be canceled and the completion
+ handler will be invoked with the error @ref error::timeout.
+
+ @param endpoints A sequence of endpoints. This this object must meet
+ the requirements of <em>EndpointSequence</em>.
+
+ @param connect_condition A function object that is called prior to each
+ connection attempt. The signature of the function object must be:
+ @code
+ bool connect_condition(
+ error_code const& ec,
+ typename Protocol::endpoint const& next);
+ @endcode
+ The @c ec parameter contains the result from the most recent connect
+ operation. Before the first connection attempt, @c ec is always set to
+ indicate success. The @c next parameter is the next endpoint to be tried.
+ The function object should return true if the next endpoint should be tried,
+ and false if it should be skipped.
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
+ // Result of operation. if the sequence is empty, set to
+ // net::error::not_found. Otherwise, contains the
+ // error from the last connection attempt.
+ error_code const& error,
+
+ // On success, the successfully connected endpoint.
+ // Otherwise, a default-constructed endpoint.
+ typename Protocol::endpoint const& endpoint
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+
+ @par Example
+ The following connect condition function object can be used to output
+ information about the individual connection attempts:
+ @code
+ struct my_connect_condition
+ {
+ bool operator()(
+ error_code const& ec,
+ net::ip::tcp::endpoint const& next)
+ {
+ if (ec)
+ std::cout << "Error: " << ec.message() << std::endl;
+ std::cout << "Trying: " << next << std::endl;
+ return true;
+ }
+ };
+ @endcode
+ */
+ template<
+ class EndpointSequence,
+ class ConnectCondition,
+ class RangeConnectHandler
+ #if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+ #endif
+ >
+ BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
+ async_connect(
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition,
+ RangeConnectHandler&& handler);
+
+ /** Establishes a connection by trying each endpoint in a sequence asynchronously.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ The algorithm, known as a <em>composed asynchronous operation</em>, is
+ implemented in terms of calls to the underlying socket's `async_connect`
+ function.
+
+ If the timeout timer expires while the operation is outstanding,
+ the current connection attempt will be canceled and the completion
+ handler will be invoked with the error @ref error::timeout.
+
+ @param begin An iterator pointing to the start of a sequence of endpoints.
+
+ @param end An iterator pointing to the end of a sequence of endpoints.
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
+ // Result of operation. if the sequence is empty, set to
+ // net::error::not_found. Otherwise, contains the
+ // error from the last connection attempt.
+ error_code const& error,
+
+ // On success, an iterator denoting the successfully
+ // connected endpoint. Otherwise, the end iterator.
+ Iterator iterator
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+ */
+ template<
+ class Iterator,
+ class IteratorConnectHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
+ async_connect(
+ Iterator begin, Iterator end,
+ IteratorConnectHandler&& handler);
+
+ /** Establishes a connection by trying each endpoint in a sequence asynchronously.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+ The algorithm, known as a <em>composed asynchronous operation</em>, is
+ implemented in terms of calls to the underlying socket's `async_connect`
+ function.
+
+ If the timeout timer expires while the operation is outstanding,
+ the current connection attempt will be canceled and the completion
+ handler will be invoked with the error @ref error::timeout.
+
+ @param begin An iterator pointing to the start of a sequence of endpoints.
+
+ @param end An iterator pointing to the end of a sequence of endpoints.
+
+ @param connect_condition A function object that is called prior to each
+ connection attempt. The signature of the function object must be:
+ @code
+ bool connect_condition(
+ error_code const& ec,
+ Iterator next);
+ @endcode
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
+ // Result of operation. if the sequence is empty, set to
+ // net::error::not_found. Otherwise, contains the
+ // error from the last connection attempt.
+ error_code const& error,
+
+ // On success, an iterator denoting the successfully
+ // connected endpoint. Otherwise, the end iterator.
+ Iterator iterator
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+ */
+ template<
+ class Iterator,
+ class ConnectCondition,
+ class IteratorConnectHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
+ async_connect(
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition,
+ IteratorConnectHandler&& handler);
+
+ //--------------------------------------------------------------------------
+
+ /** Read some data.
+
+ This function is used to read some data from the stream.
+
+ The call blocks until one of the following is true:
+
+ @li One or more bytes are read from the stream.
+
+ @li An error occurs.
+
+ @param buffers The buffers into which the data will be read. If the
+ size of the buffers is zero bytes, the call always returns
+ immediately with no error.
+
+ @returns The number of bytes read.
+
+ @throws system_error Thrown on failure.
+
+ @note The `read_some` operation may not receive all of the requested
+ number of bytes. Consider using the function `net::read` if you need
+ to ensure that the requested amount of data is read before the
+ blocking operation completes.
+ */
+ template<class MutableBufferSequence>
+ std::size_t
+ read_some(MutableBufferSequence const& buffers)
+ {
+ return impl_->socket.read_some(buffers);
+ }
+
+ /** Read some data.
+
+ This function is used to read some data from the underlying socket.
+
+ The call blocks until one of the following is true:
+
+ @li One or more bytes are read from the stream.
+
+ @li An error occurs.
+
+ @param buffers The buffers into which the data will be read. If the
+ size of the buffers is zero bytes, the call always returns
+ immediately with no error.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes read.
+
+ @note The `read_some` operation may not receive all of the requested
+ number of bytes. Consider using the function `net::read` if you need
+ to ensure that the requested amount of data is read before the
+ blocking operation completes.
+ */
+ template<class MutableBufferSequence>
+ std::size_t
+ read_some(
+ MutableBufferSequence const& buffers,
+ error_code& ec)
+ {
+ return impl_->socket.read_some(buffers, ec);
+ }
+
+ /** Read some data asynchronously.
+
+ This function is used to asynchronously read data from the stream.
+
+ This call always returns immediately. The asynchronous operation
+ will continue until one of the following conditions is true:
+
+ @li One or more bytes are read from the stream.
+
+ @li An error occurs.
+
+ The algorithm, known as a <em>composed asynchronous operation</em>,
+ is implemented in terms of calls to the next layer's `async_read_some`
+ function. The program must ensure that no other calls to @ref read_some
+ or @ref async_read_some are performed until this operation completes.
+
+ If the timeout timer expires while the operation is outstanding,
+ the operation will be canceled and the completion handler will be
+ invoked with the error @ref error::timeout.
+
+ @param buffers The buffers into which the data will be read. If the size
+ of the buffers is zero bytes, the operation always completes immediately
+ with no error.
+ Although the buffers object may be copied as necessary, ownership of the
+ underlying memory blocks is retained by the caller, which must guarantee
+ that they remain valid until the handler is called.
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
+ error_code error, // Result of operation.
+ std::size_t bytes_transferred // Number of bytes read.
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+
+ @note The `async_read_some` operation may not receive all of the requested
+ number of bytes. Consider using the function `net::async_read` if you need
+ to ensure that the requested amount of data is read before the asynchronous
+ operation completes.
+ */
+ template<class MutableBufferSequence, class ReadHandler>
+ BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
+ async_read_some(
+ MutableBufferSequence const& buffers,
+ ReadHandler&& handler);
+
+ /** Write some data.
+
+ This function is used to write some data to the stream.
+
+ The call blocks until one of the following is true:
+
+ @li One or more bytes are written to the stream.
+
+ @li An error occurs.
+
+ @param buffers The buffers from which the data will be written. If the
+ size of the buffers is zero bytes, the call always returns immediately
+ with no error.
+
+ @returns The number of bytes written.
+
+ @throws system_error Thrown on failure.
+
+ @note The `write_some` operation may not transmit all of the requested
+ number of bytes. Consider using the function `net::write` if you need
+ to ensure that the requested amount of data is written before the
+ blocking operation completes.
+ */
+ template<class ConstBufferSequence>
+ std::size_t
+ write_some(ConstBufferSequence const& buffers)
+ {
+ return impl_->socket.write_some(buffers);
+ }
+
+ /** Write some data.
+
+ This function is used to write some data to the stream.
+
+ The call blocks until one of the following is true:
+
+ @li One or more bytes are written to the stream.
+
+ @li An error occurs.
+
+ @param buffers The buffers from which the data will be written. If the
+ size of the buffers is zero bytes, the call always returns immediately
+ with no error.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes written.
+
+ @throws system_error Thrown on failure.
+
+ @note The `write_some` operation may not transmit all of the requested
+ number of bytes. Consider using the function `net::write` if you need
+ to ensure that the requested amount of data is written before the
+ blocking operation completes.
+ */
+ template<class ConstBufferSequence>
+ std::size_t
+ write_some(
+ ConstBufferSequence const& buffers,
+ error_code& ec)
+ {
+ return impl_->socket.write_some(buffers, ec);
+ }
+
+ /** Write some data asynchronously.
+
+ This function is used to asynchronously write data to the underlying socket.
+
+ This call always returns immediately. The asynchronous operation
+ will continue until one of the following conditions is true:
+
+ @li One or more bytes are written to the stream.
+
+ @li An error occurs.
+
+ The algorithm, known as a <em>composed asynchronous operation</em>,
+ is implemented in terms of calls to the next layer's `async_write_some`
+ function. The program must ensure that no other calls to @ref async_write_some
+ are performed until this operation completes.
+
+ If the timeout timer expires while the operation is outstanding,
+ the operation will be canceled and the completion handler will be
+ invoked with the error @ref error::timeout.
+
+ @param buffers The buffers from which the data will be written. If the
+ size of the buffers is zero bytes, the operation always completes
+ immediately with no error.
+ Although the buffers object may be copied as necessary, ownership of the
+ underlying memory blocks is retained by the caller, which must guarantee
+ that they remain valid until the handler is called.
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
+ error_code error, // Result of operation.
+ std::size_t bytes_transferred // Number of bytes written.
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+
+ @note The `async_write_some` operation may not transmit all of the requested
+ number of bytes. Consider using the function `net::async_write` if you need
+ to ensure that the requested amount of data is sent before the asynchronous
+ operation completes.
+ */
+ template<class ConstBufferSequence, class WriteHandler>
+ BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
+ async_write_some(
+ ConstBufferSequence const& buffers,
+ WriteHandler&& handler);
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/basic_stream.hpp>
+
+#endif
diff --git a/boost/beast/core/bind_handler.hpp b/boost/beast/core/bind_handler.hpp
index 0fb7b8233b..cfa6a74bf5 100644
--- a/boost/beast/core/bind_handler.hpp
+++ b/boost/beast/core/bind_handler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,7 +11,6 @@
#define BOOST_BEAST_BIND_HANDLER_HPP
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/detail/bind_handler.hpp>
#include <type_traits>
#include <utility>
@@ -31,21 +30,25 @@ namespace beast {
handler, whose associated allocator and associated executor will
will be the same as those of the original handler.
- Example:
+ @par Example
+
+ This function posts the invocation of the specified completion
+ handler with bound arguments:
@code
- template<class AsyncReadStream, class ReadHandler>
+ template <class AsyncReadStream, class ReadHandler>
void
- signal_aborted(AsyncReadStream& stream, ReadHandler&& handler)
+ signal_aborted (AsyncReadStream& stream, ReadHandler&& handler)
{
- boost::asio::post(
+ net::post(
stream.get_executor(),
- bind_handler(std::forward<ReadHandler>(handler),
- boost::asio::error::operation_aborted, 0));
+ bind_handler (std::forward <ReadHandler> (handler),
+ net::error::operation_aborted, 0));
}
@endcode
@param handler The handler to wrap.
+ The implementation takes ownership of the handler by performing a decay-copy.
@param args A list of arguments to bind to the handler.
The arguments are forwarded into the returned object. These
@@ -54,22 +57,73 @@ namespace beast {
*/
template<class Handler, class... Args>
#if BOOST_BEAST_DOXYGEN
-implementation_defined
+__implementation_defined__
#else
-detail::bound_handler<
- typename std::decay<Handler>::type, Args...>
+detail::bind_wrapper<
+ typename std::decay<Handler>::type,
+ typename std::decay<Args>::type...>
#endif
bind_handler(Handler&& handler, Args&&... args)
{
-#if 0
- // Can't do this because of placeholders
- static_assert(is_completion_handler<
- Handler, void(Args...)>::value,
- "Handler requirements not met");
+ return detail::bind_wrapper<
+ typename std::decay<Handler>::type,
+ typename std::decay<Args>::type...>(
+ std::forward<Handler>(handler),
+ std::forward<Args>(args)...);
+}
+
+/** Bind parameters to a completion handler, creating a new handler.
+
+ This function creates a new handler which, when invoked, calls
+ the original handler with the list of bound arguments. Any
+ parameters passed in the invocation will be forwarded in
+ the parameter list after the bound arguments.
+
+ The passed handler and arguments are forwarded into the returned
+ handler, whose associated allocator and associated executor will
+ will be the same as those of the original handler.
+
+ @par Example
+
+ This function posts the invocation of the specified completion
+ handler with bound arguments:
+
+ @code
+ template <class AsyncReadStream, class ReadHandler>
+ void
+ signal_eof (AsyncReadStream& stream, ReadHandler&& handler)
+ {
+ net::post(
+ stream.get_executor(),
+ bind_front_handler (std::forward<ReadHandler> (handler),
+ net::error::eof, 0));
+ }
+ @endcode
+
+ @param handler The handler to wrap.
+ The implementation takes ownership of the handler by performing a decay-copy.
+
+ @param args A list of arguments to bind to the handler.
+ The arguments are forwarded into the returned object.
+*/
+template<class Handler, class... Args>
+#if BOOST_BEAST_DOXYGEN
+__implementation_defined__
+#else
+auto
#endif
- return detail::bound_handler<typename std::decay<
- Handler>::type, Args...>(std::forward<
- Handler>(handler), std::forward<Args>(args)...);
+bind_front_handler(
+ Handler&& handler,
+ Args&&... args) ->
+ detail::bind_front_wrapper<
+ typename std::decay<Handler>::type,
+ typename std::decay<Args>::type...>
+{
+ return detail::bind_front_wrapper<
+ typename std::decay<Handler>::type,
+ typename std::decay<Args>::type...>(
+ std::forward<Handler>(handler),
+ std::forward<Args>(args)...);
}
} // beast
diff --git a/boost/beast/core/buffer_traits.hpp b/boost/beast/core/buffer_traits.hpp
new file mode 100644
index 0000000000..f7b9adae7a
--- /dev/null
+++ b/boost/beast/core/buffer_traits.hpp
@@ -0,0 +1,164 @@
+//
+// 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_BUFFER_TRAITS_HPP
+#define BOOST_BEAST_BUFFER_TRAITS_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/buffer_traits.hpp>
+#include <boost/beast/core/detail/static_const.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/config/workaround.hpp>
+#include <boost/mp11/function.hpp>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+
+/** Determine if a list of types satisfy the <em>ConstBufferSequence</em> requirements.
+
+ This metafunction is used to determine if all of the specified types
+ meet the requirements for constant buffer sequences. This type alias
+ will be `std::true_type` if each specified type meets the requirements,
+ otherwise, this type alias will be `std::false_type`.
+
+ @tparam BufferSequence A list of zero or more types to check. If this
+ list is empty, the resulting type alias will be `std::true_type`.
+*/
+template<class... BufferSequence>
+#if BOOST_BEAST_DOXYGEN
+using is_const_buffer_sequence = __see_below__;
+#else
+using is_const_buffer_sequence = mp11::mp_all<
+ net::is_const_buffer_sequence<
+ typename std::decay<BufferSequence>::type>...>;
+#endif
+
+/** Determine if a list of types satisfy the <em>MutableBufferSequence</em> requirements.
+
+ This metafunction is used to determine if all of the specified types
+ meet the requirements for mutable buffer sequences. This type alias
+ will be `std::true_type` if each specified type meets the requirements,
+ otherwise, this type alias will be `std::false_type`.
+
+ @tparam BufferSequence A list of zero or more types to check. If this
+ list is empty, the resulting type alias will be `std::true_type`.
+*/
+template<class... BufferSequence>
+#if BOOST_BEAST_DOXYGEN
+using is_mutable_buffer_sequence = __see_below__;
+#else
+using is_mutable_buffer_sequence = mp11::mp_all<
+ net::is_mutable_buffer_sequence<
+ typename std::decay<BufferSequence>::type>...>;
+#endif
+
+/** Type alias for the underlying buffer type of a list of buffer sequence types.
+
+ This metafunction is used to determine the underlying buffer type for
+ a list of buffer sequence. The equivalent type of the alias will vary
+ depending on the template type argument:
+
+ @li If every type in the list is a <em>MutableBufferSequence</em>,
+ the resulting type alias will be `net::mutable_buffer`, otherwise
+
+ @li The resulting type alias will be `net::const_buffer`.
+
+ @par Example
+ The following code returns the first buffer in a buffer sequence,
+ or generates a compilation error if the argument is not a buffer
+ sequence:
+ @code
+ template <class BufferSequence>
+ buffers_type <BufferSequence>
+ buffers_front (BufferSequence const& buffers)
+ {
+ static_assert(
+ net::is_const_buffer_sequence<BufferSequence>::value,
+ "BufferSequence type requirements not met");
+ auto const first = net::buffer_sequence_begin (buffers);
+ if (first == net::buffer_sequence_end (buffers))
+ return {};
+ return *first;
+ }
+ @endcode
+
+ @tparam BufferSequence A list of zero or more types to check. If this
+ list is empty, the resulting type alias will be `net::mutable_buffer`.
+*/
+template<class... BufferSequence>
+#if BOOST_BEAST_DOXYGEN
+using buffers_type = __see_below__;
+#else
+using buffers_type = typename std::conditional<
+ is_mutable_buffer_sequence<BufferSequence...>::value,
+ net::mutable_buffer, net::const_buffer>::type;
+#endif
+
+/** Type alias for the iterator type of a buffer sequence type.
+
+ This metafunction is used to determine the type of iterator
+ used by a particular buffer sequence.
+
+ @tparam T The buffer sequence type to use. The resulting
+ type alias will be equal to the iterator type used by
+ the buffer sequence.
+*/
+template <class BufferSequence>
+#if BOOST_BEAST_DOXYGEN
+using buffers_iterator_type = __see_below__;
+#elif BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+using buffers_iterator_type = typename
+ detail::buffers_iterator_type_helper<
+ typename std::decay<BufferSequence>::type>::type;
+#else
+using buffers_iterator_type =
+ decltype(net::buffer_sequence_begin(
+ std::declval<BufferSequence const&>()));
+#endif
+
+/** Return the total number of bytes in a buffer or buffer sequence
+
+ This function returns the total number of bytes in a buffer,
+ buffer sequence, or object convertible to a buffer. Specifically
+ it may be passed:
+
+ @li A <em>ConstBufferSequence</em> or <em>MutableBufferSequence</em>
+
+ @li A `net::const_buffer` or `net::mutable_buffer`
+
+ @li An object convertible to `net::const_buffer`
+
+ This function is designed as an easier-to-use replacement for
+ `net::buffer_size`. It recognizes customization points found through
+ argument-dependent lookup. The call `beast::buffer_bytes(b)` is
+ equivalent to performing:
+ @code
+ using namespace net;
+ buffer_bytes(b);
+ @endcode
+ In addition this handles types which are convertible to
+ `net::const_buffer`; these are not handled by `net::buffer_size`.
+
+ @param buffers The buffer or buffer sequence to calculate the size of.
+
+ @return The total number of bytes in the buffer or sequence.
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class BufferSequence>
+std::size_t
+buffer_bytes(BufferSequence const& buffers);
+#else
+BOOST_BEAST_INLINE_VARIABLE(buffer_bytes, detail::buffer_bytes_impl)
+#endif
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/buffered_read_stream.hpp b/boost/beast/core/buffered_read_stream.hpp
index 974062309f..66cd561e98 100644
--- a/boost/beast/core/buffered_read_stream.hpp
+++ b/boost/beast/core/buffered_read_stream.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -13,7 +13,7 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/multi_buffer.hpp>
-#include <boost/beast/core/type_traits.hpp>
+#include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_context.hpp>
@@ -23,25 +23,25 @@
namespace boost {
namespace beast {
-/** A @b Stream with attached @b DynamicBuffer to buffer reads.
+/** A <em>Stream</em> with attached <em>DynamicBuffer</em> to buffer reads.
- This wraps a @b Stream implementation so that calls to write are
+ This wraps a <em>Stream</em> implementation so that calls to write are
passed through to the underlying stream, while calls to read will
- first consume the input sequence stored in a @b DynamicBuffer which
+ first consume the input sequence stored in a <em>DynamicBuffer</em> which
is part of the object.
The use-case for this class is different than that of the
- `boost::asio::buffered_readstream`. It is designed to facilitate
- the use of `boost::asio::read_until`, and to allow buffers
+ `net::buffered_read_stream`. It is designed to facilitate
+ the use of `net::read_until`, and to allow buffers
acquired during detection of handshakes to be made transparently
available to callers. A hypothetical implementation of the
- buffered version of `boost::asio::ssl::stream::async_handshake`
+ buffered version of `net::ssl::stream::async_handshake`
could make use of this wrapper.
Uses:
@li Transparently leave untouched input acquired in calls
- to `boost::asio::read_until` behind for subsequent callers.
+ to `net::read_until` behind for subsequent callers.
@li "Preload" a stream with handshake input data acquired
from other sources.
@@ -51,9 +51,9 @@ namespace beast {
// Process the next HTTP header on the stream,
// leaving excess bytes behind for the next call.
//
- template<class DynamicBuffer>
+ template<class Stream, class DynamicBuffer>
void process_http_message(
- buffered_read_stream<DynamicBuffer>& stream)
+ buffered_read_stream<Stream, DynamicBuffer>& stream)
{
// Read up to and including the end of the HTTP
// header, leaving the sequence in the stream's
@@ -62,7 +62,7 @@ namespace beast {
// part up to the end of the delimiter.
//
std::size_t bytes_transferred =
- boost::asio::read_until(
+ net::read_until(
stream.next_layer(), stream.buffer(), "\r\n\r\n");
// Use buffers_prefix() to limit the input
@@ -92,11 +92,10 @@ template<class Stream, class DynamicBuffer>
class buffered_read_stream
{
static_assert(
- boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
- "DynamicBuffer requirements not met");
+ net::is_dynamic_buffer<DynamicBuffer>::value,
+ "DynamicBuffer type requirements not met");
- template<class Buffers, class Handler>
- class read_some_op;
+ struct ops;
DynamicBuffer buffer_;
std::size_t capacity_ = 0;
@@ -110,9 +109,6 @@ public:
using next_layer_type =
typename std::remove_reference<Stream>::type;
- /// The type of the lowest layer.
- using lowest_layer_type = get_lowest_layer<next_layer_type>;
-
/** Move constructor.
@note The behavior of move assignment on or from streams
@@ -137,31 +133,20 @@ public:
/// Get a reference to the next layer.
next_layer_type&
- next_layer()
+ next_layer() noexcept
{
return next_layer_;
}
/// Get a const reference to the next layer.
next_layer_type const&
- next_layer() const
+ next_layer() const noexcept
{
return next_layer_;
}
- /// Get a reference to the lowest layer.
- lowest_layer_type&
- lowest_layer()
- {
- return next_layer_.lowest_layer();
- }
-
- /// Get a const reference to the lowest layer.
- lowest_layer_type const&
- lowest_layer() const
- {
- return next_layer_.lowest_layer();
- }
+ using executor_type =
+ beast::executor_type<next_layer_type>;
/** Get the executor associated with the object.
@@ -169,21 +154,9 @@ public:
uses to dispatch handlers for asynchronous operations.
@return A copy of the executor that stream will use to dispatch handlers.
-
- @note This function participates in overload resolution only if
- `NextLayer` has a member function named `get_executor`.
*/
-#if BOOST_BEAST_DOXYGEN
- implementation_defined
-#else
- template<
- class T = next_layer_type,
- class = typename std::enable_if<
- has_get_executor<next_layer_type>::value>::type>
- auto
-#endif
- get_executor() noexcept ->
- decltype(std::declval<T&>().get_executor())
+ executor_type
+ get_executor() noexcept
{
return next_layer_.get_executor();
}
@@ -196,14 +169,14 @@ public:
the caller defined maximum.
*/
DynamicBuffer&
- buffer()
+ buffer() noexcept
{
return buffer_;
}
/// Access the internal buffer
DynamicBuffer const&
- buffer() const
+ buffer() const noexcept
{
return buffer_;
}
@@ -224,7 +197,7 @@ public:
than the amount of data in the buffer, no bytes are discarded.
*/
void
- capacity(std::size_t size)
+ capacity(std::size_t size) noexcept
{
capacity_ = size;
}
@@ -273,21 +246,23 @@ public:
is retained by the caller, which must guarantee that they
remain valid until the handler is called.
- @param handler Invoked when the operation completes.
- The handler may be moved or copied as needed.
- The equivalent function signature of the handler must be:
- @code void handler(
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
error_code const& error, // result of operation
std::size_t bytes_transferred // number of bytes transferred
- ); @endcode
+ );
+ @endcode
Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
- manner equivalent to using `boost::asio::io_context::post`.
+ manner equivalent to using `net::post`.
*/
template<class MutableBufferSequence, class ReadHandler>
- BOOST_ASIO_INITFN_RESULT_TYPE(
- ReadHandler, void(error_code, std::size_t))
+ BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read_some(MutableBufferSequence const& buffers,
ReadHandler&& handler);
@@ -308,7 +283,7 @@ public:
write_some(ConstBufferSequence const& buffers)
{
static_assert(is_sync_write_stream<next_layer_type>::value,
- "SyncWriteStream requirements not met");
+ "SyncWriteStream type requirements not met");
return next_layer_.write_some(buffers);
}
@@ -330,7 +305,7 @@ public:
error_code& ec)
{
static_assert(is_sync_write_stream<next_layer_type>::value,
- "SyncWriteStream requirements not met");
+ "SyncWriteStream type requirements not met");
return next_layer_.write_some(buffers, ec);
}
@@ -345,21 +320,23 @@ public:
retained by the caller, which must guarantee that they
remain valid until the handler is called.
- @param handler Invoked when the operation completes.
- The handler may be moved or copied as needed.
- The equivalent function signature of the handler must be:
- @code void handler(
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
error_code const& error, // result of operation
std::size_t bytes_transferred // number of bytes transferred
- ); @endcode
+ );
+ @endcode
Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
- manner equivalent to using `boost::asio::io_context::post`.
+ manner equivalent to using `net::post`.
*/
template<class ConstBufferSequence, class WriteHandler>
- BOOST_ASIO_INITFN_RESULT_TYPE(
- WriteHandler, void(error_code, std::size_t))
+ BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
async_write_some(ConstBufferSequence const& buffers,
WriteHandler&& handler);
};
@@ -367,6 +344,6 @@ public:
} // beast
} // boost
-#include <boost/beast/core/impl/buffered_read_stream.ipp>
+#include <boost/beast/core/impl/buffered_read_stream.hpp>
#endif
diff --git a/boost/beast/core/buffers_adapter.hpp b/boost/beast/core/buffers_adapter.hpp
index 2000ce24bb..6c584bb295 100644
--- a/boost/beast/core/buffers_adapter.hpp
+++ b/boost/beast/core/buffers_adapter.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,178 +11,25 @@
#define BOOST_BEAST_BUFFERS_ADAPTER_HPP
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/type_traits.hpp>
-#include <boost/asio/buffer.hpp>
-#include <boost/optional.hpp>
-#include <type_traits>
-namespace boost {
-namespace beast {
-
-/** Adapts a @b MutableBufferSequence into a @b DynamicBuffer.
+#ifdef BOOST_BEAST_ALLOW_DEPRECATED
- This class wraps a @b MutableBufferSequence to meet the requirements
- of @b DynamicBuffer. Upon construction the input and output sequences are
- empty. A copy of the mutable buffer sequence object is stored; however,
- ownership of the underlying memory is not transferred. The caller is
- responsible for making sure that referenced memory remains valid
- for the duration of any operations.
+#include <boost/beast/core/buffers_adaptor.hpp>
- The size of the mutable buffer sequence determines the maximum
- number of bytes which may be prepared and committed.
+namespace boost {
+namespace beast {
- @tparam MutableBufferSequence The type of mutable buffer sequence to wrap.
-*/
template<class MutableBufferSequence>
-class buffers_adapter
-{
- static_assert(boost::asio::is_mutable_buffer_sequence<MutableBufferSequence>::value,
- "MutableBufferSequence requirements not met");
-
- using iter_type = typename
- detail::buffer_sequence_iterator<
- MutableBufferSequence>::type;
-
- MutableBufferSequence bs_;
- iter_type begin_;
- iter_type out_;
- iter_type end_;
- std::size_t max_size_;
- std::size_t in_pos_ = 0; // offset in *begin_
- std::size_t in_size_ = 0; // size of input sequence
- std::size_t out_pos_ = 0; // offset in *out_
- std::size_t out_end_ = 0; // output end offset
-
- template<class Deduced>
- buffers_adapter(Deduced&& other,
- std::size_t nbegin, std::size_t nout,
- std::size_t nend)
- : bs_(std::forward<Deduced>(other).bs_)
- , begin_(std::next(bs_.begin(), nbegin))
- , out_(std::next(bs_.begin(), nout))
- , end_(std::next(bs_.begin(), nend))
- , max_size_(other.max_size_)
- , in_pos_(other.in_pos_)
- , in_size_(other.in_size_)
- , out_pos_(other.out_pos_)
- , out_end_(other.out_end_)
- {
- }
-
- iter_type end_impl() const;
-
-public:
- /// The type of the underlying mutable buffer sequence
- using value_type = MutableBufferSequence;
+using buffers_adapter = buffers_adaptor<MutableBufferSequence>;
-#if BOOST_BEAST_DOXYGEN
- /// The type used to represent the input sequence as a list of buffers.
- using const_buffers_type = implementation_defined;
-
- /// The type used to represent the output sequence as a list of buffers.
- using mutable_buffers_type = implementation_defined;
+} // beast
+} // boost
#else
- class const_buffers_type;
- class mutable_buffers_type;
+// The new filename is <boost/beast/core/buffers_adaptor.hpp>
+#error The file <boost/beast/core/buffers_adapter.hpp> is deprecated, define BOOST_BEAST_ALLOW_DEPRECATED to disable this error
#endif
- /// Move constructor.
- buffers_adapter(buffers_adapter&& other);
-
- /// Copy constructor.
- buffers_adapter(buffers_adapter const& other);
-
- /// Move assignment.
- buffers_adapter& operator=(buffers_adapter&& other);
-
- /// Copy assignment.
- buffers_adapter& operator=(buffers_adapter const&);
-
- /** Construct a buffers adapter.
-
- @param buffers The mutable buffer sequence to wrap. A copy of
- the object will be made, but ownership of the memory is not
- transferred.
- */
- explicit
- buffers_adapter(MutableBufferSequence const& buffers);
-
- /** Constructor
-
- This constructs the buffer adapter in-place from
- a list of arguments.
-
- @param args Arguments forwarded to the buffers constructor.
- */
- template<class... Args>
- explicit
- buffers_adapter(boost::in_place_init_t, Args&&... args);
-
- /// Returns the largest size output sequence possible.
- std::size_t
- max_size() const
- {
- return max_size_;
- }
-
- /// Get the size of the input sequence.
- std::size_t
- size() const
- {
- return in_size_;
- }
-
- /// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
- std::size_t
- capacity() const
- {
- return max_size_;
- }
-
- /// Returns the original mutable buffer sequence
- value_type const&
- value() const
- {
- return bs_;
- }
-
- /** Get a list of buffers that represents the output sequence, with the given size.
-
- @throws std::length_error if the size would exceed the limit
- imposed by the underlying mutable buffer sequence.
-
- @note Buffers representing the input sequence acquired prior to
- this call remain valid.
- */
- mutable_buffers_type
- prepare(std::size_t n);
-
- /** Move bytes from the output sequence to the input sequence.
-
- @note Buffers representing the input sequence acquired prior to
- this call remain valid.
- */
- void
- commit(std::size_t n);
-
- /** Get a list of buffers that represents the input sequence.
-
- @note These buffers remain valid across subsequent calls to `prepare`.
- */
- const_buffers_type
- data() const;
-
- /// Remove bytes from the input sequence.
- void
- consume(std::size_t n);
-};
-
-} // beast
-} // boost
-
-#include <boost/beast/core/impl/buffers_adapter.ipp>
-
#endif
diff --git a/boost/beast/core/buffers_adaptor.hpp b/boost/beast/core/buffers_adaptor.hpp
new file mode 100644
index 0000000000..d6400481ce
--- /dev/null
+++ b/boost/beast/core/buffers_adaptor.hpp
@@ -0,0 +1,226 @@
+//
+// 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_BUFFERS_ADAPTOR_HPP
+#define BOOST_BEAST_BUFFERS_ADAPTOR_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/optional.hpp>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+
+/** Adapts a <em>MutableBufferSequence</em> into a <em>DynamicBuffer</em>.
+
+ This class wraps a <em>MutableBufferSequence</em> to meet the requirements
+ of <em>DynamicBuffer</em>. Upon construction the input and output sequences
+ are empty. A copy of the mutable buffer sequence object is stored; however,
+ ownership of the underlying memory is not transferred. The caller is
+ responsible for making sure that referenced memory remains valid
+ for the duration of any operations.
+
+ The size of the mutable buffer sequence determines the maximum
+ number of bytes which may be prepared and committed.
+
+ @tparam MutableBufferSequence The type of mutable buffer sequence to adapt.
+*/
+template<class MutableBufferSequence>
+class buffers_adaptor
+{
+ static_assert(net::is_mutable_buffer_sequence<
+ MutableBufferSequence>::value,
+ "MutableBufferSequence type requirements not met");
+
+ using iter_type =
+ buffers_iterator_type<MutableBufferSequence>;
+
+ template<bool>
+ class readable_bytes;
+
+ MutableBufferSequence bs_;
+ iter_type begin_;
+ iter_type out_;
+ iter_type end_;
+ std::size_t max_size_;
+ std::size_t in_pos_ = 0; // offset in *begin_
+ std::size_t in_size_ = 0; // size of input sequence
+ std::size_t out_pos_ = 0; // offset in *out_
+ std::size_t out_end_ = 0; // output end offset
+
+ iter_type end_impl() const;
+
+ buffers_adaptor(
+ buffers_adaptor const& other,
+ std::size_t nbegin,
+ std::size_t nout,
+ std::size_t nend);
+
+public:
+ /// The type of the underlying mutable buffer sequence
+ using value_type = MutableBufferSequence;
+
+ /** Construct a buffers adaptor.
+
+ @param buffers The mutable buffer sequence to wrap. A copy of
+ the object will be made, but ownership of the memory is not
+ transferred.
+ */
+ explicit
+ buffers_adaptor(MutableBufferSequence const& buffers);
+
+ /** Constructor
+
+ This constructs the buffer adaptor in-place from
+ a list of arguments.
+
+ @param args Arguments forwarded to the buffers constructor.
+ */
+ template<class... Args>
+ explicit
+ buffers_adaptor(boost::in_place_init_t, Args&&... args);
+
+ /// Copy Constructor
+ buffers_adaptor(buffers_adaptor const& other);
+
+ /// Copy Assignment
+ buffers_adaptor& operator=(buffers_adaptor const&);
+
+ /// Returns the original mutable buffer sequence
+ value_type const&
+ value() const
+ {
+ return bs_;
+ }
+
+ //--------------------------------------------------------------------------
+
+#if BOOST_BEAST_DOXYGEN
+ /// The ConstBufferSequence used to represent the readable bytes.
+ using const_buffers_type = __implementation_defined__;
+
+ /// The MutableBufferSequence used to represent the readable bytes.
+ using mutable_data_type = __implementation_defined__;
+
+ /// The MutableBufferSequence used to represent the writable bytes.
+ using mutable_buffers_type = __implementation_defined__;
+
+#else
+ using const_buffers_type = readable_bytes<false>;
+ using mutable_data_type = readable_bytes<true>;
+ class mutable_buffers_type;
+#endif
+
+ /// Returns the number of readable bytes.
+ std::size_t
+ size() const noexcept
+ {
+ return in_size_;
+ }
+
+ /// Return the maximum number of bytes, both readable and writable, that can ever be held.
+ std::size_t
+ max_size() const noexcept
+ {
+ return max_size_;
+ }
+
+ /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
+ std::size_t
+ capacity() const noexcept
+ {
+ return max_size_;
+ }
+
+ /// Returns a constant buffer sequence representing the readable bytes
+ const_buffers_type
+ data() const noexcept;
+
+ /// Returns a constant buffer sequence representing the readable bytes
+ const_buffers_type
+ cdata() const noexcept
+ {
+ return data();
+ }
+
+ /// Returns a mutable buffer sequence representing the readable bytes.
+ mutable_data_type
+ data() noexcept;
+
+ /** Returns a mutable buffer sequence representing writable bytes.
+
+ Returns a mutable buffer sequence representing the writable
+ bytes containing exactly `n` bytes of storage. This function
+ does not allocate memory. Instead, the storage comes from
+ the underlying mutable buffer sequence.
+
+ All buffer sequences previously obtained using @ref prepare are
+ invalidated. Buffer sequences previously obtained using @ref data
+ remain valid.
+
+ @param n The desired number of bytes in the returned buffer
+ sequence.
+
+ @throws std::length_error if `size() + n` exceeds `max_size()`.
+
+ @esafe
+
+ Strong guarantee.
+ */
+ mutable_buffers_type
+ prepare(std::size_t n);
+
+ /** Append writable bytes to the readable bytes.
+
+ Appends n bytes from the start of the writable bytes to the
+ end of the readable bytes. The remainder of the writable bytes
+ are discarded. If n is greater than the number of writable
+ bytes, all writable bytes are appended to the readable bytes.
+
+ All buffer sequences previously obtained using @ref prepare are
+ invalidated. Buffer sequences previously obtained using @ref data
+ remain valid.
+
+ @param n The number of bytes to append. If this number
+ is greater than the number of writable bytes, all
+ writable bytes are appended.
+
+ @esafe
+
+ No-throw guarantee.
+ */
+ void
+ commit(std::size_t n) noexcept;
+
+ /** Remove bytes from beginning of the readable bytes.
+
+ Removes n bytes from the beginning of the readable bytes.
+
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare are invalidated.
+
+ @param n The number of bytes to remove. If this number
+ is greater than the number of readable bytes, all
+ readable bytes are removed.
+
+ @esafe
+
+ No-throw guarantee.
+ */
+ void
+ consume(std::size_t n) noexcept;
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/buffers_adaptor.hpp>
+
+#endif
diff --git a/boost/beast/core/buffers_cat.hpp b/boost/beast/core/buffers_cat.hpp
index 1d711b3b30..532ea32eef 100644
--- a/boost/beast/core/buffers_cat.hpp
+++ b/boost/beast/core/buffers_cat.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,66 +11,59 @@
#define BOOST_BEAST_BUFFERS_CAT_HPP
#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/beast/core/detail/tuple.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
-#include <tuple>
namespace boost {
namespace beast {
/** A buffer sequence representing a concatenation of buffer sequences.
- @see @ref buffers_cat
+ @see buffers_cat
*/
template<class... Buffers>
class buffers_cat_view
{
- std::tuple<Buffers...> bn_;
+ detail::tuple<Buffers...> bn_;
public:
/** The type of buffer returned when dereferencing an iterator.
- If every buffer sequence in the view is a @b MutableBufferSequence,
- then `value_type` will be `boost::asio::mutable_buffer`.
- Otherwise, `value_type` will be `boost::asio::const_buffer`.
+ If every buffer sequence in the view is a <em>MutableBufferSequence</em>,
+ then `value_type` will be `net::mutable_buffer`.
+ Otherwise, `value_type` will be `net::const_buffer`.
*/
#if BOOST_BEAST_DOXYGEN
- using value_type = implementation_defined;
+ using value_type = __see_below__;
#else
- using value_type = typename
- detail::common_buffers_type<Buffers...>::type;
+ using value_type = buffers_type<Buffers...>;
#endif
/// The type of iterator used by the concatenated sequence
class const_iterator;
- /// Constructor
- buffers_cat_view(buffers_cat_view&&) = default;
-
- /// Assignment
- buffers_cat_view& operator=(buffers_cat_view&&) = default;
+ /// Copy Constructor
+ buffers_cat_view(buffers_cat_view const&) = default;
- /// Assignment
+ /// Copy Assignment
buffers_cat_view& operator=(buffers_cat_view const&) = default;
/** Constructor
@param buffers The list of buffer sequences to concatenate.
- Copies of the arguments will be made; however, the ownership
- of memory is not transferred.
+ Copies of the arguments will be maintained for the lifetime
+ of the concatenated sequence; however, the ownership of the
+ memory buffers themselves is not transferred.
*/
explicit
buffers_cat_view(Buffers const&... buffers);
- //-----
-
- /// Required for @b BufferSequence
- buffers_cat_view(buffers_cat_view const&) = default;
-
- /// Required for @b BufferSequence
+ /// Returns an iterator to the first buffer in the sequence
const_iterator
begin() const;
- /// Required for @b BufferSequence
+ /// Returns an iterator to one past the last buffer in the sequence
const_iterator
end() const;
};
@@ -88,11 +81,11 @@ public:
@return A new buffer sequence that represents the concatenation of
the input buffer sequences. This buffer sequence will be a
- @b MutableBufferSequence if each of the passed buffer sequences is
- also a @b MutableBufferSequence; otherwise the returned buffer
- sequence will be a @b ConstBufferSequence.
+ <em>MutableBufferSequence</em> if each of the passed buffer sequences is
+ also a <em>MutableBufferSequence</em>; otherwise the returned buffer
+ sequence will be a <em>ConstBufferSequence</em>.
- @see @ref buffers_cat_view
+ @see buffers_cat_view
*/
#if BOOST_BEAST_DOXYGEN
template<class... BufferSequence>
@@ -100,20 +93,19 @@ buffers_cat_view<BufferSequence...>
buffers_cat(BufferSequence const&... buffers)
#else
template<class B1, class B2, class... Bn>
-inline
buffers_cat_view<B1, B2, Bn...>
buffers_cat(B1 const& b1, B2 const& b2, Bn const&... bn)
#endif
{
static_assert(
- detail::is_all_const_buffer_sequence<B1, B2, Bn...>::value,
- "BufferSequence requirements not met");
+ is_const_buffer_sequence<B1, B2, Bn...>::value,
+ "BufferSequence type requirements not met");
return buffers_cat_view<B1, B2, Bn...>{b1, b2, bn...};
}
} // beast
} // boost
-#include <boost/beast/core/impl/buffers_cat.ipp>
+#include <boost/beast/core/impl/buffers_cat.hpp>
#endif
diff --git a/boost/beast/core/buffers_prefix.hpp b/boost/beast/core/buffers_prefix.hpp
index 175610f171..5468de55e9 100644
--- a/boost/beast/core/buffers_prefix.hpp
+++ b/boost/beast/core/buffers_prefix.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,16 +11,20 @@
#define BOOST_BEAST_BUFFERS_PREFIX_HPP
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/type_traits.hpp>
-#include <boost/asio/buffer.hpp>
-#include <boost/optional/optional.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/optional/optional.hpp> // for in_place_init_t
+#include <algorithm>
#include <cstdint>
#include <type_traits>
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+#include <boost/type_traits.hpp>
+#endif
+
namespace boost {
namespace beast {
-/** A buffer sequence adapter that shortens the sequence size.
+/** A buffer sequence adaptor that shortens the sequence size.
The class adapts a buffer sequence to efficiently represent
a shorter subset of the original list of buffers starting
@@ -31,70 +35,70 @@ namespace beast {
template<class BufferSequence>
class buffers_prefix_view
{
- using buffers_type = typename
- std::decay<BufferSequence>::type;
-
- using iter_type = typename
- detail::buffer_sequence_iterator<buffers_type>::type;
+ using iter_type =
+ buffers_iterator_type<BufferSequence>;
BufferSequence bs_;
- std::size_t size_;
- std::size_t remain_;
- iter_type end_;
-
- template<class Deduced>
- buffers_prefix_view(
- Deduced&& other, std::size_t dist)
- : bs_(std::forward<Deduced>(other).bs_)
- , size_(other.size_)
- , remain_(other.remain_)
- , end_(std::next(bs_.begin(), dist))
- {
- }
+ std::size_t size_ = 0;
+ std::size_t remain_ = 0;
+ iter_type end_{};
void
setup(std::size_t size);
+ buffers_prefix_view(
+ buffers_prefix_view const& other,
+ std::size_t dist);
+
public:
- /// The type for each element in the list of buffers.
+ /** The type for each element in the list of buffers.
+
+ If the type `BufferSequence` meets the requirements of
+ <em>MutableBufferSequence</em>, then `value_type` is
+ `net::mutable_buffer`. Otherwise, `value_type` is
+ `net::const_buffer`.
+
+ @see buffers_type
+ */
+#if BOOST_BEAST_DOXYGEN
+ using value_type = __see_below__;
+#elif BOOST_WORKAROUND(BOOST_MSVC, < 1910)
using value_type = typename std::conditional<
- std::is_convertible<typename
+ boost::is_convertible<typename
std::iterator_traits<iter_type>::value_type,
- boost::asio::mutable_buffer>::value,
- boost::asio::mutable_buffer,
- boost::asio::const_buffer>::type;
+ net::mutable_buffer>::value,
+ net::mutable_buffer,
+ net::const_buffer>::type;
+#else
+ using value_type = buffers_type<BufferSequence>;
+#endif
#if BOOST_BEAST_DOXYGEN
/// A bidirectional iterator type that may be used to read elements.
- using const_iterator = implementation_defined;
+ using const_iterator = __implementation_defined__;
#else
class const_iterator;
#endif
- /// Move constructor.
- buffers_prefix_view(buffers_prefix_view&&);
-
- /// Copy constructor.
+ /// Copy Constructor
buffers_prefix_view(buffers_prefix_view const&);
- /// Move assignment.
- buffers_prefix_view& operator=(buffers_prefix_view&&);
-
- /// Copy assignment.
+ /// Copy Assignment
buffers_prefix_view& operator=(buffers_prefix_view const&);
/** Construct a buffer sequence prefix.
@param size The maximum number of bytes in the prefix.
- If this is larger than the size of passed, buffers,
+ If this is larger than the size of passed buffers,
the resulting sequence will represent the entire
input sequence.
@param buffers The buffer sequence to adapt. A copy of
the sequence will be made, but ownership of the underlying
- memory is not transferred.
+ memory is not transferred. The copy is maintained for
+ the lifetime of the view.
*/
buffers_prefix_view(
std::size_t size,
@@ -103,11 +107,11 @@ public:
/** Construct a buffer sequence prefix in-place.
@param size The maximum number of bytes in the prefix.
- If this is larger than the size of passed, buffers,
+ If this is larger than the size of passed buffers,
the resulting sequence will represent the entire
input sequence.
- @param args Arguments forwarded to the contained buffers constructor.
+ @param args Arguments forwarded to the contained buffer's constructor.
*/
template<class... Args>
buffers_prefix_view(
@@ -115,95 +119,56 @@ public:
boost::in_place_init_t,
Args&&... args);
- /// Get a bidirectional iterator to the first element.
+ /// Returns an iterator to the first buffer in the sequence
const_iterator
begin() const;
- /// Get a bidirectional iterator to one past the last element.
+ /// Returns an iterator to one past the last buffer in the sequence
const_iterator
end() const;
-};
-
-/** Returns a prefix of a constant buffer.
-
- The returned buffer points to the same memory as the
- passed buffer, but with a size that is equal to or less
- than the size of the original buffer.
- @param size The size of the returned buffer.
-
- @param buffer The buffer to shorten. The underlying
- memory is not modified.
-
- @return A new buffer that points to the first `size`
- bytes of the original buffer.
-*/
-inline
-boost::asio::const_buffer
-buffers_prefix(std::size_t size,
- boost::asio::const_buffer buffer)
-{
- return {buffer.data(),
- (std::min)(size, buffer.size())};
-}
-
-/** Returns a prefix of a mutable buffer.
-
- The returned buffer points to the same memory as the
- passed buffer, but with a size that is equal to or less
- than the size of the original buffer.
-
- @param size The size of the returned buffer.
+#if ! BOOST_BEAST_DOXYGEN
+ std::size_t
+ buffer_bytes_impl() const noexcept
+ {
+ return size_;
+ }
+#endif
+};
- @param buffer The buffer to shorten. The underlying
- memory is not modified.
+//------------------------------------------------------------------------------
- @return A new buffer that points to the first `size` bytes
- of the original buffer.
-*/
-inline
-boost::asio::mutable_buffer
-buffers_prefix(std::size_t size,
- boost::asio::mutable_buffer buffer)
-{
- return {buffer.data(),
- (std::min)(size, buffer.size())};
-}
+/** Returns a prefix of a constant or mutable buffer sequence.
-/** Returns a prefix of a buffer sequence.
+ The returned buffer sequence points to the same memory as the
+ passed buffer sequence, but with a size that is equal to or
+ smaller. No memory allocations are performed; the resulting
+ sequence is calculated as a lazy range.
- This function returns a new buffer sequence which when iterated,
- presents a shorter subset of the original list of buffers starting
- with the first byte of the original sequence.
+ @param size The maximum size of the returned buffer sequence
+ in bytes. If this is greater than or equal to the size of
+ the passed buffer sequence, the result will have the same
+ size as the original buffer sequence.
- @param size The maximum number of bytes in the wrapped
- sequence. If this is larger than the size of passed,
- buffers, the resulting sequence will represent the
- entire input sequence.
+ @param buffers An object whose type meets the requirements
+ of <em>BufferSequence</em>. The returned value will
+ maintain a copy of the passed buffers for its lifetime;
+ however, ownership of the underlying memory is not
+ transferred.
- @param buffers An instance of @b ConstBufferSequence or
- @b MutableBufferSequence to adapt. A copy of the sequence
- will be made, but ownership of the underlying memory is
- not transferred.
+ @return A constant buffer sequence that represents the prefix
+ of the original buffer sequence. If the original buffer sequence
+ also meets the requirements of <em>MutableBufferSequence</em>,
+ then the returned value will also be a mutable buffer sequence.
*/
template<class BufferSequence>
-#if BOOST_BEAST_DOXYGEN
buffers_prefix_view<BufferSequence>
-#else
-inline
-typename std::enable_if<
- ! std::is_same<BufferSequence,
- boost::asio::const_buffer>::value &&
- ! std::is_same<BufferSequence,
- boost::asio::mutable_buffer>::value,
- buffers_prefix_view<BufferSequence>>::type
-#endif
-buffers_prefix(std::size_t size, BufferSequence const& buffers)
+buffers_prefix(
+ std::size_t size, BufferSequence const& buffers)
{
static_assert(
- boost::asio::is_const_buffer_sequence<BufferSequence>::value ||
- boost::asio::is_mutable_buffer_sequence<BufferSequence>::value,
- "BufferSequence requirements not met");
+ net::is_const_buffer_sequence<BufferSequence>::value,
+ "BufferSequence type requirements not met");
return buffers_prefix_view<BufferSequence>(size, buffers);
}
@@ -218,15 +183,12 @@ buffers_prefix(std::size_t size, BufferSequence const& buffers)
Otherwise, the returned buffer sequence will be constant.
*/
template<class BufferSequence>
-typename std::conditional<
- boost::asio::is_mutable_buffer_sequence<BufferSequence>::value,
- boost::asio::mutable_buffer,
- boost::asio::const_buffer>::type
+buffers_type<BufferSequence>
buffers_front(BufferSequence const& buffers)
{
auto const first =
- boost::asio::buffer_sequence_begin(buffers);
- if(first == boost::asio::buffer_sequence_end(buffers))
+ net::buffer_sequence_begin(buffers);
+ if(first == net::buffer_sequence_end(buffers))
return {};
return *first;
}
@@ -234,6 +196,6 @@ buffers_front(BufferSequence const& buffers)
} // beast
} // boost
-#include <boost/beast/core/impl/buffers_prefix.ipp>
+#include <boost/beast/core/impl/buffers_prefix.hpp>
#endif
diff --git a/boost/beast/core/buffers_range.hpp b/boost/beast/core/buffers_range.hpp
new file mode 100644
index 0000000000..c7659e2fad
--- /dev/null
+++ b/boost/beast/core/buffers_range.hpp
@@ -0,0 +1,128 @@
+//
+// 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_BUFFERS_RANGE_HPP
+#define BOOST_BEAST_BUFFERS_RANGE_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/beast/core/detail/buffers_range_adaptor.hpp>
+
+namespace boost {
+namespace beast {
+
+/** Returns an iterable range representing a buffer sequence.
+
+ This function returns an iterable range representing the
+ passed buffer sequence. The values obtained when iterating
+ the range will be `net::const_buffer`, unless the underlying
+ buffer sequence is a <em>MutableBufferSequence</em>, in which case
+ the value obtained when iterating will be a `net::mutable_buffer`.
+
+ @par Example
+
+ The following function returns the total number of bytes in
+ the specified buffer sequence. A copy of the buffer sequence
+ is maintained for the lifetime of the range object:
+
+ @code
+ template <class BufferSequence>
+ std::size_t buffer_sequence_size (BufferSequence const& buffers)
+ {
+ std::size_t size = 0;
+ for (auto const buffer : buffers_range (buffers))
+ size += buffer.size();
+ return size;
+ }
+ @endcode
+
+ @param buffers The buffer sequence to adapt into a range. The
+ range object returned from this function will contain a copy
+ of the passed buffer sequence.
+
+ @return An object of unspecified type which meets the requirements
+ of <em>ConstBufferSequence</em>. If `buffers` is a mutable buffer
+ sequence, the returned object will also meet the requirements of
+ <em>MutableBufferSequence</em>.
+
+ @see buffers_range_ref
+*/
+template<class BufferSequence>
+#if BOOST_BEAST_DOXYGEN
+__implementation_defined__
+#else
+detail::buffers_range_adaptor<BufferSequence>
+#endif
+buffers_range(BufferSequence const& buffers)
+{
+ static_assert(
+ is_const_buffer_sequence<BufferSequence>::value,
+ "BufferSequence type requirements not met");
+ return detail::buffers_range_adaptor<
+ BufferSequence>(buffers);
+}
+
+/** Returns an iterable range representing a buffer sequence.
+
+ This function returns an iterable range representing the
+ passed buffer sequence. The values obtained when iterating
+ the range will be `net::const_buffer`, unless the underlying
+ buffer sequence is a <em>MutableBufferSequence</em>, in which case
+ the value obtained when iterating will be a `net::mutable_buffer`.
+
+ @par Example
+
+ The following function returns the total number of bytes in
+ the specified buffer sequence. A reference to the original
+ buffers is maintained for the lifetime of the range object:
+
+ @code
+ template <class BufferSequence>
+ std::size_t buffer_sequence_size_ref (BufferSequence const& buffers)
+ {
+ std::size_t size = 0;
+ for (auto const buffer : buffers_range_ref (buffers))
+ size += buffer.size();
+ return size;
+ }
+ @endcode
+
+ @param buffers The buffer sequence to adapt into a range. The
+ range returned from this function will maintain a reference to
+ these buffers. The application is responsible for ensuring that
+ the lifetime of the referenced buffers extends until the range
+ object is destroyed.
+
+ @return An object of unspecified type which meets the requirements
+ of <em>ConstBufferSequence</em>. If `buffers` is a mutable buffer
+ sequence, the returned object will also meet the requirements of
+ <em>MutableBufferSequence</em>.
+
+ @see buffers_range
+*/
+template<class BufferSequence>
+#if BOOST_BEAST_DOXYGEN
+__implementation_defined__
+#else
+detail::buffers_range_adaptor<BufferSequence const&>
+#endif
+buffers_range_ref(BufferSequence const& buffers)
+{
+ static_assert(
+ is_const_buffer_sequence<BufferSequence>::value,
+ "BufferSequence type requirements not met");
+ return detail::buffers_range_adaptor<
+ BufferSequence const&>(buffers);
+}
+/** @} */
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/buffers_suffix.hpp b/boost/beast/core/buffers_suffix.hpp
index 3959694577..adf8fd5977 100644
--- a/boost/beast/core/buffers_suffix.hpp
+++ b/boost/beast/core/buffers_suffix.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,8 +11,7 @@
#define BOOST_BEAST_BUFFERS_SUFFIX_HPP
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/detail/type_traits.hpp>
-#include <boost/asio/buffer.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
#include <boost/optional.hpp>
#include <cstdint>
#include <iterator>
@@ -21,12 +20,12 @@
namespace boost {
namespace beast {
-/** Adapter to trim the front of a `BufferSequence`.
+/** Adaptor to progressively trim the front of a <em>BufferSequence</em>.
- This adapter wraps a buffer sequence to create a new sequence
+ This adaptor wraps a buffer sequence to create a new sequence
which may be incrementally consumed. Bytes consumed are removed
from the front of the buffer. The underlying memory is not changed,
- instead the adapter efficiently iterates through a subset of
+ instead the adaptor efficiently iterates through a subset of
the buffers wrapped.
The wrapped buffer is not modified, a copy is made instead.
@@ -45,7 +44,7 @@ namespace beast {
void send(SyncWriteStream& stream, ConstBufferSequence const& buffers)
{
buffers_suffix<ConstBufferSequence> bs{buffers};
- while(boost::asio::buffer_size(bs) > 0)
+ while(buffer_bytes(bs) > 0)
bs.consume(stream.write_some(bs));
}
@endcode
@@ -53,21 +52,18 @@ namespace beast {
template<class BufferSequence>
class buffers_suffix
{
- using buffers_type =
- typename std::decay<BufferSequence>::type;
-
- using iter_type = typename
- detail::buffer_sequence_iterator<buffers_type>::type;
+ using iter_type =
+ buffers_iterator_type<BufferSequence>;
BufferSequence bs_;
- iter_type begin_;
+ iter_type begin_{};
std::size_t skip_ = 0;
template<class Deduced>
buffers_suffix(Deduced&& other, std::size_t dist)
: bs_(std::forward<Deduced>(other).bs_)
, begin_(std::next(
- boost::asio::buffer_sequence_begin(bs_),
+ net::buffer_sequence_begin(bs_),
dist))
, skip_(other.skip_)
{
@@ -76,25 +72,20 @@ class buffers_suffix
public:
/** The type for each element in the list of buffers.
- If the buffers in the underlying sequence are convertible to
- `boost::asio::mutable_buffer`, then this type will be
- `boost::asio::mutable_buffer`, else this type will be
- `boost::asio::const_buffer`.
+ If <em>BufferSequence</em> meets the requirements of
+ <em>MutableBufferSequence</em>, then this type will be
+ `net::mutable_buffer`, otherwise this type will be
+ `net::const_buffer`.
*/
#if BOOST_BEAST_DOXYGEN
- using value_type = implementation_defined;
+ using value_type = __see_below__;
#else
- using value_type = typename std::conditional<
- std::is_convertible<typename
- std::iterator_traits<iter_type>::value_type,
- boost::asio::mutable_buffer>::value,
- boost::asio::mutable_buffer,
- boost::asio::const_buffer>::type;
+ using value_type = buffers_type<BufferSequence>;
#endif
#if BOOST_BEAST_DOXYGEN
/// A bidirectional iterator type that may be used to read elements.
- using const_iterator = implementation_defined;
+ using const_iterator = __implementation_defined__;
#else
class const_iterator;
@@ -104,10 +95,7 @@ public:
/// Constructor
buffers_suffix();
- /// Constructor
- buffers_suffix(buffers_suffix&&);
-
- /// Constructor
+ /// Copy Constructor
buffers_suffix(buffers_suffix const&);
/** Constructor
@@ -126,12 +114,10 @@ public:
@param args Arguments forwarded to the buffers constructor.
*/
template<class... Args>
+ explicit
buffers_suffix(boost::in_place_init_t, Args&&... args);
- /// Assignment
- buffers_suffix& operator=(buffers_suffix&&);
-
- /// Assignment
+ /// Copy Assignment
buffers_suffix& operator=(buffers_suffix const&);
/// Get a bidirectional iterator to the first element.
@@ -155,6 +141,6 @@ public:
} // beast
} // boost
-#include <boost/beast/core/impl/buffers_suffix.ipp>
+#include <boost/beast/core/impl/buffers_suffix.hpp>
#endif
diff --git a/boost/beast/core/buffers_to_string.hpp b/boost/beast/core/buffers_to_string.hpp
index 1c70768ebc..86efa3d3cc 100644
--- a/boost/beast/core/buffers_to_string.hpp
+++ b/boost/beast/core/buffers_to_string.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,7 +11,8 @@
#define BOOST_BEAST_BUFFERS_TO_STRING_HPP
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/beast/core/buffers_range.hpp>
#include <boost/asio/buffer.hpp>
#include <string>
@@ -41,16 +42,17 @@ namespace beast {
@endcode
*/
template<class ConstBufferSequence>
-inline
std::string
buffers_to_string(ConstBufferSequence const& buffers)
{
+ static_assert(
+ net::is_const_buffer_sequence<ConstBufferSequence>::value,
+ "ConstBufferSequence type requirements not met");
std::string result;
- result.reserve(boost::asio::buffer_size(buffers));
- for(boost::asio::const_buffer buffer :
- detail::buffers_range(buffers))
- result.append(static_cast<
- char const*>(buffer.data()), buffer.size());
+ result.reserve(buffer_bytes(buffers));
+ for(auto const buffer : buffers_range_ref(buffers))
+ result.append(static_cast<char const*>(
+ buffer.data()), buffer.size());
return result;
}
diff --git a/boost/beast/core/detail/allocator.hpp b/boost/beast/core/detail/allocator.hpp
index e893f5c274..d6b24ccb09 100644
--- a/boost/beast/core/detail/allocator.hpp
+++ b/boost/beast/core/detail/allocator.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
diff --git a/boost/beast/core/detail/async_base.hpp b/boost/beast/core/detail/async_base.hpp
new file mode 100644
index 0000000000..0224daf703
--- /dev/null
+++ b/boost/beast/core/detail/async_base.hpp
@@ -0,0 +1,46 @@
+//
+// 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_CORE_DETAIL_ASYNC_BASE_HPP
+#define BOOST_BEAST_CORE_DETAIL_ASYNC_BASE_HPP
+
+#include <boost/core/exchange.hpp>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+struct stable_base
+{
+ static
+ void
+ destroy_list(stable_base*& list)
+ {
+ while(list)
+ {
+ auto next = list->next_;
+ list->destroy();
+ list = next;
+ }
+ }
+
+ stable_base* next_ = nullptr;
+
+protected:
+ stable_base() = default;
+ virtual ~stable_base() = default;
+
+ virtual void destroy() = 0;
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/base64.hpp b/boost/beast/core/detail/base64.hpp
index 6cb3f67a77..7f91c04777 100644
--- a/boost/beast/core/detail/base64.hpp
+++ b/boost/beast/core/detail/base64.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -7,39 +7,10 @@
// Official repository: https://github.com/boostorg/beast
//
-/*
- Portions from http://www.adp-gmbh.ch/cpp/common/base64.html
- Copyright notice:
-
- base64.cpp and base64.h
-
- Copyright (C) 2004-2008 Rene Nyffenegger
-
- This source code is provided 'as-is', without any express or implied
- warranty. In no event will the author be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this source code must not be misrepresented; you must not
- claim that you wrote the original source code. If you use this source code
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
-
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original source code.
-
- 3. This notice may not be removed or altered from any source distribution.
-
- Rene Nyffenegger rene.nyffenegger@adp-gmbh.ch
-
-*/
-
#ifndef BOOST_BEAST_DETAIL_BASE64_HPP
#define BOOST_BEAST_DETAIL_BASE64_HPP
+#include <boost/beast/core/string.hpp>
#include <cctype>
#include <string>
#include <utility>
@@ -50,44 +21,16 @@ namespace detail {
namespace base64 {
-inline
+BOOST_BEAST_DECL
char const*
-get_alphabet()
-{
- static char constexpr tab[] = {
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
- };
- return &tab[0];
-}
+get_alphabet();
-inline
+BOOST_BEAST_DECL
signed char const*
-get_inverse()
-{
- static signed char constexpr tab[] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0-15
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 48-63
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80-95
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255
- };
- return &tab[0];
-}
-
+get_inverse();
/// Returns max chars needed to encode a base64 string
-inline
+BOOST_BEAST_DECL
std::size_t constexpr
encoded_size(std::size_t n)
{
@@ -100,7 +43,6 @@ std::size_t constexpr
decoded_size(std::size_t n)
{
return n / 4 * 3; // requires n&3==0, smaller
- //return 3 * n / 4;
}
/** Encode a series of octets as a padded, base64 string.
@@ -115,45 +57,9 @@ decoded_size(std::size_t n)
@return The number of characters written to `out`. This
will exclude any null termination.
*/
-template<class = void>
+BOOST_BEAST_DECL
std::size_t
-encode(void* dest, void const* src, std::size_t len)
-{
- char* out = static_cast<char*>(dest);
- char const* in = static_cast<char const*>(src);
- auto const tab = base64::get_alphabet();
-
- for(auto n = len / 3; n--;)
- {
- *out++ = tab[ (in[0] & 0xfc) >> 2];
- *out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];
- *out++ = tab[((in[2] & 0xc0) >> 6) + ((in[1] & 0x0f) << 2)];
- *out++ = tab[ in[2] & 0x3f];
- in += 3;
- }
-
- switch(len % 3)
- {
- case 2:
- *out++ = tab[ (in[0] & 0xfc) >> 2];
- *out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];
- *out++ = tab[ (in[1] & 0x0f) << 2];
- *out++ = '=';
- break;
-
- case 1:
- *out++ = tab[ (in[0] & 0xfc) >> 2];
- *out++ = tab[((in[0] & 0x03) << 4)];
- *out++ = '=';
- *out++ = '=';
- break;
-
- case 0:
- break;
- }
-
- return out - static_cast<char*>(dest);
-}
+encode(void* dest, void const* src, std::size_t len);
/** Decode a padded base64 string into a series of octets.
@@ -166,75 +72,23 @@ encode(void* dest, void const* src, std::size_t len)
the number of characters read from the input string,
expressed as a pair.
*/
-template<class = void>
+BOOST_BEAST_DECL
std::pair<std::size_t, std::size_t>
-decode(void* dest, char const* src, std::size_t len)
-{
- char* out = static_cast<char*>(dest);
- auto in = reinterpret_cast<unsigned char const*>(src);
- unsigned char c3[3], c4[4];
- int i = 0;
- int j = 0;
-
- auto const inverse = base64::get_inverse();
-
- while(len-- && *in != '=')
- {
- auto const v = inverse[*in];
- if(v == -1)
- break;
- ++in;
- c4[i] = v;
- if(++i == 4)
- {
- c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
- c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
- c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
-
- for(i = 0; i < 3; i++)
- *out++ = c3[i];
- i = 0;
- }
- }
-
- if(i)
- {
- c3[0] = ( c4[0] << 2) + ((c4[1] & 0x30) >> 4);
- c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
- c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
-
- for(j = 0; j < i - 1; j++)
- *out++ = c3[j];
- }
-
- return {out - static_cast<char*>(dest),
- in - reinterpret_cast<unsigned char const*>(src)};
-}
+decode(void* dest, char const* src, std::size_t len);
} // base64
-template<class = void>
+BOOST_BEAST_DECL
std::string
-base64_encode (std::uint8_t const* data,
- std::size_t len)
-{
- std::string dest;
- dest.resize(base64::encoded_size(len));
- dest.resize(base64::encode(&dest[0], data, len));
- return dest;
-}
+base64_encode(std::uint8_t const* data, std::size_t len);
-inline
+BOOST_BEAST_DECL
std::string
-base64_encode(std::string const& s)
-{
- return base64_encode (reinterpret_cast <
- std::uint8_t const*> (s.data()), s.size());
-}
+base64_encode(string_view s);
template<class = void>
std::string
-base64_decode(std::string const& data)
+base64_decode(string_view data)
{
std::string dest;
dest.resize(base64::decoded_size(data.size()));
@@ -248,4 +102,8 @@ base64_decode(std::string const& data)
} // beast
} // boost
+#ifdef BOOST_BEAST_HEADER_ONLY
+#include <boost/beast/core/detail/base64.ipp>
+#endif
+
#endif
diff --git a/boost/beast/core/detail/base64.ipp b/boost/beast/core/detail/base64.ipp
new file mode 100644
index 0000000000..7e11d188b6
--- /dev/null
+++ b/boost/beast/core/detail/base64.ipp
@@ -0,0 +1,220 @@
+//
+// 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
+//
+
+/*
+ Portions from http://www.adp-gmbh.ch/cpp/common/base64.html
+ Copyright notice:
+
+ base64.cpp and base64.h
+
+ Copyright (C) 2004-2008 Rene Nyffenegger
+
+ This source code is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this source code must not be misrepresented; you must not
+ claim that you wrote the original source code. If you use this source code
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original source code.
+
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Rene Nyffenegger rene.nyffenegger@adp-gmbh.ch
+*/
+
+#ifndef BOOST_BEAST_DETAIL_BASE64_IPP
+#define BOOST_BEAST_DETAIL_BASE64_IPP
+
+#include <boost/beast/core/detail/base64.hpp>
+#include <boost/beast/core/string.hpp>
+#include <cctype>
+#include <string>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+namespace base64 {
+
+char const*
+get_alphabet()
+{
+ static char constexpr tab[] = {
+ "ABCDEFGHIJKLMNOP"
+ "QRSTUVWXYZabcdef"
+ "ghijklmnopqrstuv"
+ "wxyz0123456789+/"
+ };
+ return &tab[0];
+}
+
+signed char const*
+get_inverse()
+{
+ static signed char constexpr tab[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0-15
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 48-63
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80-95
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255
+ };
+ return &tab[0];
+}
+
+/** Encode a series of octets as a padded, base64 string.
+
+ The resulting string will not be null terminated.
+
+ @par Requires
+
+ The memory pointed to by `out` points to valid memory
+ of at least `encoded_size(len)` bytes.
+
+ @return The number of characters written to `out`. This
+ will exclude any null termination.
+*/
+std::size_t
+encode(void* dest, void const* src, std::size_t len)
+{
+ char* out = static_cast<char*>(dest);
+ char const* in = static_cast<char const*>(src);
+ auto const tab = base64::get_alphabet();
+
+ for(auto n = len / 3; n--;)
+ {
+ *out++ = tab[ (in[0] & 0xfc) >> 2];
+ *out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];
+ *out++ = tab[((in[2] & 0xc0) >> 6) + ((in[1] & 0x0f) << 2)];
+ *out++ = tab[ in[2] & 0x3f];
+ in += 3;
+ }
+
+ switch(len % 3)
+ {
+ case 2:
+ *out++ = tab[ (in[0] & 0xfc) >> 2];
+ *out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];
+ *out++ = tab[ (in[1] & 0x0f) << 2];
+ *out++ = '=';
+ break;
+
+ case 1:
+ *out++ = tab[ (in[0] & 0xfc) >> 2];
+ *out++ = tab[((in[0] & 0x03) << 4)];
+ *out++ = '=';
+ *out++ = '=';
+ break;
+
+ case 0:
+ break;
+ }
+
+ return out - static_cast<char*>(dest);
+}
+
+/** Decode a padded base64 string into a series of octets.
+
+ @par Requires
+
+ The memory pointed to by `out` points to valid memory
+ of at least `decoded_size(len)` bytes.
+
+ @return The number of octets written to `out`, and
+ the number of characters read from the input string,
+ expressed as a pair.
+*/
+std::pair<std::size_t, std::size_t>
+decode(void* dest, char const* src, std::size_t len)
+{
+ char* out = static_cast<char*>(dest);
+ auto in = reinterpret_cast<unsigned char const*>(src);
+ unsigned char c3[3], c4[4];
+ int i = 0;
+ int j = 0;
+
+ auto const inverse = base64::get_inverse();
+
+ while(len-- && *in != '=')
+ {
+ auto const v = inverse[*in];
+ if(v == -1)
+ break;
+ ++in;
+ c4[i] = v;
+ if(++i == 4)
+ {
+ c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
+ c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
+ c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
+
+ for(i = 0; i < 3; i++)
+ *out++ = c3[i];
+ i = 0;
+ }
+ }
+
+ if(i)
+ {
+ c3[0] = ( c4[0] << 2) + ((c4[1] & 0x30) >> 4);
+ c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
+ c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
+
+ for(j = 0; j < i - 1; j++)
+ *out++ = c3[j];
+ }
+
+ return {out - static_cast<char*>(dest),
+ in - reinterpret_cast<unsigned char const*>(src)};
+}
+
+} // base64
+
+std::string
+base64_encode(
+ std::uint8_t const* data,
+ std::size_t len)
+{
+ std::string dest;
+ dest.resize(base64::encoded_size(len));
+ dest.resize(base64::encode(&dest[0], data, len));
+ return dest;
+}
+
+std::string
+base64_encode(string_view s)
+{
+ return base64_encode (reinterpret_cast <
+ std::uint8_t const*> (s.data()), s.size());
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/bind_continuation.hpp b/boost/beast/core/detail/bind_continuation.hpp
new file mode 100644
index 0000000000..2c4b6e5265
--- /dev/null
+++ b/boost/beast/core/detail/bind_continuation.hpp
@@ -0,0 +1,110 @@
+//
+// 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_BIND_CONTINUATION_HPP
+#define BOOST_BEAST_DETAIL_BIND_CONTINUATION_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/remap_post_to_defer.hpp>
+#include <boost/asio/bind_executor.hpp>
+#include <boost/core/empty_value.hpp>
+#include <type_traits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+#if 0
+/** Mark a completion handler as a continuation.
+
+ This function wraps a completion handler to associate it with an
+ executor whose `post` operation is remapped to the `defer` operation.
+ It is used by composed asynchronous operation implementations to
+ indicate that a completion handler submitted to an initiating
+ function represents a continuation of the current asynchronous
+ flow of control.
+
+ @param handler The handler to wrap.
+ The implementation takes ownership of the handler by performing a decay-copy.
+
+ @see
+
+ @li <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4242.html">[N4242] Executors and Asynchronous Operations, Revision 1</a>
+*/
+template<class CompletionHandler>
+#if BOOST_BEAST_DOXYGEN
+__implementation_defined__
+#else
+net::executor_binder<
+ typename std::decay<CompletionHandler>::type,
+ detail::remap_post_to_defer<
+ net::associated_executor_t<CompletionHandler>>>
+#endif
+bind_continuation(CompletionHandler&& handler)
+{
+ return net::bind_executor(
+ detail::remap_post_to_defer<
+ net::associated_executor_t<CompletionHandler>>(
+ net::get_associated_executor(handler)),
+ std::forward<CompletionHandler>(handler));
+}
+
+/** Mark a completion handler as a continuation.
+
+ This function wraps a completion handler to associate it with an
+ executor whose `post` operation is remapped to the `defer` operation.
+ It is used by composed asynchronous operation implementations to
+ indicate that a completion handler submitted to an initiating
+ function represents a continuation of the current asynchronous
+ flow of control.
+
+ @param ex The executor to use
+
+ @param handler The handler to wrap
+ The implementation takes ownership of the handler by performing a decay-copy.
+
+ @see
+
+ @li <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4242.html">[N4242] Executors and Asynchronous Operations, Revision 1</a>
+*/
+template<class Executor, class CompletionHandler>
+#if BOOST_BEAST_DOXYGEN
+__implementation_defined__
+#else
+net::executor_binder<typename
+ std::decay<CompletionHandler>::type,
+ detail::remap_post_to_defer<Executor>>
+#endif
+bind_continuation(
+ Executor const& ex, CompletionHandler&& handler)
+{
+ return net::bind_executor(
+ detail::remap_post_to_defer<Executor>(ex),
+ std::forward<CompletionHandler>(handler));
+}
+#else
+// VFALCO I turned these off at the last minute because they cause
+// the completion handler to be moved before the initiating
+// function is invoked rather than after, which is a foot-gun.
+//
+// REMINDER: Uncomment the tests when this is put back
+template<class F>
+F&&
+bind_continuation(F&& f)
+{
+ return std::forward<F>(f);
+}
+#endif
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/bind_default_executor.hpp b/boost/beast/core/detail/bind_default_executor.hpp
new file mode 100644
index 0000000000..6fa006e160
--- /dev/null
+++ b/boost/beast/core/detail/bind_default_executor.hpp
@@ -0,0 +1,123 @@
+//
+// 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_CORE_DETAIL_BIND_DEFAULT_EXECUTOR_HPP
+#define BOOST_BEAST_CORE_DETAIL_BIND_DEFAULT_EXECUTOR_HPP
+
+#include <boost/asio/associated_allocator.hpp>
+#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/dispatch.hpp>
+#include <boost/asio/executor.hpp>
+#include <boost/asio/handler_alloc_hook.hpp>
+#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
+#include <boost/core/empty_value.hpp>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<class Handler, class Executor>
+class bind_default_executor_wrapper
+ : private boost::empty_value<Executor>
+{
+ Handler h_;
+
+public:
+ template<class Handler_>
+ bind_default_executor_wrapper(
+ Handler_&& h,
+ Executor const& ex)
+ : boost::empty_value<Executor>(
+ boost::empty_init_t{}, ex)
+ , h_(std::forward<Handler_>(h))
+ {
+ }
+
+ template<class... Args>
+ void
+ operator()(Args&&... args)
+ {
+ h_(std::forward<Args>(args)...);
+ }
+
+ using allocator_type =
+ net::associated_allocator_t<Handler>;
+
+ allocator_type
+ get_allocator() const noexcept
+ {
+ return net::get_associated_allocator(h_);
+ }
+
+ using executor_type =
+ net::associated_executor_t<Handler, Executor>;
+
+ executor_type
+ get_executor() const noexcept
+ {
+ return net::get_associated_executor(
+ h_, this->get());
+ }
+
+ template<class Function>
+ void
+ asio_handler_invoke(Function&& f,
+ bind_default_executor_wrapper* p)
+ {
+ net::dispatch(p->get_executor(), std::move(f));
+ }
+
+ friend
+ void* asio_handler_allocate(
+ std::size_t size, bind_default_executor_wrapper* p)
+ {
+ using net::asio_handler_allocate;
+ return asio_handler_allocate(
+ size, std::addressof(p->h_));
+ }
+
+ friend
+ void asio_handler_deallocate(
+ void* mem, std::size_t size,
+ bind_default_executor_wrapper* p)
+ {
+ using net::asio_handler_deallocate;
+ asio_handler_deallocate(mem, size,
+ std::addressof(p->h_));
+ }
+
+ friend
+ bool asio_handler_is_continuation(
+ bind_default_executor_wrapper* p)
+ {
+ using net::asio_handler_is_continuation;
+ return asio_handler_is_continuation(
+ std::addressof(p->h_));
+ }
+};
+
+template<class Executor, class Handler>
+auto
+bind_default_executor(Executor const& ex, Handler&& h) ->
+ bind_default_executor_wrapper<
+ typename std::decay<Handler>::type,
+ Executor>
+{
+ return bind_default_executor_wrapper<
+ typename std::decay<Handler>::type,
+ Executor>(std::forward<Handler>(h), ex);
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/bind_handler.hpp b/boost/beast/core/detail/bind_handler.hpp
index 8bacc921f7..db481757f9 100644
--- a/boost/beast/core/detail/bind_handler.hpp
+++ b/boost/beast/core/detail/bind_handler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -10,39 +10,44 @@
#ifndef BOOST_BEAST_DETAIL_BIND_HANDLER_HPP
#define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP
-#include <boost/beast/core/detail/integer_sequence.hpp>
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/detail/tuple.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/handler_alloc_hook.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/core/ignore_unused.hpp>
+#include <boost/mp11/integer_sequence.hpp>
#include <boost/is_placeholder.hpp>
#include <functional>
+#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
namespace detail {
-/* Nullary handler that calls Handler with bound arguments.
+//------------------------------------------------------------------------------
+//
+// bind_handler
+//
+//------------------------------------------------------------------------------
- The bound handler provides the same io_context execution
- guarantees as the original handler.
-*/
template<class Handler, class... Args>
-class bound_handler
+class bind_wrapper
{
- // Can't friend partial specializations,
- // so we just friend the whole thing.
- template<class T, class Executor>
- friend struct boost::asio::associated_executor;
-
- using args_type = std::tuple<
- typename std::decay<Args>::type...>;
+ using args_type = detail::tuple<Args...>;
Handler h_;
args_type args_;
+ template<class T, class Executor>
+ friend struct net::associated_executor;
+
+ template<class T, class Allocator>
+ friend struct net::associated_allocator;
+
template<class Arg, class Vals>
static
typename std::enable_if<
@@ -62,13 +67,12 @@ class bound_handler
typename std::enable_if<
std::is_placeholder<typename
std::decay<Arg>::type>::value != 0,
- typename std::tuple_element<
- std::is_placeholder<
- typename std::decay<Arg>::type>::value - 1,
- Vals>>::type::type&&
+ tuple_element<std::is_placeholder<
+ typename std::decay<Arg>::type>::value - 1,
+ Vals>>::type&&
extract(Arg&&, Vals&& vals)
{
- return std::get<std::is_placeholder<
+ return detail::get<std::is_placeholder<
typename std::decay<Arg>::type>::value - 1>(
std::forward<Vals>(vals));
}
@@ -78,30 +82,27 @@ class bound_handler
typename std::enable_if<
boost::is_placeholder<typename
std::decay<Arg>::type>::value != 0,
- typename std::tuple_element<
- boost::is_placeholder<
- typename std::decay<Arg>::type>::value - 1,
- Vals>>::type::type&&
+ tuple_element<boost::is_placeholder<
+ typename std::decay<Arg>::type>::value - 1,
+ Vals>>::type&&
extract(Arg&&, Vals&& vals)
{
- return std::get<boost::is_placeholder<
+ return detail::get<boost::is_placeholder<
typename std::decay<Arg>::type>::value - 1>(
std::forward<Vals>(vals));
}
- template<
- class ArgsTuple,
- std::size_t... S>
+ template<class ArgsTuple, std::size_t... S>
static
void
invoke(
Handler& h,
ArgsTuple& args,
- std::tuple<>&&,
- index_sequence<S...>)
+ tuple<>&&,
+ mp11::index_sequence<S...>)
{
boost::ignore_unused(args);
- h(std::get<S>(std::move(args))...);
+ h(detail::get<S>(std::move(args))...);
}
template<
@@ -114,104 +115,296 @@ class bound_handler
Handler& h,
ArgsTuple& args,
ValsTuple&& vals,
- index_sequence<S...>)
+ mp11::index_sequence<S...>)
{
boost::ignore_unused(args);
boost::ignore_unused(vals);
- h(extract(std::get<S>(std::move(args)),
+ h(extract(detail::get<S>(std::move(args)),
std::forward<ValsTuple>(vals))...);
}
public:
- using result_type = void;
+ using result_type = void; // asio needs this
- using allocator_type =
- boost::asio::associated_allocator_t<Handler>;
+ bind_wrapper(bind_wrapper&&) = default;
+ bind_wrapper(bind_wrapper const&) = default;
- bound_handler(bound_handler&&) = default;
- bound_handler(bound_handler const&) = delete;
-
- template<class DeducedHandler>
+ template<
+ class DeducedHandler,
+ class... Args_>
explicit
- bound_handler(
- DeducedHandler&& handler, Args&&... args)
+ bind_wrapper(
+ DeducedHandler&& handler,
+ Args_&&... args)
: h_(std::forward<DeducedHandler>(handler))
- , args_(std::forward<Args>(args)...)
+ , args_(std::forward<Args_>(args)...)
+ {
+ }
+
+ template<class... Values>
+ void
+ operator()(Values&&... values)
{
+ invoke(h_, args_,
+ tuple<Values&&...>(
+ std::forward<Values>(values)...),
+ mp11::index_sequence_for<Args...>());
}
- allocator_type
- get_allocator() const noexcept
+ //
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(
+ Function&& f, bind_wrapper* op)
{
- return (boost::asio::get_associated_allocator)(h_);
+ using net::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
}
friend
- bool
- asio_handler_is_continuation(bound_handler* h)
+ bool asio_handler_is_continuation(
+ bind_wrapper* op)
{
- using boost::asio::asio_handler_is_continuation;
- return asio_handler_is_continuation(std::addressof(h->h_));
+ using net::asio_handler_is_continuation;
+ return asio_handler_is_continuation(
+ std::addressof(op->h_));
}
- template<class Function>
friend
- void asio_handler_invoke(Function&& f, bound_handler* h)
+ void* asio_handler_allocate(
+ std::size_t size, bind_wrapper* op)
{
- using boost::asio::asio_handler_invoke;
- asio_handler_invoke(f, std::addressof(h->h_));
+ using net::asio_handler_allocate;
+ return asio_handler_allocate(
+ size, std::addressof(op->h_));
}
- template<class... Values>
+ friend
+ void asio_handler_deallocate(
+ void* p, std::size_t size, bind_wrapper* op)
+ {
+ using net::asio_handler_deallocate;
+ asio_handler_deallocate(
+ p, size, std::addressof(op->h_));
+ }
+};
+
+template<class Handler, class... Args>
+class bind_back_wrapper;
+
+template<class Handler, class... Args>
+class bind_front_wrapper;
+
+//------------------------------------------------------------------------------
+//
+// bind_front
+//
+//------------------------------------------------------------------------------
+
+template<class Handler, class... Args>
+class bind_front_wrapper
+{
+ Handler h_;
+ detail::tuple<Args...> args_;
+
+ template<class T, class Executor>
+ friend struct net::associated_executor;
+
+ template<class T, class Allocator>
+ friend struct net::associated_allocator;
+
+ template<std::size_t... I, class... Ts>
void
- operator()(Values&&... values)
+ invoke(
+ std::false_type,
+ mp11::index_sequence<I...>,
+ Ts&&... ts)
{
- invoke(h_, args_,
- std::forward_as_tuple(
- std::forward<Values>(values)...),
- index_sequence_for<Args...>());
+ h_( detail::get<I>(std::move(args_))...,
+ std::forward<Ts>(ts)...);
}
- template<class... Values>
+ template<std::size_t... I, class... Ts>
void
- operator()(Values&&... values) const
+ invoke(
+ std::true_type,
+ mp11::index_sequence<I...>,
+ Ts&&... ts)
{
- invoke(h_, args_,
- std::forward_as_tuple(
- std::forward<Values>(values)...),
- index_sequence_for<Args...>());
+ std::mem_fn(h_)(
+ detail::get<I>(std::move(args_))...,
+ std::forward<Ts>(ts)...);
+ }
+
+public:
+ using result_type = void; // asio needs this
+
+ bind_front_wrapper(bind_front_wrapper&&) = default;
+ bind_front_wrapper(bind_front_wrapper const&) = default;
+
+ template<class Handler_, class... Args_>
+ bind_front_wrapper(
+ Handler_&& handler,
+ Args_&&... args)
+ : h_(std::forward<Handler_>(handler))
+ , args_(std::forward<Args_>(args)...)
+ {
+ }
+
+ template<class... Ts>
+ void operator()(Ts&&... ts)
+ {
+ invoke(
+ std::is_member_function_pointer<Handler>{},
+ mp11::index_sequence_for<Args...>{},
+ std::forward<Ts>(ts)...);
+ }
+
+ //
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(
+ Function&& f, bind_front_wrapper* op)
+ {
+ using net::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
+
+ friend
+ bool asio_handler_is_continuation(
+ bind_front_wrapper* op)
+ {
+ using net::asio_handler_is_continuation;
+ return asio_handler_is_continuation(
+ std::addressof(op->h_));
+ }
+
+ friend
+ void* asio_handler_allocate(
+ std::size_t size, bind_front_wrapper* op)
+ {
+ using net::asio_handler_allocate;
+ return asio_handler_allocate(
+ size, std::addressof(op->h_));
+ }
+
+ friend
+ void asio_handler_deallocate(
+ void* p, std::size_t size, bind_front_wrapper* op)
+ {
+ using net::asio_handler_deallocate;
+ asio_handler_deallocate(
+ p, size, std::addressof(op->h_));
}
};
} // detail
} // beast
+} // boost
+//------------------------------------------------------------------------------
+
+namespace boost {
namespace asio {
+
template<class Handler, class... Args, class Executor>
struct associated_executor<
- beast::detail::bound_handler<Handler, Args...>, Executor>
+ beast::detail::bind_wrapper<Handler, Args...>, Executor>
{
using type = typename
associated_executor<Handler, Executor>::type;
static
type
- get(beast::detail::bound_handler<Handler, Args...> const& h,
- Executor const& ex = Executor()) noexcept
+ get(beast::detail::bind_wrapper<Handler, Args...> const& op,
+ Executor const& ex = Executor{}) noexcept
{
return associated_executor<
- Handler, Executor>::get(h.h_, ex);
+ Handler, Executor>::get(op.h_, ex);
}
};
-} // asio
+template<class Handler, class... Args, class Executor>
+struct associated_executor<
+ beast::detail::bind_front_wrapper<Handler, Args...>, Executor>
+{
+ using type = typename
+ associated_executor<Handler, Executor>::type;
+
+ static
+ type
+ get(beast::detail::bind_front_wrapper<Handler, Args...> const& op,
+ Executor const& ex = Executor{}) noexcept
+ {
+ return associated_executor<
+ Handler, Executor>::get(op.h_, ex);
+ }
+};
+
+//
+
+template<class Handler, class... Args, class Allocator>
+struct associated_allocator<
+ beast::detail::bind_wrapper<Handler, Args...>, Allocator>
+{
+ using type = typename
+ associated_allocator<Handler, Allocator>::type;
+
+ static
+ type
+ get(beast::detail::bind_wrapper<Handler, Args...> const& op,
+ Allocator const& alloc = Allocator{}) noexcept
+ {
+ return associated_allocator<
+ Handler, Allocator>::get(op.h_, alloc);
+ }
+};
+
+template<class Handler, class... Args, class Allocator>
+struct associated_allocator<
+ beast::detail::bind_front_wrapper<Handler, Args...>, Allocator>
+{
+ using type = typename
+ associated_allocator<Handler, Allocator>::type;
+
+ static
+ type
+ get(beast::detail::bind_front_wrapper<Handler, Args...> const& op,
+ Allocator const& alloc = Allocator{}) noexcept
+ {
+ return associated_allocator<
+ Handler, Allocator>::get(op.h_, alloc);
+ }
+};
+
+} // asio
} // boost
+//------------------------------------------------------------------------------
+
namespace std {
+
+// VFALCO Using std::bind on a completion handler will
+// cause undefined behavior later, because the executor
+// associated with the handler is not propagated to the
+// wrapper returned by std::bind; these overloads are
+// deleted to prevent mistakes. If this creates a problem
+// please contact me.
+
template<class Handler, class... Args>
void
-bind(boost::beast::detail::bound_handler<
+bind(boost::beast::detail::bind_wrapper<
Handler, Args...>, ...) = delete;
+
+template<class Handler, class... Args>
+void
+bind(boost::beast::detail::bind_front_wrapper<
+ Handler, Args...>, ...) = delete;
+
} // std
+//------------------------------------------------------------------------------
+
#endif
diff --git a/boost/beast/core/detail/buffer.hpp b/boost/beast/core/detail/buffer.hpp
index d359d10059..c898d95c61 100644
--- a/boost/beast/core/detail/buffer.hpp
+++ b/boost/beast/core/detail/buffer.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -39,7 +39,7 @@ dynamic_buffer_prepare_noexcept(
boost::optional<typename
DynamicBuffer::mutable_buffers_type> result;
result.emplace(buffer.prepare(size));
- ec.assign(0, ec.category());
+ ec = {};
return result;
}
@@ -61,7 +61,7 @@ dynamic_buffer_prepare(
boost::optional<typename
DynamicBuffer::mutable_buffers_type> result;
result.emplace(buffer.prepare(size));
- ec.assign(0, ec.category());
+ ec = {};
return result;
}
catch(std::length_error const&)
diff --git a/boost/beast/core/detail/buffer_traits.hpp b/boost/beast/core/detail/buffer_traits.hpp
new file mode 100644
index 0000000000..a50aa5d80d
--- /dev/null
+++ b/boost/beast/core/detail/buffer_traits.hpp
@@ -0,0 +1,98 @@
+//
+// 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_BUFFER_TRAITS_HPP
+#define BOOST_BEAST_DETAIL_BUFFER_TRAITS_HPP
+
+#include <boost/asio/buffer.hpp>
+#include <boost/config/workaround.hpp>
+#include <boost/type_traits/make_void.hpp>
+#include <cstdint>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+
+template<class T>
+struct buffers_iterator_type_helper
+{
+ using type = decltype(
+ net::buffer_sequence_begin(
+ std::declval<T const&>()));
+};
+
+template<>
+struct buffers_iterator_type_helper<
+ net::const_buffer>
+{
+ using type = net::const_buffer const*;
+};
+
+template<>
+struct buffers_iterator_type_helper<
+ net::mutable_buffer>
+{
+ using type = net::mutable_buffer const*;
+};
+
+#endif
+
+struct buffer_bytes_impl
+{
+ std::size_t
+ operator()(net::const_buffer b) const noexcept
+ {
+ return net::const_buffer(b).size();
+ }
+
+ std::size_t
+ operator()(net::mutable_buffer b) const noexcept
+ {
+ return net::mutable_buffer(b).size();
+ }
+
+ template<
+ class B,
+ class = typename std::enable_if<
+ net::is_const_buffer_sequence<B>::value>::type>
+ std::size_t
+ operator()(B const& b) const noexcept
+ {
+ using net::buffer_size;
+ return buffer_size(b);
+ }
+};
+
+/** Return `true` if a buffer sequence is empty
+
+ This is sometimes faster than using @ref buffer_bytes
+*/
+template<class ConstBufferSequence>
+bool
+buffers_empty(ConstBufferSequence const& buffers)
+{
+ auto it = net::buffer_sequence_begin(buffers);
+ auto end = net::buffer_sequence_end(buffers);
+ while(it != end)
+ {
+ if(net::const_buffer(*it).size() > 0)
+ return false;
+ ++it;
+ }
+ return true;
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/buffers_pair.hpp b/boost/beast/core/detail/buffers_pair.hpp
new file mode 100644
index 0000000000..d8e6505d36
--- /dev/null
+++ b/boost/beast/core/detail/buffers_pair.hpp
@@ -0,0 +1,115 @@
+//
+// 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_BUFFERS_PAIR_HPP
+#define BOOST_BEAST_DETAIL_BUFFERS_PAIR_HPP
+
+#include <boost/asio/buffer.hpp>
+#include <boost/assert.hpp>
+#include <boost/config/workaround.hpp>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+# pragma warning (push)
+# pragma warning (disable: 4521) // multiple copy constructors specified
+# pragma warning (disable: 4522) // multiple assignment operators specified
+#endif
+
+template<bool isMutable>
+class buffers_pair
+{
+public:
+ // VFALCO: This type is public otherwise
+ // asio::buffers_iterator won't compile.
+ using value_type = typename
+ std::conditional<isMutable,
+ net::mutable_buffer,
+ net::const_buffer>::type;
+
+ using const_iterator = value_type const*;
+
+ buffers_pair() = default;
+
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+ buffers_pair(buffers_pair const& other)
+ : buffers_pair(
+ *other.begin(), *(other.begin() + 1))
+ {
+ }
+
+ buffers_pair&
+ operator=(buffers_pair const& other)
+ {
+ b_[0] = *other.begin();
+ b_[1] = *(other.begin() + 1);
+ return *this;
+ }
+#else
+ buffers_pair(buffers_pair const& other) = default;
+ buffers_pair& operator=(buffers_pair const& other) = default;
+#endif
+
+ template<
+ bool isMutable_ = isMutable,
+ class = typename std::enable_if<
+ ! isMutable_>::type>
+ buffers_pair(buffers_pair<true> const& other)
+ : buffers_pair(
+ *other.begin(), *(other.begin() + 1))
+ {
+ }
+
+ template<
+ bool isMutable_ = isMutable,
+ class = typename std::enable_if<
+ ! isMutable_>::type>
+ buffers_pair&
+ operator=(buffers_pair<true> const& other)
+ {
+ b_[0] = *other.begin();
+ b_[1] = *(other.begin() + 1);
+ return *this;
+ }
+
+ buffers_pair(value_type b0, value_type b1)
+ : b_{b0, b1}
+ {
+ }
+
+ const_iterator
+ begin() const noexcept
+ {
+ return &b_[0];
+ }
+
+ const_iterator
+ end() const noexcept
+ {
+ if(b_[1].size() > 0)
+ return &b_[2];
+ return &b_[1];
+ }
+
+private:
+ value_type b_[2];
+};
+
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+# pragma warning (pop)
+#endif
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/buffers_range_adaptor.hpp b/boost/beast/core/detail/buffers_range_adaptor.hpp
new file mode 100644
index 0000000000..2e04d14f6d
--- /dev/null
+++ b/boost/beast/core/detail/buffers_range_adaptor.hpp
@@ -0,0 +1,142 @@
+//
+// 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_BUFFERS_RANGE_ADAPTOR_HPP
+#define BOOST_BEAST_DETAIL_BUFFERS_RANGE_ADAPTOR_HPP
+
+#include <boost/beast/core/buffer_traits.hpp>
+#include <iterator>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<class BufferSequence>
+class buffers_range_adaptor
+{
+ BufferSequence b_;
+
+public:
+#if BOOST_BEAST_DOXYGEN
+ using value_type = __see_below__;
+#else
+ using value_type = buffers_type<BufferSequence>;
+#endif
+
+ class const_iterator
+ {
+ friend class buffers_range_adaptor;
+
+ using iter_type =
+ buffers_iterator_type<BufferSequence>;
+
+ iter_type it_{};
+ buffers_range_adaptor const* b_ = nullptr;
+
+ const_iterator(
+ buffers_range_adaptor const& b,
+ iter_type const& it)
+ : it_(it)
+ , b_(&b)
+ {
+ }
+
+ public:
+ using value_type = typename
+ buffers_range_adaptor::value_type;
+ using pointer = value_type const*;
+ using reference = value_type;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category =
+ std::bidirectional_iterator_tag;
+
+ const_iterator() = default;
+
+ bool
+ operator==(const_iterator const& other) const
+ {
+ return b_ == other.b_ && it_ == other.it_;
+ }
+
+ bool
+ operator!=(const_iterator const& other) const
+ {
+ return !(*this == other);
+ }
+
+ reference
+ operator*() const
+ {
+ return *it_;
+ }
+
+ pointer
+ operator->() const = delete;
+
+ const_iterator&
+ operator++()
+ {
+ ++it_;
+ return *this;
+ }
+
+ const_iterator
+ operator++(int)
+ {
+ auto temp = *this;
+ ++(*this);
+ return temp;
+ }
+
+ const_iterator&
+ operator--()
+ {
+ --it_;
+ return *this;
+ }
+
+ const_iterator
+ operator--(int)
+ {
+ auto temp = *this;
+ --(*this);
+ return temp;
+ }
+ };
+
+ buffers_range_adaptor(
+ buffers_range_adaptor const&) = default;
+ buffers_range_adaptor& operator=(
+ buffers_range_adaptor const&) = default;
+
+ explicit
+ buffers_range_adaptor(BufferSequence const& b)
+ : b_(b)
+ {
+ }
+
+ const_iterator
+ begin() const noexcept
+ {
+ return {*this, net::buffer_sequence_begin(b_)};
+ }
+
+ const_iterator
+ end() const noexcept
+ {
+ return {*this, net::buffer_sequence_end(b_)};
+ }
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/buffers_ref.hpp b/boost/beast/core/detail/buffers_ref.hpp
index e56a9764fd..a4f60248b4 100644
--- a/boost/beast/core/detail/buffers_ref.hpp
+++ b/boost/beast/core/detail/buffers_ref.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -10,8 +10,9 @@
#ifndef BOOST_BEAST_DETAIL_BUFFERS_REF_HPP
#define BOOST_BEAST_DETAIL_BUFFERS_REF_HPP
-#include <boost/beast/core/type_traits.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
#include <iterator>
+#include <memory>
namespace boost {
namespace beast {
@@ -24,11 +25,11 @@ class buffers_ref
BufferSequence const* buffers_;
public:
- using const_iterator = typename
- buffer_sequence_iterator<BufferSequence>::type;
+ using const_iterator =
+ buffers_iterator_type<BufferSequence>;
- using value_type = typename std::iterator_traits<
- const_iterator>::value_type;
+ using value_type = typename
+ std::iterator_traits<const_iterator>::value_type;
buffers_ref(buffers_ref const&) = default;
buffers_ref& operator=(buffers_ref const&) = default;
@@ -42,13 +43,13 @@ public:
const_iterator
begin() const
{
- return boost::asio::buffer_sequence_begin(*buffers_);
+ return net::buffer_sequence_begin(*buffers_);
}
const_iterator
end() const
{
- return boost::asio::buffer_sequence_end(*buffers_);
+ return net::buffer_sequence_end(*buffers_);
}
};
@@ -57,6 +58,9 @@ template<class BufferSequence>
buffers_ref<BufferSequence>
make_buffers_ref(BufferSequence const& buffers)
{
+ static_assert(
+ is_const_buffer_sequence<BufferSequence>::value,
+ "BufferSequence type requirements not met");
return buffers_ref<BufferSequence>(buffers);
}
diff --git a/boost/beast/core/detail/chacha.hpp b/boost/beast/core/detail/chacha.hpp
index 976ade5607..d13e323309 100644
--- a/boost/beast/core/detail/chacha.hpp
+++ b/boost/beast/core/detail/chacha.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -35,7 +35,6 @@
#include <cstdint>
#include <limits>
-#include <iosfwd>
namespace boost {
namespace beast {
@@ -44,150 +43,81 @@ namespace detail {
template<std::size_t R>
class chacha
{
- void generate_block();
- void chacha_core();
-
alignas(16) std::uint32_t block_[16];
std::uint32_t keysetup_[8];
std::uint64_t ctr_ = 0;
int idx_ = 16;
-public:
- static constexpr std::size_t state_size = sizeof(chacha::keysetup_);
-
- using result_type = std::uint32_t;
-
- chacha(std::uint32_t const* v, std::uint64_t stream);
-
- std::uint32_t
- operator()();
-
-#if 0
- template<std::size_t R_>
- friend
- bool
- operator==(chacha<R_> const& lhs, chacha<R_> const& rhs);
-
- template<std::size_t R_>
- friend
- bool
- operator!=(chacha<R_> const& lhs, chacha<R_> const& rhs);
-
- static
- constexpr
- std::uint32_t
- min()
+ void generate_block()
{
- return (std::numeric_limits<std::uint32_t>::min)();
+ std::uint32_t constexpr constants[4] = {
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
+ std::uint32_t input[16];
+ for (int i = 0; i < 4; ++i)
+ input[i] = constants[i];
+ for (int i = 0; i < 8; ++i)
+ input[4 + i] = keysetup_[i];
+ input[12] = (ctr_ / 16) & 0xffffffffu;
+ input[13] = (ctr_ / 16) >> 32;
+ input[14] = input[15] = 0xdeadbeef; // Could use 128-bit counter.
+ for (int i = 0; i < 16; ++i)
+ block_[i] = input[i];
+ chacha_core();
+ for (int i = 0; i < 16; ++i)
+ block_[i] += input[i];
}
- static
- constexpr
- std::uint32_t
- max()
+ void chacha_core()
{
- return (std::numeric_limits<std::uint32_t>::max)();
+ #define BOOST_BEAST_CHACHA_ROTL32(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ #define BOOST_BEAST_CHACHA_QUARTERROUND(x, a, b, c, d) \
+ x[a] = x[a] + x[b]; x[d] ^= x[a]; x[d] = BOOST_BEAST_CHACHA_ROTL32(x[d], 16); \
+ x[c] = x[c] + x[d]; x[b] ^= x[c]; x[b] = BOOST_BEAST_CHACHA_ROTL32(x[b], 12); \
+ x[a] = x[a] + x[b]; x[d] ^= x[a]; x[d] = BOOST_BEAST_CHACHA_ROTL32(x[d], 8); \
+ x[c] = x[c] + x[d]; x[b] ^= x[c]; x[b] = BOOST_BEAST_CHACHA_ROTL32(x[b], 7)
+
+ for (unsigned i = 0; i < R; i += 2)
+ {
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 0, 4, 8, 12);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 1, 5, 9, 13);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 2, 6, 10, 14);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 3, 7, 11, 15);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 0, 5, 10, 15);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 1, 6, 11, 12);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 2, 7, 8, 13);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 3, 4, 9, 14);
+ }
+
+ #undef BOOST_BEAST_CHACHA_QUARTERROUND
+ #undef BOOST_BEAST_CHACHA_ROTL32
}
-#endif
-};
-template<std::size_t R>
-chacha<R>::
-chacha(std::uint32_t const* v, std::uint64_t stream)
-{
- for (int i = 0; i < 6; ++i)
- keysetup_[i] = v[i];
- keysetup_[6] = v[6] + (stream & 0xffffffff);
- keysetup_[7] = v[7] + ((stream >> 32) & 0xffffffff);
-}
+public:
+ static constexpr std::size_t state_size = sizeof(chacha::keysetup_);
-template<std::size_t R>
-std::uint32_t
-chacha<R>::
-operator()()
-{
- if(idx_ == 16)
+ using result_type = std::uint32_t;
+
+ chacha(std::uint32_t const* v, std::uint64_t stream)
{
- idx_ = 0;
- ++ctr_;
- generate_block();
+ for (int i = 0; i < 6; ++i)
+ keysetup_[i] = v[i];
+ keysetup_[6] = v[6] + (stream & 0xffffffff);
+ keysetup_[7] = v[7] + ((stream >> 32) & 0xffffffff);
}
- return block_[idx_++];
-}
-template<std::size_t R>
-void
-chacha<R>::
-generate_block()
-{
- std::uint32_t constexpr constants[4] = {
- 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
- std::uint32_t input[16];
- for (int i = 0; i < 4; ++i)
- input[i] = constants[i];
- for (int i = 0; i < 8; ++i)
- input[4 + i] = keysetup_[i];
- input[12] = (ctr_ / 16) & 0xffffffffu;
- input[13] = (ctr_ / 16) >> 32;
- input[14] = input[15] = 0xdeadbeef; // Could use 128-bit counter.
- for (int i = 0; i < 16; ++i)
- block_[i] = input[i];
- chacha_core();
- for (int i = 0; i < 16; ++i)
- block_[i] += input[i];
-}
-
-template<std::size_t R>
-void
-chacha<R>::
-chacha_core()
-{
- #define BOOST_BEAST_CHACHA_ROTL32(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
- #define BOOST_BEAST_CHACHA_QUARTERROUND(x, a, b, c, d) \
- x[a] = x[a] + x[b]; x[d] ^= x[a]; x[d] = BOOST_BEAST_CHACHA_ROTL32(x[d], 16); \
- x[c] = x[c] + x[d]; x[b] ^= x[c]; x[b] = BOOST_BEAST_CHACHA_ROTL32(x[b], 12); \
- x[a] = x[a] + x[b]; x[d] ^= x[a]; x[d] = BOOST_BEAST_CHACHA_ROTL32(x[d], 8); \
- x[c] = x[c] + x[d]; x[b] ^= x[c]; x[b] = BOOST_BEAST_CHACHA_ROTL32(x[b], 7)
-
- for (unsigned i = 0; i < R; i += 2)
+ std::uint32_t
+ operator()()
{
- BOOST_BEAST_CHACHA_QUARTERROUND(block_, 0, 4, 8, 12);
- BOOST_BEAST_CHACHA_QUARTERROUND(block_, 1, 5, 9, 13);
- BOOST_BEAST_CHACHA_QUARTERROUND(block_, 2, 6, 10, 14);
- BOOST_BEAST_CHACHA_QUARTERROUND(block_, 3, 7, 11, 15);
- BOOST_BEAST_CHACHA_QUARTERROUND(block_, 0, 5, 10, 15);
- BOOST_BEAST_CHACHA_QUARTERROUND(block_, 1, 6, 11, 12);
- BOOST_BEAST_CHACHA_QUARTERROUND(block_, 2, 7, 8, 13);
- BOOST_BEAST_CHACHA_QUARTERROUND(block_, 3, 4, 9, 14);
+ if(idx_ == 16)
+ {
+ idx_ = 0;
+ ++ctr_;
+ generate_block();
+ }
+ return block_[idx_++];
}
-
- #undef BOOST_BEAST_CHACHA_QUARTERROUND
- #undef BOOST_BEAST_CHACHA_ROTL32
-}
-
-//#endif
-
-#if 0
-// Implement <random> interface.
-
-template<std::size_t R>
-bool
-operator==(chacha<R> const& lhs, chacha<R> const& rhs)
-{
- for (int i = 0; i < 8; ++i)
- if (lhs.keysetup_[i] != rhs.keysetup_[i])
- return false;
- return lhs.ctr_ == rhs.ctr_;
-}
-
-template<std::size_t R>
-bool
-operator!=(chacha<R> const& lhs, chacha<R> const& rhs)
-{
- return !(lhs == rhs);
-}
-#endif
+};
} // detail
} // beast
diff --git a/boost/beast/core/detail/clamp.hpp b/boost/beast/core/detail/clamp.hpp
index 95a8fab425..0ec2768caa 100644
--- a/boost/beast/core/detail/clamp.hpp
+++ b/boost/beast/core/detail/clamp.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
diff --git a/boost/beast/core/detail/config.hpp b/boost/beast/core/detail/config.hpp
index 68e3dda8ee..bebe8c79ef 100644
--- a/boost/beast/core/detail/config.hpp
+++ b/boost/beast/core/detail/config.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -10,14 +10,21 @@
#ifndef BOOST_BEAST_CORE_DETAIL_CONFIG_HPP
#define BOOST_BEAST_CORE_DETAIL_CONFIG_HPP
-#include <boost/config.hpp>
-#include <boost/version.hpp>
-
// Available to every header
#include <boost/config.hpp>
+#include <boost/version.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/static_assert.hpp>
+namespace boost {
+namespace asio
+{
+} // asio
+namespace beast {
+namespace net = boost::asio;
+} // beast
+} // boost
+
/*
_MSC_VER and _MSC_FULL_VER by version:
@@ -51,4 +58,39 @@
#define BOOST_BEAST_DEPRECATION_STRING \
"This is a deprecated interface, #define BOOST_BEAST_ALLOW_DEPRECATED to allow it"
+#ifndef BOOST_BEAST_ASSUME
+# ifdef BOOST_GCC
+# define BOOST_BEAST_ASSUME(cond) \
+ do { if (!(cond)) __builtin_unreachable(); } while (0)
+# else
+# define BOOST_BEAST_ASSUME(cond) do { } while(0)
+# endif
+#endif
+
+// Default to a header-only implementation. The user must specifically
+// request separate compilation by defining BOOST_BEAST_SEPARATE_COMPILATION
+#ifndef BOOST_BEAST_HEADER_ONLY
+# ifndef BOOST_BEAST_SEPARATE_COMPILATION
+# define BOOST_BEAST_HEADER_ONLY 1
+# endif
+#endif
+
+#if BOOST_BEAST_DOXYGEN
+# define BOOST_BEAST_DECL
+#elif defined(BOOST_BEAST_HEADER_ONLY)
+# define BOOST_BEAST_DECL inline
+#else
+# define BOOST_BEAST_DECL
+#endif
+
+#ifndef BOOST_BEAST_ASYNC_RESULT1
+#define BOOST_BEAST_ASYNC_RESULT1(type) \
+ BOOST_ASIO_INITFN_RESULT_TYPE(type, void(::boost::beast::error_code))
+#endif
+
+#ifndef BOOST_BEAST_ASYNC_RESULT2
+#define BOOST_BEAST_ASYNC_RESULT2(type) \
+ BOOST_ASIO_INITFN_RESULT_TYPE(type, void(::boost::beast::error_code, std::size_t))
+#endif
+
#endif
diff --git a/boost/beast/core/detail/flat_stream.hpp b/boost/beast/core/detail/flat_stream.hpp
new file mode 100644
index 0000000000..59f00e970c
--- /dev/null
+++ b/boost/beast/core/detail/flat_stream.hpp
@@ -0,0 +1,73 @@
+//
+// 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_CORE_DETAIL_FLAT_STREAM_HPP
+#define BOOST_BEAST_CORE_DETAIL_FLAT_STREAM_HPP
+
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/asio/buffer.hpp>
+#include <cstdlib>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+class flat_stream_base
+{
+public:
+ // Largest buffer size we will flatten.
+ // 16KB is the upper limit on reasonably sized HTTP messages.
+ static std::size_t constexpr max_size = 16 * 1024;
+
+ // Largest stack we will use to flatten
+ static std::size_t constexpr max_stack = 8 * 1024;
+
+ struct flatten_result
+ {
+ std::size_t size;
+ bool flatten;
+ };
+
+ // calculates the flatten settings for a buffer sequence
+ template<class BufferSequence>
+ static
+ flatten_result
+ flatten(
+ BufferSequence const& buffers, std::size_t limit)
+ {
+ flatten_result result{0, false};
+ auto first = net::buffer_sequence_begin(buffers);
+ auto last = net::buffer_sequence_end(buffers);
+ if(first != last)
+ {
+ result.size = buffer_bytes(*first);
+ if(result.size < limit)
+ {
+ auto it = first;
+ auto prev = first;
+ while(++it != last)
+ {
+ auto const n = buffer_bytes(*it);
+ if(result.size + n > limit)
+ break;
+ result.size += n;
+ prev = it;
+ }
+ result.flatten = prev != first;
+ }
+ }
+ return result;
+ }
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/get_io_context.hpp b/boost/beast/core/detail/get_io_context.hpp
new file mode 100644
index 0000000000..27c816ea43
--- /dev/null
+++ b/boost/beast/core/detail/get_io_context.hpp
@@ -0,0 +1,107 @@
+//
+// 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_GET_IO_CONTEXT_HPP
+#define BOOST_BEAST_DETAIL_GET_IO_CONTEXT_HPP
+
+#include <boost/beast/core/stream_traits.hpp>
+#include <boost/asio/executor.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/strand.hpp>
+#include <memory>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+//------------------------------------------------------------------------------
+
+inline
+net::io_context*
+get_io_context(net::io_context& ioc)
+{
+ return std::addressof(ioc);
+}
+
+inline
+net::io_context*
+get_io_context(net::io_context::executor_type const& ex)
+{
+ return std::addressof(ex.context());
+}
+
+inline
+net::io_context*
+get_io_context(net::strand<
+ net::io_context::executor_type> const& ex)
+{
+ return std::addressof(
+ ex.get_inner_executor().context());
+}
+
+template<class Executor>
+net::io_context*
+get_io_context(net::strand<Executor> const& ex)
+{
+ return get_io_context(ex.get_inner_executor());
+}
+
+template<
+ class T,
+ class = typename std::enable_if<
+ std::is_same<T, net::executor>::value>::type>
+net::io_context*
+get_io_context(T const& ex)
+{
+ auto p = ex.template target<typename
+ net::io_context::executor_type>();
+ if(! p)
+ return nullptr;
+ return std::addressof(p->context());
+}
+
+inline
+net::io_context*
+get_io_context(...)
+{
+ return nullptr;
+}
+
+//------------------------------------------------------------------------------
+
+template<class T>
+net::io_context*
+get_io_context_impl(T& t, std::true_type)
+{
+ return get_io_context(
+ t.get_executor());
+}
+
+template<class T>
+net::io_context*
+get_io_context_impl(T const&, std::false_type)
+{
+ return nullptr;
+}
+
+// Returns the io_context*, or nullptr, for any object.
+template<class T>
+net::io_context*
+get_io_context(T& t)
+{
+ return get_io_context_impl(t,
+ has_get_executor<T>{});
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
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
diff --git a/boost/beast/core/detail/integer_sequence.hpp b/boost/beast/core/detail/integer_sequence.hpp
deleted file mode 100644
index 71664229af..0000000000
--- a/boost/beast/core/detail/integer_sequence.hpp
+++ /dev/null
@@ -1,143 +0,0 @@
-//
-// 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_DETAIL_INTEGER_SEQUENCE_HPP
-#define BOOST_BEAST_DETAIL_INTEGER_SEQUENCE_HPP
-
-#include <boost/config.hpp>
-#include <cstddef>
-#include <type_traits>
-#include <utility>
-
-namespace boost {
-namespace beast {
-namespace detail {
-
-template<class T, T... Ints>
-struct integer_sequence
-{
- using value_type = T;
- BOOST_STATIC_ASSERT(std::is_integral<T>::value);
-
- static std::size_t constexpr static_size = sizeof...(Ints);
-
- static std::size_t constexpr size()
- {
- return sizeof...(Ints);
- }
-};
-
-template<std::size_t... Ints>
-using index_sequence = integer_sequence<std::size_t, Ints...>;
-
-// This workaround is needed for broken sizeof...
-template<class... Args>
-struct sizeof_workaround
-{
- static std::size_t constexpr size = sizeof... (Args);
-};
-
-#ifdef BOOST_MSVC
-
-// This implementation compiles on real MSVC and clang but not gcc
-
-template<class T, unsigned long long N, class Seq>
-struct make_integer_sequence_unchecked;
-
-template<class T, unsigned long long N, unsigned long long ...Indices>
-struct make_integer_sequence_unchecked<
- T, N, integer_sequence<T, Indices...>>
-{
- using type = typename make_integer_sequence_unchecked<
- T, N-1, integer_sequence<T, N-1, Indices...>>::type;
-};
-
-template<class T, unsigned long long ...Indices>
-struct make_integer_sequence_unchecked<
- T, 0, integer_sequence<T, Indices...>>
-{
- using type = integer_sequence<T, Indices...>;
-};
-
-template<class T, T N>
-struct make_integer_sequence_checked
-{
- BOOST_STATIC_ASSERT(std::is_integral<T>::value);
- BOOST_STATIC_ASSERT(N >= 0);
-
- using type = typename make_integer_sequence_unchecked<
- T, N, integer_sequence<T>>::type;
-};
-
-template<class T, T N>
-using make_integer_sequence =
- typename make_integer_sequence_checked<T, N>::type;
-
-template<std::size_t N>
-using make_index_sequence = make_integer_sequence<std::size_t, N>;
-
-template<class... Args>
-using index_sequence_for =
- make_index_sequence<sizeof_workaround<Args...>::size>;
-
-#else
-
-// This implementation compiles on gcc but not MSVC
-
-template<std::size_t... Ints>
-struct index_tuple
-{
- using next = index_tuple<Ints..., sizeof... (Ints)>;
-
-};
-
-template<std::size_t N>
-struct build_index_tuple
-{
- using type = typename build_index_tuple<N-1>::type::next;
-};
-
-template<>
-struct build_index_tuple<0>
-{
- using type = index_tuple<>;
-};
-
-template<class T, T N,
- class Seq = typename build_index_tuple<N>::type
->
-struct integer_sequence_helper;
-
-template<class T, T N, std::size_t... Ints>
-struct integer_sequence_helper<T, N, index_tuple<Ints...>>
-{
- BOOST_STATIC_ASSERT(std::is_integral<T>::value);
- BOOST_STATIC_ASSERT(N >= 0);
-
- using type = integer_sequence<T, static_cast<T> (Ints)...>;
-};
-
-template<class T, T N>
-using make_integer_sequence =
- typename integer_sequence_helper<T, N>::type;
-
-template<std::size_t N>
-using make_index_sequence = make_integer_sequence<std::size_t, N>;
-
-template<class... Args>
-using index_sequence_for =
- make_index_sequence<sizeof_workaround<Args...>::size>;
-
-#endif
-
-} // detail
-} // beast
-} // boost
-
-#endif
diff --git a/boost/beast/core/detail/is_invocable.hpp b/boost/beast/core/detail/is_invocable.hpp
new file mode 100644
index 0000000000..65f1b6c842
--- /dev/null
+++ b/boost/beast/core/detail/is_invocable.hpp
@@ -0,0 +1,58 @@
+//
+// 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_IS_INVOCABLE_HPP
+#define BOOST_BEAST_DETAIL_IS_INVOCABLE_HPP
+
+#include <type_traits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<class R, class C, class ...A>
+auto
+is_invocable_test(C&& c, int, A&& ...a)
+ -> decltype(std::is_convertible<
+ decltype(c(std::forward<A>(a)...)), R>::value ||
+ std::is_same<R, void>::value,
+ std::true_type());
+
+template<class R, class C, class ...A>
+std::false_type
+is_invocable_test(C&& c, long, A&& ...a);
+
+/** Metafunction returns `true` if F callable as R(A...)
+
+ Example:
+
+ @code
+ is_invocable<T, void(std::string)>::value
+ @endcode
+*/
+/** @{ */
+template<class C, class F>
+struct is_invocable : std::false_type
+{
+};
+
+template<class C, class R, class ...A>
+struct is_invocable<C, R(A...)>
+ : decltype(is_invocable_test<R>(
+ std::declval<C>(), 1, std::declval<A>()...))
+{
+};
+/** @} */
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/ostream.hpp b/boost/beast/core/detail/ostream.hpp
index 6b921367d8..65da560179 100644
--- a/boost/beast/core/detail/ostream.hpp
+++ b/boost/beast/core/detail/ostream.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,11 +11,12 @@
#define BOOST_BEAST_DETAIL_OSTREAM_HPP
#include <boost/beast/core/buffers_prefix.hpp>
-#include <boost/beast/core/read_size.hpp>
+#include <boost/beast/core/buffers_range.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/throw_exception.hpp>
#include <boost/asio/buffer.hpp>
#include <memory>
-#include <iosfwd>
+#include <ostream>
#include <streambuf>
#include <type_traits>
#include <utility>
@@ -24,37 +25,6 @@ namespace boost {
namespace beast {
namespace detail {
-template<class Buffers>
-class buffers_helper
-{
- Buffers b_;
-
-public:
- explicit
- buffers_helper(Buffers const& b)
- : b_(b)
- {
- }
-
- template<class B>
- friend
- std::ostream&
- operator<<(std::ostream& os,
- buffers_helper<B> const& v);
-};
-
-template<class Buffers>
-std::ostream&
-operator<<(std::ostream& os,
- buffers_helper<Buffers> const& v)
-{
- for(auto b : buffers_range(v.b_))
- os.write(static_cast<char const*>(b.data()), b.size());
- return os;
-}
-
-//------------------------------------------------------------------------------
-
struct basic_streambuf_movable_helper :
std::basic_streambuf<char, std::char_traits<char>>
{
@@ -65,12 +35,12 @@ struct basic_streambuf_movable_helper :
using basic_streambuf_movable =
std::is_move_constructible<basic_streambuf_movable_helper>;
-//------------------------------------------------------------------------------
-
template<class DynamicBuffer,
class CharT, class Traits, bool isMovable>
class ostream_buffer;
+//------------------------------------------------------------------------------
+
template<class DynamicBuffer, class CharT, class Traits>
class ostream_buffer
<DynamicBuffer, CharT, Traits, true>
@@ -82,9 +52,7 @@ class ostream_buffer
using traits_type = typename
std::basic_streambuf<CharT, Traits>::traits_type;
- static std::size_t constexpr max_size = 512;
-
- DynamicBuffer& buf_;
+ DynamicBuffer& b_;
public:
ostream_buffer(ostream_buffer&&) = default;
@@ -96,56 +64,48 @@ public:
}
explicit
- ostream_buffer(DynamicBuffer& buf)
- : buf_(buf)
+ ostream_buffer(DynamicBuffer& b)
+ : b_(b)
{
- prepare();
}
int_type
overflow(int_type ch) override
{
- if(! Traits::eq_int_type(ch, Traits::eof()))
- {
- Traits::assign(*this->pptr(),
- static_cast<CharT>(ch));
- flush(1);
- prepare();
- return ch;
- }
- flush();
- return traits_type::eof();
- }
-
- int
- sync() override
- {
- flush();
- prepare();
- return 0;
- }
+ BOOST_ASSERT(! Traits::eq_int_type(
+ ch, Traits::eof()));
+ sync();
-private:
- void
- prepare()
- {
- auto bs = buf_.prepare(
- read_size_or_throw(buf_, max_size));
+ static std::size_t constexpr max_size = 65536;
+ auto const 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)
+ return Traits::eof();
+ auto const bs = b_.prepare(max_prepare);
auto const b = buffers_front(bs);
auto const p = static_cast<CharT*>(b.data());
- this->setp(p,
- p + b.size() / sizeof(CharT) - 1);
+ this->setp(p, p + b.size() / sizeof(CharT));
+
+ BOOST_ASSERT(b_.capacity() > b_.size());
+ return this->sputc(
+ Traits::to_char_type(ch));
}
- void
- flush(int extra = 0)
+ int
+ sync() override
{
- buf_.commit(
- (this->pptr() - this->pbase() + extra) *
- sizeof(CharT));
+ b_.commit(
+ (this->pptr() - this->pbase()) *
+ sizeof(CharT));
+ return 0;
}
};
+//------------------------------------------------------------------------------
+
// This nonsense is all to work around a glitch in libstdc++
// where std::basic_streambuf copy constructor is private:
// https://github.com/gcc-mirror/gcc/blob/gcc-4_8-branch/libstdc%2B%2B-v3/include/std/streambuf#L799
@@ -161,9 +121,7 @@ class ostream_buffer
using traits_type = typename
std::basic_streambuf<CharT, Traits>::traits_type;
- static std::size_t constexpr max_size = 512;
-
- DynamicBuffer& buf_;
+ DynamicBuffer& b_;
public:
ostream_buffer(ostream_buffer&&) = delete;
@@ -175,53 +133,43 @@ public:
}
explicit
- ostream_buffer(DynamicBuffer& buf)
- : buf_(buf)
+ ostream_buffer(DynamicBuffer& b)
+ : b_(b)
{
- prepare();
}
int_type
overflow(int_type ch) override
{
- if(! Traits::eq_int_type(ch, Traits::eof()))
- {
- Traits::assign(*this->pptr(),
- static_cast<CharT>(ch));
- flush(1);
- prepare();
- return ch;
- }
- flush();
- return traits_type::eof();
- }
-
- int
- sync() override
- {
- flush();
- prepare();
- return 0;
- }
+ BOOST_ASSERT(! Traits::eq_int_type(
+ ch, Traits::eof()));
+ sync();
-private:
- void
- prepare()
- {
- auto bs = buf_.prepare(
- read_size_or_throw(buf_, max_size));
+ static std::size_t constexpr max_size = 65536;
+ auto const 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)
+ return Traits::eof();
+ auto const bs = b_.prepare(max_prepare);
auto const b = buffers_front(bs);
auto const p = static_cast<CharT*>(b.data());
- this->setp(p,
- p + b.size() / sizeof(CharT) - 1);
+ this->setp(p, p + b.size() / sizeof(CharT));
+
+ BOOST_ASSERT(b_.capacity() > b_.size());
+ return this->sputc(
+ Traits::to_char_type(ch));
}
- void
- flush(int extra = 0)
+ int
+ sync() override
{
- buf_.commit(
- (this->pptr() - this->pbase() + extra) *
- sizeof(CharT));
+ b_.commit(
+ (this->pptr() - this->pbase()) *
+ sizeof(CharT));
+ return 0;
}
};
@@ -241,24 +189,22 @@ class ostream_helper<
public:
explicit
- ostream_helper(DynamicBuffer& buf);
+ ostream_helper(DynamicBuffer& b);
ostream_helper(ostream_helper&& other);
};
template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, true>::
-ostream_helper(DynamicBuffer& buf)
- : std::basic_ostream<CharT, Traits>(
- &this->osb_)
- , osb_(buf)
+ostream_helper(DynamicBuffer& b)
+ : std::basic_ostream<CharT, Traits>(&this->osb_)
+ , osb_(b)
{
}
template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, true>::
-ostream_helper(
- ostream_helper&& other)
+ostream_helper(ostream_helper&& other)
: std::basic_ostream<CharT, Traits>(&osb_)
, osb_(std::move(other.osb_))
{
@@ -292,12 +238,13 @@ class ostream_helper<
{
public:
explicit
- ostream_helper(DynamicBuffer& buf)
+ ostream_helper(DynamicBuffer& b)
: ostream_helper_base<ostream_buffer<
DynamicBuffer, CharT, Traits, false>>(
new ostream_buffer<DynamicBuffer,
- CharT, Traits, false>(buf))
- , std::basic_ostream<CharT, Traits>(this->member.get())
+ CharT, Traits, false>(b))
+ , std::basic_ostream<CharT, Traits>(
+ this->member.get())
{
}
@@ -305,7 +252,8 @@ public:
: ostream_helper_base<ostream_buffer<
DynamicBuffer, CharT, Traits, false>>(
std::move(other))
- , std::basic_ostream<CharT, Traits>(this->member.get())
+ , std::basic_ostream<CharT, Traits>(
+ this->member.get())
{
}
};
diff --git a/boost/beast/core/detail/pcg.hpp b/boost/beast/core/detail/pcg.hpp
new file mode 100644
index 0000000000..2815882afa
--- /dev/null
+++ b/boost/beast/core/detail/pcg.hpp
@@ -0,0 +1,65 @@
+//
+// 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_CORE_DETAIL_PCG_HPP
+#define BOOST_BEAST_CORE_DETAIL_PCG_HPP
+
+#include <boost/core/ignore_unused.hpp>
+#include <cstdint>
+#include <random>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+class pcg
+{
+ std::uint64_t state_ = 0;
+ std::uint64_t increment_;
+
+public:
+ using result_type = std::uint32_t;
+
+ // Initialize the generator.
+ // There are no restrictions on the input values.
+ pcg(
+ std::uint64_t seed,
+ std::uint64_t stream)
+ {
+ // increment must be odd
+ increment_ = 2 * stream + 1;
+ boost::ignore_unused((*this)());
+ state_ += seed;
+ boost::ignore_unused((*this)());
+ }
+
+ std::uint32_t
+ operator()()
+ {
+ std::uint64_t const p = state_;
+ state_ = p *
+ 6364136223846793005ULL +
+ increment_;
+ std::uint32_t const x =
+ static_cast<std::uint32_t>(
+ ((p >> 18) ^ p) >> 27);
+ std::uint32_t const r = p >> 59;
+ #ifdef BOOST_MSVC
+ return _rotr(x, r);
+ #else
+ return (x >> r) | (x << ((1 + ~r) & 31));
+ #endif
+ }
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/read.hpp b/boost/beast/core/detail/read.hpp
new file mode 100644
index 0000000000..3f7c17f27f
--- /dev/null
+++ b/boost/beast/core/detail/read.hpp
@@ -0,0 +1,245 @@
+//
+// 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_READ_HPP
+#define BOOST_BEAST_DETAIL_READ_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/stream_traits.hpp>
+#include <boost/beast/core/detail/is_invocable.hpp>
+#include <boost/asio/async_result.hpp>
+#include <cstdlib>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+//------------------------------------------------------------------------------
+
+/** Read data into a dynamic buffer from a stream until a condition is met.
+
+ This function is used to read from a stream into a dynamic buffer until
+ a condition is met. The call will block until one of the following is true:
+
+ @li The specified dynamic buffer sequence is full (that is, it has
+ reached its currently configured maximum size).
+
+ @li The `completion_condition` function object returns 0.
+
+ This operation is implemented in terms of zero or more calls to the
+ stream's `read_some` function.
+
+ @param stream The stream from which the data is to be read. The type
+ must support the <em>SyncReadStream</em> requirements.
+
+ @param buffer The dynamic buffer sequence into which the data will be read.
+
+ @param completion_condition The function object to be called to determine
+ whether the read operation is complete. The function object must be invocable
+ with this signature:
+ @code
+ std::size_t
+ completion_condition(
+ // Modifiable result of latest read_some operation.
+ error_code& ec,
+
+ // Number of bytes transferred so far.
+ std::size_t bytes_transferred
+
+ // The dynamic buffer used to store the bytes read
+ DynamicBuffer& buffer
+ );
+ @endcode
+ A non-zero return value indicates the maximum number of bytes to be read on
+ the next call to the stream's `read_some` function. A return value of 0
+ from the completion condition indicates that the read operation is complete;
+ in this case the optionally modifiable error passed to the completion
+ condition will be delivered to the caller as an exception.
+
+ @returns The number of bytes transferred from the stream.
+
+ @throws net::system_error Thrown on failure.
+*/
+template<
+ class SyncReadStream,
+ class DynamicBuffer,
+ class CompletionCondition
+#if ! BOOST_BEAST_DOXYGEN
+ , class = typename std::enable_if<
+ is_sync_read_stream<SyncReadStream>::value &&
+ net::is_dynamic_buffer<DynamicBuffer>::value &&
+ detail::is_invocable<CompletionCondition,
+ void(error_code&, std::size_t, DynamicBuffer&)>::value
+ >::type
+#endif
+>
+std::size_t
+read(
+ SyncReadStream& stream,
+ DynamicBuffer& buffer,
+ CompletionCondition completion_condition);
+
+/** Read data into a dynamic buffer from a stream until a condition is met.
+
+ This function is used to read from a stream into a dynamic buffer until
+ a condition is met. The call will block until one of the following is true:
+
+ @li The specified dynamic buffer sequence is full (that is, it has
+ reached its currently configured maximum size).
+
+ @li The `completion_condition` function object returns 0.
+
+ This operation is implemented in terms of zero or more calls to the
+ stream's `read_some` function.
+
+ @param stream The stream from which the data is to be read. The type
+ must support the <em>SyncReadStream</em> requirements.
+
+ @param buffer The dynamic buffer sequence into which the data will be read.
+
+ @param completion_condition The function object to be called to determine
+ whether the read operation is complete. The function object must be invocable
+ with this signature:
+ @code
+ std::size_t
+ completion_condition(
+ // Modifiable result of latest read_some operation.
+ error_code& ec,
+
+ // Number of bytes transferred so far.
+ std::size_t bytes_transferred
+
+ // The dynamic buffer used to store the bytes read
+ DynamicBuffer& buffer
+ );
+ @endcode
+ A non-zero return value indicates the maximum number of bytes to be read on
+ the next call to the stream's `read_some` function. A return value of 0
+ from the completion condition indicates that the read operation is complete;
+ in this case the optionally modifiable error passed to the completion
+ condition will be delivered to the caller.
+
+ @returns The number of bytes transferred from the stream.
+*/
+template<
+ class SyncReadStream,
+ class DynamicBuffer,
+ class CompletionCondition
+#if ! BOOST_BEAST_DOXYGEN
+ , class = typename std::enable_if<
+ is_sync_read_stream<SyncReadStream>::value &&
+ net::is_dynamic_buffer<DynamicBuffer>::value &&
+ detail::is_invocable<CompletionCondition,
+ void(error_code&, std::size_t, DynamicBuffer&)>::value
+ >::type
+#endif
+>
+std::size_t
+read(
+ SyncReadStream& stream,
+ DynamicBuffer& buffer,
+ CompletionCondition completion_condition,
+ error_code& ec);
+
+/** Asynchronously read data into a dynamic buffer from a stream until a condition is met.
+
+ This function is used to asynchronously read from a stream into a dynamic
+ buffer until a condition is met. The function call always returns immediately.
+ The asynchronous operation will continue until one of the following is true:
+
+ @li The specified dynamic buffer sequence is full (that is, it has
+ reached its currently configured maximum size).
+
+ @li The `completion_condition` function object returns 0.
+
+ This operation is implemented in terms of zero or more calls to the stream's
+ `async_read_some` function, and is known as a <em>composed operation</em>. The
+ program must ensure that the stream performs no other read operations (such
+ as `async_read`, the stream's `async_read_some` function, or any other composed
+ operations that perform reads) until this operation completes.
+
+ @param stream The stream from which the data is to be read. The type must
+ support the <em>AsyncReadStream</em> requirements.
+
+ @param buffer The dynamic buffer sequence into which the data will be read.
+ Ownership of the object is retained by the caller, which must guarantee
+ that it remains valid until the handler is called.
+
+ @param completion_condition The function object to be called to determine
+ whether the read operation is complete. The function object must be invocable
+ with this signature:
+ @code
+ std::size_t
+ completion_condition(
+ // Modifiable result of latest async_read_some operation.
+ error_code& ec,
+
+ // Number of bytes transferred so far.
+ std::size_t bytes_transferred,
+
+ // The dynamic buffer used to store the bytes read
+ DynamicBuffer& buffer
+ );
+ @endcode
+ A non-zero return value indicates the maximum number of bytes to be read on
+ the next call to the stream's `async_read_some` function. A return value of 0
+ from the completion condition indicates that the read operation is complete;
+ in this case the optionally modifiable error passed to the completion
+ condition will be delivered to the completion handler.
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void
+ handler(
+ error_code const& ec, // Result of operation.
+
+ std::size_t bytes_transferred // Number of bytes copied into
+ // the dynamic buffer. If an error
+ // occurred, this will be the number
+ // of bytes successfully transferred
+ // prior to the error.
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+*/
+template<
+ class AsyncReadStream,
+ class DynamicBuffer,
+ class CompletionCondition,
+ class ReadHandler
+#if ! BOOST_BEAST_DOXYGEN
+ , class = typename std::enable_if<
+ is_async_read_stream<AsyncReadStream>::value &&
+ net::is_dynamic_buffer<DynamicBuffer>::value &&
+ detail::is_invocable<CompletionCondition,
+ void(error_code&, std::size_t, DynamicBuffer&)>::value
+ >::type
+#endif
+>
+BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
+async_read(
+ AsyncReadStream& stream,
+ DynamicBuffer& buffer,
+ CompletionCondition&& completion_condition,
+ ReadHandler&& handler);
+
+} // detail
+} // beast
+} // boost
+
+#include <boost/beast/core/detail/impl/read.hpp>
+
+#endif
diff --git a/boost/beast/core/detail/remap_post_to_defer.hpp b/boost/beast/core/detail/remap_post_to_defer.hpp
new file mode 100644
index 0000000000..77f7d8ab20
--- /dev/null
+++ b/boost/beast/core/detail/remap_post_to_defer.hpp
@@ -0,0 +1,109 @@
+//
+// 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_REMAP_POST_TO_DEFER_HPP
+#define BOOST_BEAST_DETAIL_REMAP_POST_TO_DEFER_HPP
+
+#include <boost/asio/bind_executor.hpp>
+#include <boost/asio/is_executor.hpp>
+#include <boost/core/empty_value.hpp>
+#include <type_traits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<class Executor>
+class remap_post_to_defer
+ : private boost::empty_value<Executor>
+{
+ BOOST_STATIC_ASSERT(
+ net::is_executor<Executor>::value);
+
+ Executor const&
+ ex() const noexcept
+ {
+ return this->get();
+ }
+
+public:
+ remap_post_to_defer(
+ remap_post_to_defer&&) = default;
+
+ remap_post_to_defer(
+ remap_post_to_defer const&) = default;
+
+ explicit
+ remap_post_to_defer(
+ Executor const& ex)
+ : boost::empty_value<Executor>(
+ boost::empty_init_t{}, ex)
+ {
+ }
+
+ bool
+ operator==(
+ remap_post_to_defer const& other) const noexcept
+ {
+ return ex() == other.ex();
+ }
+
+ bool
+ operator!=(
+ remap_post_to_defer const& other) const noexcept
+ {
+ return ex() != other.ex();
+ }
+
+ decltype(std::declval<Executor const&>().context())
+ context() const noexcept
+ {
+ return ex().context();
+ }
+
+ void
+ on_work_started() const noexcept
+ {
+ ex().on_work_started();
+ }
+
+ void
+ on_work_finished() const noexcept
+ {
+ ex().on_work_finished();
+ }
+
+ template<class F, class A>
+ void
+ dispatch(F&& f, A const& a) const
+ {
+ ex().dispatch(std::forward<F>(f), a);
+ }
+
+ template<class F, class A>
+ void
+ post(F&& f, A const& a) const
+ {
+ ex().defer(std::forward<F>(f), a);
+ }
+
+ template<class F, class A>
+ void
+ defer(F&& f, A const& a) const
+ {
+ ex().defer(std::forward<F>(f), a);
+ }
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/service_base.hpp b/boost/beast/core/detail/service_base.hpp
new file mode 100644
index 0000000000..adec09bbf1
--- /dev/null
+++ b/boost/beast/core/detail/service_base.hpp
@@ -0,0 +1,43 @@
+//
+// 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_SERVICE_BASE_HPP
+#define BOOST_BEAST_DETAIL_SERVICE_BASE_HPP
+
+#include <boost/asio/execution_context.hpp>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<class T>
+struct service_id : net::execution_context::id
+{
+};
+
+template<class T>
+struct service_base : net::execution_context::service
+{
+ static service_id<T> id;
+
+ explicit
+ service_base(net::execution_context& ctx)
+ : net::execution_context::service(ctx)
+ {
+ }
+};
+
+template<class T>
+service_id<T> service_base<T>::id;
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/sha1.hpp b/boost/beast/core/detail/sha1.hpp
index 034fb9befe..abcc307407 100644
--- a/boost/beast/core/detail/sha1.hpp
+++ b/boost/beast/core/detail/sha1.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -10,6 +10,8 @@
#ifndef BOOST_BEAST_DETAIL_SHA1_HPP
#define BOOST_BEAST_DETAIL_SHA1_HPP
+#include <boost/beast/core/detail/config.hpp>
+
#include <algorithm>
#include <cstdint>
#include <cstring>
@@ -34,189 +36,6 @@ static std::size_t constexpr BLOCK_INTS = 16;
static std::size_t constexpr BLOCK_BYTES = 64;
static std::size_t constexpr DIGEST_BYTES = 20;
-inline
-std::uint32_t
-rol(std::uint32_t value, std::size_t bits)
-{
- return (value << bits) | (value >> (32 - bits));
-}
-
-inline
-std::uint32_t
-blk(std::uint32_t block[BLOCK_INTS], std::size_t i)
-{
- return rol(
- block[(i+13)&15] ^ block[(i+8)&15] ^
- block[(i+2)&15] ^ block[i], 1);
-}
-
-inline
-void
-R0(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
- std::uint32_t &w, std::uint32_t x, std::uint32_t y,
- std::uint32_t &z, std::size_t i)
-{
- z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5);
- w = rol(w, 30);
-}
-
-
-inline
-void
-R1(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
- std::uint32_t &w, std::uint32_t x, std::uint32_t y,
- std::uint32_t &z, std::size_t i)
-{
- block[i] = blk(block, i);
- z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5);
- w = rol(w, 30);
-}
-
-inline
-void
-R2(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
- std::uint32_t &w, std::uint32_t x, std::uint32_t y,
- std::uint32_t &z, std::size_t i)
-{
- block[i] = blk(block, i);
- z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(v, 5);
- w = rol(w, 30);
-}
-
-inline
-void
-R3(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
- std::uint32_t &w, std::uint32_t x, std::uint32_t y,
- std::uint32_t &z, std::size_t i)
-{
- block[i] = blk(block, i);
- z += (((w|x)&y)|(w&x)) + block[i] + 0x8f1bbcdc + rol(v, 5);
- w = rol(w, 30);
-}
-
-inline
-void
-R4(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
- std::uint32_t &w, std::uint32_t x, std::uint32_t y,
- std::uint32_t &z, std::size_t i)
-{
- block[i] = blk(block, i);
- z += (w^x^y) + block[i] + 0xca62c1d6 + rol(v, 5);
- w = rol(w, 30);
-}
-
-inline
-void
-make_block(std::uint8_t const* p,
- std::uint32_t block[BLOCK_INTS])
-{
- for(std::size_t i = 0; i < BLOCK_INTS; i++)
- block[i] =
- (static_cast<std::uint32_t>(p[4*i+3])) |
- (static_cast<std::uint32_t>(p[4*i+2]))<< 8 |
- (static_cast<std::uint32_t>(p[4*i+1]))<<16 |
- (static_cast<std::uint32_t>(p[4*i+0]))<<24;
-}
-
-template<class = void>
-void
-transform(
- std::uint32_t digest[], std::uint32_t block[BLOCK_INTS])
-{
- std::uint32_t a = digest[0];
- std::uint32_t b = digest[1];
- std::uint32_t c = digest[2];
- std::uint32_t d = digest[3];
- std::uint32_t e = digest[4];
-
- R0(block, a, b, c, d, e, 0);
- R0(block, e, a, b, c, d, 1);
- R0(block, d, e, a, b, c, 2);
- R0(block, c, d, e, a, b, 3);
- R0(block, b, c, d, e, a, 4);
- R0(block, a, b, c, d, e, 5);
- R0(block, e, a, b, c, d, 6);
- R0(block, d, e, a, b, c, 7);
- R0(block, c, d, e, a, b, 8);
- R0(block, b, c, d, e, a, 9);
- R0(block, a, b, c, d, e, 10);
- R0(block, e, a, b, c, d, 11);
- R0(block, d, e, a, b, c, 12);
- R0(block, c, d, e, a, b, 13);
- R0(block, b, c, d, e, a, 14);
- R0(block, a, b, c, d, e, 15);
- R1(block, e, a, b, c, d, 0);
- R1(block, d, e, a, b, c, 1);
- R1(block, c, d, e, a, b, 2);
- R1(block, b, c, d, e, a, 3);
- R2(block, a, b, c, d, e, 4);
- R2(block, e, a, b, c, d, 5);
- R2(block, d, e, a, b, c, 6);
- R2(block, c, d, e, a, b, 7);
- R2(block, b, c, d, e, a, 8);
- R2(block, a, b, c, d, e, 9);
- R2(block, e, a, b, c, d, 10);
- R2(block, d, e, a, b, c, 11);
- R2(block, c, d, e, a, b, 12);
- R2(block, b, c, d, e, a, 13);
- R2(block, a, b, c, d, e, 14);
- R2(block, e, a, b, c, d, 15);
- R2(block, d, e, a, b, c, 0);
- R2(block, c, d, e, a, b, 1);
- R2(block, b, c, d, e, a, 2);
- R2(block, a, b, c, d, e, 3);
- R2(block, e, a, b, c, d, 4);
- R2(block, d, e, a, b, c, 5);
- R2(block, c, d, e, a, b, 6);
- R2(block, b, c, d, e, a, 7);
- R3(block, a, b, c, d, e, 8);
- R3(block, e, a, b, c, d, 9);
- R3(block, d, e, a, b, c, 10);
- R3(block, c, d, e, a, b, 11);
- R3(block, b, c, d, e, a, 12);
- R3(block, a, b, c, d, e, 13);
- R3(block, e, a, b, c, d, 14);
- R3(block, d, e, a, b, c, 15);
- R3(block, c, d, e, a, b, 0);
- R3(block, b, c, d, e, a, 1);
- R3(block, a, b, c, d, e, 2);
- R3(block, e, a, b, c, d, 3);
- R3(block, d, e, a, b, c, 4);
- R3(block, c, d, e, a, b, 5);
- R3(block, b, c, d, e, a, 6);
- R3(block, a, b, c, d, e, 7);
- R3(block, e, a, b, c, d, 8);
- R3(block, d, e, a, b, c, 9);
- R3(block, c, d, e, a, b, 10);
- R3(block, b, c, d, e, a, 11);
- R4(block, a, b, c, d, e, 12);
- R4(block, e, a, b, c, d, 13);
- R4(block, d, e, a, b, c, 14);
- R4(block, c, d, e, a, b, 15);
- R4(block, b, c, d, e, a, 0);
- R4(block, a, b, c, d, e, 1);
- R4(block, e, a, b, c, d, 2);
- R4(block, d, e, a, b, c, 3);
- R4(block, c, d, e, a, b, 4);
- R4(block, b, c, d, e, a, 5);
- R4(block, a, b, c, d, e, 6);
- R4(block, e, a, b, c, d, 7);
- R4(block, d, e, a, b, c, 8);
- R4(block, c, d, e, a, b, 9);
- R4(block, b, c, d, e, a, 10);
- R4(block, a, b, c, d, e, 11);
- R4(block, e, a, b, c, d, 12);
- R4(block, d, e, a, b, c, 13);
- R4(block, c, d, e, a, b, 14);
- R4(block, b, c, d, e, a, 15);
-
- digest[0] += a;
- digest[1] += b;
- digest[2] += c;
- digest[3] += d;
- digest[4] += e;
-}
-
} // sha1
struct sha1_context
@@ -230,84 +49,29 @@ struct sha1_context
std::uint8_t buf[block_size];
};
-template<class = void>
+BOOST_BEAST_DECL
void
-init(sha1_context& ctx) noexcept
-{
- ctx.buflen = 0;
- ctx.blocks = 0;
- ctx.digest[0] = 0x67452301;
- ctx.digest[1] = 0xefcdab89;
- ctx.digest[2] = 0x98badcfe;
- ctx.digest[3] = 0x10325476;
- ctx.digest[4] = 0xc3d2e1f0;
-}
+init(sha1_context& ctx) noexcept;
-template<class = void>
+BOOST_BEAST_DECL
void
-update(sha1_context& ctx,
- void const* message, std::size_t size) noexcept
-{
- auto p = static_cast<
- std::uint8_t const*>(message);
- for(;;)
- {
- auto const n = (std::min)(
- size, sizeof(ctx.buf) - ctx.buflen);
- std::memcpy(ctx.buf + ctx.buflen, p, n);
- ctx.buflen += n;
- if(ctx.buflen != 64)
- return;
- p += n;
- size -= n;
- ctx.buflen = 0;
- std::uint32_t block[sha1::BLOCK_INTS];
- sha1::make_block(ctx.buf, block);
- sha1::transform(ctx.digest, block);
- ++ctx.blocks;
- }
-}
+update(
+ sha1_context& ctx,
+ void const* message,
+ std::size_t size) noexcept;
-template<class = void>
+BOOST_BEAST_DECL
void
-finish(sha1_context& ctx, void* digest) noexcept
-{
- using sha1::BLOCK_INTS;
- using sha1::BLOCK_BYTES;
-
- std::uint64_t total_bits =
- (ctx.blocks*64 + ctx.buflen) * 8;
- // pad
- ctx.buf[ctx.buflen++] = 0x80;
- auto const buflen = ctx.buflen;
- while(ctx.buflen < 64)
- ctx.buf[ctx.buflen++] = 0x00;
- std::uint32_t block[BLOCK_INTS];
- sha1::make_block(ctx.buf, block);
- if(buflen > BLOCK_BYTES - 8)
- {
- sha1::transform(ctx.digest, block);
- for(size_t i = 0; i < BLOCK_INTS - 2; i++)
- block[i] = 0;
- }
-
- /* Append total_bits, split this uint64_t into two uint32_t */
- block[BLOCK_INTS - 1] = total_bits & 0xffffffff;
- block[BLOCK_INTS - 2] = (total_bits >> 32);
- sha1::transform(ctx.digest, block);
- for(std::size_t i = 0; i < sha1::DIGEST_BYTES/4; i++)
- {
- std::uint8_t* d =
- static_cast<std::uint8_t*>(digest) + 4 * i;
- d[3] = ctx.digest[i] & 0xff;
- d[2] = (ctx.digest[i] >> 8) & 0xff;
- d[1] = (ctx.digest[i] >> 16) & 0xff;
- d[0] = (ctx.digest[i] >> 24) & 0xff;
- }
-}
+finish(
+ sha1_context& ctx,
+ void* digest) noexcept;
} // detail
} // beast
} // boost
+#ifdef BOOST_BEAST_HEADER_ONLY
+#include <boost/beast/core/detail/sha1.ipp>
+#endif
+
#endif
diff --git a/boost/beast/core/detail/sha1.ipp b/boost/beast/core/detail/sha1.ipp
new file mode 100644
index 0000000000..8d739f3449
--- /dev/null
+++ b/boost/beast/core/detail/sha1.ipp
@@ -0,0 +1,301 @@
+//
+// 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_SHA1_IPP
+#define BOOST_BEAST_DETAIL_SHA1_IPP
+
+#include <boost/beast/core/detail/sha1.hpp>
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+
+// Based on https://github.com/vog/sha1
+/*
+ Original authors:
+ Steve Reid (Original C Code)
+ Bruce Guenter (Small changes to fit into bglibs)
+ Volker Grabsch (Translation to simpler C++ Code)
+ Eugene Hopkinson (Safety improvements)
+ Vincent Falco (beast adaptation)
+*/
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+namespace sha1 {
+
+inline
+std::uint32_t
+rol(std::uint32_t value, std::size_t bits)
+{
+ return (value << bits) | (value >> (32 - bits));
+}
+
+inline
+std::uint32_t
+blk(std::uint32_t block[BLOCK_INTS], std::size_t i)
+{
+ return rol(
+ block[(i+13)&15] ^ block[(i+8)&15] ^
+ block[(i+2)&15] ^ block[i], 1);
+}
+
+inline
+void
+R0(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
+ std::uint32_t &w, std::uint32_t x, std::uint32_t y,
+ std::uint32_t &z, std::size_t i)
+{
+ z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5);
+ w = rol(w, 30);
+}
+
+
+inline
+void
+R1(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
+ std::uint32_t &w, std::uint32_t x, std::uint32_t y,
+ std::uint32_t &z, std::size_t i)
+{
+ block[i] = blk(block, i);
+ z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5);
+ w = rol(w, 30);
+}
+
+inline
+void
+R2(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
+ std::uint32_t &w, std::uint32_t x, std::uint32_t y,
+ std::uint32_t &z, std::size_t i)
+{
+ block[i] = blk(block, i);
+ z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(v, 5);
+ w = rol(w, 30);
+}
+
+inline
+void
+R3(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
+ std::uint32_t &w, std::uint32_t x, std::uint32_t y,
+ std::uint32_t &z, std::size_t i)
+{
+ block[i] = blk(block, i);
+ z += (((w|x)&y)|(w&x)) + block[i] + 0x8f1bbcdc + rol(v, 5);
+ w = rol(w, 30);
+}
+
+inline
+void
+R4(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
+ std::uint32_t &w, std::uint32_t x, std::uint32_t y,
+ std::uint32_t &z, std::size_t i)
+{
+ block[i] = blk(block, i);
+ z += (w^x^y) + block[i] + 0xca62c1d6 + rol(v, 5);
+ w = rol(w, 30);
+}
+
+inline
+void
+make_block(std::uint8_t const* p,
+ std::uint32_t block[BLOCK_INTS])
+{
+ for(std::size_t i = 0; i < BLOCK_INTS; i++)
+ block[i] =
+ (static_cast<std::uint32_t>(p[4*i+3])) |
+ (static_cast<std::uint32_t>(p[4*i+2]))<< 8 |
+ (static_cast<std::uint32_t>(p[4*i+1]))<<16 |
+ (static_cast<std::uint32_t>(p[4*i+0]))<<24;
+}
+
+inline
+void
+transform(
+ std::uint32_t digest[], std::uint32_t block[BLOCK_INTS])
+{
+ std::uint32_t a = digest[0];
+ std::uint32_t b = digest[1];
+ std::uint32_t c = digest[2];
+ std::uint32_t d = digest[3];
+ std::uint32_t e = digest[4];
+
+ R0(block, a, b, c, d, e, 0);
+ R0(block, e, a, b, c, d, 1);
+ R0(block, d, e, a, b, c, 2);
+ R0(block, c, d, e, a, b, 3);
+ R0(block, b, c, d, e, a, 4);
+ R0(block, a, b, c, d, e, 5);
+ R0(block, e, a, b, c, d, 6);
+ R0(block, d, e, a, b, c, 7);
+ R0(block, c, d, e, a, b, 8);
+ R0(block, b, c, d, e, a, 9);
+ R0(block, a, b, c, d, e, 10);
+ R0(block, e, a, b, c, d, 11);
+ R0(block, d, e, a, b, c, 12);
+ R0(block, c, d, e, a, b, 13);
+ R0(block, b, c, d, e, a, 14);
+ R0(block, a, b, c, d, e, 15);
+ R1(block, e, a, b, c, d, 0);
+ R1(block, d, e, a, b, c, 1);
+ R1(block, c, d, e, a, b, 2);
+ R1(block, b, c, d, e, a, 3);
+ R2(block, a, b, c, d, e, 4);
+ R2(block, e, a, b, c, d, 5);
+ R2(block, d, e, a, b, c, 6);
+ R2(block, c, d, e, a, b, 7);
+ R2(block, b, c, d, e, a, 8);
+ R2(block, a, b, c, d, e, 9);
+ R2(block, e, a, b, c, d, 10);
+ R2(block, d, e, a, b, c, 11);
+ R2(block, c, d, e, a, b, 12);
+ R2(block, b, c, d, e, a, 13);
+ R2(block, a, b, c, d, e, 14);
+ R2(block, e, a, b, c, d, 15);
+ R2(block, d, e, a, b, c, 0);
+ R2(block, c, d, e, a, b, 1);
+ R2(block, b, c, d, e, a, 2);
+ R2(block, a, b, c, d, e, 3);
+ R2(block, e, a, b, c, d, 4);
+ R2(block, d, e, a, b, c, 5);
+ R2(block, c, d, e, a, b, 6);
+ R2(block, b, c, d, e, a, 7);
+ R3(block, a, b, c, d, e, 8);
+ R3(block, e, a, b, c, d, 9);
+ R3(block, d, e, a, b, c, 10);
+ R3(block, c, d, e, a, b, 11);
+ R3(block, b, c, d, e, a, 12);
+ R3(block, a, b, c, d, e, 13);
+ R3(block, e, a, b, c, d, 14);
+ R3(block, d, e, a, b, c, 15);
+ R3(block, c, d, e, a, b, 0);
+ R3(block, b, c, d, e, a, 1);
+ R3(block, a, b, c, d, e, 2);
+ R3(block, e, a, b, c, d, 3);
+ R3(block, d, e, a, b, c, 4);
+ R3(block, c, d, e, a, b, 5);
+ R3(block, b, c, d, e, a, 6);
+ R3(block, a, b, c, d, e, 7);
+ R3(block, e, a, b, c, d, 8);
+ R3(block, d, e, a, b, c, 9);
+ R3(block, c, d, e, a, b, 10);
+ R3(block, b, c, d, e, a, 11);
+ R4(block, a, b, c, d, e, 12);
+ R4(block, e, a, b, c, d, 13);
+ R4(block, d, e, a, b, c, 14);
+ R4(block, c, d, e, a, b, 15);
+ R4(block, b, c, d, e, a, 0);
+ R4(block, a, b, c, d, e, 1);
+ R4(block, e, a, b, c, d, 2);
+ R4(block, d, e, a, b, c, 3);
+ R4(block, c, d, e, a, b, 4);
+ R4(block, b, c, d, e, a, 5);
+ R4(block, a, b, c, d, e, 6);
+ R4(block, e, a, b, c, d, 7);
+ R4(block, d, e, a, b, c, 8);
+ R4(block, c, d, e, a, b, 9);
+ R4(block, b, c, d, e, a, 10);
+ R4(block, a, b, c, d, e, 11);
+ R4(block, e, a, b, c, d, 12);
+ R4(block, d, e, a, b, c, 13);
+ R4(block, c, d, e, a, b, 14);
+ R4(block, b, c, d, e, a, 15);
+
+ digest[0] += a;
+ digest[1] += b;
+ digest[2] += c;
+ digest[3] += d;
+ digest[4] += e;
+}
+
+} // sha1
+
+void
+init(sha1_context& ctx) noexcept
+{
+ ctx.buflen = 0;
+ ctx.blocks = 0;
+ ctx.digest[0] = 0x67452301;
+ ctx.digest[1] = 0xefcdab89;
+ ctx.digest[2] = 0x98badcfe;
+ ctx.digest[3] = 0x10325476;
+ ctx.digest[4] = 0xc3d2e1f0;
+}
+
+void
+update(
+ sha1_context& ctx,
+ void const* message,
+ std::size_t size) noexcept
+{
+ auto p = static_cast<
+ std::uint8_t const*>(message);
+ for(;;)
+ {
+ auto const n = (std::min)(
+ size, sizeof(ctx.buf) - ctx.buflen);
+ std::memcpy(ctx.buf + ctx.buflen, p, n);
+ ctx.buflen += n;
+ if(ctx.buflen != 64)
+ return;
+ p += n;
+ size -= n;
+ ctx.buflen = 0;
+ std::uint32_t block[sha1::BLOCK_INTS];
+ sha1::make_block(ctx.buf, block);
+ sha1::transform(ctx.digest, block);
+ ++ctx.blocks;
+ }
+}
+
+void
+finish(
+ sha1_context& ctx,
+ void* digest) noexcept
+{
+ using sha1::BLOCK_INTS;
+ using sha1::BLOCK_BYTES;
+
+ std::uint64_t total_bits =
+ (ctx.blocks*64 + ctx.buflen) * 8;
+ // pad
+ ctx.buf[ctx.buflen++] = 0x80;
+ auto const buflen = ctx.buflen;
+ while(ctx.buflen < 64)
+ ctx.buf[ctx.buflen++] = 0x00;
+ std::uint32_t block[BLOCK_INTS];
+ sha1::make_block(ctx.buf, block);
+ if(buflen > BLOCK_BYTES - 8)
+ {
+ sha1::transform(ctx.digest, block);
+ for(size_t i = 0; i < BLOCK_INTS - 2; i++)
+ block[i] = 0;
+ }
+
+ /* Append total_bits, split this uint64_t into two uint32_t */
+ block[BLOCK_INTS - 1] = total_bits & 0xffffffff;
+ block[BLOCK_INTS - 2] = (total_bits >> 32);
+ sha1::transform(ctx.digest, block);
+ for(std::size_t i = 0; i < sha1::DIGEST_BYTES/4; i++)
+ {
+ std::uint8_t* d =
+ static_cast<std::uint8_t*>(digest) + 4 * i;
+ d[3] = ctx.digest[i] & 0xff;
+ d[2] = (ctx.digest[i] >> 8) & 0xff;
+ d[1] = (ctx.digest[i] >> 16) & 0xff;
+ d[0] = (ctx.digest[i] >> 24) & 0xff;
+ }
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/static_const.hpp b/boost/beast/core/detail/static_const.hpp
new file mode 100644
index 0000000000..f8582326c8
--- /dev/null
+++ b/boost/beast/core/detail/static_const.hpp
@@ -0,0 +1,49 @@
+//
+// 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_STATIC_CONST_HPP
+#define BOOST_BEAST_DETAIL_STATIC_CONST_HPP
+
+/* This is a derivative work, original copyright:
+
+ Copyright Eric Niebler 2013-present
+
+ Use, modification and distribution is subject to 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)
+
+ Project home: https://github.com/ericniebler/range-v3
+*/
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<typename T>
+struct static_const
+{
+ static constexpr T value {};
+};
+
+template<typename T>
+constexpr T static_const<T>::value;
+
+#define BOOST_BEAST_INLINE_VARIABLE(name, type) \
+ namespace \
+ { \
+ constexpr auto& name = \
+ ::boost::beast::detail::static_const<type>::value; \
+ }
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/static_ostream.hpp b/boost/beast/core/detail/static_ostream.hpp
index cb5a00b3da..5eaa413b30 100644
--- a/boost/beast/core/detail/static_ostream.hpp
+++ b/boost/beast/core/detail/static_ostream.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
diff --git a/boost/beast/core/detail/static_string.hpp b/boost/beast/core/detail/static_string.hpp
index a5384591ff..3b080e916e 100644
--- a/boost/beast/core/detail/static_string.hpp
+++ b/boost/beast/core/detail/static_string.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -41,24 +41,22 @@ lexicographical_compare(
}
template<class CharT, class Traits>
-inline
int
lexicographical_compare(
basic_string_view<CharT, Traits> s1,
CharT const* s2, std::size_t n2)
{
- return lexicographical_compare<CharT, Traits>(
- s1.data(), s1.size(), s2, n2);
+ return detail::lexicographical_compare<
+ CharT, Traits>(s1.data(), s1.size(), s2, n2);
}
template<class CharT, class Traits>
-inline
int
lexicographical_compare(
basic_string_view<CharT, Traits> s1,
basic_string_view<CharT, Traits> s2)
{
- return lexicographical_compare<CharT, Traits>(
+ return detail::lexicographical_compare<CharT, Traits>(
s1.data(), s1.size(), s2.data(), s2.size());
}
diff --git a/boost/beast/core/detail/stream_base.hpp b/boost/beast/core/detail/stream_base.hpp
new file mode 100644
index 0000000000..00591216de
--- /dev/null
+++ b/boost/beast/core/detail/stream_base.hpp
@@ -0,0 +1,107 @@
+//
+// 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_CORE_DETAIL_STREAM_BASE_HPP
+#define BOOST_BEAST_CORE_DETAIL_STREAM_BASE_HPP
+
+#include <boost/asio/steady_timer.hpp>
+#include <boost/assert.hpp>
+#include <boost/core/exchange.hpp>
+#include <chrono>
+#include <cstdint>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+struct any_endpoint
+{
+ template<class Error, class Endpoint>
+ bool
+ operator()(
+ Error const&, Endpoint const&) const noexcept
+ {
+ return true;
+ }
+};
+
+struct stream_base
+{
+ using clock_type = std::chrono::steady_clock;
+ using time_point = typename
+ std::chrono::steady_clock::time_point;
+ using tick_type = std::uint64_t;
+
+ struct op_state
+ {
+ net::steady_timer timer; // for timing out
+ tick_type tick = 0; // counts waits
+ bool pending = false; // if op is pending
+ bool timeout = false; // if timed out
+
+ template<class... Args>
+ explicit
+ op_state(Args&&... args)
+ : timer(std::forward<Args>(args)...)
+ {
+ }
+ };
+
+ class pending_guard
+ {
+ bool& b_;
+ bool clear_ = true;
+
+ public:
+ ~pending_guard()
+ {
+ if(clear_)
+ b_ = false;
+ }
+
+ explicit
+ pending_guard(bool& b)
+ : b_(b)
+ {
+ BOOST_ASSERT(! b_);
+ b_ = true;
+ }
+
+ pending_guard(
+ pending_guard&& other) noexcept
+ : b_(other.b_)
+ , clear_(boost::exchange(
+ other.clear_, false))
+ {
+ }
+
+ void
+ reset()
+ {
+ BOOST_ASSERT(clear_);
+ b_ = false;
+ clear_ = false;
+ }
+ };
+
+ static time_point never() noexcept
+ {
+ return (time_point::max)();
+ }
+
+ static std::size_t constexpr no_limit =
+ (std::numeric_limits<std::size_t>::max)();
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/stream_traits.hpp b/boost/beast/core/detail/stream_traits.hpp
new file mode 100644
index 0000000000..bb1e29c2d3
--- /dev/null
+++ b/boost/beast/core/detail/stream_traits.hpp
@@ -0,0 +1,111 @@
+//
+// 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_STREAM_TRAITS_HPP
+#define BOOST_BEAST_DETAIL_STREAM_TRAITS_HPP
+
+#include <boost/beast/core/error.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/type_traits/make_void.hpp>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+//------------------------------------------------------------------------------
+//
+// get_lowest_layer
+// lowest_layer_type
+// detail::has_next_layer
+//
+
+template <class T>
+std::false_type has_next_layer_impl(void*);
+
+template <class T>
+auto has_next_layer_impl(decltype(nullptr)) ->
+ decltype(std::declval<T&>().next_layer(), std::true_type{});
+
+template <class T>
+using has_next_layer = decltype(has_next_layer_impl<T>(nullptr));
+
+template<class T, bool = has_next_layer<T>::value>
+struct lowest_layer_type_impl
+{
+ using type = typename std::remove_reference<T>::type;
+};
+
+template<class T>
+struct lowest_layer_type_impl<T, true>
+{
+ using type = typename lowest_layer_type_impl<
+ decltype(std::declval<T&>().next_layer())>::type;
+};
+
+template<class T>
+using lowest_layer_type = typename
+ lowest_layer_type_impl<T>::type;
+
+template<class T>
+T&
+get_lowest_layer_impl(
+ T& t, std::false_type) noexcept
+{
+ return t;
+}
+
+template<class T>
+lowest_layer_type<T>&
+get_lowest_layer_impl(
+ T& t, std::true_type) noexcept
+{
+ return get_lowest_layer_impl(t.next_layer(),
+ has_next_layer<typename std::decay<
+ decltype(t.next_layer())>::type>{});
+}
+
+//------------------------------------------------------------------------------
+
+// Types that meet the requirements,
+// for use with std::declval only.
+template<class BufferType>
+struct BufferSequence
+{
+ using value_type = BufferType;
+ using const_iterator = BufferType const*;
+ ~BufferSequence() = default;
+ BufferSequence(BufferSequence const&) = default;
+ const_iterator begin() const noexcept { return {}; }
+ const_iterator end() const noexcept { return {}; }
+};
+using ConstBufferSequence =
+ BufferSequence<net::const_buffer>;
+using MutableBufferSequence =
+ BufferSequence<net::mutable_buffer>;
+
+//
+
+// Types that meet the requirements,
+// for use with std::declval only.
+struct StreamHandler
+{
+ StreamHandler(StreamHandler const&) = default;
+ void operator()(error_code, std::size_t) {}
+};
+using ReadHandler = StreamHandler;
+using WriteHandler = StreamHandler;
+
+//------------------------------------------------------------------------------
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/tuple.hpp b/boost/beast/core/detail/tuple.hpp
new file mode 100644
index 0000000000..5d65e9de77
--- /dev/null
+++ b/boost/beast/core/detail/tuple.hpp
@@ -0,0 +1,116 @@
+//
+// Copyright (c) 2016-2019Damian Jarek (damian dot jarek93 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_TUPLE_HPP
+#define BOOST_BEAST_DETAIL_TUPLE_HPP
+
+#include <boost/mp11/integer_sequence.hpp>
+#include <boost/mp11/algorithm.hpp>
+#include <boost/type_traits/remove_cv.hpp>
+#include <boost/type_traits/copy_cv.hpp>
+#include <cstdlib>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<std::size_t I, class T>
+struct tuple_element_impl
+{
+ T t;
+
+ tuple_element_impl(T const& t_)
+ : t(t_)
+ {
+ }
+
+ tuple_element_impl(T&& t_)
+ : t(std::move(t_))
+ {
+ }
+};
+
+template<std::size_t I, class T>
+struct tuple_element_impl<I, T&>
+{
+ T& t;
+
+ tuple_element_impl(T& t_)
+ : t(t_)
+ {
+ }
+};
+
+template<class... Ts>
+struct tuple_impl;
+
+template<class... Ts, std::size_t... Is>
+struct tuple_impl<
+ boost::mp11::index_sequence<Is...>, Ts...>
+ : tuple_element_impl<Is, Ts>...
+{
+ template<class... Us>
+ explicit tuple_impl(Us&&... us)
+ : tuple_element_impl<Is, Ts>(
+ std::forward<Us>(us))...
+ {
+ }
+};
+
+template<class... Ts>
+struct tuple : tuple_impl<
+ boost::mp11::index_sequence_for<Ts...>, Ts...>
+{
+ template<class... Us>
+ explicit tuple(Us&&... us)
+ : tuple_impl<
+ boost::mp11::index_sequence_for<Ts...>, Ts...>{
+ std::forward<Us>(us)...}
+ {
+ }
+};
+
+template<std::size_t I, class T>
+T&
+get(tuple_element_impl<I, T>& te)
+{
+ return te.t;
+}
+
+template<std::size_t I, class T>
+T const&
+get(tuple_element_impl<I, T> const& te)
+{
+ return te.t;
+}
+
+template<std::size_t I, class T>
+T&&
+get(tuple_element_impl<I, T>&& te)
+{
+ return std::move(te.t);
+}
+
+template<std::size_t I, class T>
+T&
+get(tuple_element_impl<I, T&>&& te)
+{
+ return te.t;
+}
+
+template <std::size_t I, class T>
+using tuple_element = typename boost::copy_cv<
+ mp11::mp_at_c<typename remove_cv<T>::type, I>, T>::type;
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/type_traits.hpp b/boost/beast/core/detail/type_traits.hpp
index 3d379846b9..3d895403b3 100644
--- a/boost/beast/core/detail/type_traits.hpp
+++ b/boost/beast/core/detail/type_traits.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,8 +11,10 @@
#define BOOST_BEAST_DETAIL_TYPE_TRAITS_HPP
#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/asio/buffer.hpp>
-#include <boost/type_traits.hpp>
+#include <boost/mp11/function.hpp>
+#include <boost/type_traits/make_void.hpp>
#include <iterator>
#include <tuple>
#include <type_traits>
@@ -23,8 +25,22 @@ namespace boost {
namespace beast {
namespace detail {
+// variadic min
+template<class T>
+T constexpr min(T t)
+{
+ return t;
+}
+
+template<class T, class...Tn>
+T constexpr min(T t0, T t1, Tn... tn)
+{
+ return (t0 < t1) ?
+ (detail::min)(t0, tn...) :
+ (detail::min)(t1, tn...);
+}
+
template<class U>
-inline
std::size_t constexpr
max_sizeof()
{
@@ -32,7 +48,6 @@ max_sizeof()
}
template<class U0, class U1, class... Us>
-inline
std::size_t constexpr
max_sizeof()
{
@@ -42,7 +57,6 @@ max_sizeof()
}
template<class U>
-inline
std::size_t constexpr
max_alignof()
{
@@ -84,76 +98,11 @@ using aligned_union_t =
//------------------------------------------------------------------------------
template<class T>
-inline
void
accept_rv(T){}
//------------------------------------------------------------------------------
-template<unsigned N, class T, class... Tn>
-struct repeat_tuple_impl
-{
- using type = typename repeat_tuple_impl<
- N - 1, T, T, Tn...>::type;
-};
-
-template<class T, class... Tn>
-struct repeat_tuple_impl<0, T, Tn...>
-{
- using type = std::tuple<T, Tn...>;
-};
-
-template<unsigned N, class T>
-struct repeat_tuple
-{
- using type =
- typename repeat_tuple_impl<N-1, T>::type;
-};
-
-template<class T>
-struct repeat_tuple<0, T>
-{
- using type = std::tuple<>;
-};
-
-//------------------------------------------------------------------------------
-
-template<class R, class C, class ...A>
-auto
-is_invocable_test(C&& c, int, A&& ...a)
- -> decltype(std::is_convertible<
- decltype(c(std::forward<A>(a)...)), R>::value ||
- std::is_same<R, void>::value,
- std::true_type());
-
-template<class R, class C, class ...A>
-std::false_type
-is_invocable_test(C&& c, long, A&& ...a);
-
-/** Metafunction returns `true` if F callable as R(A...)
-
- Example:
-
- @code
- is_invocable<T, void(std::string)>
- @endcode
-*/
-/** @{ */
-template<class C, class F>
-struct is_invocable : std::false_type
-{
-};
-
-template<class C, class R, class ...A>
-struct is_invocable<C, R(A...)>
- : decltype(is_invocable_test<R>(
- std::declval<C>(), 1, std::declval<A>()...))
-{
-};
-/** @} */
-
-//------------------------------------------------------------------------------
-
// for span
template<class T, class E, class = void>
struct is_contiguous_container: std::false_type {};
@@ -175,297 +124,6 @@ struct is_contiguous_container<T, E, void_t<
>::type>>: std::true_type
{};
-//------------------------------------------------------------------------------
-
-template<class...>
-struct unwidest_unsigned;
-
-template<class U0>
-struct unwidest_unsigned<U0>
-{
- using type = U0;
-};
-
-template<class U0, class... UN>
-struct unwidest_unsigned<U0, UN...>
-{
- BOOST_STATIC_ASSERT(std::is_unsigned<U0>::value);
- using type = typename std::conditional<
- (sizeof(U0) < sizeof(typename unwidest_unsigned<UN...>::type)),
- U0, typename unwidest_unsigned<UN...>::type>::type;
-};
-
-template<class...>
-struct widest_unsigned;
-
-template<class U0>
-struct widest_unsigned<U0>
-{
- using type = U0;
-};
-
-template<class U0, class... UN>
-struct widest_unsigned<U0, UN...>
-{
- BOOST_STATIC_ASSERT(std::is_unsigned<U0>::value);
- using type = typename std::conditional<
- (sizeof(U0) > sizeof(typename widest_unsigned<UN...>::type)),
- U0, typename widest_unsigned<UN...>::type>::type;
-};
-
-template<class U>
-inline
-constexpr
-U
-min_all(U u)
-{
- BOOST_STATIC_ASSERT(std::is_unsigned<U>::value);
- return u;
-}
-
-template<class U0, class U1, class... UN>
-inline
-constexpr
-typename unwidest_unsigned<U0, U1, UN...>::type
-min_all(U0 u0, U1 u1, UN... un)
-{
- using type =
- typename unwidest_unsigned<U0, U1, UN...>::type;
- return u0 < u1 ?
- static_cast<type>(min_all(u0, un...)) :
- static_cast<type>(min_all(u1, un...));
-}
-
-template<class U>
-inline
-constexpr
-U
-max_all(U u)
-{
- BOOST_STATIC_ASSERT(std::is_unsigned<U>::value);
- return u;
-}
-
-template<class U0, class U1, class... UN>
-inline
-constexpr
-typename widest_unsigned<U0, U1, UN...>::type
-max_all(U0 u0, U1 u1, UN... un)
-{
- return u0 > u1? max_all(u0, un...) : max_all(u1, un...);
-}
-
-//------------------------------------------------------------------------------
-
-template<class T, class = void>
-struct get_lowest_layer_helper
-{
- using type = T;
-};
-
-template<class T>
-struct get_lowest_layer_helper<T,
- void_t<typename T::lowest_layer_type>>
-{
- using type = typename T::lowest_layer_type;
-};
-
-//------------------------------------------------------------------------------
-
-//
-// buffer concepts
-//
-
-// Types that meet the requirements,
-// for use with std::declval only.
-template<class BufferType>
-struct BufferSequence
-{
- using value_type = BufferType;
- using const_iterator = BufferType const*;
- ~BufferSequence();
- BufferSequence(BufferSequence const&) = default;
- const_iterator begin() const noexcept;
- const_iterator end() const noexcept;
-};
-using ConstBufferSequence =
- BufferSequence<boost::asio::const_buffer>;
-using MutableBufferSequence =
- BufferSequence<boost::asio::mutable_buffer>;
-
-template<class B1, class... Bn>
-struct is_all_const_buffer_sequence
- : std::integral_constant<bool,
- boost::asio::is_const_buffer_sequence<B1>::value &&
- is_all_const_buffer_sequence<Bn...>::value>
-{
-};
-
-template<class B>
-struct is_all_const_buffer_sequence<B>
- : boost::asio::is_const_buffer_sequence<B>
-{
-};
-
-template<class... Bn>
-struct common_buffers_type
-{
- using type = typename std::conditional<
- boost::is_convertible<std::tuple<Bn...>,
- typename repeat_tuple<sizeof...(Bn),
- boost::asio::mutable_buffer>::type>::value,
- boost::asio::mutable_buffer,
- boost::asio::const_buffer>::type;
-};
-
-template<class B>
-struct buffer_sequence_iterator
-{
- using type = decltype(
- boost::asio::buffer_sequence_begin(
- std::declval<B const&>()));
-};
-
-// Types that meet the requirements,
-// for use with std::declval only.
-struct StreamHandler
-{
- StreamHandler(StreamHandler const&) = default;
- void operator()(error_code ec, std::size_t);
-};
-using ReadHandler = StreamHandler;
-using WriteHandler = StreamHandler;
-
-template<class Buffers>
-class buffers_range_adaptor
-{
- Buffers const& b_;
-
-public:
- using value_type = typename std::conditional<
- boost::is_convertible<
- typename std::iterator_traits<
- typename buffer_sequence_iterator<
- Buffers>::type>::value_type,
- boost::asio::mutable_buffer>::value,
- boost::asio::mutable_buffer,
- boost::asio::const_buffer>::type;
-
- class const_iterator
- {
- friend class buffers_range_adaptor;
-
- using iter_type = typename
- buffer_sequence_iterator<Buffers>::type;
-
- iter_type it_;
-
- const_iterator(iter_type const& it)
- : it_(it)
- {
- }
-
- public:
- using value_type = typename
- buffers_range_adaptor::value_type;
- using pointer = value_type const*;
- using reference = value_type;
- using difference_type = std::ptrdiff_t;
- using iterator_category =
- std::bidirectional_iterator_tag;
-
- bool
- operator==(const_iterator const& other) const
- {
- return it_ == other.it_;
- }
-
- bool
- operator!=(const_iterator const& other) const
- {
- return ! (*this == other);
- }
-
- reference
- operator*() const
- {
- return *it_;
- }
-
- pointer
- operator->() const = delete;
-
- const_iterator&
- operator++()
- {
- ++it_;
- return *this;
- }
-
- const_iterator
- operator++(int)
- {
- auto temp = *this;
- ++(*this);
- return temp;
- }
-
- // deprecated
- const_iterator&
- operator--()
- {
- --it_;
- return *this;
- }
-
- // deprecated
- const_iterator
- operator--(int)
- {
- auto temp = *this;
- --(*this);
- return temp;
- }
- };
-
- explicit
- buffers_range_adaptor(Buffers const& b)
- : b_(b)
- {
- }
-
- const_iterator
- begin() const noexcept
- {
- return boost::asio::buffer_sequence_begin(b_);
- }
-
- const_iterator
- end() const noexcept
- {
- return boost::asio::buffer_sequence_end(b_);
- }
-};
-
-template<class Buffers>
-buffers_range_adaptor<Buffers>
-buffers_range(Buffers const& buffers)
-{
- return buffers_range_adaptor<Buffers>{buffers};
-}
-
-/* If this static assert goes off, it means that the completion
- handler you provided to an asynchronous initiating function did
- not have the right signature. Check the parameter types for your
- completion handler and make sure they match the list of types
- expected by the initiating function,
-*/
-#define BOOST_BEAST_HANDLER_INIT(type, sig) \
- static_assert(boost::beast::is_completion_handler< \
- BOOST_ASIO_HANDLER_TYPE(type, sig), sig>::value, \
- "CompletionHandler signature requirements not met"); \
- boost::asio::async_completion<type, sig> init{handler}
-
} // detail
} // beast
} // boost
diff --git a/boost/beast/core/detail/variant.hpp b/boost/beast/core/detail/variant.hpp
index 536cb7593f..94bd4c040c 100644
--- a/boost/beast/core/detail/variant.hpp
+++ b/boost/beast/core/detail/variant.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -12,9 +12,7 @@
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/assert.hpp>
-#include <cstddef>
-#include <tuple>
-#include <type_traits>
+#include <boost/mp11/algorithm.hpp>
namespace boost {
namespace beast {
@@ -34,19 +32,115 @@ class variant
detail::aligned_union_t<1, TN...> buf_;
unsigned char i_ = 0;
- template<std::size_t I>
- using type = typename std::tuple_element<
- I, std::tuple<TN...>>::type;
+ struct destroy
+ {
+ variant& self;
- template<std::size_t I>
- using C = std::integral_constant<std::size_t, I>;
+ void operator()(mp11::mp_size_t<0>)
+ {
+ }
+
+ template<class I>
+ void operator()(I) noexcept
+ {
+ using T =
+ mp11::mp_at_c<variant, I::value - 1>;
+ reinterpret_cast<T&>(self.buf_).~T();
+ }
+ };
+
+ struct copy
+ {
+ variant& self;
+ variant const& other;
+
+ void operator()(mp11::mp_size_t<0>)
+ {
+ }
+
+ template<class I>
+ void operator()(I)
+ {
+ using T =
+ mp11::mp_at_c<variant, I::value - 1>;
+ ::new(&self.buf_) T(
+ reinterpret_cast<T const&>(other.buf_));
+ self.i_ = I::value;
+ }
+ };
+
+ struct move
+ {
+ variant& self;
+ variant& other;
+
+ void operator()(mp11::mp_size_t<0>)
+ {
+ }
+
+ template<class I>
+ void operator()(I)
+ {
+ using T =
+ mp11::mp_at_c<variant, I::value - 1>;
+ ::new(&self.buf_) T(
+ reinterpret_cast<T&&>(other.buf_));
+ reinterpret_cast<T&>(other.buf_).~T();
+ self.i_ = I::value;
+ }
+ };
+
+ struct equals
+ {
+ variant const& self;
+ variant const& other;
+
+ bool operator()(mp11::mp_size_t<0>)
+ {
+ return true;
+ }
+
+ template<class I>
+ bool operator()(I)
+ {
+ using T =
+ mp11::mp_at_c<variant, I::value - 1>;
+ return
+ reinterpret_cast<T const&>(self.buf_) ==
+ reinterpret_cast<T const&>(other.buf_);
+ }
+ };
+
+
+ void destruct()
+ {
+ mp11::mp_with_index<
+ sizeof...(TN) + 1>(
+ i_, destroy{*this});
+ i_ = 0;
+ }
+
+ void copy_construct(variant const& other)
+ {
+ mp11::mp_with_index<
+ sizeof...(TN) + 1>(
+ other.i_, copy{*this, other});
+ }
+
+ void move_construct(variant& other)
+ {
+ mp11::mp_with_index<
+ sizeof...(TN) + 1>(
+ other.i_, move{*this, other});
+ other.i_ = 0;
+ }
public:
variant() = default;
~variant()
{
- destroy(C<0>{});
+ destruct();
}
bool
@@ -54,7 +148,9 @@ public:
{
if(i_ != other.i_)
return false;
- return equal(other, C<0>{});
+ return mp11::mp_with_index<
+ sizeof...(TN) + 1>(
+ i_, equals{*this, other});
}
// 0 = empty
@@ -65,15 +161,14 @@ public:
}
// moved-from object becomes empty
- variant(variant&& other)
+ variant(variant&& other) noexcept
{
- i_ = other.move(&buf_, C<0>{});
- other.i_ = 0;
+ move_construct(other);
}
variant(variant const& other)
{
- i_ = other.copy(&buf_, C<0>{});
+ copy_construct(other);
}
// moved-from object becomes empty
@@ -81,182 +176,55 @@ public:
{
if(this != &other)
{
- destroy(C<0>{});
- i_ = other.move(&buf_, C<0>{});
- other.i_ = 0;
+ destruct();
+ move_construct(other);
}
return *this;
}
-
+
variant& operator=(variant const& other)
{
if(this != &other)
{
- destroy(C<0>{});
- i_ = other.copy(&buf_, C<0>{});
+ destruct();
+ copy_construct(other);
+
}
return *this;
}
template<std::size_t I, class... Args>
void
- emplace(Args&&... args)
+ emplace(Args&&... args) noexcept
{
- destroy(C<0>{});
- new(&buf_) type<I-1>(
+ destruct();
+ ::new(&buf_) mp11::mp_at_c<variant, I - 1>(
std::forward<Args>(args)...);
i_ = I;
}
template<std::size_t I>
- type<I-1>&
+ mp11::mp_at_c<variant, I - 1>&
get()
{
BOOST_ASSERT(i_ == I);
return *reinterpret_cast<
- type<I-1>*>(&buf_);
+ mp11::mp_at_c<variant, I - 1>*>(&buf_);
}
template<std::size_t I>
- type<I-1> const&
+ mp11::mp_at_c<variant, I - 1> const&
get() const
{
BOOST_ASSERT(i_ == I);
return *reinterpret_cast<
- type<I-1> const*>(&buf_);
+ mp11::mp_at_c<variant, I - 1> const*>(&buf_);
}
void
reset()
{
- destroy(C<0>{});
- }
-
-private:
- void
- destroy(C<0>)
- {
- auto const I = 0;
- if(i_ == I)
- return;
- destroy(C<I+1>{});
- i_ = 0;
- }
-
- template<std::size_t I>
- void
- destroy(C<I>)
- {
- if(i_ == I)
- {
- using T = type<I-1>;
- get<I>().~T();
- return;
- }
- destroy(C<I+1>{});
- }
-
- void
- destroy(C<sizeof...(TN)>)
- {
- auto const I = sizeof...(TN);
- BOOST_ASSERT(i_ == I);
- using T = type<I-1>;
- get<I>().~T();
- }
-
- unsigned char
- move(void* dest, C<0>)
- {
- auto const I = 0;
- if(i_ == I)
- return I;
- return move(dest, C<I+1>{});
- }
-
- template<std::size_t I>
- unsigned char
- move(void* dest, C<I>)
- {
- if(i_ == I)
- {
- using T = type<I-1>;
- new(dest) T(std::move(get<I>()));
- get<I>().~T();
- return I;
- }
- return move(dest, C<I+1>{});
- }
-
- unsigned char
- move(void* dest, C<sizeof...(TN)>)
- {
- auto const I = sizeof...(TN);
- BOOST_ASSERT(i_ == I);
- using T = type<I-1>;
- new(dest) T(std::move(get<I>()));
- get<I>().~T();
- return I;
- }
-
- unsigned char
- copy(void* dest, C<0>) const
- {
- auto const I = 0;
- if(i_ == I)
- return I;
- return copy(dest, C<I+1>{});
- }
-
- template<std::size_t I>
- unsigned char
- copy(void* dest, C<I>) const
- {
- if(i_ == I)
- {
- using T = type<I-1>;
- auto const& t = get<I>();
- new(dest) T(t);
- return I;
- }
- return copy(dest, C<I+1>{});
- }
-
- unsigned char
- copy(void* dest, C<sizeof...(TN)>) const
- {
- auto const I = sizeof...(TN);
- BOOST_ASSERT(i_ == I);
- using T = type<I-1>;
- auto const& t = get<I>();
- new(dest) T(t);
- return I;
- }
-
- bool
- equal(variant const& other, C<0>) const
- {
- auto constexpr I = 0;
- if(i_ == I)
- return true;
- return equal(other, C<I+1>{});
- }
-
- template<std::size_t I>
- bool
- equal(variant const& other, C<I>) const
- {
- if(i_ == I)
- return get<I>() == other.get<I>();
- return equal(other, C<I+1>{});
- }
-
- bool
- equal(variant const& other, C<sizeof...(TN)>) const
- {
- auto constexpr I = sizeof...(TN);
- BOOST_ASSERT(i_ == I);
- return get<I>() == other.get<I>();
+ destruct();
}
};
diff --git a/boost/beast/core/detect_ssl.hpp b/boost/beast/core/detect_ssl.hpp
new file mode 100644
index 0000000000..b7b0550175
--- /dev/null
+++ b/boost/beast/core/detect_ssl.hpp
@@ -0,0 +1,651 @@
+//
+// 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_CORE_DETECT_SSL_HPP
+#define BOOST_BEAST_CORE_DETECT_SSL_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/async_base.hpp>
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/read_size.hpp>
+#include <boost/beast/core/stream_traits.hpp>
+#include <boost/logic/tribool.hpp>
+#include <boost/asio/async_result.hpp>
+#include <boost/asio/coroutine.hpp>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+
+//------------------------------------------------------------------------------
+//
+// Example: Detect TLS client_hello
+//
+// This is an example and also a public interface. It implements
+// an algorithm for determining if a "TLS client_hello" message
+// is received. It can be used to implement a listening port that
+// can handle both plain and TLS encrypted connections.
+//
+//------------------------------------------------------------------------------
+
+//[example_core_detect_ssl_1
+
+// By convention, the "detail" namespace means "not-public."
+// Identifiers in a detail namespace are not visible in the documentation,
+// and users should not directly use those identifiers in programs, otherwise
+// their program may break in the future.
+//
+// Using a detail namespace gives the library writer the freedom to change
+// the interface or behavior later, and maintain backward-compatibility.
+
+namespace detail {
+
+/** Return `true` if the buffer contains a TLS Protocol client_hello message.
+
+ This function analyzes the bytes at the beginning of the buffer
+ and compares it to a valid client_hello message. This is the
+ message required to be sent by a client at the beginning of
+ any TLS (encrypted communication) session, including when
+ resuming a session.
+
+ The return value will be:
+
+ @li `true` if the contents of the buffer unambiguously define
+ contain a client_hello message,
+
+ @li `false` if the contents of the buffer cannot possibly
+ be a valid client_hello message, or
+
+ @li `boost::indeterminate` if the buffer contains an
+ insufficient number of bytes to determine the result. In
+ this case the caller should read more data from the relevant
+ stream, append it to the buffers, and call this function again.
+
+ @param buffers The buffer sequence to inspect.
+ This type must meet the requirements of <em>ConstBufferSequence</em>.
+
+ @return `boost::tribool` indicating whether the buffer contains
+ a TLS client handshake, does not contain a handshake, or needs
+ additional bytes to determine an outcome.
+
+ @see
+
+ <a href="https://tools.ietf.org/html/rfc2246#section-7.4">7.4. Handshake protocol</a>
+ (RFC2246: The TLS Protocol)
+*/
+template <class ConstBufferSequence>
+boost::tribool
+is_tls_client_hello (ConstBufferSequence const& buffers);
+
+} // detail
+
+//]
+
+//[example_core_detect_ssl_2
+
+namespace detail {
+
+template <class ConstBufferSequence>
+boost::tribool
+is_tls_client_hello (ConstBufferSequence const& buffers)
+{
+ // Make sure buffers meets the requirements
+ static_assert(
+ net::is_const_buffer_sequence<ConstBufferSequence>::value,
+ "ConstBufferSequence type requirements not met");
+
+/*
+ The first message on a TLS connection must be the client_hello,
+ which is a type of handshake record, and it cannot be compressed
+ or encrypted. A plaintext record has this format:
+
+ 0 byte record_type // 0x16 = handshake
+ 1 byte major // major protocol version
+ 2 byte minor // minor protocol version
+ 3-4 uint16 length // size of the payload
+ 5 byte handshake_type // 0x01 = client_hello
+ 6 uint24 length // size of the ClientHello
+ 9 byte major // major protocol version
+ 10 byte minor // minor protocol version
+ 11 uint32 gmt_unix_time
+ 15 byte random_bytes[28]
+ ...
+*/
+
+ // Flatten the input buffers into a single contiguous range
+ // of bytes on the stack to make it easier to work with the data.
+ unsigned char buf[9];
+ auto const n = net::buffer_copy(
+ net::mutable_buffer(buf, sizeof(buf)), buffers);
+
+ // Can't do much without any bytes
+ if(n < 1)
+ return boost::indeterminate;
+
+ // Require the first byte to be 0x16, indicating a TLS handshake record
+ if(buf[0] != 0x16)
+ return false;
+
+ // We need at least 5 bytes to know the record payload size
+ if(n < 5)
+ return boost::indeterminate;
+
+ // Calculate the record payload size
+ std::uint32_t const length = (buf[3] << 8) + buf[4];
+
+ // A ClientHello message payload is at least 34 bytes.
+ // There can be multiple handshake messages in the same record.
+ if(length < 34)
+ return false;
+
+ // We need at least 6 bytes to know the handshake type
+ if(n < 6)
+ return boost::indeterminate;
+
+ // The handshake_type must be 0x01 == client_hello
+ if(buf[5] != 0x01)
+ return false;
+
+ // We need at least 9 bytes to know the payload size
+ if(n < 9)
+ return boost::indeterminate;
+
+ // Calculate the message payload size
+ std::uint32_t const size =
+ (buf[6] << 16) + (buf[7] << 8) + buf[8];
+
+ // The message payload can't be bigger than the enclosing record
+ if(size + 4 > length)
+ return false;
+
+ // This can only be a TLS client_hello message
+ return true;
+}
+
+} // detail
+
+//]
+
+//[example_core_detect_ssl_3
+
+/** Detect a TLS client handshake on a stream.
+
+ This function reads from a stream to determine if a client
+ handshake message is being received.
+
+ The call blocks until one of the following is true:
+
+ @li A TLS client opening handshake is detected,
+
+ @li The received data is invalid for a TLS client handshake, or
+
+ @li An error occurs.
+
+ The algorithm, known as a <em>composed operation</em>, is implemented
+ in terms of calls to the next layer's `read_some` function.
+
+ Bytes read from the stream will be stored in the passed dynamic
+ buffer, which may be used to perform the TLS handshake if the
+ detector returns true, or be otherwise consumed by the caller based
+ on the expected protocol.
+
+ @param stream The stream to read from. This type must meet the
+ requirements of <em>SyncReadStream</em>.
+
+ @param buffer The dynamic buffer to use. This type must meet the
+ requirements of <em>DynamicBuffer</em>.
+
+ @param ec Set to the error if any occurred.
+
+ @return `true` if the buffer contains a TLS client handshake and
+ no error occurred, otherwise `false`.
+*/
+template<
+ class SyncReadStream,
+ class DynamicBuffer>
+bool
+detect_ssl(
+ SyncReadStream& stream,
+ DynamicBuffer& buffer,
+ error_code& ec)
+{
+ namespace beast = boost::beast;
+
+ // Make sure arguments meet the requirements
+
+ 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");
+
+ // Loop until an error occurs or we get a definitive answer
+ for(;;)
+ {
+ // There could already be data in the buffer
+ // so we do this first, before reading from the stream.
+ auto const result = detail::is_tls_client_hello(buffer.data());
+
+ // If we got an answer, return it
+ if(! boost::indeterminate(result))
+ {
+ // A definite answer is a success
+ ec = {};
+ return static_cast<bool>(result);
+ }
+
+ // Try to fill our buffer by reading from the stream.
+ // The function read_size calculates a reasonable size for the
+ // amount to read next, using existing capacity if possible to
+ // avoid allocating memory, up to the limit of 1536 bytes which
+ // is the size of a normal TCP frame.
+
+ std::size_t const bytes_transferred = stream.read_some(
+ buffer.prepare(beast::read_size(buffer, 1536)), ec);
+
+ // Commit what we read into the buffer's input area.
+ buffer.commit(bytes_transferred);
+
+ // Check for an error
+ if(ec)
+ break;
+ }
+
+ // error
+ return false;
+}
+
+//]
+
+//[example_core_detect_ssl_4
+
+/** Detect a TLS/SSL handshake asynchronously on a stream.
+
+ This function reads asynchronously from a stream to determine
+ if a client handshake message is being received.
+
+ This call always returns immediately. The asynchronous operation
+ will continue until one of the following conditions is true:
+
+ @li A TLS client opening handshake is detected,
+
+ @li The received data is invalid for a TLS client handshake, or
+
+ @li An error occurs.
+
+ The algorithm, known as a <em>composed asynchronous operation</em>,
+ is implemented in terms of calls to the next layer's `async_read_some`
+ function. The program must ensure that no other calls to
+ `async_read_some` are performed until this operation completes.
+
+ Bytes read from the stream will be stored in the passed dynamic
+ buffer, which may be used to perform the TLS handshake if the
+ detector returns true, or be otherwise consumed by the caller based
+ on the expected protocol.
+
+ @param stream The stream to read from. This type must meet the
+ requirements of <em>AsyncReadStream</em>.
+
+ @param buffer The dynamic buffer to use. This type must meet the
+ requirements of <em>DynamicBuffer</em>.
+
+ @param token The completion token used to determine the method
+ used to provide the result of the asynchronous operation. If
+ this is a completion handler, the implementation takes ownership
+ of the handler by performing a decay-copy, and the equivalent
+ function signature of the handler must be:
+ @code
+ void handler(
+ error_code const& error, // Set to the error, if any
+ bool result // The result of the detector
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+*/
+template<
+ class AsyncReadStream,
+ class DynamicBuffer,
+ class CompletionToken>
+#if BOOST_BEAST_DOXYGEN
+BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, bool))
+#else
+auto
+#endif
+async_detect_ssl(
+ AsyncReadStream& stream,
+ DynamicBuffer& buffer,
+ CompletionToken&& token) ->
+ typename net::async_result<
+ typename std::decay<CompletionToken>::type, /*< `async_result` customizes the return value based on the completion token >*/
+ void(error_code, bool)>::return_type; /*< This is the signature for the completion handler >*/
+//]
+
+//[example_core_detect_ssl_5
+
+// These implementation details don't need to be public
+
+namespace detail {
+
+// The composed operation object
+template<
+ class DetectHandler,
+ class AsyncReadStream,
+ class DynamicBuffer>
+class detect_ssl_op;
+
+// This is a function object which `net::async_initiate` can use to launch
+// our composed operation. This is a relatively new feature in networking
+// which allows the asynchronous operation to be "lazily" executed (meaning
+// that it is launched later). Users don't need to worry about this, but
+// authors of composed operations need to write it this way to get the
+// very best performance, for example when using Coroutines TS (`co_await`).
+
+struct run_detect_ssl_op
+{
+ // The implementation of `net::async_initiate` captures the
+ // arguments of the initiating function, and then calls this
+ // function object later with the captured arguments in order
+ // to launch the composed operation. All we need to do here
+ // is take those arguments and construct our composed operation
+ // object.
+ //
+ // `async_initiate` takes care of transforming the completion
+ // token into the "real handler" which must have the correct
+ // signature, in this case `void(error_code, boost::tri_bool)`.
+
+ template<
+ class DetectHandler,
+ class AsyncReadStream,
+ class DynamicBuffer>
+ void operator()(
+ DetectHandler&& h,
+ AsyncReadStream* s, // references are passed as pointers
+ DynamicBuffer& b)
+ {
+ detect_ssl_op<
+ typename std::decay<DetectHandler>::type,
+ AsyncReadStream,
+ DynamicBuffer>(
+ std::forward<DetectHandler>(h), *s, b);
+ }
+};
+
+} // detail
+
+//]
+
+//[example_core_detect_ssl_6
+
+// Here is the implementation of the asynchronous initiation function
+template<
+ class AsyncReadStream,
+ class DynamicBuffer,
+ class CompletionToken>
+#if BOOST_BEAST_DOXYGEN
+BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, bool))
+#else
+auto
+#endif
+async_detect_ssl(
+ AsyncReadStream& stream,
+ DynamicBuffer& buffer,
+ CompletionToken&& token)
+ -> typename net::async_result<
+ typename std::decay<CompletionToken>::type,
+ void(error_code, bool)>::return_type
+{
+ // Make sure arguments meet the type requirements
+
+ static_assert(
+ is_async_read_stream<AsyncReadStream>::value,
+ "SyncReadStream type requirements not met");
+
+ static_assert(
+ net::is_dynamic_buffer<DynamicBuffer>::value,
+ "DynamicBuffer type requirements not met");
+
+ // The function `net::async_initate` uses customization points
+ // to allow one asynchronous initiating function to work with
+ // all sorts of notification systems, such as callbacks but also
+ // fibers, futures, coroutines, and user-defined types.
+ //
+ // It works by capturing all of the arguments using perfect
+ // forwarding, and then depending on the specialization of
+ // `net::async_result` for the type of `CompletionToken`,
+ // the `initiation` object will be invoked with the saved
+ // parameters and the actual completion handler. Our
+ // initiating object is `run_detect_ssl_op`.
+ //
+ // Non-const references need to be passed as pointers,
+ // since we don't want a decay-copy.
+
+
+ return net::async_initiate<
+ CompletionToken,
+ void(error_code, bool)>(
+ detail::run_detect_ssl_op{},
+ token,
+ &stream, // pass the reference by pointer
+ buffer);
+}
+
+//]
+
+//[example_core_detect_ssl_7
+
+namespace detail {
+
+// Read from a stream, calling is_tls_client_hello on the data
+// data to determine if the TLS client handshake is present.
+//
+// This will be implemented using Asio's "stackless coroutines"
+// which are based on macros forming a switch statement. The
+// operation is derived from `coroutine` for this reason.
+//
+// The library type `async_base` takes care of all of the
+// boilerplate for writing composed operations, including:
+//
+// * Storing the user's completion handler
+// * Maintaining the work guard for the handler's associated executor
+// * Propagating the associated allocator of the handler
+// * Propagating the associated executor of the handler
+// * Deallocating temporary storage before invoking the handler
+// * Posting the handler to the executor on an immediate completion
+//
+// `async_base` needs to know the type of the handler, as well
+// as the executor of the I/O object being used. The metafunction
+// `executor_type` returns the type of executor used by an
+// I/O object.
+//
+template<
+ class DetectHandler,
+ class AsyncReadStream,
+ class DynamicBuffer>
+class detect_ssl_op
+ : public boost::asio::coroutine
+ , public async_base<
+ DetectHandler, executor_type<AsyncReadStream>>
+{
+ // This composed operation has trivial state,
+ // so it is just kept inside the class and can
+ // be cheaply copied as needed by the implementation.
+
+ AsyncReadStream& stream_;
+
+ // The callers buffer is used to hold all received data
+ DynamicBuffer& buffer_;
+
+ // We're going to need this in case we have to post the handler
+ error_code ec_;
+
+ boost::tribool result_ = false;
+
+public:
+ // Completion handlers must be MoveConstructible.
+ detect_ssl_op(detect_ssl_op&&) = default;
+
+ // Construct the operation. The handler is deduced through
+ // the template type `DetectHandler_`, this lets the same constructor
+ // work properly for both lvalues and rvalues.
+ //
+ template<class DetectHandler_>
+ detect_ssl_op(
+ DetectHandler_&& handler,
+ AsyncReadStream& stream,
+ DynamicBuffer& buffer)
+ : beast::async_base<
+ DetectHandler_,
+ beast::executor_type<AsyncReadStream>>(
+ std::forward<DetectHandler_>(handler),
+ stream.get_executor())
+ , stream_(stream)
+ , buffer_(buffer)
+ {
+ // This starts the operation. We pass `false` to tell the
+ // algorithm that it needs to use net::post if it wants to
+ // complete immediately. This is required by Networking,
+ // as initiating functions are not allowed to invoke the
+ // completion handler on the caller's thread before
+ // returning.
+ (*this)({}, 0, false);
+ }
+
+ // Our main entry point. This will get called as our
+ // intermediate operations complete. Definition below.
+ //
+ // The parameter `cont` indicates if we are being called subsequently
+ // from the original invocation
+ //
+ void operator()(
+ error_code ec,
+ std::size_t bytes_transferred,
+ bool cont = true);
+};
+
+} // detail
+
+//]
+
+//[example_core_detect_ssl_8
+
+namespace detail {
+
+// This example uses the Asio's stackless "fauxroutines", implemented
+// using a macro-based solution. It makes the code easier to write and
+// easier to read. This include file defines the necessary macros and types.
+#include <boost/asio/yield.hpp>
+
+// detect_ssl_op is callable with the signature void(error_code, bytes_transferred),
+// allowing `*this` to be used as a ReadHandler
+//
+template<
+ class AsyncStream,
+ class DynamicBuffer,
+ class Handler>
+void
+detect_ssl_op<AsyncStream, DynamicBuffer, Handler>::
+operator()(error_code ec, std::size_t bytes_transferred, bool cont)
+{
+ namespace beast = boost::beast;
+
+ // This introduces the scope of the stackless coroutine
+ reenter(*this)
+ {
+ // Loop until an error occurs or we get a definitive answer
+ for(;;)
+ {
+ // There could already be a hello in the buffer so check first
+ result_ = is_tls_client_hello(buffer_.data());
+
+ // If we got an answer, then the operation is complete
+ if(! boost::indeterminate(result_))
+ break;
+
+ // Try to fill our buffer by reading from the stream.
+ // The function read_size calculates a reasonable size for the
+ // amount to read next, using existing capacity if possible to
+ // avoid allocating memory, up to the limit of 1536 bytes which
+ // is the size of a normal TCP frame.
+ //
+ // `async_read_some` expects a ReadHandler as the completion
+ // handler. The signature of a read handler is void(error_code, size_t),
+ // and this function matches that signature (the `cont` parameter has
+ // a default of true). We pass `std::move(*this)` as the completion
+ // handler for the read operation. This transfers ownership of this
+ // entire state machine back into the `async_read_some` operation.
+ // Care must be taken with this idiom, to ensure that parameters
+ // passed to the initiating function which could be invalidated
+ // by the move, are first moved to the stack before calling the
+ // initiating function.
+
+ yield stream_.async_read_some(buffer_.prepare(
+ read_size(buffer_, 1536)), std::move(*this));
+
+ // Commit what we read into the buffer's input area.
+ buffer_.commit(bytes_transferred);
+
+ // Check for an error
+ if(ec)
+ break;
+ }
+
+ // If `cont` is true, the handler will be invoked directly.
+ //
+ // Otherwise, the handler cannot be invoked directly, because
+ // initiating functions are not allowed to call the handler
+ // before returning. Instead, the handler must be posted to
+ // the I/O context. We issue a zero-byte read using the same
+ // type of buffers used in the ordinary read above, to prevent
+ // the compiler from creating an extra instantiation of the
+ // function template. This reduces compile times and the size
+ // of the program executable.
+
+ if(! cont)
+ {
+ // Save the error, otherwise it will be overwritten with
+ // a successful error code when this read completes
+ // immediately.
+ ec_ = ec;
+
+ // Zero-byte reads and writes are guaranteed to complete
+ // immediately with succcess. The type of buffers and the
+ // type of handler passed here need to exactly match the types
+ // used in the call to async_read_some above, to avoid
+ // instantiating another version of the function template.
+
+ yield stream_.async_read_some(buffer_.prepare(0), std::move(*this));
+
+ // Restore the saved error code
+ ec = ec_;
+ }
+
+ // Invoke the final handler.
+ // At this point, we are guaranteed that the original initiating
+ // function is no longer on our stack frame.
+
+ this->complete_now(ec, static_cast<bool>(result_));
+ }
+}
+
+// Including this file undefines the macros used by the stackless fauxroutines.
+#include <boost/asio/unyield.hpp>
+
+} // detail
+
+//]
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/error.hpp b/boost/beast/core/error.hpp
index f034f7a404..29a8648a3d 100644
--- a/boost/beast/core/error.hpp
+++ b/boost/beast/core/error.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -52,7 +52,37 @@ enum errc{};
namespace errc = boost::system::errc;
#endif
+//------------------------------------------------------------------------------
+
+/// Error codes returned from library operations
+enum class error
+{
+ /** The socket was closed due to a timeout
+
+ This error indicates that a socket was closed due to a
+ a timeout detected during an operation.
+
+ Error codes with this value will compare equal to @ref condition::timeout.
+ */
+ timeout = 1
+};
+
+/// Error conditions corresponding to sets of library error codes.
+enum class condition
+{
+ /** The operation timed out
+
+ This error indicates that an operation took took too long.
+ */
+ timeout = 1
+};
+
} // beast
} // boost
+#include <boost/beast/core/impl/error.hpp>
+#ifdef BOOST_BEAST_HEADER_ONLY
+#include <boost/beast/core/impl/error.ipp>
+#endif
+
#endif
diff --git a/boost/beast/core/file.hpp b/boost/beast/core/file.hpp
index 09c8e82081..207f8ef26c 100644
--- a/boost/beast/core/file.hpp
+++ b/boost/beast/core/file.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2015-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)
@@ -15,7 +15,6 @@
#include <boost/beast/core/file_posix.hpp>
#include <boost/beast/core/file_stdio.hpp>
#include <boost/beast/core/file_win32.hpp>
-#include <boost/config.hpp>
namespace boost {
namespace beast {
@@ -23,7 +22,7 @@ namespace beast {
/** An implementation of File.
This alias is set to the best available implementation
- of @b File given the platform and build settings.
+ of <em>File</em> given the platform and build settings.
*/
#if BOOST_BEAST_DOXYGEN
struct file : file_stdio
diff --git a/boost/beast/core/file_base.hpp b/boost/beast/core/file_base.hpp
index c2b3c53a53..cf75e78579 100644
--- a/boost/beast/core/file_base.hpp
+++ b/boost/beast/core/file_base.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2015-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)
@@ -11,42 +11,63 @@
#define BOOST_BEAST_CORE_FILE_BASE_HPP
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/string.hpp>
+#include <boost/beast/core/error.hpp>
+#include <boost/type_traits/make_void.hpp>
+#include <type_traits>
namespace boost {
namespace beast {
+/*
+
+file_mode acesss sharing seeking file std mode
+--------------------------------------------------------------------------------------
+read read-only shared random must exist "rb"
+scan read-only shared sequential must exist "rbS"
+write read/write exclusive random create/truncate "wb+"
+write_new read/write exclusive random must not exist "wbx"
+write_existing read/write exclusive random must exist "rb+"
+append write-only exclusive sequential create/truncate "ab"
+append_existing write-only exclusive sequential must exist "ab"
+
+*/
+
/** File open modes
These modes are used when opening files using
- instances of the @b File concept.
+ instances of the <em>File</em> concept.
@see file_stdio
*/
enum class file_mode
{
- /// Random reading
+ /// Random read-only access to an existing file
read,
- /// Sequential reading
+ /// Sequential read-only access to an existing file
scan,
- /** Random writing to a new or truncated file
-
- @li If the file does not exist, it is created.
+ /** Random reading and writing to a new or truncated file
- @li If the file exists, it is truncated to
- zero size upon opening.
+ This mode permits random-access reading and writing
+ for the specified file. If the file does not exist
+ prior to the function call, it is created with an
+ initial size of zero bytes. Otherwise if the file
+ already exists, the size is truncated to zero bytes.
*/
write,
- /** Random writing to new file only
+ /** Random reading and writing to a new file only
- If the file exists, an error is generated.
+ This mode permits random-access reading and writing
+ for the specified file. The file will be created with
+ an initial size of zero bytes. If the file already exists
+ prior to the function call, an error is returned and
+ no file is opened.
*/
write_new,
- /** Random writing to existing file
+ /** Random write-only access to existing file
If the file does not exist, an error is generated.
*/
@@ -64,15 +85,6 @@ enum class file_mode
*/
append,
- /** Appending to a new file only
-
- The current file position shall be set to the end of
- the file prior to each write.
-
- If the file exists, an error is generated.
- */
- append_new,
-
/** Appending to an existing file
The current file position shall be set to the end of
@@ -83,6 +95,69 @@ enum class file_mode
append_existing
};
+/** Determine if `T` meets the requirements of <em>File</em>.
+
+ Metafunctions are used to perform compile time checking of template
+ types. This type will be `std::true_type` if `T` meets the requirements,
+ else the type will be `std::false_type`.
+
+ @par Example
+
+ Use with `static_assert`:
+
+ @code
+ template<class File>
+ void f(File& file)
+ {
+ static_assert(is_file<File>::value,
+ "File type requirements not met");
+ ...
+ @endcode
+
+ Use with `std::enable_if` (SFINAE):
+
+ @code
+ template<class File>
+ typename std::enable_if<is_file<File>::value>::type
+ f(File& file);
+ @endcode
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+struct is_file : std::integral_constant<bool, ...>{};
+#else
+template<class T, class = void>
+struct is_file : std::false_type {};
+
+template<class T>
+struct is_file<T, boost::void_t<decltype(
+ std::declval<bool&>() = std::declval<T const&>().is_open(),
+ std::declval<T&>().close(std::declval<error_code&>()),
+ std::declval<T&>().open(
+ std::declval<char const*>(),
+ std::declval<file_mode>(),
+ std::declval<error_code&>()),
+ std::declval<std::uint64_t&>() = std::declval<T&>().size(
+ std::declval<error_code&>()),
+ std::declval<std::uint64_t&>() = std::declval<T&>().pos(
+ std::declval<error_code&>()),
+ std::declval<T&>().seek(
+ std::declval<std::uint64_t>(),
+ std::declval<error_code&>()),
+ std::declval<std::size_t&>() = std::declval<T&>().read(
+ std::declval<void*>(),
+ std::declval<std::size_t>(),
+ std::declval<error_code&>()),
+ std::declval<std::size_t&>() = std::declval<T&>().write(
+ std::declval<void const*>(),
+ std::declval<std::size_t>(),
+ std::declval<error_code&>())
+ )>> : std::integral_constant<bool,
+ std::is_default_constructible<T>::value &&
+ std::is_destructible<T>::value
+ > {};
+#endif
+
} // beast
} // boost
diff --git a/boost/beast/core/file_posix.hpp b/boost/beast/core/file_posix.hpp
index 65bac2065d..b7a70a54ae 100644
--- a/boost/beast/core/file_posix.hpp
+++ b/boost/beast/core/file_posix.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2015-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)
@@ -10,7 +10,7 @@
#ifndef BOOST_BEAST_CORE_FILE_POSIX_HPP
#define BOOST_BEAST_CORE_FILE_POSIX_HPP
-#include <boost/config.hpp>
+#include <boost/beast/core/detail/config.hpp>
#if ! defined(BOOST_BEAST_NO_POSIX_FILE)
# if ! defined(__APPLE__) && ! defined(__linux__)
@@ -37,12 +37,17 @@ namespace beast {
/** An implementation of File for POSIX systems.
- This class implements a @b File using POSIX interfaces.
+ This class implements a <em>File</em> using POSIX interfaces.
*/
class file_posix
{
int fd_ = -1;
+ BOOST_BEAST_DECL
+ static
+ int
+ native_close(int& fd);
+
public:
/** The type of the underlying file handle.
@@ -54,6 +59,7 @@ public:
If the file is open it is first closed.
*/
+ BOOST_BEAST_DECL
~file_posix();
/** Constructor
@@ -66,12 +72,14 @@ public:
The moved-from object behaves as if default constructed.
*/
+ BOOST_BEAST_DECL
file_posix(file_posix&& other);
/** Assignment
The moved-from object behaves as if default constructed.
*/
+ BOOST_BEAST_DECL
file_posix& operator=(file_posix&& other);
/// Returns the native handle associated with the file.
@@ -87,6 +95,7 @@ public:
@param fd The native file handle to assign.
*/
+ BOOST_BEAST_DECL
void
native_handle(native_handle_type fd);
@@ -101,6 +110,7 @@ public:
@param ec Set to the error, if any occurred.
*/
+ BOOST_BEAST_DECL
void
close(error_code& ec);
@@ -112,6 +122,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
void
open(char const* path, file_mode mode, error_code& ec);
@@ -121,6 +132,7 @@ public:
@return The size in bytes
*/
+ BOOST_BEAST_DECL
std::uint64_t
size(error_code& ec) const;
@@ -130,6 +142,7 @@ public:
@return The offset in bytes from the beginning of the file
*/
+ BOOST_BEAST_DECL
std::uint64_t
pos(error_code& ec) const;
@@ -139,6 +152,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
void
seek(std::uint64_t offset, error_code& ec);
@@ -150,6 +164,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
std::size_t
read(void* buffer, std::size_t n, error_code& ec) const;
@@ -161,6 +176,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
std::size_t
write(void const* buffer, std::size_t n, error_code& ec);
};
@@ -168,7 +184,9 @@ public:
} // beast
} // boost
+#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/beast/core/impl/file_posix.ipp>
+#endif
#endif
diff --git a/boost/beast/core/file_stdio.hpp b/boost/beast/core/file_stdio.hpp
index 09ca0c42de..d56632b899 100644
--- a/boost/beast/core/file_stdio.hpp
+++ b/boost/beast/core/file_stdio.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2015-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)
@@ -39,6 +39,7 @@ public:
If the file is open it is first closed.
*/
+ BOOST_BEAST_DECL
~file_stdio();
/** Constructor
@@ -51,12 +52,14 @@ public:
The moved-from object behaves as if default constructed.
*/
+ BOOST_BEAST_DECL
file_stdio(file_stdio&& other);
/** Assignment
The moved-from object behaves as if default constructed.
*/
+ BOOST_BEAST_DECL
file_stdio& operator=(file_stdio&& other);
/// Returns the native handle associated with the file.
@@ -72,6 +75,7 @@ public:
@param f The native file handle to assign.
*/
+ BOOST_BEAST_DECL
void
native_handle(FILE* f);
@@ -86,6 +90,7 @@ public:
@param ec Set to the error, if any occurred.
*/
+ BOOST_BEAST_DECL
void
close(error_code& ec);
@@ -97,6 +102,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
void
open(char const* path, file_mode mode, error_code& ec);
@@ -106,6 +112,7 @@ public:
@return The size in bytes
*/
+ BOOST_BEAST_DECL
std::uint64_t
size(error_code& ec) const;
@@ -115,6 +122,7 @@ public:
@return The offset in bytes from the beginning of the file
*/
+ BOOST_BEAST_DECL
std::uint64_t
pos(error_code& ec) const;
@@ -124,6 +132,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
void
seek(std::uint64_t offset, error_code& ec);
@@ -135,6 +144,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
std::size_t
read(void* buffer, std::size_t n, error_code& ec) const;
@@ -146,6 +156,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
std::size_t
write(void const* buffer, std::size_t n, error_code& ec);
};
@@ -153,6 +164,8 @@ public:
} // beast
} // boost
+#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/beast/core/impl/file_stdio.ipp>
+#endif
#endif
diff --git a/boost/beast/core/file_win32.hpp b/boost/beast/core/file_win32.hpp
index 3e9a18abaa..908076d7fe 100644
--- a/boost/beast/core/file_win32.hpp
+++ b/boost/beast/core/file_win32.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2015-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)
@@ -10,7 +10,7 @@
#ifndef BOOST_BEAST_CORE_FILE_WIN32_HPP
#define BOOST_BEAST_CORE_FILE_WIN32_HPP
-#include <boost/config.hpp>
+#include <boost/beast/core/detail/config.hpp>
#if ! defined(BOOST_BEAST_USE_WIN32_FILE)
# ifdef BOOST_MSVC
@@ -34,7 +34,7 @@ namespace beast {
/** An implementation of File for Win32.
- This class implements a @b File using Win32 native interfaces.
+ This class implements a <em>File</em> using Win32 native interfaces.
*/
class file_win32
{
@@ -56,6 +56,7 @@ public:
If the file is open it is first closed.
*/
+ BOOST_BEAST_DECL
~file_win32();
/** Constructor
@@ -68,12 +69,14 @@ public:
The moved-from object behaves as if default constructed.
*/
+ BOOST_BEAST_DECL
file_win32(file_win32&& other);
/** Assignment
The moved-from object behaves as if default constructed.
*/
+ BOOST_BEAST_DECL
file_win32& operator=(file_win32&& other);
/// Returns the native handle associated with the file.
@@ -89,6 +92,7 @@ public:
@param h The native file handle to assign.
*/
+ BOOST_BEAST_DECL
void
native_handle(native_handle_type h);
@@ -103,6 +107,7 @@ public:
@param ec Set to the error, if any occurred.
*/
+ BOOST_BEAST_DECL
void
close(error_code& ec);
@@ -114,6 +119,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
void
open(char const* path, file_mode mode, error_code& ec);
@@ -123,6 +129,7 @@ public:
@return The size in bytes
*/
+ BOOST_BEAST_DECL
std::uint64_t
size(error_code& ec) const;
@@ -132,6 +139,7 @@ public:
@return The offset in bytes from the beginning of the file
*/
+ BOOST_BEAST_DECL
std::uint64_t
pos(error_code& ec);
@@ -141,6 +149,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
void
seek(std::uint64_t offset, error_code& ec);
@@ -152,6 +161,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
std::size_t
read(void* buffer, std::size_t n, error_code& ec);
@@ -163,6 +173,7 @@ public:
@param ec Set to the error, if any occurred
*/
+ BOOST_BEAST_DECL
std::size_t
write(void const* buffer, std::size_t n, error_code& ec);
};
@@ -170,7 +181,9 @@ public:
} // beast
} // boost
+#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/beast/core/impl/file_win32.ipp>
+#endif
#endif
diff --git a/boost/beast/core/flat_buffer.hpp b/boost/beast/core/flat_buffer.hpp
index 1e0f0ef519..9e8d639c4d 100644
--- a/boost/beast/core/flat_buffer.hpp
+++ b/boost/beast/core/flat_buffer.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -16,22 +16,35 @@
#include <boost/core/empty_value.hpp>
#include <limits>
#include <memory>
+#include <type_traits>
namespace boost {
namespace beast {
-/** A linear dynamic buffer.
+/** A dynamic buffer providing buffer sequences of length one.
- Objects of this type meet the requirements of @b DynamicBuffer
- and offer additional invariants:
-
- @li Buffer sequences returned by @ref data and @ref prepare
- will always be of length one.
+ A dynamic buffer encapsulates memory storage that may be
+ automatically resized as required, where the memory is
+ divided into two regions: readable bytes followed by
+ writable bytes. These memory regions are internal to
+ the dynamic buffer, but direct access to the elements
+ is provided to permit them to be efficiently used with
+ I/O operations.
+
+ Objects of this type meet the requirements of <em>DynamicBuffer</em>
+ and have the following additional properties:
+
+ @li A mutable buffer sequence representing the readable
+ bytes is returned by @ref data when `this` is non-const.
@li A configurable maximum buffer size may be set upon
construction. Attempts to exceed the buffer size will throw
`std::length_error`.
+ @li Buffer sequences representing the readable and writable
+ bytes, returned by @ref data and @ref prepare, will have
+ length one.
+
Upon construction, a maximum size for the buffer may be
specified. If this limit is exceeded, the `std::length_error`
exception will be thrown.
@@ -49,11 +62,6 @@ class basic_flat_buffer
template rebind_alloc<char>>
#endif
{
- enum
- {
- min_size = 512
- };
-
template<class OtherAlloc>
friend class basic_flat_buffer;
@@ -61,13 +69,21 @@ class basic_flat_buffer
detail::allocator_traits<Allocator>::
template rebind_alloc<char>;
+ static bool constexpr default_nothrow =
+ std::is_nothrow_default_constructible<Allocator>::value;
+
using alloc_traits =
- detail::allocator_traits<base_alloc_type>;
+ beast::detail::allocator_traits<base_alloc_type>;
+
+ using pocma = typename
+ alloc_traits::propagate_on_container_move_assignment;
+
+ using pocca = typename
+ alloc_traits::propagate_on_container_copy_assignment;
static
- inline
std::size_t
- dist(char const* first, char const* last)
+ dist(char const* first, char const* last) noexcept
{
return static_cast<std::size_t>(last - first);
}
@@ -83,260 +99,435 @@ public:
/// The type of allocator used.
using allocator_type = Allocator;
- /// The type used to represent the input sequence as a list of buffers.
- using const_buffers_type = boost::asio::const_buffer;
-
- /// The type used to represent the output sequence as a list of buffers.
- using mutable_buffers_type = boost::asio::mutable_buffer;
-
/// Destructor
~basic_flat_buffer();
/** Constructor
- Upon construction, capacity will be zero.
+ After construction, @ref capacity will return zero, and
+ @ref max_size will return the largest value which may
+ be passed to the allocator's `allocate` function.
*/
- basic_flat_buffer();
+ basic_flat_buffer() noexcept(default_nothrow);
/** Constructor
- Upon construction, capacity will be zero.
+ After construction, @ref capacity will return zero, and
+ @ref max_size will return the specified value of `limit`.
- @param limit The setting for @ref max_size.
+ @param limit The desired maximum size.
*/
explicit
- basic_flat_buffer(std::size_t limit);
+ basic_flat_buffer(
+ std::size_t limit) noexcept(default_nothrow);
/** Constructor
- Upon construction, capacity will be zero.
+ After construction, @ref capacity will return zero, and
+ @ref max_size will return the largest value which may
+ be passed to the allocator's `allocate` function.
- @param alloc The allocator to construct with.
+ @param alloc The allocator to use for the object.
+
+ @esafe
+
+ No-throw guarantee.
*/
explicit
- basic_flat_buffer(Allocator const& alloc);
+ basic_flat_buffer(Allocator const& alloc) noexcept;
/** Constructor
- Upon construction, capacity will be zero.
+ After construction, @ref capacity will return zero, and
+ @ref max_size will return the specified value of `limit`.
+
+ @param limit The desired maximum size.
+
+ @param alloc The allocator to use for the object.
- @param limit The setting for @ref max_size.
+ @esafe
- @param alloc The allocator to use.
+ No-throw guarantee.
*/
basic_flat_buffer(
- std::size_t limit, Allocator const& alloc);
+ std::size_t limit,
+ Allocator const& alloc) noexcept;
- /** Constructor
+ /** Move Constructor
- After the move, `*this` will have an empty output sequence.
+ The container is constructed with the contents of `other`
+ using move semantics. The maximum size will be the same
+ as the moved-from object.
- @param other The object to move from. After the move,
- The object's state will be as if constructed using
- its current allocator and limit.
+ Buffer sequences previously obtained from `other` using
+ @ref data or @ref prepare remain valid after the move.
+
+ @param other The object to move from. After the move, the
+ moved-from object will have zero capacity, zero readable
+ bytes, and zero writable bytes.
+
+ @esafe
+
+ No-throw guarantee.
*/
- basic_flat_buffer(basic_flat_buffer&& other);
+ basic_flat_buffer(basic_flat_buffer&& other) noexcept;
- /** Constructor
+ /** Move Constructor
- After the move, `*this` will have an empty output sequence.
+ Using `alloc` as the allocator for the new container, the
+ contents of `other` are moved. If `alloc != other.get_allocator()`,
+ this results in a copy. The maximum size will be the same
+ as the moved-from object.
+
+ Buffer sequences previously obtained from `other` using
+ @ref data or @ref prepare become invalid after the move.
@param other The object to move from. After the move,
- The object's state will be as if constructed using
- its current allocator and limit.
+ the moved-from object will have zero capacity, zero readable
+ bytes, and zero writable bytes.
+
+ @param alloc The allocator to use for the object.
- @param alloc The allocator to use.
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of `alloc`.
*/
basic_flat_buffer(
- basic_flat_buffer&& other, Allocator const& alloc);
+ basic_flat_buffer&& other,
+ Allocator const& alloc);
- /** Constructor
+ /** Copy Constructor
+
+ This container is constructed with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
@param other The object to copy from.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of the allocator.
*/
basic_flat_buffer(basic_flat_buffer const& other);
- /** Constructor
+ /** Copy Constructor
+
+ This container is constructed with the contents of `other`
+ using copy semantics and the specified allocator. The maximum
+ size will be the same as the copied object.
@param other The object to copy from.
- @param alloc The allocator to use.
+ @param alloc The allocator to use for the object.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of `alloc`.
*/
- basic_flat_buffer(basic_flat_buffer const& other,
+ basic_flat_buffer(
+ basic_flat_buffer const& other,
Allocator const& alloc);
- /** Constructor
+ /** Copy Constructor
+
+ This container is constructed with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
@param other The object to copy from.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of the allocator.
*/
template<class OtherAlloc>
basic_flat_buffer(
- basic_flat_buffer<OtherAlloc> const& other);
+ basic_flat_buffer<OtherAlloc> const& other)
+ noexcept(default_nothrow);
- /** Constructor
+ /** Copy Constructor
+
+ This container is constructed with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
@param other The object to copy from.
- @param alloc The allocator to use.
+ @param alloc The allocator to use for the object.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of `alloc`.
*/
template<class OtherAlloc>
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const& other,
- Allocator const& alloc);
+ Allocator const& alloc);
+
+ /** Move Assignment
- /** Assignment
+ The container is assigned with the contents of `other`
+ using move semantics. The maximum size will be the same
+ as the moved-from object.
- After the move, `*this` will have an empty output sequence.
+ Buffer sequences previously obtained from `other` using
+ @ref data or @ref prepare remain valid after the move.
@param other The object to move from. After the move,
- the object's state will be as if constructed using
- its current allocator and limit.
+ the moved-from object will have zero capacity, zero readable
+ bytes, and zero writable bytes.
+
+ @esafe
+
+ No-throw guarantee.
*/
basic_flat_buffer&
- operator=(basic_flat_buffer&& other);
+ operator=(basic_flat_buffer&& other) noexcept;
- /** Assignment
+ /** Copy Assignment
- After the copy, `*this` will have an empty output sequence.
+ The container is assigned with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
+
+ After the copy, `this` will have zero writable bytes.
@param other The object to copy from.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of the allocator.
*/
basic_flat_buffer&
operator=(basic_flat_buffer const& other);
/** Copy assignment
- After the copy, `*this` will have an empty output sequence.
+ The container is assigned with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
+
+ After the copy, `this` will have zero writable bytes.
@param other The object to copy from.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of the allocator.
*/
template<class OtherAlloc>
basic_flat_buffer&
operator=(basic_flat_buffer<OtherAlloc> const& other);
- /// Returns a copy of the associated allocator.
+ /// Returns a copy of the allocator used.
allocator_type
get_allocator() const
{
return this->get();
}
- /// Returns the size of the input sequence.
+ /** Set the maximum allowed capacity
+
+ This function changes the currently configured upper limit
+ on capacity to the specified value.
+
+ @param n The maximum number of bytes ever allowed for capacity.
+
+ @esafe
+
+ No-throw guarantee.
+ */
+ void
+ max_size(std::size_t n) noexcept
+ {
+ max_ = n;
+ }
+
+ /** Guarantee a minimum capacity
+
+ This function adjusts the internal storage (if necessary)
+ to guarantee space for at least `n` bytes.
+
+ Buffer sequences previously obtained using @ref data or
+ @ref prepare become invalid.
+
+ @param n The minimum number of byte for the new capacity.
+ If this value is greater than the maximum size, then the
+ maximum size will be adjusted upwards to this value.
+
+ @esafe
+
+ Basic guarantee.
+
+ @throws std::length_error if n is larger than the maximum
+ allocation size of the allocator.
+ */
+ void
+ reserve(std::size_t n);
+
+ /** Reallocate the buffer to fit the readable bytes exactly.
+
+ Buffer sequences previously obtained using @ref data or
+ @ref prepare become invalid.
+
+ @esafe
+
+ Strong guarantee.
+ */
+ void
+ shrink_to_fit();
+
+ /** Set the size of the readable and writable bytes to zero.
+
+ This clears the buffer without changing capacity.
+ Buffer sequences previously obtained using @ref data or
+ @ref prepare become invalid.
+
+ @esafe
+
+ No-throw guarantee.
+ */
+ void
+ clear() noexcept;
+
+ /// Exchange two dynamic buffers
+ template<class Alloc>
+ friend
+ void
+ swap(
+ basic_flat_buffer<Alloc>&,
+ basic_flat_buffer<Alloc>&);
+
+ //--------------------------------------------------------------------------
+
+ /// The ConstBufferSequence used to represent the readable bytes.
+ using const_buffers_type = net::const_buffer;
+
+ /// The MutableBufferSequence used to represent the readable bytes.
+ using mutable_data_type = net::mutable_buffer;
+
+ /// The MutableBufferSequence used to represent the writable bytes.
+ using mutable_buffers_type = net::mutable_buffer;
+
+ /// Returns the number of readable bytes.
std::size_t
- size() const
+ size() const noexcept
{
return dist(in_, out_);
}
- /// Return the maximum sum of the input and output sequence sizes.
+ /// Return the maximum number of bytes, both readable and writable, that can ever be held.
std::size_t
- max_size() const
+ max_size() const noexcept
{
return max_;
}
- /// Return the maximum sum of input and output sizes that can be held without an allocation.
+ /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
std::size_t
- capacity() const
+ capacity() const noexcept
{
return dist(begin_, end_);
}
- /// Get a list of buffers that represent the input sequence.
+ /// Returns a constant buffer sequence representing the readable bytes
const_buffers_type
- data() const
+ data() const noexcept
{
return {in_, dist(in_, out_)};
}
- /** Get a list of buffers that represent the output sequence, with the given size.
-
- @throws std::length_error if `size() + n` exceeds `max_size()`.
+ /// Returns a constant buffer sequence representing the readable bytes
+ const_buffers_type
+ cdata() const noexcept
+ {
+ return data();
+ }
- @note All previous buffers sequences obtained from
- calls to @ref data or @ref prepare are invalidated.
- */
- mutable_buffers_type
- prepare(std::size_t n);
+ /// Returns a mutable buffer sequence representing the readable bytes
+ mutable_data_type
+ data() noexcept
+ {
+ return {in_, dist(in_, out_)};
+ }
- /** Move bytes from the output sequence to the input sequence.
+ /** Returns a mutable buffer sequence representing writable bytes.
+
+ Returns a mutable buffer sequence representing the writable
+ bytes containing exactly `n` bytes of storage. Memory may be
+ reallocated as needed.
- @param n The number of bytes to move. If this is larger than
- the number of bytes in the output sequences, then the entire
- output sequences is moved.
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare become invalid.
- @note All previous buffers sequences obtained from
- calls to @ref data or @ref prepare are invalidated.
- */
- void
- commit(std::size_t n)
- {
- out_ += (std::min)(n, dist(out_, last_));
- }
+ @param n The desired number of bytes in the returned buffer
+ sequence.
- /** Remove bytes from the input sequence.
+ @throws std::length_error if `size() + n` exceeds either
+ `max_size()` or the allocator's maximum allocation size.
- If `n` is greater than the number of bytes in the input
- sequence, all bytes in the input sequence are removed.
+ @esafe
- @note All previous buffers sequences obtained from
- calls to @ref data or @ref prepare are invalidated.
+ Strong guarantee.
*/
- void
- consume(std::size_t n);
+ mutable_buffers_type
+ prepare(std::size_t n);
- /** Reallocate the buffer to fit the input sequence.
+ /** Append writable bytes to the readable bytes.
- @note All previous buffers sequences obtained from
- calls to @ref data or @ref prepare are invalidated.
- */
- void
- shrink_to_fit();
+ Appends n bytes from the start of the writable bytes to the
+ end of the readable bytes. The remainder of the writable bytes
+ are discarded. If n is greater than the number of writable
+ bytes, all writable bytes are appended to the readable bytes.
- /// Exchange two flat buffers
- template<class Alloc>
- friend
- void
- swap(
- basic_flat_buffer<Alloc>& lhs,
- basic_flat_buffer<Alloc>& rhs);
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare become invalid.
-private:
- void
- reset();
+ @param n The number of bytes to append. If this number
+ is greater than the number of writable bytes, all
+ writable bytes are appended.
- template<class DynamicBuffer>
- void
- copy_from(DynamicBuffer const& other);
+ @esafe
+ No-throw guarantee.
+ */
void
- move_assign(basic_flat_buffer&, std::true_type);
+ commit(std::size_t n) noexcept
+ {
+ out_ += (std::min)(n, dist(out_, last_));
+ }
- void
- move_assign(basic_flat_buffer&, std::false_type);
+ /** Remove bytes from beginning of the readable bytes.
- void
- copy_assign(basic_flat_buffer const&, std::true_type);
+ Removes n bytes from the beginning of the readable bytes.
- void
- copy_assign(basic_flat_buffer const&, std::false_type);
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare become invalid.
- void
- swap(basic_flat_buffer&);
+ @param n The number of bytes to remove. If this number
+ is greater than the number of readable bytes, all
+ readable bytes are removed.
- void
- swap(basic_flat_buffer&, std::true_type);
+ @esafe
+ No-throw guarantee.
+ */
void
- swap(basic_flat_buffer&, std::false_type);
+ consume(std::size_t n) noexcept;
+
+private:
+ template<class OtherAlloc>
+ void copy_from(basic_flat_buffer<OtherAlloc> const& other);
+ void move_assign(basic_flat_buffer&, std::true_type);
+ void move_assign(basic_flat_buffer&, std::false_type);
+ void copy_assign(basic_flat_buffer const&, std::true_type);
+ void copy_assign(basic_flat_buffer const&, std::false_type);
+ void swap(basic_flat_buffer&);
+ void swap(basic_flat_buffer&, std::true_type);
+ void swap(basic_flat_buffer&, std::false_type);
+ char* alloc(std::size_t n);
};
+/// A flat buffer which uses the default allocator.
using flat_buffer =
basic_flat_buffer<std::allocator<char>>;
} // beast
} // boost
-#include <boost/beast/core/impl/flat_buffer.ipp>
+#include <boost/beast/core/impl/flat_buffer.hpp>
#endif
diff --git a/boost/beast/core/flat_static_buffer.hpp b/boost/beast/core/flat_static_buffer.hpp
index c8eae90945..f951fe2c62 100644
--- a/boost/beast/core/flat_static_buffer.hpp
+++ b/boost/beast/core/flat_static_buffer.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -19,22 +19,34 @@
namespace boost {
namespace beast {
-/** A flat @b DynamicBuffer with a fixed size internal buffer.
+/** A dynamic buffer using a fixed size internal buffer.
- Buffer sequences returned by @ref data and @ref prepare
- will always be of length one.
- Ownership of the underlying storage belongs to the derived class.
+ A dynamic buffer encapsulates memory storage that may be
+ automatically resized as required, where the memory is
+ divided into two regions: readable bytes followed by
+ writable bytes. These memory regions are internal to
+ the dynamic buffer, but direct access to the elements
+ is provided to permit them to be efficiently used with
+ I/O operations.
- @note Variables are usually declared using the template class
- @ref flat_static_buffer; however, to reduce the number of instantiations
- of template functions receiving static stream buffer arguments in a
- deduced context, the signature of the receiving function should use
- @ref flat_static_buffer_base.
+ Objects of this type meet the requirements of <em>DynamicBuffer</em>
+ and have the following additional properties:
+
+ @li A mutable buffer sequence representing the readable
+ bytes is returned by @ref data when `this` is non-const.
+
+ @li Buffer sequences representing the readable and writable
+ bytes, returned by @ref data and @ref prepare, will have
+ length one.
- When used with @ref flat_static_buffer this implements a dynamic
- buffer using no memory allocations.
+ @li Ownership of the underlying storage belongs to the
+ derived class.
- @see @ref flat_static_buffer
+ @note Variables are usually declared using the template class
+ @ref flat_static_buffer; however, to reduce the number of template
+ instantiations, objects should be passed `flat_static_buffer_base&`.
+
+ @see flat_static_buffer
*/
class flat_static_buffer_base
{
@@ -44,95 +56,175 @@ class flat_static_buffer_base
char* last_;
char* end_;
- flat_static_buffer_base(flat_static_buffer_base const& other) = delete;
- flat_static_buffer_base& operator=(flat_static_buffer_base const&) = delete;
+ flat_static_buffer_base(
+ flat_static_buffer_base const& other) = delete;
+ flat_static_buffer_base& operator=(
+ flat_static_buffer_base const&) = delete;
public:
- /** The type used to represent the input sequence as a list of buffers.
+ /** Constructor
- This buffer sequence is guaranteed to have length 1.
- */
- using const_buffers_type = boost::asio::const_buffer;
+ This creates a dynamic buffer using the provided storage area.
- /** The type used to represent the output sequence as a list of buffers.
+ @param p A pointer to valid storage of at least `n` bytes.
- This buffer sequence is guaranteed to have length 1.
+ @param n The number of valid bytes pointed to by `p`.
*/
- using mutable_buffers_type = boost::asio::mutable_buffer;
+ flat_static_buffer_base(
+ void* p, std::size_t n) noexcept
+ {
+ reset(p, n);
+ }
- /** Constructor
+ /** Clear the readable and writable bytes to zero.
- This creates a dynamic buffer using the provided storage area.
+ This function causes the readable and writable bytes
+ to become empty. The capacity is not changed.
- @param p A pointer to valid storage of at least `n` bytes.
+ Buffer sequences previously obtained using @ref data or
+ @ref prepare become invalid.
- @param n The number of valid bytes pointed to by `p`.
+ @esafe
+
+ No-throw guarantee.
*/
- flat_static_buffer_base(void* p, std::size_t n)
+ BOOST_BEAST_DECL
+ void
+ clear() noexcept;
+
+#ifdef BOOST_BEAST_ALLOW_DEPRECATED
+ /// Change the number of readable and writable bytes to zero.
+ void
+ reset() noexcept
{
- reset_impl(p, n);
+ clear();
}
+#elif ! BOOST_BEAST_DOXYGEN
+ template<std::size_t I = 0>
+ void
+ reset() noexcept
+ {
+ static_assert(I != 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+ }
+#endif
+
+ //--------------------------------------------------------------------------
- /// Return the size of the input sequence.
+ /// The ConstBufferSequence used to represent the readable bytes.
+ using const_buffers_type = net::const_buffer;
+
+ /// The MutableBufferSequence used to represent the readable bytes.
+ using mutable_data_type = net::mutable_buffer;
+
+ /// The MutableBufferSequence used to represent the writable bytes.
+ using mutable_buffers_type = net::mutable_buffer;
+
+ /// Returns the number of readable bytes.
std::size_t
- size() const
+ size() const noexcept
{
return out_ - in_;
}
- /// Return the maximum sum of the input and output sequence sizes.
+ /// Return the maximum number of bytes, both readable and writable, that can ever be held.
std::size_t
- max_size() const
+ max_size() const noexcept
{
return dist(begin_, end_);
}
- /// Return the maximum sum of input and output sizes that can be held without an allocation.
+ /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
std::size_t
- capacity() const
+ capacity() const noexcept
{
return max_size();
}
- /** Get a list of buffers that represent the input sequence.
+ /// Returns a constant buffer sequence representing the readable bytes
+ const_buffers_type
+ data() const noexcept
+ {
+ return {in_, dist(in_, out_)};
+ }
- @note These buffers remain valid across subsequent calls to `prepare`.
- */
+ /// Returns a constant buffer sequence representing the readable bytes
const_buffers_type
- data() const;
+ cdata() const noexcept
+ {
+ return data();
+ }
- /// Set the input and output sequences to size 0
- void
- reset();
+ /// Returns a mutable buffer sequence representing the readable bytes
+ mutable_data_type
+ data() noexcept
+ {
+ return {in_, dist(in_, out_)};
+ }
+
+ /** Returns a mutable buffer sequence representing writable bytes.
+
+ Returns a mutable buffer sequence representing the writable
+ bytes containing exactly `n` bytes of storage.
- /** Get a list of buffers that represent the output sequence, with the given size.
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare are invalidated.
- @throws std::length_error if the size would exceed the limit
- imposed by the underlying mutable buffer sequence.
+ @param n The desired number of bytes in the returned buffer
+ sequence.
- @note Buffers representing the input sequence acquired prior to
- this call remain valid.
+ @throws std::length_error if `size() + n` exceeds `max_size()`.
+
+ @esafe
+
+ Strong guarantee.
*/
+ BOOST_BEAST_DECL
mutable_buffers_type
prepare(std::size_t n);
- /** Move bytes from the output sequence to the input sequence.
+ /** Append writable bytes to the readable bytes.
+
+ Appends n bytes from the start of the writable bytes to the
+ end of the readable bytes. The remainder of the writable bytes
+ are discarded. If n is greater than the number of writable
+ bytes, all writable bytes are appended to the readable bytes.
+
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare are invalidated.
+
+ @param n The number of bytes to append. If this number
+ is greater than the number of writable bytes, all
+ writable bytes are appended.
- @note Buffers representing the input sequence acquired prior to
- this call remain valid.
+ @esafe
+
+ No-throw guarantee.
*/
void
- commit(std::size_t n)
+ commit(std::size_t n) noexcept
{
out_ += (std::min<std::size_t>)(n, last_ - out_);
}
- /// Remove bytes from the input sequence.
+ /** Remove bytes from beginning of the readable bytes.
+
+ Removes n bytes from the beginning of the readable bytes.
+
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare are invalidated.
+
+ @param n The number of bytes to remove. If this number
+ is greater than the number of readable bytes, all
+ readable bytes are removed.
+
+ @esafe
+
+ No-throw guarantee.
+ */
+ BOOST_BEAST_DECL
void
- consume(std::size_t n)
- {
- consume_impl(n);
- }
+ consume(std::size_t n) noexcept;
protected:
/** Constructor
@@ -153,39 +245,27 @@ protected:
@param p A pointer to valid storage of at least `n` bytes.
@param n The number of valid bytes pointed to by `p`.
+
+ @esafe
+
+ No-throw guarantee.
*/
+ BOOST_BEAST_DECL
void
- reset(void* p, std::size_t n);
+ reset(void* p, std::size_t n) noexcept;
private:
static
- inline
std::size_t
- dist(char const* first, char const* last)
+ dist(char const* first, char const* last) noexcept
{
return static_cast<std::size_t>(last - first);
}
-
- template<class = void>
- void
- reset_impl();
-
- template<class = void>
- void
- reset_impl(void* p, std::size_t n);
-
- template<class = void>
- mutable_buffers_type
- prepare_impl(std::size_t n);
-
- template<class = void>
- void
- consume_impl(std::size_t n);
};
//------------------------------------------------------------------------------
-/** A @b DynamicBuffer with a fixed size internal buffer.
+/** A <em>DynamicBuffer</em> with a fixed size internal buffer.
Buffer sequences returned by @ref data and @ref prepare
will always be of length one.
@@ -197,7 +277,7 @@ private:
objects of this type in a deduced context, the signature of the
receiving function should use @ref flat_static_buffer_base instead.
- @see @ref flat_static_buffer_base
+ @see flat_static_buffer_base
*/
template<std::size_t N>
class flat_static_buffer : public flat_static_buffer_base
@@ -249,6 +329,9 @@ public:
} // beast
} // boost
+#include <boost/beast/core/impl/flat_static_buffer.hpp>
+#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/beast/core/impl/flat_static_buffer.ipp>
-
#endif
+
+#endif \ No newline at end of file
diff --git a/boost/beast/core/flat_stream.hpp b/boost/beast/core/flat_stream.hpp
new file mode 100644
index 0000000000..fb8d9c19c9
--- /dev/null
+++ b/boost/beast/core/flat_stream.hpp
@@ -0,0 +1,347 @@
+//
+// 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_CORE_FLAT_STREAM_HPP
+#define BOOST_BEAST_CORE_FLAT_STREAM_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/flat_buffer.hpp>
+#include <boost/beast/core/stream_traits.hpp>
+#include <boost/beast/core/detail/flat_stream.hpp>
+#include <boost/asio/async_result.hpp>
+#include <cstdlib>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+/** Stream wrapper to improve write performance.
+
+ This wrapper flattens writes for buffer sequences having length
+ greater than 1 and total size below a predefined amount, using
+ a dynamic memory allocation. It is primarily designed to overcome
+ a performance limitation of the current version of `net::ssl::stream`,
+ which does not use OpenSSL's scatter/gather interface for its
+ low-level read some and write some operations.
+
+ It is normally not necessary to use this class directly if you
+ are already using @ref ssl_stream. The following examples shows
+ how to use this class with the ssl stream that comes with
+ networking:
+
+ @par Example
+
+ To use the @ref flat_stream template with SSL streams, declare
+ a variable of the correct type. Parameters passed to the constructor
+ will be forwarded to the next layer's constructor:
+
+ @code
+ flat_stream<net::ssl::stream<ip::tcp::socket>> fs{ioc, ctx};
+ @endcode
+ Alternatively you can write
+ @code
+ ssl::stream<ip::tcp::socket> ss{ioc, ctx};
+ flat_stream<net::ssl::stream<ip::tcp::socket>&> fs{ss};
+ @endcode
+
+ The resulting stream may be passed to any stream algorithms which
+ operate on synchronous or asynchronous read or write streams,
+ examples include:
+
+ @li `net::read`, `net::async_read`
+
+ @li `net::write`, `net::async_write`
+
+ @li `net::read_until`, `net::async_read_until`
+
+ The stream may also be used as a template parameter in other
+ stream wrappers, such as for websocket:
+ @code
+ websocket::stream<flat_stream<net::ssl::stream<ip::tcp::socket>>> ws{ioc, ctx};
+ @endcode
+
+ @tparam NextLayer The type representing the next layer, to which
+ data will be read and written during operations. For synchronous
+ operations, the type must support the @b SyncStream concept. For
+ asynchronous operations, the type must support the @b AsyncStream
+ concept. This type will usually be some variation of
+ `net::ssl::stream`.
+
+ @par Concepts
+ @li SyncStream
+ @li AsyncStream
+
+ @see
+ @li https://github.com/boostorg/asio/issues/100
+ @li https://github.com/boostorg/beast/issues/1108
+ @li https://stackoverflow.com/questions/38198638/openssl-ssl-write-from-multiple-buffers-ssl-writev
+ @li https://stackoverflow.com/questions/50026167/performance-drop-on-port-from-beast-1-0-0-b66-to-boost-1-67-0-beast
+*/
+template<class NextLayer>
+class flat_stream
+#if ! BOOST_BEAST_DOXYGEN
+ : private detail::flat_stream_base
+#endif
+{
+ NextLayer stream_;
+ flat_buffer buffer_;
+
+ BOOST_STATIC_ASSERT(has_get_executor<NextLayer>::value);
+
+ struct ops;
+
+ template<class ConstBufferSequence>
+ std::size_t
+ stack_write_some(
+ std::size_t size,
+ ConstBufferSequence const& buffers,
+ error_code& ec);
+
+public:
+ /// The type of the next layer.
+ using next_layer_type =
+ typename std::remove_reference<NextLayer>::type;
+
+ /// The type of the executor associated with the object.
+ using executor_type = beast::executor_type<next_layer_type>;
+
+ flat_stream(flat_stream&&) = default;
+ flat_stream(flat_stream const&) = default;
+ flat_stream& operator=(flat_stream&&) = default;
+ flat_stream& operator=(flat_stream const&) = default;
+
+ /** Destructor
+
+ The treatment of pending operations will be the same as that
+ of the next layer.
+ */
+ ~flat_stream() = default;
+
+ /** Constructor
+
+ Arguments, if any, are forwarded to the next layer's constructor.
+ */
+ template<class... Args>
+ explicit
+ flat_stream(Args&&... args);
+
+ //--------------------------------------------------------------------------
+
+ /** Get the executor associated with the object.
+
+ This function may be used to obtain the executor object that the
+ stream uses to dispatch handlers for asynchronous operations.
+
+ @return A copy of the executor that stream will use to dispatch handlers.
+ */
+ executor_type
+ get_executor() noexcept
+ {
+ return stream_.get_executor();
+ }
+
+ /** Get a reference to the next layer
+
+ This function returns a reference to the next layer
+ in a stack of stream layers.
+
+ @return A reference to the next layer in the stack of
+ stream layers.
+ */
+ next_layer_type&
+ next_layer() noexcept
+ {
+ return stream_;
+ }
+
+ /** Get a reference to the next layer
+
+ This function returns a reference to the next layer in a
+ stack of stream layers.
+
+ @return A reference to the next layer in the stack of
+ stream layers.
+ */
+ next_layer_type const&
+ next_layer() const noexcept
+ {
+ return stream_;
+ }
+
+ //--------------------------------------------------------------------------
+
+ /** Read some data from the stream.
+
+ This function is used to read data from the stream. The function call will
+ block until one or more bytes of data has been read successfully, or until
+ an error occurs.
+
+ @param buffers The buffers into which the data will be read.
+
+ @returns The number of bytes read.
+
+ @throws boost::system::system_error Thrown on failure.
+
+ @note The `read_some` operation may not read all of the requested number of
+ bytes. Consider using the function `net::read` if you need to ensure
+ that the requested amount of data is read before the blocking operation
+ completes.
+ */
+ template<class MutableBufferSequence>
+ std::size_t
+ read_some(MutableBufferSequence const& buffers);
+
+ /** Read some data from the stream.
+
+ This function is used to read data from the stream. The function call will
+ block until one or more bytes of data has been read successfully, or until
+ an error occurs.
+
+ @param buffers The buffers into which the data will be read.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes read.
+
+ @note The `read_some` operation may not read all of the requested number of
+ bytes. Consider using the function `net::read` if you need to ensure
+ that the requested amount of data is read before the blocking operation
+ completes.
+ */
+ template<class MutableBufferSequence>
+ std::size_t
+ read_some(
+ MutableBufferSequence const& buffers,
+ error_code& ec);
+
+ /** Start an asynchronous read.
+
+ This function is used to asynchronously read one or more bytes of data from
+ the stream. The function call always returns immediately.
+
+ @param buffers The buffers into which the data will be read. Although the
+ buffers object may be copied as necessary, ownership of the underlying
+ buffers is retained by the caller, which must guarantee that they remain
+ valid until the handler is called.
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
+ error_code const& error, // Result of operation.
+ std::size_t bytes_transferred // Number of bytes read.
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+
+ @note The `read_some` operation may not read all of the requested number of
+ bytes. Consider using the function `net::async_read` if you need
+ to ensure that the requested amount of data is read before the asynchronous
+ operation completes.
+ */
+ template<
+ class MutableBufferSequence,
+ class ReadHandler>
+ BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
+ async_read_some(
+ MutableBufferSequence const& buffers,
+ ReadHandler&& handler);
+
+ /** Write some data to the stream.
+
+ This function is used to write data on the stream. The function call will
+ block until one or more bytes of data has been written successfully, or
+ until an error occurs.
+
+ @param buffers The data to be written.
+
+ @returns The number of bytes written.
+
+ @throws boost::system::system_error Thrown on failure.
+
+ @note The `write_some` operation may not transmit all of the data to the
+ peer. Consider using the function `net::write` if you need to
+ ensure that all data is written before the blocking operation completes.
+ */
+ template<class ConstBufferSequence>
+ std::size_t
+ write_some(ConstBufferSequence const& buffers);
+
+ /** Write some data to the stream.
+
+ This function is used to write data on the stream. The function call will
+ block until one or more bytes of data has been written successfully, or
+ until an error occurs.
+
+ @param buffers The data to be written.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes written.
+
+ @note The `write_some` operation may not transmit all of the data to the
+ peer. Consider using the function `net::write` if you need to
+ ensure that all data is written before the blocking operation completes.
+ */
+ template<class ConstBufferSequence>
+ std::size_t
+ write_some(
+ ConstBufferSequence const& buffers,
+ error_code& ec);
+
+ /** Start an asynchronous write.
+
+ This function is used to asynchronously write one or more bytes of data to
+ the stream. The function call always returns immediately.
+
+ @param buffers The data to be written to the stream. Although the buffers
+ object may be copied as necessary, ownership of the underlying buffers is
+ retained by the caller, which must guarantee that they remain valid until
+ the handler is called.
+
+ @param handler The completion handler to invoke when the operation
+ completes. The implementation takes ownership of the handler by
+ performing a decay-copy. The equivalent function signature of
+ the handler must be:
+ @code
+ void handler(
+ error_code const& ec, // Result of operation.
+ std::size_t bytes_transferred // Number of bytes written.
+ );
+ @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `net::post`.
+
+ @note The `async_write_some` operation may not transmit all of the data to
+ the peer. Consider using the function `net::async_write` if you need
+ to ensure that all data is written before the asynchronous operation completes.
+ */
+ template<
+ class ConstBufferSequence,
+ class WriteHandler>
+ BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
+ async_write_some(
+ ConstBufferSequence const& buffers,
+ WriteHandler&& handler);
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/flat_stream.hpp>
+
+#endif
diff --git a/boost/beast/core/handler_ptr.hpp b/boost/beast/core/handler_ptr.hpp
index 64de1b7dab..24fd244fd9 100644
--- a/boost/beast/core/handler_ptr.hpp
+++ b/boost/beast/core/handler_ptr.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -10,13 +10,17 @@
#ifndef BOOST_BEAST_HANDLER_PTR_HPP
#define BOOST_BEAST_HANDLER_PTR_HPP
-#include <boost/beast/core/detail/allocator.hpp>
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/beast/core/detail/allocator.hpp>
#include <boost/assert.hpp>
+#include <boost/config/pragma_message.hpp>
#include <type_traits>
#include <utility>
+#ifndef BOOST_BEAST_DOXYGEN
+
+BOOST_PRAGMA_MESSAGE("<boost/beast/core/handler_ptr.hpp> is DEPRECATED and will be removed in a future release.")
+
namespace boost {
namespace beast {
@@ -50,17 +54,20 @@ namespace beast {
template<class T, class Handler>
class handler_ptr
{
- using handler_storage_t = typename detail::aligned_union<1, Handler>::type;
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ static_assert(sizeof(T) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
T* t_ = nullptr;
- handler_storage_t h_;
+ union
+ {
+ Handler h_;
+ };
void clear();
public:
- static_assert(std::is_nothrow_destructible<T>::value,
- "T must be nothrow destructible");
-
/// The type of element stored
using element_type = T;
@@ -106,30 +113,31 @@ public:
T::T(Handler const&, Args&&...)
@endcode
- @par Exception Safety
+ @esafe
Strong guarantee.
- @param handler The handler to associate with the owned
- object. The argument will be moved if it is an xvalue.
+ @param handler The handler to associate with the owned object.
+ The implementation takes ownership of the handler by performing a decay-copy.
@param args Optional arguments forwarded to
the owned object's constructor.
*/
template<class DeducedHandler, class... Args>
- explicit handler_ptr(DeducedHandler&& handler, Args&&... args);
+ explicit
+ handler_ptr(DeducedHandler&& handler, Args&&... args);
/// Return a reference to the handler
handler_type const&
- handler() const
+ handler() const noexcept
{
- return *reinterpret_cast<Handler const*>(&h_);
+ return h_;
}
/// Return a reference to the handler
handler_type&
- handler()
+ handler() noexcept
{
- return *reinterpret_cast<Handler*>(&h_);
+ return h_;
}
/// Return `true` if `*this` owns an object
@@ -167,10 +175,11 @@ public:
T*
operator->() const
{
+ BOOST_ASSERT(t_);
return t_;
}
- /** Return ownership of the handler
+ /** Returns ownership of the handler
Before this function returns, the owned object is
destroyed, satisfying the deallocation-before-invocation
@@ -213,6 +222,8 @@ public:
} // beast
} // boost
-#include <boost/beast/core/impl/handler_ptr.ipp>
+#include <boost/beast/core/impl/handler_ptr.hpp>
+
+#endif
#endif
diff --git a/boost/beast/core/impl/async_base.hpp b/boost/beast/core/impl/async_base.hpp
new file mode 100644
index 0000000000..ec17b1cc1e
--- /dev/null
+++ b/boost/beast/core/impl/async_base.hpp
@@ -0,0 +1,156 @@
+//
+// 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_CORE_IMPL_ASYNC_BASE_HPP
+#define BOOST_BEAST_CORE_IMPL_ASYNC_BASE_HPP
+
+#include <boost/core/exchange.hpp>
+
+namespace boost {
+namespace beast {
+
+namespace detail {
+
+template<class State, class Allocator>
+struct allocate_stable_state final
+ : stable_base
+ , boost::empty_value<Allocator>
+{
+ State value;
+
+ template<class... Args>
+ explicit
+ allocate_stable_state(
+ Allocator const& alloc,
+ Args&&... args)
+ : boost::empty_value<Allocator>(
+ boost::empty_init_t{}, alloc)
+ , value{std::forward<Args>(args)...}
+ {
+ }
+
+ void destroy() override
+ {
+ using A = typename allocator_traits<
+ Allocator>::template rebind_alloc<
+ allocate_stable_state>;
+
+ A a(this->get());
+ detail::allocator_traits<A>::destroy(a, this);
+ detail::allocator_traits<A>::deallocate(a, this, 1);
+ }
+};
+
+} // detail
+
+template<
+ class Handler,
+ class Executor1,
+ class Allocator,
+ class Function>
+void asio_handler_invoke(
+ Function&& f,
+ async_base<Handler, Executor1, Allocator>* p)
+{
+ using net::asio_handler_invoke;
+ asio_handler_invoke(f,
+ p->get_legacy_handler_pointer());
+}
+
+template<
+ class Handler,
+ class Executor1,
+ class Allocator>
+void*
+asio_handler_allocate(
+ std::size_t size,
+ async_base<Handler, Executor1, Allocator>* p)
+{
+ using net::asio_handler_allocate;
+ return asio_handler_allocate(size,
+ p->get_legacy_handler_pointer());
+}
+
+template<
+ class Handler,
+ class Executor1,
+ class Allocator>
+void
+asio_handler_deallocate(
+ void* mem, std::size_t size,
+ async_base<Handler, Executor1, Allocator>* p)
+{
+ using net::asio_handler_deallocate;
+ asio_handler_deallocate(mem, size,
+ p->get_legacy_handler_pointer());
+}
+
+template<
+ class Handler,
+ class Executor1,
+ class Allocator>
+bool
+asio_handler_is_continuation(
+ async_base<Handler, Executor1, Allocator>* p)
+{
+ using net::asio_handler_is_continuation;
+ return asio_handler_is_continuation(
+ p->get_legacy_handler_pointer());
+}
+
+template<
+ class State,
+ class Handler,
+ class Executor1,
+ class Allocator,
+ class... Args>
+State&
+allocate_stable(
+ stable_async_base<
+ Handler, Executor1, Allocator>& base,
+ Args&&... args)
+{
+ using allocator_type = typename stable_async_base<
+ Handler, Executor1, Allocator>::allocator_type;
+
+ using A = typename detail::allocator_traits<
+ allocator_type>::template rebind_alloc<
+ detail::allocate_stable_state<
+ State, allocator_type>>;
+
+ struct deleter
+ {
+ allocator_type alloc;
+ detail::allocate_stable_state<
+ State, allocator_type>* ptr;
+
+ ~deleter()
+ {
+ if(ptr)
+ {
+ A a(alloc);
+ detail::allocator_traits<A>::deallocate(a, ptr, 1);
+ }
+ }
+ };
+
+ A a(base.get_allocator());
+ deleter d{base.get_allocator(), nullptr};
+ d.ptr = detail::allocator_traits<A>::allocate(a, 1);
+ detail::allocator_traits<A>::construct(a, d.ptr,
+ d.alloc, std::forward<Args>(args)...);
+ d.ptr->next_ = base.list_;
+ base.list_ = d.ptr;
+ return boost::exchange(d.ptr, nullptr)->value;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/basic_stream.hpp b/boost/beast/core/impl/basic_stream.hpp
new file mode 100644
index 0000000000..c871944552
--- /dev/null
+++ b/boost/beast/core/impl/basic_stream.hpp
@@ -0,0 +1,995 @@
+//
+// 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_CORE_IMPL_BASIC_STREAM_HPP
+#define BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
+
+#include <boost/beast/core/async_base.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/beast/core/buffers_prefix.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/beast/websocket/teardown.hpp>
+#include <boost/asio/bind_executor.hpp>
+#include <boost/asio/coroutine.hpp>
+#include <boost/assert.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/core/exchange.hpp>
+#include <cstdlib>
+#include <type_traits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+//------------------------------------------------------------------------------
+
+template<class Protocol, class Executor, class RatePolicy>
+template<class... Args>
+basic_stream<Protocol, Executor, RatePolicy>::
+impl_type::
+impl_type(std::false_type, Args&&... args)
+ : socket(std::forward<Args>(args)...)
+ , read(ex())
+ , write(ex())
+ , timer(ex())
+{
+ reset();
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+template<class RatePolicy_, class... Args>
+basic_stream<Protocol, Executor, RatePolicy>::
+impl_type::
+impl_type(std::true_type,
+ RatePolicy_&& policy, Args&&... args)
+ : boost::empty_value<RatePolicy>(
+ boost::empty_init_t{},
+ std::forward<RatePolicy_>(policy))
+ , socket(std::forward<Args>(args)...)
+ , read(ex())
+ , write(ex())
+ , timer(ex())
+{
+ reset();
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+template<class Executor2>
+void
+basic_stream<Protocol, Executor, RatePolicy>::
+impl_type::
+on_timer(Executor2 const& ex2)
+{
+ BOOST_ASSERT(waiting > 0);
+
+ // the last waiter starts the new slice
+ if(--waiting > 0)
+ return;
+
+ // update the expiration time
+ BOOST_VERIFY(timer.expires_after(
+ std::chrono::seconds(1)) == 0);
+
+ rate_policy_access::on_timer(policy());
+
+ struct handler : boost::empty_value<Executor2>
+ {
+ boost::weak_ptr<impl_type> wp;
+
+ using executor_type = Executor2;
+
+ executor_type
+ get_executor() const noexcept
+ {
+ return this->get();
+ }
+
+ handler(
+ Executor2 const& ex2,
+ boost::shared_ptr<impl_type> const& sp)
+ : boost::empty_value<Executor2>(
+ boost::empty_init_t{}, ex2)
+ , wp(sp)
+ {
+ }
+
+ void
+ operator()(error_code ec)
+ {
+ auto sp = wp.lock();
+ if(! sp)
+ return;
+ if(ec == net::error::operation_aborted)
+ return;
+ BOOST_ASSERT(! ec);
+ if(ec)
+ return;
+ sp->on_timer(this->get());
+ }
+ };
+
+ // wait on the timer again
+ ++waiting;
+ timer.async_wait(handler(ex2, this->shared_from_this()));
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+void
+basic_stream<Protocol, Executor, RatePolicy>::
+impl_type::
+reset()
+{
+ // If assert goes off, it means that there are
+ // already read or write (or connect) operations
+ // outstanding, so there is nothing to apply
+ // the expiration time to!
+ //
+ BOOST_ASSERT(! read.pending || ! write.pending);
+
+ if(! read.pending)
+ BOOST_VERIFY(
+ read.timer.expires_at(never()) == 0);
+
+ if(! write.pending)
+ BOOST_VERIFY(
+ write.timer.expires_at(never()) == 0);
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+void
+basic_stream<Protocol, Executor, RatePolicy>::
+impl_type::
+close()
+{
+ socket.close();
+ timer.cancel();
+
+ // have to let the read/write ops cancel the timer,
+ // otherwise we will get error::timeout on close when
+ // we actually want net::error::operation_aborted.
+ //
+ //read.timer.cancel();
+ //write.timer.cancel();
+}
+
+//------------------------------------------------------------------------------
+
+template<class Protocol, class Executor, class RatePolicy>
+struct basic_stream<Protocol, Executor, RatePolicy>::
+ timeout_handler
+{
+ op_state& state;
+ boost::weak_ptr<impl_type> wp;
+ tick_type tick;
+
+ void
+ operator()(error_code ec)
+ {
+ // timer canceled
+ if(ec == net::error::operation_aborted)
+ return;
+ BOOST_ASSERT(! ec);
+
+ auto sp = wp.lock();
+
+ // stream destroyed
+ if(! sp)
+ return;
+
+ // stale timer
+ if(tick < state.tick)
+ return;
+ BOOST_ASSERT(tick == state.tick);
+
+ // timeout
+ BOOST_ASSERT(! state.timeout);
+ sp->close();
+ state.timeout = true;
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template<class Protocol, class Executor, class RatePolicy>
+struct basic_stream<Protocol, Executor, RatePolicy>::ops
+{
+
+template<bool isRead, class Buffers, class Handler>
+class transfer_op
+ : public async_base<Handler, Executor>
+ , public boost::asio::coroutine
+{
+ boost::shared_ptr<impl_type> impl_;
+ pending_guard pg_;
+ Buffers b_;
+
+ using is_read = std::integral_constant<bool, isRead>;
+
+ op_state&
+ state(std::true_type)
+ {
+ return impl_->read;
+ }
+
+ op_state&
+ state(std::false_type)
+ {
+ return impl_->write;
+ }
+
+ op_state&
+ state()
+ {
+ return state(
+ std::integral_constant<bool, isRead>{});
+ }
+
+ std::size_t
+ available_bytes(std::true_type)
+ {
+ return rate_policy_access::
+ available_read_bytes(impl_->policy());
+ }
+
+ std::size_t
+ available_bytes(std::false_type)
+ {
+ return rate_policy_access::
+ available_write_bytes(impl_->policy());
+ }
+
+ std::size_t
+ available_bytes()
+ {
+ return available_bytes(is_read{});
+ }
+
+ void
+ transfer_bytes(std::size_t n, std::true_type)
+ {
+ rate_policy_access::
+ transfer_read_bytes(impl_->policy(), n);
+ }
+
+ void
+ transfer_bytes(std::size_t n, std::false_type)
+ {
+ rate_policy_access::
+ transfer_write_bytes(impl_->policy(), n);
+ }
+
+ void
+ transfer_bytes(std::size_t n)
+ {
+ transfer_bytes(n, is_read{});
+ }
+
+ void
+ async_perform(
+ std::size_t amount, std::true_type)
+ {
+ impl_->socket.async_read_some(
+ beast::buffers_prefix(amount, b_),
+ std::move(*this));
+ }
+
+ void
+ async_perform(
+ std::size_t amount, std::false_type)
+ {
+ impl_->socket.async_write_some(
+ beast::buffers_prefix(amount, b_),
+ std::move(*this));
+ }
+
+public:
+ template<class Handler_>
+ transfer_op(
+ Handler_&& h,
+ basic_stream& s,
+ Buffers const& b)
+ : async_base<Handler, Executor>(
+ std::forward<Handler_>(h), s.get_executor())
+ , impl_(s.impl_)
+ , pg_(state().pending)
+ , b_(b)
+ {
+ (*this)({});
+ }
+
+ void
+ operator()(
+ error_code ec,
+ std::size_t bytes_transferred = 0)
+ {
+ BOOST_ASIO_CORO_REENTER(*this)
+ {
+ // handle empty buffers
+ if(detail::buffers_empty(b_))
+ {
+ // make sure we perform the no-op
+ BOOST_ASIO_CORO_YIELD
+ async_perform(0, is_read{});
+ // apply the timeout manually, otherwise
+ // behavior varies across platforms.
+ if(state().timer.expiry() <= clock_type::now())
+ {
+ impl_->close();
+ ec = beast::error::timeout;
+ }
+ goto upcall;
+ }
+
+ // if a timeout is active, wait on the timer
+ if(state().timer.expiry() != never())
+ state().timer.async_wait(
+ net::bind_executor(
+ this->get_executor(),
+ timeout_handler{
+ state(),
+ impl_,
+ state().tick
+ }));
+
+ // check rate limit, maybe wait
+ std::size_t amount;
+ amount = available_bytes();
+ if(amount == 0)
+ {
+ ++impl_->waiting;
+ BOOST_ASIO_CORO_YIELD
+ impl_->timer.async_wait(std::move(*this));
+ if(ec)
+ {
+ // socket was closed, or a timeout
+ BOOST_ASSERT(ec ==
+ net::error::operation_aborted);
+ // timeout handler invoked?
+ if(state().timeout)
+ {
+ // yes, socket already closed
+ ec = beast::error::timeout;
+ state().timeout = false;
+ }
+ goto upcall;
+ }
+ impl_->on_timer(this->get_executor());
+
+ // Allow at least one byte, otherwise
+ // bytes_transferred could be 0.
+ amount = std::max<std::size_t>(
+ available_bytes(), 1);
+ }
+
+ BOOST_ASIO_CORO_YIELD
+ async_perform(amount, is_read{});
+
+ if(state().timer.expiry() != never())
+ {
+ ++state().tick;
+
+ // try cancelling timer
+ auto const n =
+ state().timer.cancel();
+ if(n == 0)
+ {
+ // timeout handler invoked?
+ if(state().timeout)
+ {
+ // yes, socket already closed
+ ec = beast::error::timeout;
+ state().timeout = false;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(n == 1);
+ BOOST_ASSERT(! state().timeout);
+ }
+ }
+
+ upcall:
+ pg_.reset();
+ transfer_bytes(bytes_transferred);
+ this->complete_now(ec, bytes_transferred);
+ }
+ }
+};
+
+template<class Handler>
+class connect_op
+ : public async_base<Handler, Executor>
+{
+ boost::shared_ptr<impl_type> impl_;
+ pending_guard pg0_;
+ pending_guard pg1_;
+
+ op_state&
+ state() noexcept
+ {
+ return impl_->write;
+ }
+
+public:
+ template<class Handler_>
+ connect_op(
+ Handler_&& h,
+ basic_stream& s,
+ endpoint_type ep)
+ : async_base<Handler, Executor>(
+ std::forward<Handler_>(h), s.get_executor())
+ , impl_(s.impl_)
+ , pg0_(impl_->read.pending)
+ , pg1_(impl_->write.pending)
+ {
+ if(state().timer.expiry() != stream_base::never())
+ impl_->write.timer.async_wait(
+ net::bind_executor(
+ this->get_executor(),
+ timeout_handler{
+ state(),
+ impl_,
+ state().tick}));
+
+ impl_->socket.async_connect(
+ ep, std::move(*this));
+ // *this is now moved-from
+ }
+
+ template<
+ class Endpoints, class Condition,
+ class Handler_>
+ connect_op(
+ Handler_&& h,
+ basic_stream& s,
+ Endpoints const& eps,
+ Condition const& cond)
+ : async_base<Handler, Executor>(
+ std::forward<Handler_>(h), s.get_executor())
+ , impl_(s.impl_)
+ , pg0_(impl_->read.pending)
+ , pg1_(impl_->write.pending)
+ {
+ if(state().timer.expiry() != stream_base::never())
+ impl_->write.timer.async_wait(
+ net::bind_executor(
+ this->get_executor(),
+ timeout_handler{
+ state(),
+ impl_,
+ state().tick}));
+
+ net::async_connect(impl_->socket,
+ eps, cond, std::move(*this));
+ // *this is now moved-from
+ }
+
+ template<
+ class Iterator, class Condition,
+ class Handler_>
+ connect_op(
+ Handler_&& h,
+ basic_stream& s,
+ Iterator begin, Iterator end,
+ Condition const& cond)
+ : async_base<Handler, Executor>(
+ std::forward<Handler_>(h), s.get_executor())
+ , impl_(s.impl_)
+ , pg0_(impl_->read.pending)
+ , pg1_(impl_->write.pending)
+ {
+ if(state().timer.expiry() != stream_base::never())
+ impl_->write.timer.async_wait(
+ net::bind_executor(
+ this->get_executor(),
+ timeout_handler{
+ state(),
+ impl_,
+ state().tick}));
+
+ net::async_connect(impl_->socket,
+ begin, end, cond, std::move(*this));
+ // *this is now moved-from
+ }
+
+ template<class... Args>
+ void
+ operator()(error_code ec, Args&&... args)
+ {
+ if(state().timer.expiry() != stream_base::never())
+ {
+ ++state().tick;
+
+ // try cancelling timer
+ auto const n =
+ impl_->write.timer.cancel();
+ if(n == 0)
+ {
+ // timeout handler invoked?
+ if(state().timeout)
+ {
+ // yes, socket already closed
+ ec = beast::error::timeout;
+ state().timeout = false;
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(n == 1);
+ BOOST_ASSERT(! state().timeout);
+ }
+ }
+
+ pg0_.reset();
+ pg1_.reset();
+ this->complete_now(ec, std::forward<Args>(args)...);
+ }
+};
+
+struct run_read_op
+{
+ template<class ReadHandler, class Buffers>
+ void
+ operator()(
+ ReadHandler&& h,
+ basic_stream* s,
+ Buffers const& b)
+ {
+ // 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(
+ detail::is_invocable<ReadHandler,
+ void(error_code, std::size_t)>::value,
+ "ReadHandler type requirements not met");
+
+ transfer_op<
+ true,
+ Buffers,
+ typename std::decay<ReadHandler>::type>(
+ std::forward<ReadHandler>(h), *s, b);
+ }
+};
+
+struct run_write_op
+{
+ template<class WriteHandler, class Buffers>
+ void
+ operator()(
+ WriteHandler&& h,
+ basic_stream* s,
+ Buffers const& b)
+ {
+ // 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(
+ detail::is_invocable<WriteHandler,
+ void(error_code, std::size_t)>::value,
+ "WriteHandler type requirements not met");
+
+ transfer_op<
+ false,
+ Buffers,
+ typename std::decay<WriteHandler>::type>(
+ std::forward<WriteHandler>(h), *s, b);
+ }
+};
+
+struct run_connect_op
+{
+ template<class ConnectHandler>
+ void
+ operator()(
+ ConnectHandler&& h,
+ basic_stream* s,
+ endpoint_type const& ep)
+ {
+ // 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(
+ detail::is_invocable<ConnectHandler,
+ void(error_code)>::value,
+ "ConnectHandler type requirements not met");
+
+ connect_op<typename std::decay<ConnectHandler>::type>(
+ std::forward<ConnectHandler>(h), *s, ep);
+ }
+};
+
+struct run_connect_range_op
+{
+ template<
+ class RangeConnectHandler,
+ class EndpointSequence,
+ class Condition>
+ void
+ operator()(
+ RangeConnectHandler&& h,
+ basic_stream* s,
+ EndpointSequence const& eps,
+ Condition const& cond)
+ {
+ // 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(
+ detail::is_invocable<RangeConnectHandler,
+ void(error_code, typename Protocol::endpoint)>::value,
+ "RangeConnectHandler type requirements not met");
+
+ connect_op<typename std::decay<RangeConnectHandler>::type>(
+ std::forward<RangeConnectHandler>(h), *s, eps, cond);
+ }
+};
+
+struct run_connect_iter_op
+{
+ template<
+ class IteratorConnectHandler,
+ class Iterator,
+ class Condition>
+ void
+ operator()(
+ IteratorConnectHandler&& h,
+ basic_stream* s,
+ Iterator begin, Iterator end,
+ Condition const& cond)
+ {
+ // 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(
+ detail::is_invocable<IteratorConnectHandler,
+ void(error_code, Iterator)>::value,
+ "IteratorConnectHandler type requirements not met");
+
+ connect_op<typename std::decay<IteratorConnectHandler>::type>(
+ std::forward<IteratorConnectHandler>(h), *s, begin, end, cond);
+ }
+};
+
+};
+
+//------------------------------------------------------------------------------
+
+template<class Protocol, class Executor, class RatePolicy>
+basic_stream<Protocol, Executor, RatePolicy>::
+~basic_stream()
+{
+ // the shared object can outlive *this,
+ // cancel any operations so the shared
+ // object is destroyed as soon as possible.
+ impl_->close();
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+template<class Arg0, class... Args, class>
+basic_stream<Protocol, Executor, RatePolicy>::
+basic_stream(Arg0&& arg0, Args&&... args)
+ : impl_(boost::make_shared<impl_type>(
+ std::false_type{},
+ std::forward<Arg0>(arg0),
+ std::forward<Args>(args)...))
+{
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+template<class RatePolicy_, class Arg0, class... Args, class>
+basic_stream<Protocol, Executor, RatePolicy>::
+basic_stream(
+ RatePolicy_&& policy, Arg0&& arg0, Args&&... args)
+ : impl_(boost::make_shared<impl_type>(
+ std::true_type{},
+ std::forward<RatePolicy_>(policy),
+ std::forward<Arg0>(arg0),
+ std::forward<Args>(args)...))
+{
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+basic_stream<Protocol, Executor, RatePolicy>::
+basic_stream(basic_stream&& other)
+ : impl_(boost::make_shared<impl_type>(
+ std::move(*other.impl_)))
+{
+ // VFALCO I'm not sure this implementation is correct...
+}
+
+//------------------------------------------------------------------------------
+
+template<class Protocol, class Executor, class RatePolicy>
+auto
+basic_stream<Protocol, Executor, RatePolicy>::
+release_socket() ->
+ socket_type
+{
+ this->cancel();
+ return std::move(impl_->socket);
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+void
+basic_stream<Protocol, Executor, RatePolicy>::
+expires_after(std::chrono::nanoseconds expiry_time)
+{
+ // If assert goes off, it means that there are
+ // already read or write (or connect) operations
+ // outstanding, so there is nothing to apply
+ // the expiration time to!
+ //
+ BOOST_ASSERT(
+ ! impl_->read.pending ||
+ ! impl_->write.pending);
+
+ if(! impl_->read.pending)
+ BOOST_VERIFY(
+ impl_->read.timer.expires_after(
+ expiry_time) == 0);
+
+ if(! impl_->write.pending)
+ BOOST_VERIFY(
+ impl_->write.timer.expires_after(
+ expiry_time) == 0);
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+void
+basic_stream<Protocol, Executor, RatePolicy>::
+expires_at(
+ net::steady_timer::time_point expiry_time)
+{
+ // If assert goes off, it means that there are
+ // already read or write (or connect) operations
+ // outstanding, so there is nothing to apply
+ // the expiration time to!
+ //
+ BOOST_ASSERT(
+ ! impl_->read.pending ||
+ ! impl_->write.pending);
+
+ if(! impl_->read.pending)
+ BOOST_VERIFY(
+ impl_->read.timer.expires_at(
+ expiry_time) == 0);
+
+ if(! impl_->write.pending)
+ BOOST_VERIFY(
+ impl_->write.timer.expires_at(
+ expiry_time) == 0);
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+void
+basic_stream<Protocol, Executor, RatePolicy>::
+expires_never()
+{
+ impl_->reset();
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+void
+basic_stream<Protocol, Executor, RatePolicy>::
+cancel()
+{
+ error_code ec;
+ impl_->socket.cancel(ec);
+ impl_->timer.cancel();
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+void
+basic_stream<Protocol, Executor, RatePolicy>::
+close()
+{
+ impl_->close();
+}
+
+//------------------------------------------------------------------------------
+
+template<class Protocol, class Executor, class RatePolicy>
+template<class ConnectHandler>
+BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)
+basic_stream<Protocol, Executor, RatePolicy>::
+async_connect(
+ endpoint_type const& ep,
+ ConnectHandler&& handler)
+{
+ return net::async_initiate<
+ ConnectHandler,
+ void(error_code)>(
+ typename ops::run_connect_op{},
+ handler,
+ this,
+ ep);
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+template<
+ class EndpointSequence,
+ class RangeConnectHandler,
+ class>
+BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void(error_code, typename Protocol::endpoint))
+basic_stream<Protocol, Executor, RatePolicy>::
+async_connect(
+ EndpointSequence const& endpoints,
+ RangeConnectHandler&& handler)
+{
+ return net::async_initiate<
+ RangeConnectHandler,
+ void(error_code, typename Protocol::endpoint)>(
+ typename ops::run_connect_range_op{},
+ handler,
+ this,
+ endpoints,
+ detail::any_endpoint{});
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+template<
+ class EndpointSequence,
+ class ConnectCondition,
+ class RangeConnectHandler,
+ class>
+BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
+basic_stream<Protocol, Executor, RatePolicy>::
+async_connect(
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition,
+ RangeConnectHandler&& handler)
+{
+ return net::async_initiate<
+ RangeConnectHandler,
+ void(error_code, typename Protocol::endpoint)>(
+ typename ops::run_connect_range_op{},
+ handler,
+ this,
+ endpoints,
+ connect_condition);
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+template<
+ class Iterator,
+ class IteratorConnectHandler>
+BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
+basic_stream<Protocol, Executor, RatePolicy>::
+async_connect(
+ Iterator begin, Iterator end,
+ IteratorConnectHandler&& handler)
+{
+ return net::async_initiate<
+ IteratorConnectHandler,
+ void(error_code, Iterator)>(
+ typename ops::run_connect_iter_op{},
+ handler,
+ this,
+ begin, end,
+ detail::any_endpoint{});
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+template<
+ class Iterator,
+ class ConnectCondition,
+ class IteratorConnectHandler>
+BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
+basic_stream<Protocol, Executor, RatePolicy>::
+async_connect(
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition,
+ IteratorConnectHandler&& handler)
+{
+ return net::async_initiate<
+ IteratorConnectHandler,
+ void(error_code, Iterator)>(
+ typename ops::run_connect_iter_op{},
+ handler,
+ this,
+ begin, end,
+ connect_condition);
+}
+
+//------------------------------------------------------------------------------
+
+template<class Protocol, class Executor, class RatePolicy>
+template<class MutableBufferSequence, class ReadHandler>
+BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
+basic_stream<Protocol, Executor, RatePolicy>::
+async_read_some(
+ MutableBufferSequence const& buffers,
+ ReadHandler&& handler)
+{
+ static_assert(net::is_mutable_buffer_sequence<
+ MutableBufferSequence>::value,
+ "MutableBufferSequence type requirements not met");
+ return net::async_initiate<
+ ReadHandler,
+ void(error_code, std::size_t)>(
+ typename ops::run_read_op{},
+ handler,
+ this,
+ buffers);
+}
+
+template<class Protocol, class Executor, class RatePolicy>
+template<class ConstBufferSequence, class WriteHandler>
+BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
+basic_stream<Protocol, Executor, RatePolicy>::
+async_write_some(
+ ConstBufferSequence const& buffers,
+ WriteHandler&& handler)
+{
+ static_assert(net::is_const_buffer_sequence<
+ ConstBufferSequence>::value,
+ "ConstBufferSequence type requirements not met");
+ return net::async_initiate<
+ WriteHandler,
+ void(error_code, std::size_t)>(
+ typename ops::run_write_op{},
+ handler,
+ this,
+ buffers);
+}
+
+//------------------------------------------------------------------------------
+//
+// Customization points
+//
+
+#if ! BOOST_BEAST_DOXYGEN
+
+template<
+ class Protocol, class Executor, class RatePolicy>
+void
+beast_close_socket(
+ basic_stream<Protocol, Executor, RatePolicy>& stream)
+{
+ error_code ec;
+ stream.socket().close(ec);
+}
+
+template<
+ class Protocol, class Executor, class RatePolicy>
+void
+teardown(
+ role_type role,
+ basic_stream<Protocol, Executor, RatePolicy>& stream,
+ error_code& ec)
+{
+ using beast::websocket::teardown;
+ teardown(role, stream.socket(), ec);
+}
+
+template<
+ class Protocol, class Executor, class RatePolicy,
+ class TeardownHandler>
+void
+async_teardown(
+ role_type role,
+ basic_stream<Protocol, Executor, RatePolicy>& stream,
+ TeardownHandler&& handler)
+{
+ using beast::websocket::async_teardown;
+ async_teardown(role, stream.socket(),
+ std::forward<TeardownHandler>(handler));
+}
+
+#endif
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/buffered_read_stream.hpp b/boost/beast/core/impl/buffered_read_stream.hpp
new file mode 100644
index 0000000000..184881164f
--- /dev/null
+++ b/boost/beast/core/impl/buffered_read_stream.hpp
@@ -0,0 +1,242 @@
+//
+// 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_IMPL_BUFFERED_READ_STREAM_HPP
+#define BOOST_BEAST_IMPL_BUFFERED_READ_STREAM_HPP
+
+#include <boost/beast/core/async_base.hpp>
+#include <boost/beast/core/bind_handler.hpp>
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/read_size.hpp>
+#include <boost/beast/core/stream_traits.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/asio/post.hpp>
+#include <boost/throw_exception.hpp>
+
+namespace boost {
+namespace beast {
+
+
+template<class Stream, class DynamicBuffer>
+struct buffered_read_stream<Stream, DynamicBuffer>::ops
+{
+
+template<class MutableBufferSequence, class Handler>
+class read_op
+ : public async_base<Handler,
+ beast::executor_type<buffered_read_stream>>
+{
+ buffered_read_stream& s_;
+ MutableBufferSequence b_;
+ int step_ = 0;
+
+public:
+ read_op(read_op&&) = default;
+ read_op(read_op const&) = delete;
+
+ template<class Handler_>
+ read_op(
+ Handler_&& h,
+ buffered_read_stream& s,
+ MutableBufferSequence const& b)
+ : async_base<
+ Handler, beast::executor_type<buffered_read_stream>>(
+ std::forward<Handler_>(h), s.get_executor())
+ , s_(s)
+ , b_(b)
+ {
+ (*this)({}, 0);
+ }
+
+ void
+ operator()(
+ error_code ec,
+ std::size_t bytes_transferred)
+ {
+ // VFALCO TODO Rewrite this using reenter/yield
+ switch(step_)
+ {
+ case 0:
+ if(s_.buffer_.size() == 0)
+ {
+ if(s_.capacity_ == 0)
+ {
+ // read (unbuffered)
+ step_ = 1;
+ return s_.next_layer_.async_read_some(
+ b_, std::move(*this));
+ }
+ // read
+ step_ = 2;
+ return s_.next_layer_.async_read_some(
+ s_.buffer_.prepare(read_size(
+ s_.buffer_, s_.capacity_)),
+ std::move(*this));
+ }
+ step_ = 3;
+ return net::post(
+ s_.get_executor(),
+ beast::bind_front_handler(
+ std::move(*this), ec, 0));
+
+ case 1:
+ // upcall
+ break;
+
+ case 2:
+ s_.buffer_.commit(bytes_transferred);
+ BOOST_FALLTHROUGH;
+
+ case 3:
+ bytes_transferred =
+ net::buffer_copy(b_, s_.buffer_.data());
+ s_.buffer_.consume(bytes_transferred);
+ break;
+ }
+ this->complete_now(ec, bytes_transferred);
+ }
+};
+
+struct run_read_op
+{
+ template<class ReadHandler, class Buffers>
+ void
+ operator()(
+ ReadHandler&& h,
+ buffered_read_stream* s,
+ Buffers const& b)
+ {
+ // 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<
+ Buffers,
+ typename std::decay<ReadHandler>::type>(
+ std::forward<ReadHandler>(h), *s, b);
+ }
+};
+
+};
+
+//------------------------------------------------------------------------------
+
+template<class Stream, class DynamicBuffer>
+template<class... Args>
+buffered_read_stream<Stream, DynamicBuffer>::
+buffered_read_stream(Args&&... args)
+ : next_layer_(std::forward<Args>(args)...)
+{
+}
+
+template<class Stream, class DynamicBuffer>
+template<class ConstBufferSequence, class WriteHandler>
+BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
+buffered_read_stream<Stream, DynamicBuffer>::
+async_write_some(
+ ConstBufferSequence const& buffers,
+ WriteHandler&& handler)
+{
+ static_assert(is_async_write_stream<next_layer_type>::value,
+ "AsyncWriteStream type requirements not met");
+ static_assert(net::is_const_buffer_sequence<
+ ConstBufferSequence>::value,
+ "ConstBufferSequence type requirements not met");
+ static_assert(detail::is_invocable<WriteHandler,
+ void(error_code, std::size_t)>::value,
+ "WriteHandler type requirements not met");
+ return next_layer_.async_write_some(buffers,
+ std::forward<WriteHandler>(handler));
+}
+
+template<class Stream, class DynamicBuffer>
+template<class MutableBufferSequence>
+std::size_t
+buffered_read_stream<Stream, DynamicBuffer>::
+read_some(
+ MutableBufferSequence const& buffers)
+{
+ static_assert(is_sync_read_stream<next_layer_type>::value,
+ "SyncReadStream type requirements not met");
+ static_assert(net::is_mutable_buffer_sequence<
+ MutableBufferSequence>::value,
+ "MutableBufferSequence type requirements not met");
+ error_code ec;
+ auto n = read_some(buffers, ec);
+ if(ec)
+ BOOST_THROW_EXCEPTION(system_error{ec});
+ return n;
+}
+
+template<class Stream, class DynamicBuffer>
+template<class MutableBufferSequence>
+std::size_t
+buffered_read_stream<Stream, DynamicBuffer>::
+read_some(MutableBufferSequence const& buffers,
+ error_code& ec)
+{
+ static_assert(is_sync_read_stream<next_layer_type>::value,
+ "SyncReadStream type requirements not met");
+ static_assert(net::is_mutable_buffer_sequence<
+ MutableBufferSequence>::value,
+ "MutableBufferSequence type requirements not met");
+ if(buffer_.size() == 0)
+ {
+ if(capacity_ == 0)
+ return next_layer_.read_some(buffers, ec);
+ buffer_.commit(next_layer_.read_some(
+ buffer_.prepare(read_size(buffer_,
+ capacity_)), ec));
+ if(ec)
+ return 0;
+ }
+ else
+ {
+ ec = {};
+ }
+ auto bytes_transferred =
+ net::buffer_copy(buffers, buffer_.data());
+ buffer_.consume(bytes_transferred);
+ return bytes_transferred;
+}
+
+template<class Stream, class DynamicBuffer>
+template<class MutableBufferSequence, class ReadHandler>
+BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
+buffered_read_stream<Stream, DynamicBuffer>::
+async_read_some(
+ MutableBufferSequence const& buffers,
+ ReadHandler&& handler)
+{
+ static_assert(is_async_read_stream<next_layer_type>::value,
+ "AsyncReadStream type requirements not met");
+ static_assert(net::is_mutable_buffer_sequence<
+ MutableBufferSequence>::value,
+ "MutableBufferSequence type requirements not met");
+ if(buffer_.size() == 0 && capacity_ == 0)
+ return next_layer_.async_read_some(buffers,
+ std::forward<ReadHandler>(handler));
+ return net::async_initiate<
+ ReadHandler,
+ void(error_code, std::size_t)>(
+ typename ops::run_read_op{},
+ handler,
+ this,
+ buffers);
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/buffered_read_stream.ipp b/boost/beast/core/impl/buffered_read_stream.ipp
deleted file mode 100644
index b199ea0687..0000000000
--- a/boost/beast/core/impl/buffered_read_stream.ipp
+++ /dev/null
@@ -1,261 +0,0 @@
-//
-// 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_IMPL_BUFFERED_READ_STREAM_IPP
-#define BOOST_BEAST_IMPL_BUFFERED_READ_STREAM_IPP
-
-#include <boost/beast/core/bind_handler.hpp>
-#include <boost/beast/core/error.hpp>
-#include <boost/beast/core/handler_ptr.hpp>
-#include <boost/beast/core/read_size.hpp>
-#include <boost/beast/core/type_traits.hpp>
-#include <boost/beast/core/detail/config.hpp>
-#include <boost/asio/associated_allocator.hpp>
-#include <boost/asio/associated_executor.hpp>
-#include <boost/asio/executor_work_guard.hpp>
-#include <boost/asio/handler_continuation_hook.hpp>
-#include <boost/asio/handler_invoke_hook.hpp>
-#include <boost/asio/post.hpp>
-#include <boost/throw_exception.hpp>
-
-namespace boost {
-namespace beast {
-
-template<class Stream, class DynamicBuffer>
-template<class MutableBufferSequence, class Handler>
-class buffered_read_stream<
- Stream, DynamicBuffer>::read_some_op
-{
- buffered_read_stream& s_;
- boost::asio::executor_work_guard<decltype(
- std::declval<Stream&>().get_executor())> wg_;
- MutableBufferSequence b_;
- Handler h_;
- int step_ = 0;
-
-public:
- read_some_op(read_some_op&&) = default;
- read_some_op(read_some_op const&) = delete;
-
- template<class DeducedHandler, class... Args>
- read_some_op(DeducedHandler&& h,
- buffered_read_stream& s,
- MutableBufferSequence const& b)
- : s_(s)
- , wg_(s_.get_executor())
- , b_(b)
- , 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<buffered_read_stream&>().get_executor())>;
-
- executor_type
- get_executor() const noexcept
- {
- return (boost::asio::get_associated_executor)(
- h_, s_.get_executor());
- }
-
- void
- operator()(error_code const& ec,
- std::size_t bytes_transferred);
-
- friend
- bool asio_handler_is_continuation(read_some_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, read_some_op* op)
- {
- using boost::asio::asio_handler_invoke;
- asio_handler_invoke(f, std::addressof(op->h_));
- }
-};
-
-template<class Stream, class DynamicBuffer>
-template<class MutableBufferSequence, class Handler>
-void
-buffered_read_stream<Stream, DynamicBuffer>::
-read_some_op<MutableBufferSequence, Handler>::operator()(
- error_code const& ec, std::size_t bytes_transferred)
-{
- switch(step_)
- {
- case 0:
- if(s_.buffer_.size() == 0)
- {
- if(s_.capacity_ == 0)
- {
- // read (unbuffered)
- step_ = 1;
- return s_.next_layer_.async_read_some(
- b_, std::move(*this));
- }
-
- // read
- step_ = 2;
- return s_.next_layer_.async_read_some(
- s_.buffer_.prepare(read_size(
- s_.buffer_, s_.capacity_)),
- std::move(*this));
-
- }
- step_ = 3;
- return boost::asio::post(
- s_.get_executor(),
- bind_handler(std::move(*this), ec, 0));
-
- case 1:
- // upcall
- break;
-
- case 2:
- s_.buffer_.commit(bytes_transferred);
- BOOST_FALLTHROUGH;
-
- case 3:
- bytes_transferred =
- boost::asio::buffer_copy(b_, s_.buffer_.data());
- s_.buffer_.consume(bytes_transferred);
- break;
- }
- h_(ec, bytes_transferred);
-}
-
-//------------------------------------------------------------------------------
-
-template<class Stream, class DynamicBuffer>
-template<class... Args>
-buffered_read_stream<Stream, DynamicBuffer>::
-buffered_read_stream(Args&&... args)
- : next_layer_(std::forward<Args>(args)...)
-{
-}
-
-template<class Stream, class DynamicBuffer>
-template<class ConstBufferSequence, class WriteHandler>
-BOOST_ASIO_INITFN_RESULT_TYPE(
- WriteHandler, void(error_code, std::size_t))
-buffered_read_stream<Stream, DynamicBuffer>::
-async_write_some(
- ConstBufferSequence const& buffers,
- WriteHandler&& handler)
-{
- static_assert(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");
- static_assert(is_completion_handler<WriteHandler,
- void(error_code, std::size_t)>::value,
- "WriteHandler requirements not met");
- return next_layer_.async_write_some(buffers,
- std::forward<WriteHandler>(handler));
-}
-
-template<class Stream, class DynamicBuffer>
-template<class MutableBufferSequence>
-std::size_t
-buffered_read_stream<Stream, DynamicBuffer>::
-read_some(
- MutableBufferSequence const& buffers)
-{
- static_assert(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(system_error{ec});
- return n;
-}
-
-template<class Stream, class DynamicBuffer>
-template<class MutableBufferSequence>
-std::size_t
-buffered_read_stream<Stream, DynamicBuffer>::
-read_some(MutableBufferSequence const& buffers,
- error_code& ec)
-{
- static_assert(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");
- using boost::asio::buffer_size;
- using boost::asio::buffer_copy;
- if(buffer_.size() == 0)
- {
- if(capacity_ == 0)
- return next_layer_.read_some(buffers, ec);
- buffer_.commit(next_layer_.read_some(
- buffer_.prepare(read_size(buffer_,
- capacity_)), ec));
- if(ec)
- return 0;
- }
- else
- {
- ec.assign(0, ec.category());
- }
- auto bytes_transferred =
- buffer_copy(buffers, buffer_.data());
- buffer_.consume(bytes_transferred);
- return bytes_transferred;
-}
-
-template<class Stream, class DynamicBuffer>
-template<class MutableBufferSequence, class ReadHandler>
-BOOST_ASIO_INITFN_RESULT_TYPE(
- ReadHandler, void(error_code, std::size_t))
-buffered_read_stream<Stream, DynamicBuffer>::
-async_read_some(
- MutableBufferSequence const& buffers,
- ReadHandler&& handler)
-{
- static_assert(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");
- if(buffer_.size() == 0 && capacity_ == 0)
- return next_layer_.async_read_some(buffers,
- std::forward<ReadHandler>(handler));
- BOOST_BEAST_HANDLER_INIT(
- ReadHandler, void(error_code, std::size_t));
- read_some_op<MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
- ReadHandler, void(error_code, std::size_t))>{
- std::move(init.completion_handler), *this, buffers}(
- error_code{}, 0);
- return init.result.get();
-}
-
-} // beast
-} // boost
-
-#endif
diff --git a/boost/beast/core/impl/buffers_adapter.ipp b/boost/beast/core/impl/buffers_adaptor.hpp
index f077c521f0..91caad5463 100644
--- a/boost/beast/core/impl/buffers_adapter.ipp
+++ b/boost/beast/core/impl/buffers_adaptor.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -7,37 +7,85 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP
-#define BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP
+#ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
+#define BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
+#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
+#include <boost/config/workaround.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
+#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
+//------------------------------------------------------------------------------
+
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+# pragma warning (push)
+# pragma warning (disable: 4521) // multiple copy constructors specified
+# pragma warning (disable: 4522) // multiple assignment operators specified
+#endif
+
template<class MutableBufferSequence>
-class buffers_adapter<MutableBufferSequence>::
- const_buffers_type
+template<bool isMutable>
+class buffers_adaptor<MutableBufferSequence>::
+ readable_bytes
{
- buffers_adapter const* b_;
+ buffers_adaptor const* b_;
public:
- using value_type = boost::asio::const_buffer;
+ using value_type = typename
+ std::conditional<isMutable,
+ net::mutable_buffer,
+ net::const_buffer>::type;
class const_iterator;
- const_buffers_type() = delete;
- const_buffers_type(
- const_buffers_type const&) = default;
- const_buffers_type& operator=(
- const_buffers_type const&) = default;
+ readable_bytes() = delete;
+
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+ readable_bytes(
+ readable_bytes const& other)
+ : b_(other.b_)
+ {
+ }
+
+ readable_bytes& operator=(
+ readable_bytes const& other)
+ {
+ b_ = other.b_;
+ return *this;
+ }
+#else
+ readable_bytes(
+ readable_bytes const&) = default;
+ readable_bytes& operator=(
+ readable_bytes const&) = default;
+#endif
+
+ template<bool isMutable_ = isMutable, class =
+ typename std::enable_if<! isMutable_>::type>
+ readable_bytes(
+ readable_bytes<true> const& other) noexcept
+ : b_(other.b_)
+ {
+ }
+
+ template<bool isMutable_ = isMutable, class =
+ typename std::enable_if<! isMutable_>::type>
+ readable_bytes& operator=(
+ readable_bytes<true> const& other) noexcept
+ {
+ b_ = other.b_;
+ return *this;
+ }
const_iterator
begin() const;
@@ -46,23 +94,34 @@ public:
end() const;
private:
- friend class buffers_adapter;
+ friend class buffers_adaptor;
- const_buffers_type(buffers_adapter const& b)
+ readable_bytes(buffers_adaptor const& b)
: b_(&b)
{
}
};
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+# pragma warning (pop)
+#endif
+
+//------------------------------------------------------------------------------
+
template<class MutableBufferSequence>
-class buffers_adapter<MutableBufferSequence>::
- const_buffers_type::const_iterator
+template<bool isMutable>
+class buffers_adaptor<MutableBufferSequence>::
+ readable_bytes<isMutable>::
+ const_iterator
{
- iter_type it_;
- buffers_adapter const* b_ = nullptr;
+ iter_type it_{};
+ buffers_adaptor const* b_ = nullptr;
public:
- using value_type = boost::asio::const_buffer;
+ using value_type = typename
+ std::conditional<isMutable,
+ net::mutable_buffer,
+ net::const_buffer>::type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
@@ -70,28 +129,13 @@ public:
std::bidirectional_iterator_tag;
const_iterator() = default;
- const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
- const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
- return
- (b_ == nullptr) ?
- (
- other.b_ == nullptr ||
- other.it_ == other.b_->end_impl()
- ):(
- (other.b_ == nullptr) ?
- (
- it_ == b_->end_impl()
- ): (
- b_ == other.b_ &&
- it_ == other.it_
- )
- );
+ return b_ == other.b_ && it_ == other.it_;
}
bool
@@ -105,7 +149,7 @@ public:
{
value_type const b = *it_;
return value_type{b.data(),
- (b_->out_ == boost::asio::buffer_sequence_end(b_->bs_) ||
+ (b_->out_ == net::buffer_sequence_end(b_->bs_) ||
it_ != b_->out_) ? b.size() : b_->out_pos_} +
(it_ == b_->begin_ ? b_->in_pos_ : 0);
}
@@ -144,10 +188,11 @@ public:
}
private:
- friend class const_buffers_type;
+ friend class readable_bytes;
- const_iterator(buffers_adapter const& b,
- iter_type iter)
+ const_iterator(
+ buffers_adaptor const& b,
+ iter_type iter)
: it_(iter)
, b_(&b)
{
@@ -155,18 +200,22 @@ private:
};
template<class MutableBufferSequence>
+template<bool isMutable>
auto
-buffers_adapter<MutableBufferSequence>::
-const_buffers_type::begin() const ->
+buffers_adaptor<MutableBufferSequence>::
+readable_bytes<isMutable>::
+begin() const ->
const_iterator
{
return const_iterator{*b_, b_->begin_};
}
template<class MutableBufferSequence>
+template<bool isMutable>
auto
-buffers_adapter<MutableBufferSequence>::
-const_buffers_type::end() const ->
+buffers_adaptor<MutableBufferSequence>::
+readable_bytes<isMutable>::
+readable_bytes::end() const ->
const_iterator
{
return const_iterator{*b_, b_->end_impl()};
@@ -175,13 +224,13 @@ const_buffers_type::end() const ->
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
-class buffers_adapter<MutableBufferSequence>::
+class buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type
{
- buffers_adapter const* b_;
+ buffers_adaptor const* b_;
public:
- using value_type = boost::asio::mutable_buffer;
+ using value_type = net::mutable_buffer;
class const_iterator;
@@ -198,24 +247,24 @@ public:
end() const;
private:
- friend class buffers_adapter;
+ friend class buffers_adaptor;
mutable_buffers_type(
- buffers_adapter const& b)
+ buffers_adaptor const& b)
: b_(&b)
{
}
};
template<class MutableBufferSequence>
-class buffers_adapter<MutableBufferSequence>::
+class buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::const_iterator
{
- iter_type it_;
- buffers_adapter const* b_ = nullptr;
+ iter_type it_{};
+ buffers_adaptor const* b_ = nullptr;
public:
- using value_type = boost::asio::mutable_buffer;
+ using value_type = net::mutable_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
@@ -223,28 +272,13 @@ public:
std::bidirectional_iterator_tag;
const_iterator() = default;
- const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
- const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
- return
- (b_ == nullptr) ?
- (
- other.b_ == nullptr ||
- other.it_ == other.b_->end_
- ):(
- (other.b_ == nullptr) ?
- (
- it_ == b_->end_
- ): (
- b_ == other.b_ &&
- it_ == other.it_
- )
- );
+ return b_ == other.b_ && it_ == other.it_;
}
bool
@@ -299,7 +333,7 @@ public:
private:
friend class mutable_buffers_type;
- const_iterator(buffers_adapter const& b,
+ const_iterator(buffers_adaptor const& b,
iter_type iter)
: it_(iter)
, b_(&b)
@@ -308,9 +342,8 @@ private:
};
template<class MutableBufferSequence>
-inline
auto
-buffers_adapter<MutableBufferSequence>::
+buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::
begin() const ->
const_iterator
@@ -319,9 +352,8 @@ begin() const ->
}
template<class MutableBufferSequence>
-inline
auto
-buffers_adapter<MutableBufferSequence>::
+buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::
end() const ->
const_iterator
@@ -333,7 +365,7 @@ end() const ->
template<class MutableBufferSequence>
auto
-buffers_adapter<MutableBufferSequence>::
+buffers_adaptor<MutableBufferSequence>::
end_impl() const ->
iter_type
{
@@ -341,71 +373,97 @@ end_impl() const ->
}
template<class MutableBufferSequence>
-buffers_adapter<MutableBufferSequence>::
-buffers_adapter(buffers_adapter&& other)
- : buffers_adapter(std::move(other),
- std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.begin_),
- std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.out_),
- std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.end_))
+buffers_adaptor<MutableBufferSequence>::
+buffers_adaptor(
+ buffers_adaptor const& other,
+ std::size_t nbegin,
+ std::size_t nout,
+ std::size_t nend)
+ : bs_(other.bs_)
+ , begin_(std::next(bs_.begin(), nbegin))
+ , out_(std::next(bs_.begin(), nout))
+ , end_(std::next(bs_.begin(), nend))
+ , max_size_(other.max_size_)
+ , in_pos_(other.in_pos_)
+ , in_size_(other.in_size_)
+ , out_pos_(other.out_pos_)
+ , out_end_(other.out_end_)
{
}
template<class MutableBufferSequence>
-buffers_adapter<MutableBufferSequence>::
-buffers_adapter(buffers_adapter const& other)
- : buffers_adapter(other,
- std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.begin_),
- std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.out_),
- std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.end_))
+buffers_adaptor<MutableBufferSequence>::
+buffers_adaptor(MutableBufferSequence const& bs)
+ : bs_(bs)
+ , begin_(net::buffer_sequence_begin(bs_))
+ , out_ (net::buffer_sequence_begin(bs_))
+ , end_ (net::buffer_sequence_begin(bs_))
+ , max_size_(
+ [&bs]
+ {
+ return buffer_bytes(bs);
+ }())
{
}
template<class MutableBufferSequence>
-auto
-buffers_adapter<MutableBufferSequence>::
-operator=(buffers_adapter&& other) ->
- buffers_adapter&
+template<class... Args>
+buffers_adaptor<MutableBufferSequence>::
+buffers_adaptor(
+ boost::in_place_init_t, Args&&... args)
+ : bs_{std::forward<Args>(args)...}
+ , begin_(net::buffer_sequence_begin(bs_))
+ , out_ (net::buffer_sequence_begin(bs_))
+ , end_ (net::buffer_sequence_begin(bs_))
+ , max_size_(
+ [&]
+ {
+ return buffer_bytes(bs_);
+ }())
+{
+}
+
+template<class MutableBufferSequence>
+buffers_adaptor<MutableBufferSequence>::
+buffers_adaptor(buffers_adaptor const& other)
+ : buffers_adaptor(
+ other,
+ std::distance<iter_type>(
+ net::buffer_sequence_begin(other.bs_),
+ other.begin_),
+ std::distance<iter_type>(
+ net::buffer_sequence_begin(other.bs_),
+ other.out_),
+ std::distance<iter_type>(
+ net::buffer_sequence_begin(other.bs_),
+ other.end_))
{
- auto const nbegin = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
- other.begin_);
- auto const nout = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
- other.out_);
- auto const nend = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
- other.end_);
- bs_ = std::move(other.bs_);
- begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin);
- out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout);
- end_ = std::next(boost::asio::buffer_sequence_begin(bs_), nend);
- max_size_ = other.max_size_;
- in_pos_ = other.in_pos_;
- in_size_ = other.in_size_;
- out_pos_ = other.out_pos_;
- out_end_ = other.out_end_;
- return *this;
}
template<class MutableBufferSequence>
auto
-buffers_adapter<MutableBufferSequence>::
-operator=(buffers_adapter const& other) ->
- buffers_adapter&
+buffers_adaptor<MutableBufferSequence>::
+operator=(buffers_adaptor const& other) ->
+ buffers_adaptor&
{
+ if(this == &other)
+ return *this;
auto const nbegin = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
+ net::buffer_sequence_begin(other.bs_),
other.begin_);
auto const nout = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
+ net::buffer_sequence_begin(other.bs_),
other.out_);
auto const nend = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
+ net::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = other.bs_;
- begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin);
- out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout);
- end_ = std::next(boost::asio::buffer_sequence_begin(bs_), nend);
+ begin_ = std::next(
+ net::buffer_sequence_begin(bs_), nbegin);
+ out_ = std::next(
+ net::buffer_sequence_begin(bs_), nout);
+ end_ = std::next(
+ net::buffer_sequence_begin(bs_), nend);
max_size_ = other.max_size_;
in_pos_ = other.in_pos_;
in_size_ = other.in_size_;
@@ -414,47 +472,43 @@ operator=(buffers_adapter const& other) ->
return *this;
}
+//
+
template<class MutableBufferSequence>
-buffers_adapter<MutableBufferSequence>::
-buffers_adapter(MutableBufferSequence const& bs)
- : bs_(bs)
- , begin_(boost::asio::buffer_sequence_begin(bs_))
- , out_ (boost::asio::buffer_sequence_begin(bs_))
- , end_ (boost::asio::buffer_sequence_begin(bs_))
- , max_size_(boost::asio::buffer_size(bs_))
+auto
+buffers_adaptor<MutableBufferSequence>::
+data() const noexcept ->
+ const_buffers_type
{
+ return const_buffers_type{*this};
}
template<class MutableBufferSequence>
-template<class... Args>
-buffers_adapter<MutableBufferSequence>::
-buffers_adapter(boost::in_place_init_t, Args&&... args)
- : bs_{std::forward<Args>(args)...}
- , begin_(boost::asio::buffer_sequence_begin(bs_))
- , out_ (boost::asio::buffer_sequence_begin(bs_))
- , end_ (boost::asio::buffer_sequence_begin(bs_))
- , max_size_(boost::asio::buffer_size(bs_))
+auto
+buffers_adaptor<MutableBufferSequence>::
+data() noexcept ->
+ mutable_data_type
{
+ return mutable_data_type{*this};
}
template<class MutableBufferSequence>
auto
-buffers_adapter<MutableBufferSequence>::
+buffers_adaptor<MutableBufferSequence>::
prepare(std::size_t n) ->
mutable_buffers_type
{
- using boost::asio::buffer_size;
end_ = out_;
- if(end_ != boost::asio::buffer_sequence_end(bs_))
+ if(end_ != net::buffer_sequence_end(bs_))
{
- auto size = buffer_size(*end_) - out_pos_;
+ auto size = buffer_bytes(*end_) - out_pos_;
if(n > size)
{
n -= size;
while(++end_ !=
- boost::asio::buffer_sequence_end(bs_))
+ net::buffer_sequence_end(bs_))
{
- size = buffer_size(*end_);
+ size = buffer_bytes(*end_);
if(n < size)
{
out_end_ = n;
@@ -475,23 +529,22 @@ prepare(std::size_t n) ->
}
if(n > 0)
BOOST_THROW_EXCEPTION(std::length_error{
- "buffer overflow"});
+ "buffers_adaptor too long"});
return mutable_buffers_type{*this};
}
template<class MutableBufferSequence>
void
-buffers_adapter<MutableBufferSequence>::
-commit(std::size_t n)
+buffers_adaptor<MutableBufferSequence>::
+commit(std::size_t n) noexcept
{
- using boost::asio::buffer_size;
if(out_ == end_)
return;
auto const last = std::prev(end_);
while(out_ != last)
{
auto const avail =
- buffer_size(*out_) - out_pos_;
+ buffer_bytes(*out_) - out_pos_;
if(n < avail)
{
out_pos_ += n;
@@ -504,10 +557,11 @@ commit(std::size_t n)
in_size_ += avail;
}
- n = (std::min)(n, out_end_ - out_pos_);
+ n = std::min<std::size_t>(
+ n, out_end_ - out_pos_);
out_pos_ += n;
in_size_ += n;
- if(out_pos_ == buffer_size(*out_))
+ if(out_pos_ == buffer_bytes(*out_))
{
++out_;
out_pos_ = 0;
@@ -516,25 +570,14 @@ commit(std::size_t n)
}
template<class MutableBufferSequence>
-inline
-auto
-buffers_adapter<MutableBufferSequence>::
-data() const ->
- const_buffers_type
-{
- return const_buffers_type{*this};
-}
-
-template<class MutableBufferSequence>
void
-buffers_adapter<MutableBufferSequence>::
-consume(std::size_t n)
+buffers_adaptor<MutableBufferSequence>::
+consume(std::size_t n) noexcept
{
- using boost::asio::buffer_size;
while(begin_ != out_)
{
auto const avail =
- buffer_size(*begin_) - in_pos_;
+ buffer_bytes(*begin_) - in_pos_;
if(n < avail)
{
in_size_ -= n;
diff --git a/boost/beast/core/impl/buffers_cat.hpp b/boost/beast/core/impl/buffers_cat.hpp
new file mode 100644
index 0000000000..255153f2bd
--- /dev/null
+++ b/boost/beast/core/impl/buffers_cat.hpp
@@ -0,0 +1,443 @@
+//
+// 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_IMPL_BUFFERS_CAT_HPP
+#define BOOST_BEAST_IMPL_BUFFERS_CAT_HPP
+
+#include <boost/beast/core/detail/tuple.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/beast/core/detail/variant.hpp>
+#include <boost/asio/buffer.hpp>
+#include <cstdint>
+#include <iterator>
+#include <new>
+#include <stdexcept>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+#if defined(_MSC_VER) && ! defined(__clang__)
+# define BOOST_BEAST_UNREACHABLE() __assume(false)
+# define BOOST_BEAST_UNREACHABLE_RETURN(v) __assume(false)
+#else
+# define BOOST_BEAST_UNREACHABLE() __builtin_unreachable()
+# define BOOST_BEAST_UNREACHABLE_RETURN(v) \
+ do { __builtin_unreachable(); return v; } while(false)
+#endif
+
+#ifdef BOOST_BEAST_TESTS
+
+#define BOOST_BEAST_LOGIC_ERROR(s) \
+ do { \
+ BOOST_THROW_EXCEPTION(std::logic_error((s))); \
+ BOOST_BEAST_UNREACHABLE(); \
+ } while(false)
+
+#define BOOST_BEAST_LOGIC_ERROR_RETURN(v, s) \
+ do { \
+ BOOST_THROW_EXCEPTION(std::logic_error(s)); \
+ BOOST_BEAST_UNREACHABLE_RETURN(v); \
+ } while(false)
+
+#else
+
+#define BOOST_BEAST_LOGIC_ERROR(s) \
+ do { \
+ BOOST_ASSERT_MSG(false, s); \
+ BOOST_BEAST_UNREACHABLE(); \
+ } while(false)
+
+#define BOOST_BEAST_LOGIC_ERROR_RETURN(v, s) \
+ do { \
+ BOOST_ASSERT_MSG(false, (s)); \
+ BOOST_BEAST_UNREACHABLE_RETURN(v); \
+ } while(false)
+
+#endif
+
+namespace detail {
+
+struct buffers_cat_view_iterator_base
+{
+ struct past_end
+ {
+ char unused = 0; // make g++8 happy
+
+ net::mutable_buffer
+ operator*() const
+ {
+ BOOST_BEAST_LOGIC_ERROR_RETURN({},
+ "Dereferencing a one-past-the-end iterator");
+ }
+
+ operator bool() const noexcept
+ {
+ return true;
+ }
+ };
+};
+
+} // detail
+
+template<class... Bn>
+class buffers_cat_view<Bn...>::const_iterator
+ : private detail::buffers_cat_view_iterator_base
+{
+ // VFALCO The logic to skip empty sequences fails
+ // if there is just one buffer in the list.
+ static_assert(sizeof...(Bn) >= 2,
+ "A minimum of two sequences are required");
+
+ detail::tuple<Bn...> const* bn_ = nullptr;
+ detail::variant<
+ buffers_iterator_type<Bn>..., past_end> it_{};
+
+ friend class buffers_cat_view<Bn...>;
+
+ template<std::size_t I>
+ using C = std::integral_constant<std::size_t, I>;
+
+public:
+ using value_type = typename
+ buffers_cat_view<Bn...>::value_type;
+ using pointer = value_type const*;
+ using reference = value_type;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category =
+ std::bidirectional_iterator_tag;
+
+ const_iterator() = default;
+ const_iterator(const_iterator const& other) = default;
+ const_iterator& operator=(
+ const_iterator const& other) = default;
+
+ bool
+ operator==(const_iterator const& other) const;
+
+ bool
+ operator!=(const_iterator const& other) const
+ {
+ return ! (*this == other);
+ }
+
+ reference
+ operator*() const;
+
+ pointer
+ operator->() const = delete;
+
+ const_iterator&
+ operator++();
+
+ const_iterator
+ operator++(int);
+
+ const_iterator&
+ operator--();
+
+ const_iterator
+ operator--(int);
+
+private:
+ const_iterator(
+ detail::tuple<Bn...> const& bn,
+ std::true_type);
+
+ const_iterator(
+ detail::tuple<Bn...> const& bn,
+ std::false_type);
+
+ struct dereference
+ {
+ const_iterator const& self;
+
+ reference
+ operator()(mp11::mp_size_t<0>)
+ {
+ BOOST_BEAST_LOGIC_ERROR_RETURN({},
+ "Dereferencing a default-constructed iterator");
+ }
+
+ template<class I>
+ reference operator()(I)
+ {
+ return *self.it_.template get<I::value>();
+ }
+ };
+
+ struct increment
+ {
+ const_iterator& self;
+
+ void
+ operator()(mp11::mp_size_t<0>)
+ {
+ BOOST_BEAST_LOGIC_ERROR(
+ "Incrementing a default-constructed iterator");
+ }
+
+ template<std::size_t I>
+ void
+ operator()(mp11::mp_size_t<I>)
+ {
+ ++self.it_.template get<I>();
+ next(mp11::mp_size_t<I>{});
+ }
+
+ template<std::size_t I>
+ void
+ next(mp11::mp_size_t<I>)
+ {
+ auto& it = self.it_.template get<I>();
+ for(;;)
+ {
+ if (it == net::buffer_sequence_end(
+ detail::get<I-1>(*self.bn_)))
+ break;
+ if(net::const_buffer(*it).size() > 0)
+ return;
+ ++it;
+ }
+ self.it_.template emplace<I+1>(
+ net::buffer_sequence_begin(
+ detail::get<I>(*self.bn_)));
+ next(mp11::mp_size_t<I+1>{});
+ }
+
+ void
+ operator()(mp11::mp_size_t<sizeof...(Bn)>)
+ {
+ auto constexpr I = sizeof...(Bn);
+ ++self.it_.template get<I>();
+ next(mp11::mp_size_t<I>{});
+ }
+
+ void
+ next(mp11::mp_size_t<sizeof...(Bn)>)
+ {
+ auto constexpr I = sizeof...(Bn);
+ auto& it = self.it_.template get<I>();
+ for(;;)
+ {
+ if (it == net::buffer_sequence_end(
+ detail::get<I-1>(*self.bn_)))
+ break;
+ if(net::const_buffer(*it).size() > 0)
+ return;
+ ++it;
+ }
+ // end
+ self.it_.template emplace<I+1>();
+ }
+
+ void
+ operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
+ {
+ BOOST_BEAST_LOGIC_ERROR(
+ "Incrementing a one-past-the-end iterator");
+ }
+ };
+
+ struct decrement
+ {
+ const_iterator& self;
+
+ void
+ operator()(mp11::mp_size_t<0>)
+ {
+ BOOST_BEAST_LOGIC_ERROR(
+ "Decrementing a default-constructed iterator");
+ }
+
+ void
+ operator()(mp11::mp_size_t<1>)
+ {
+ auto constexpr I = 1;
+
+ auto& it = self.it_.template get<I>();
+ for(;;)
+ {
+ if(it == net::buffer_sequence_begin(
+ detail::get<I-1>(*self.bn_)))
+ {
+ BOOST_BEAST_LOGIC_ERROR(
+ "Decrementing an iterator to the beginning");
+ }
+ --it;
+ if(net::const_buffer(*it).size() > 0)
+ return;
+ }
+ }
+
+ template<std::size_t I>
+ void
+ operator()(mp11::mp_size_t<I>)
+ {
+ auto& it = self.it_.template get<I>();
+ for(;;)
+ {
+ if(it == net::buffer_sequence_begin(
+ detail::get<I-1>(*self.bn_)))
+ break;
+ --it;
+ if(net::const_buffer(*it).size() > 0)
+ return;
+ }
+ self.it_.template emplace<I-1>(
+ net::buffer_sequence_end(
+ detail::get<I-2>(*self.bn_)));
+ (*this)(mp11::mp_size_t<I-1>{});
+ }
+
+ void
+ operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
+ {
+ auto constexpr I = sizeof...(Bn)+1;
+ self.it_.template emplace<I-1>(
+ net::buffer_sequence_end(
+ detail::get<I-2>(*self.bn_)));
+ (*this)(mp11::mp_size_t<I-1>{});
+ }
+ };
+};
+
+//------------------------------------------------------------------------------
+
+template<class... Bn>
+buffers_cat_view<Bn...>::
+const_iterator::
+const_iterator(
+ detail::tuple<Bn...> const& bn,
+ std::true_type)
+ : bn_(&bn)
+{
+ // one past the end
+ it_.template emplace<sizeof...(Bn)+1>();
+}
+
+template<class... Bn>
+buffers_cat_view<Bn...>::
+const_iterator::
+const_iterator(
+ detail::tuple<Bn...> const& bn,
+ std::false_type)
+ : bn_(&bn)
+{
+ it_.template emplace<1>(
+ net::buffer_sequence_begin(
+ detail::get<0>(*bn_)));
+ increment{*this}.next(
+ mp11::mp_size_t<1>{});
+}
+
+template<class... Bn>
+bool
+buffers_cat_view<Bn...>::
+const_iterator::
+operator==(const_iterator const& other) const
+{
+ return bn_ == other.bn_ && it_ == other.it_;
+}
+
+template<class... Bn>
+auto
+buffers_cat_view<Bn...>::
+const_iterator::
+operator*() const ->
+ reference
+{
+ return mp11::mp_with_index<
+ sizeof...(Bn) + 2>(
+ it_.index(),
+ dereference{*this});
+}
+
+template<class... Bn>
+auto
+buffers_cat_view<Bn...>::
+const_iterator::
+operator++() ->
+ const_iterator&
+{
+ mp11::mp_with_index<
+ sizeof...(Bn) + 2>(
+ it_.index(),
+ increment{*this});
+ return *this;
+}
+
+template<class... Bn>
+auto
+buffers_cat_view<Bn...>::
+const_iterator::
+operator++(int) ->
+ const_iterator
+{
+ auto temp = *this;
+ ++(*this);
+ return temp;
+}
+
+template<class... Bn>
+auto
+buffers_cat_view<Bn...>::
+const_iterator::
+operator--() ->
+ const_iterator&
+{
+ mp11::mp_with_index<
+ sizeof...(Bn) + 2>(
+ it_.index(),
+ decrement{*this});
+ return *this;
+}
+
+template<class... Bn>
+auto
+buffers_cat_view<Bn...>::
+const_iterator::
+operator--(int) ->
+ const_iterator
+{
+ auto temp = *this;
+ --(*this);
+ return temp;
+}
+
+//------------------------------------------------------------------------------
+
+template<class... Bn>
+buffers_cat_view<Bn...>::
+buffers_cat_view(Bn const&... bn)
+ : bn_(bn...)
+{
+}
+
+
+template<class... Bn>
+auto
+buffers_cat_view<Bn...>::begin() const ->
+ const_iterator
+{
+ return const_iterator{bn_, std::false_type{}};
+}
+
+template<class... Bn>
+auto
+buffers_cat_view<Bn...>::end() const->
+ const_iterator
+{
+ return const_iterator{bn_, std::true_type{}};
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/buffers_cat.ipp b/boost/beast/core/impl/buffers_cat.ipp
deleted file mode 100644
index 9de1187f36..0000000000
--- a/boost/beast/core/impl/buffers_cat.ipp
+++ /dev/null
@@ -1,389 +0,0 @@
-//
-// 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_IMPL_BUFFERS_CAT_IPP
-#define BOOST_BEAST_IMPL_BUFFERS_CAT_IPP
-
-#include <boost/beast/core/detail/type_traits.hpp>
-#include <boost/beast/core/detail/variant.hpp>
-#include <boost/asio/buffer.hpp>
-#include <boost/throw_exception.hpp>
-#include <cstdint>
-#include <iterator>
-#include <new>
-#include <stdexcept>
-#include <tuple>
-#include <utility>
-
-namespace boost {
-namespace beast {
-
-template<class... Bn>
-class buffers_cat_view<Bn...>::const_iterator
-{
- // VFALCO The logic to skip empty sequences fails
- // if there is just one buffer in the list.
- static_assert(sizeof...(Bn) >= 2,
- "A minimum of two sequences are required");
-
- struct past_end
- {
- char unused = 0; // make g++8 happy
-
- operator bool() const noexcept
- {
- return true;
- }
- };
-
- std::tuple<Bn...> const* bn_ = nullptr;
- detail::variant<typename
- detail::buffer_sequence_iterator<Bn>::type...,
- past_end> it_;
-
- friend class buffers_cat_view<Bn...>;
-
- template<std::size_t I>
- using C = std::integral_constant<std::size_t, I>;
-
-public:
- using value_type = typename
- detail::common_buffers_type<Bn...>::type;
- using pointer = value_type const*;
- using reference = value_type;
- using difference_type = std::ptrdiff_t;
- using iterator_category =
- std::bidirectional_iterator_tag;
-
- const_iterator() = default;
- const_iterator(const_iterator&& other) = default;
- const_iterator(const_iterator const& other) = default;
- const_iterator& operator=(const_iterator&& other) = default;
- const_iterator& operator=(const_iterator const& other) = default;
-
- bool
- operator==(const_iterator const& other) const;
-
- bool
- operator!=(const_iterator const& other) const
- {
- return ! (*this == other);
- }
-
- reference
- operator*() const;
-
- pointer
- operator->() const = delete;
-
- const_iterator&
- operator++();
-
- const_iterator
- operator++(int);
-
- // deprecated
- const_iterator&
- operator--();
-
- // deprecated
- const_iterator
- operator--(int);
-
-private:
- const_iterator(
- std::tuple<Bn...> const& bn, bool at_end);
-
- template<std::size_t I>
- void
- construct(C<I> const&)
- {
- if(boost::asio::buffer_size(
- std::get<I>(*bn_)) != 0)
- {
- it_.template emplace<I+1>(
- boost::asio::buffer_sequence_begin(
- std::get<I>(*bn_)));
- return;
- }
- construct(C<I+1>{});
- }
-
- void
- construct(C<sizeof...(Bn)-1> const&)
- {
- auto constexpr I = sizeof...(Bn)-1;
- it_.template emplace<I+1>(
- boost::asio::buffer_sequence_begin(
- std::get<I>(*bn_)));
- }
-
- void
- construct(C<sizeof...(Bn)> const&)
- {
- // end
- auto constexpr I = sizeof...(Bn);
- it_.template emplace<I+1>();
- }
-
- template<std::size_t I>
- void
- next(C<I> const&)
- {
- if(boost::asio::buffer_size(
- std::get<I>(*bn_)) != 0)
- {
- it_.template emplace<I+1>(
- boost::asio::buffer_sequence_begin(
- std::get<I>(*bn_)));
- return;
- }
- next(C<I+1>{});
- }
-
- void
- next(C<sizeof...(Bn)> const&)
- {
- // end
- auto constexpr I = sizeof...(Bn);
- it_.template emplace<I+1>();
- }
-
- template<std::size_t I>
- void
- prev(C<I> const&)
- {
- if(boost::asio::buffer_size(
- std::get<I>(*bn_)) != 0)
- {
- it_.template emplace<I+1>(
- boost::asio::buffer_sequence_end(
- std::get<I>(*bn_)));
- return;
- }
- prev(C<I-1>{});
- }
-
- void
- prev(C<0> const&)
- {
- auto constexpr I = 0;
- it_.template emplace<I+1>(
- boost::asio::buffer_sequence_end(
- std::get<I>(*bn_)));
- }
-
- template<std::size_t I>
- reference
- dereference(C<I> const&) const
- {
- if(it_.index() == I+1)
- return *it_.template get<I+1>();
- return dereference(C<I+1>{});
- }
-
- [[noreturn]]
- reference
- dereference(C<sizeof...(Bn)> const&) const
- {
- BOOST_THROW_EXCEPTION(std::logic_error{
- "invalid iterator"});
- }
-
- template<std::size_t I>
- void
- increment(C<I> const&)
- {
- if(it_.index() == I+1)
- {
- if(++it_.template get<I+1>() !=
- boost::asio::buffer_sequence_end(
- std::get<I>(*bn_)))
- return;
- return next(C<I+1>{});
- }
- increment(C<I+1>{});
- }
-
- [[noreturn]]
- void
- increment(C<sizeof...(Bn)> const&)
- {
- BOOST_THROW_EXCEPTION(std::logic_error{
- "invalid iterator"});
- }
-
- void
- decrement(C<sizeof...(Bn)> const&)
- {
- auto constexpr I = sizeof...(Bn);
- if(it_.index() == I+1)
- prev(C<I-1>{});
- decrement(C<I-1>{});
- }
-
- template<std::size_t I>
- void
- decrement(C<I> const&)
- {
- if(it_.index() == I+1)
- {
- if(it_.template get<I+1>() !=
- boost::asio::buffer_sequence_begin(
- std::get<I>(*bn_)))
- {
- --it_.template get<I+1>();
- return;
- }
- prev(C<I-1>{});
- }
- decrement(C<I-1>{});
- }
-
- void
- decrement(C<0> const&)
- {
- auto constexpr I = 0;
- if(it_.template get<I+1>() !=
- boost::asio::buffer_sequence_begin(
- std::get<I>(*bn_)))
- {
- --it_.template get<I+1>();
- return;
- }
- BOOST_THROW_EXCEPTION(std::logic_error{
- "invalid iterator"});
- }
-};
-
-//------------------------------------------------------------------------------
-
-template<class... Bn>
-buffers_cat_view<Bn...>::
-const_iterator::
-const_iterator(
- std::tuple<Bn...> const& bn, bool at_end)
- : bn_(&bn)
-{
- if(! at_end)
- construct(C<0>{});
- else
- construct(C<sizeof...(Bn)>{});
-}
-
-template<class... Bn>
-bool
-buffers_cat_view<Bn...>::
-const_iterator::
-operator==(const_iterator const& other) const
-{
- return
- (bn_ == nullptr) ?
- (
- other.bn_ == nullptr ||
- other.it_.index() == sizeof...(Bn)
- ):(
- (other.bn_ == nullptr) ?
- (
- it_.index() == sizeof...(Bn)
- ): (
- bn_ == other.bn_ &&
- it_ == other.it_
- )
- );
-}
-
-template<class... Bn>
-auto
-buffers_cat_view<Bn...>::
-const_iterator::
-operator*() const ->
- reference
-{
- return dereference(C<0>{});
-}
-
-template<class... Bn>
-auto
-buffers_cat_view<Bn...>::
-const_iterator::
-operator++() ->
- const_iterator&
-{
- increment(C<0>{});
- return *this;
-}
-
-template<class... Bn>
-auto
-buffers_cat_view<Bn...>::
-const_iterator::
-operator++(int) ->
- const_iterator
-{
- auto temp = *this;
- ++(*this);
- return temp;
-}
-
-template<class... Bn>
-auto
-buffers_cat_view<Bn...>::
-const_iterator::
-operator--() ->
- const_iterator&
-{
- decrement(C<sizeof...(Bn)>{});
- return *this;
-}
-
-template<class... Bn>
-auto
-buffers_cat_view<Bn...>::
-const_iterator::
-operator--(int) ->
- const_iterator
-{
- auto temp = *this;
- --(*this);
- return temp;
-}
-
-//------------------------------------------------------------------------------
-
-template<class... Bn>
-buffers_cat_view<Bn...>::
-buffers_cat_view(Bn const&... bn)
- : bn_(bn...)
-{
-}
-
-
-template<class... Bn>
-inline
-auto
-buffers_cat_view<Bn...>::begin() const ->
- const_iterator
-{
- return const_iterator{bn_, false};
-}
-
-template<class... Bn>
-inline
-auto
-buffers_cat_view<Bn...>::end() const ->
- const_iterator
-{
- return const_iterator{bn_, true};
-}
-
-} // beast
-} // boost
-
-#endif
diff --git a/boost/beast/core/impl/buffers_prefix.hpp b/boost/beast/core/impl/buffers_prefix.hpp
new file mode 100644
index 0000000000..e4a484bcee
--- /dev/null
+++ b/boost/beast/core/impl/buffers_prefix.hpp
@@ -0,0 +1,326 @@
+//
+// 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_IMPL_BUFFERS_PREFIX_HPP
+#define BOOST_BEAST_IMPL_BUFFERS_PREFIX_HPP
+
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/config/workaround.hpp>
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <stdexcept>
+#include <type_traits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+template<class Buffers>
+class buffers_prefix_view<Buffers>::const_iterator
+{
+ friend class buffers_prefix_view<Buffers>;
+
+ buffers_prefix_view const* b_ = nullptr;
+ std::size_t remain_ = 0;
+ iter_type it_{};
+
+public:
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+ using value_type = typename std::conditional<
+ boost::is_convertible<typename
+ std::iterator_traits<iter_type>::value_type,
+ net::mutable_buffer>::value,
+ net::mutable_buffer,
+ net::const_buffer>::type;
+#else
+ using value_type = buffers_type<Buffers>;
+#endif
+
+ BOOST_STATIC_ASSERT(std::is_same<
+ typename const_iterator::value_type,
+ typename buffers_prefix_view::value_type>::value);
+
+ using pointer = value_type const*;
+ using reference = value_type;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category =
+ std::bidirectional_iterator_tag;
+
+ const_iterator() = default;
+ const_iterator(
+ const_iterator const& other) = default;
+ const_iterator& operator=(
+ const_iterator const& other) = default;
+
+ bool
+ operator==(const_iterator const& other) const
+ {
+ return b_ == other.b_ && it_ == other.it_;
+ }
+
+ bool
+ operator!=(const_iterator const& other) const
+ {
+ return !(*this == other);
+ }
+
+ reference
+ operator*() const
+ {
+ value_type v(*it_);
+ if(remain_ < v.size())
+ return {v.data(), remain_};
+ return v;
+ }
+
+ pointer
+ operator->() const = delete;
+
+ const_iterator&
+ operator++()
+ {
+ value_type const v = *it_++;
+ remain_ -= v.size();
+ return *this;
+ }
+
+ const_iterator
+ operator++(int)
+ {
+ auto temp = *this;
+ value_type const v = *it_++;
+ remain_ -= v.size();
+ return temp;
+ }
+
+ const_iterator&
+ operator--()
+ {
+ value_type const v = *--it_;
+ remain_ += v.size();
+ return *this;
+ }
+
+ const_iterator
+ operator--(int)
+ {
+ auto temp = *this;
+ value_type const v = *--it_;
+ remain_ += v.size();
+ return temp;
+ }
+
+private:
+ const_iterator(
+ buffers_prefix_view const& b,
+ std::true_type)
+ : b_(&b)
+ , remain_(b.remain_)
+ , it_(b_->end_)
+ {
+ }
+
+ const_iterator(
+ buffers_prefix_view const& b,
+ std::false_type)
+ : b_(&b)
+ , remain_(b_->size_)
+ , it_(net::buffer_sequence_begin(b_->bs_))
+ {
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template<class Buffers>
+void
+buffers_prefix_view<Buffers>::
+setup(std::size_t size)
+{
+ size_ = 0;
+ remain_ = 0;
+ end_ = net::buffer_sequence_begin(bs_);
+ auto const last = bs_.end();
+ while(end_ != last)
+ {
+ auto const len = buffer_bytes(*end_++);
+ if(len >= size)
+ {
+ size_ += size;
+
+ // by design, this subtraction can wrap
+ BOOST_STATIC_ASSERT(std::is_unsigned<
+ decltype(remain_)>::value);
+ remain_ = size - len;
+ break;
+ }
+ size -= len;
+ size_ += len;
+ }
+}
+
+template<class Buffers>
+buffers_prefix_view<Buffers>::
+buffers_prefix_view(
+ buffers_prefix_view const& other,
+ std::size_t dist)
+ : bs_(other.bs_)
+ , size_(other.size_)
+ , remain_(other.remain_)
+ , end_(std::next(bs_.begin(), dist))
+{
+}
+
+template<class Buffers>
+buffers_prefix_view<Buffers>::
+buffers_prefix_view(buffers_prefix_view const& other)
+ : buffers_prefix_view(other,
+ std::distance<iter_type>(
+ net::buffer_sequence_begin(other.bs_),
+ other.end_))
+{
+}
+
+template<class Buffers>
+auto
+buffers_prefix_view<Buffers>::
+operator=(buffers_prefix_view const& other) ->
+ buffers_prefix_view&
+{
+ auto const dist = std::distance<iter_type>(
+ net::buffer_sequence_begin(other.bs_),
+ other.end_);
+ bs_ = other.bs_;
+ size_ = other.size_;
+ remain_ = other.remain_;
+ end_ = std::next(
+ net::buffer_sequence_begin(bs_),
+ dist);
+ return *this;
+}
+
+template<class Buffers>
+buffers_prefix_view<Buffers>::
+buffers_prefix_view(
+ std::size_t size,
+ Buffers const& bs)
+ : bs_(bs)
+{
+ setup(size);
+}
+
+template<class Buffers>
+template<class... Args>
+buffers_prefix_view<Buffers>::
+buffers_prefix_view(
+ std::size_t size,
+ boost::in_place_init_t,
+ Args&&... args)
+ : bs_(std::forward<Args>(args)...)
+{
+ setup(size);
+}
+
+template<class Buffers>
+auto
+buffers_prefix_view<Buffers>::
+begin() const ->
+ const_iterator
+{
+ return const_iterator{
+ *this, std::false_type{}};
+}
+
+template<class Buffers>
+auto
+buffers_prefix_view<Buffers>::
+end() const ->
+ const_iterator
+{
+ return const_iterator{
+ *this, std::true_type{}};
+}
+
+//------------------------------------------------------------------------------
+
+template<>
+class buffers_prefix_view<net::const_buffer>
+ : public net::const_buffer
+{
+public:
+ using net::const_buffer::const_buffer;
+ buffers_prefix_view(buffers_prefix_view const&) = default;
+ buffers_prefix_view& operator=(buffers_prefix_view const&) = default;
+
+ buffers_prefix_view(
+ std::size_t size,
+ net::const_buffer buffer)
+ : net::const_buffer(
+ buffer.data(),
+ std::min<std::size_t>(size, buffer.size())
+ #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ , buffer.get_debug_check()
+ #endif
+ )
+ {
+ }
+
+ template<class... Args>
+ buffers_prefix_view(
+ std::size_t size,
+ boost::in_place_init_t,
+ Args&&... args)
+ : buffers_prefix_view(size,
+ net::const_buffer(
+ std::forward<Args>(args)...))
+ {
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template<>
+class buffers_prefix_view<net::mutable_buffer>
+ : public net::mutable_buffer
+{
+public:
+ using net::mutable_buffer::mutable_buffer;
+ buffers_prefix_view(buffers_prefix_view const&) = default;
+ buffers_prefix_view& operator=(buffers_prefix_view const&) = default;
+
+ buffers_prefix_view(
+ std::size_t size,
+ net::mutable_buffer buffer)
+ : net::mutable_buffer(
+ buffer.data(),
+ std::min<std::size_t>(size, buffer.size())
+ #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ , buffer.get_debug_check()
+ #endif
+ )
+ {
+ }
+
+ template<class... Args>
+ buffers_prefix_view(
+ std::size_t size,
+ boost::in_place_init_t,
+ Args&&... args)
+ : buffers_prefix_view(size,
+ net::mutable_buffer(
+ std::forward<Args>(args)...))
+ {
+ }
+};
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/buffers_prefix.ipp b/boost/beast/core/impl/buffers_prefix.ipp
deleted file mode 100644
index c595455d60..0000000000
--- a/boost/beast/core/impl/buffers_prefix.ipp
+++ /dev/null
@@ -1,277 +0,0 @@
-//
-// 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_IMPL_BUFFERS_PREFIX_IPP
-#define BOOST_BEAST_IMPL_BUFFERS_PREFIX_IPP
-
-#include <algorithm>
-#include <cstdint>
-#include <iterator>
-#include <stdexcept>
-#include <type_traits>
-#include <utility>
-
-namespace boost {
-namespace beast {
-
-namespace detail {
-
-inline
-boost::asio::const_buffer
-buffers_prefix(std::size_t size,
- boost::asio::const_buffer buffer)
-{
- return {buffer.data(),
- (std::min)(size, buffer.size())};
-}
-
-inline
-boost::asio::mutable_buffer
-buffers_prefix(std::size_t size,
- boost::asio::mutable_buffer buffer)
-{
- return {buffer.data(),
- (std::min)(size, buffer.size())};
-}
-
-} // detail
-
-template<class BufferSequence>
-class buffers_prefix_view<BufferSequence>::const_iterator
-{
- friend class buffers_prefix_view<BufferSequence>;
-
- buffers_prefix_view const* b_ = nullptr;
- std::size_t remain_;
- iter_type it_;
-
-public:
- using value_type = typename std::conditional<
- boost::is_convertible<typename
- std::iterator_traits<iter_type>::value_type,
- boost::asio::mutable_buffer>::value,
- boost::asio::mutable_buffer,
- boost::asio::const_buffer>::type;
- using pointer = value_type const*;
- using reference = value_type;
- using difference_type = std::ptrdiff_t;
- using iterator_category =
- std::bidirectional_iterator_tag;
-
- const_iterator() = default;
- const_iterator(const_iterator&& other) = default;
- const_iterator(const_iterator const& other) = default;
- const_iterator& operator=(const_iterator&& other) = default;
- const_iterator& operator=(const_iterator const& other) = default;
-
- bool
- operator==(const_iterator const& other) const
- {
- return
- (b_ == nullptr) ?
- (
- other.b_ == nullptr ||
- other.it_ == other.b_->end_
- ):(
- (other.b_ == nullptr) ?
- (
- it_ == b_->end_
- ): (
- b_ == other.b_ &&
- it_ == other.it_
- )
- );
- }
-
- bool
- operator!=(const_iterator const& other) const
- {
- return !(*this == other);
- }
-
- reference
- operator*() const
- {
- return detail::buffers_prefix(remain_, *it_);
- }
-
- pointer
- operator->() const = delete;
-
- const_iterator&
- operator++()
- {
- remain_ -= boost::asio::buffer_size(*it_++);
- return *this;
- }
-
- const_iterator
- operator++(int)
- {
- auto temp = *this;
- remain_ -= boost::asio::buffer_size(*it_++);
- return temp;
- }
-
- const_iterator&
- operator--()
- {
- remain_ += boost::asio::buffer_size(*--it_);
- return *this;
- }
-
- const_iterator
- operator--(int)
- {
- auto temp = *this;
- remain_ += boost::asio::buffer_size(*--it_);
- return temp;
- }
-
-private:
- const_iterator(buffers_prefix_view const& b,
- std::true_type)
- : b_(&b)
- , remain_(b.remain_)
- , it_(b_->end_)
- {
- }
-
- const_iterator(buffers_prefix_view const& b,
- std::false_type)
- : b_(&b)
- , remain_(b_->size_)
- , it_(boost::asio::buffer_sequence_begin(b_->bs_))
- {
- }
-};
-
-//------------------------------------------------------------------------------
-
-template<class BufferSequence>
-void
-buffers_prefix_view<BufferSequence>::
-setup(std::size_t size)
-{
- size_ = 0;
- remain_ = 0;
- end_ = boost::asio::buffer_sequence_begin(bs_);
- auto const last = bs_.end();
- while(end_ != last)
- {
- auto const len =
- boost::asio::buffer_size(*end_++);
- if(len >= size)
- {
- size_ += size;
- remain_ = size - len;
- break;
- }
- size -= len;
- size_ += len;
- }
-}
-
-template<class BufferSequence>
-buffers_prefix_view<BufferSequence>::
-buffers_prefix_view(buffers_prefix_view&& other)
- : buffers_prefix_view(std::move(other),
- std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
- other.end_))
-{
-}
-
-template<class BufferSequence>
-buffers_prefix_view<BufferSequence>::
-buffers_prefix_view(buffers_prefix_view const& other)
- : buffers_prefix_view(other,
- std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
- other.end_))
-{
-}
-
-template<class BufferSequence>
-auto
-buffers_prefix_view<BufferSequence>::
-operator=(buffers_prefix_view&& other) ->
- buffers_prefix_view&
-{
- auto const dist = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
- other.end_);
- bs_ = std::move(other.bs_);
- size_ = other.size_;
- remain_ = other.remain_;
- end_ = std::next(
- boost::asio::buffer_sequence_begin(bs_),
- dist);
- return *this;
-}
-
-template<class BufferSequence>
-auto
-buffers_prefix_view<BufferSequence>::
-operator=(buffers_prefix_view const& other) ->
- buffers_prefix_view&
-{
- auto const dist = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
- other.end_);
- bs_ = other.bs_;
- size_ = other.size_;
- remain_ = other.remain_;
- end_ = std::next(
- boost::asio::buffer_sequence_begin(bs_),
- dist);
- return *this;
-}
-
-template<class BufferSequence>
-buffers_prefix_view<BufferSequence>::
-buffers_prefix_view(std::size_t size,
- BufferSequence const& bs)
- : bs_(bs)
-{
- setup(size);
-}
-
-template<class BufferSequence>
-template<class... Args>
-buffers_prefix_view<BufferSequence>::
-buffers_prefix_view(std::size_t size,
- boost::in_place_init_t, Args&&... args)
- : bs_(std::forward<Args>(args)...)
-{
- setup(size);
-}
-
-template<class BufferSequence>
-inline
-auto
-buffers_prefix_view<BufferSequence>::begin() const ->
- const_iterator
-{
- return const_iterator{*this, std::false_type{}};
-}
-
-template<class BufferSequence>
-inline
-auto
-buffers_prefix_view<BufferSequence>::end() const ->
- const_iterator
-{
- return const_iterator{*this, std::true_type{}};
-}
-
-} // beast
-} // boost
-
-#endif
diff --git a/boost/beast/core/impl/buffers_suffix.ipp b/boost/beast/core/impl/buffers_suffix.hpp
index 62b5f4634e..9822b4df70 100644
--- a/boost/beast/core/impl/buffers_suffix.ipp
+++ b/boost/beast/core/impl/buffers_suffix.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -7,10 +7,11 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_IMPL_BUFFERS_SUFFIX_IPP
-#define BOOST_BEAST_IMPL_BUFFERS_SUFFIX_IPP
+#ifndef BOOST_BEAST_IMPL_BUFFERS_SUFFIX_HPP
+#define BOOST_BEAST_IMPL_BUFFERS_SUFFIX_HPP
-#include <boost/beast/core/type_traits.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
#include <boost/type_traits.hpp>
#include <algorithm>
#include <cstdint>
@@ -26,19 +27,22 @@ class buffers_suffix<Buffers>::const_iterator
{
friend class buffers_suffix<Buffers>;
- using iter_type = typename
- detail::buffer_sequence_iterator<Buffers>::type;
+ using iter_type = buffers_iterator_type<Buffers>;
- iter_type it_;
+ iter_type it_{};
buffers_suffix const* b_ = nullptr;
public:
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
using value_type = typename std::conditional<
boost::is_convertible<typename
std::iterator_traits<iter_type>::value_type,
- boost::asio::mutable_buffer>::value,
- boost::asio::mutable_buffer,
- boost::asio::const_buffer>::type;
+ net::mutable_buffer>::value,
+ net::mutable_buffer,
+ net::const_buffer>::type;
+#else
+ using value_type = buffers_type<Buffers>;
+#endif
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
@@ -46,28 +50,15 @@ public:
std::bidirectional_iterator_tag;
const_iterator() = default;
- const_iterator(const_iterator&& other) = default;
- const_iterator(const_iterator const& other) = default;
- const_iterator& operator=(const_iterator&& other) = default;
- const_iterator& operator=(const_iterator const& other) = default;
+ const_iterator(
+ const_iterator const& other) = default;
+ const_iterator& operator=(
+ const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
- return
- (b_ == nullptr) ?
- (
- other.b_ == nullptr ||
- other.it_ == boost::asio::buffer_sequence_end(other.b_->bs_)
- ):(
- (other.b_ == nullptr) ?
- (
- it_ == boost::asio::buffer_sequence_end(b_->bs_)
- ): (
- b_ == other.b_ &&
- it_ == other.it_
- )
- );
+ return b_ == other.b_ && it_ == other.it_;
}
bool
@@ -79,9 +70,9 @@ public:
reference
operator*() const
{
- return it_ == b_->begin_
- ? value_type{*it_} + b_->skip_
- : *it_;
+ if(it_ == b_->begin_)
+ return value_type(*it_) + b_->skip_;
+ return value_type(*it_);
}
pointer
@@ -118,8 +109,9 @@ public:
}
private:
- const_iterator(buffers_suffix const& b,
- iter_type it)
+ const_iterator(
+ buffers_suffix const& b,
+ iter_type it)
: it_(it)
, b_(&b)
{
@@ -131,17 +123,7 @@ private:
template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix()
- : begin_(boost::asio::buffer_sequence_begin(bs_))
-{
-}
-
-template<class Buffers>
-buffers_suffix<Buffers>::
-buffers_suffix(buffers_suffix&& other)
- : buffers_suffix(std::move(other),
- std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(
- other.bs_), other.begin_))
+ : begin_(net::buffer_sequence_begin(bs_))
{
}
@@ -150,7 +132,7 @@ buffers_suffix<Buffers>::
buffers_suffix(buffers_suffix const& other)
: buffers_suffix(other,
std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(
+ net::buffer_sequence_begin(
other.bs_), other.begin_))
{
}
@@ -159,12 +141,12 @@ template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix(Buffers const& bs)
: bs_(bs)
- , begin_(boost::asio::buffer_sequence_begin(bs_))
+ , begin_(net::buffer_sequence_begin(bs_))
{
static_assert(
- boost::asio::is_const_buffer_sequence<Buffers>::value||
- boost::asio::is_mutable_buffer_sequence<Buffers>::value,
- "BufferSequence requirements not met");
+ net::is_const_buffer_sequence<Buffers>::value ||
+ net::is_mutable_buffer_sequence<Buffers>::value,
+ "BufferSequence type requirements not met");
}
template<class Buffers>
@@ -172,7 +154,7 @@ template<class... Args>
buffers_suffix<Buffers>::
buffers_suffix(boost::in_place_init_t, Args&&... args)
: bs_(std::forward<Args>(args)...)
- , begin_(boost::asio::buffer_sequence_begin(bs_))
+ , begin_(net::buffer_sequence_begin(bs_))
{
static_assert(sizeof...(Args) > 0,
"Missing constructor arguments");
@@ -184,38 +166,20 @@ buffers_suffix(boost::in_place_init_t, Args&&... args)
template<class Buffers>
auto
buffers_suffix<Buffers>::
-operator=(buffers_suffix&& other) ->
- buffers_suffix&
-{
- auto const dist = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
- other.begin_);
- bs_ = std::move(other.bs_);
- begin_ = std::next(
- boost::asio::buffer_sequence_begin(bs_),
- dist);
- skip_ = other.skip_;
- return *this;
-}
-
-template<class Buffers>
-auto
-buffers_suffix<Buffers>::
operator=(buffers_suffix const& other) ->
buffers_suffix&
{
auto const dist = std::distance<iter_type>(
- boost::asio::buffer_sequence_begin(other.bs_),
+ net::buffer_sequence_begin(other.bs_),
other.begin_);
bs_ = other.bs_;
begin_ = std::next(
- boost::asio::buffer_sequence_begin(bs_), dist);
+ net::buffer_sequence_begin(bs_), dist);
skip_ = other.skip_;
return *this;
}
template<class Buffers>
-inline
auto
buffers_suffix<Buffers>::
begin() const ->
@@ -225,14 +189,13 @@ begin() const ->
}
template<class Buffers>
-inline
auto
buffers_suffix<Buffers>::
end() const ->
const_iterator
{
return const_iterator{*this,
- boost::asio::buffer_sequence_end(bs_)};
+ net::buffer_sequence_end(bs_)};
}
template<class Buffers>
@@ -240,13 +203,12 @@ void
buffers_suffix<Buffers>::
consume(std::size_t amount)
{
- using boost::asio::buffer_size;
auto const end =
- boost::asio::buffer_sequence_end(bs_);
+ net::buffer_sequence_end(bs_);
for(;amount > 0 && begin_ != end; ++begin_)
{
auto const len =
- buffer_size(*begin_) - skip_;
+ buffer_bytes(*begin_) - skip_;
if(amount < len)
{
skip_ += amount;
diff --git a/boost/beast/core/impl/error.hpp b/boost/beast/core/impl/error.hpp
new file mode 100644
index 0000000000..a02caeefe2
--- /dev/null
+++ b/boost/beast/core/impl/error.hpp
@@ -0,0 +1,44 @@
+//
+// 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_IMPL_ERROR_HPP
+#define BOOST_BEAST_IMPL_ERROR_HPP
+
+#include <type_traits>
+
+namespace boost {
+namespace system {
+template<>
+struct is_error_code_enum<::boost::beast::error>
+{
+ static bool const value = true;
+};
+template<>
+struct is_error_condition_enum<::boost::beast::condition>
+{
+ static bool const value = true;
+};
+} // system
+} // boost
+
+namespace boost {
+namespace beast {
+
+BOOST_BEAST_DECL
+error_code
+make_error_code(error e);
+
+BOOST_BEAST_DECL
+error_condition
+make_error_condition(condition c);
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/error.ipp b/boost/beast/core/impl/error.ipp
new file mode 100644
index 0000000000..0b3015775b
--- /dev/null
+++ b/boost/beast/core/impl/error.ipp
@@ -0,0 +1,99 @@
+//
+// 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_IMPL_ERROR_IPP
+#define BOOST_BEAST_IMPL_ERROR_IPP
+
+#include <boost/beast/core/error.hpp>
+
+namespace boost {
+namespace beast {
+
+namespace detail {
+
+class error_codes : public error_category
+{
+public:
+ const char*
+ name() const noexcept override
+ {
+ return "boost.beast";
+ }
+
+ BOOST_BEAST_DECL
+ std::string
+ message(int ev) const override
+ {
+ switch(static_cast<error>(ev))
+ {
+ default:
+ case error::timeout: return
+ "The socket was closed due to a timeout";
+ }
+ }
+
+ BOOST_BEAST_DECL
+ error_condition
+ default_error_condition(int ev) const noexcept override
+ {
+ switch(static_cast<error>(ev))
+ {
+ default:
+ // return {ev, *this};
+ case error::timeout:
+ return condition::timeout;
+ }
+ }
+};
+
+class error_conditions : public error_category
+{
+public:
+ BOOST_BEAST_DECL
+ const char*
+ name() const noexcept override
+ {
+ return "boost.beast";
+ }
+
+ BOOST_BEAST_DECL
+ std::string
+ message(int cv) const override
+ {
+ switch(static_cast<condition>(cv))
+ {
+ default:
+ case condition::timeout:
+ return "The operation timed out";
+ }
+ }
+};
+
+} // detail
+
+error_code
+make_error_code(error e)
+{
+ static detail::error_codes const cat{};
+ return error_code{static_cast<
+ std::underlying_type<error>::type>(e), cat};
+}
+
+error_condition
+make_error_condition(condition c)
+{
+ static detail::error_conditions const cat{};
+ return error_condition{static_cast<
+ std::underlying_type<condition>::type>(c), cat};
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/file_posix.ipp b/boost/beast/core/impl/file_posix.ipp
index 8136bb83c2..0f7f42ac8d 100644
--- a/boost/beast/core/impl/file_posix.ipp
+++ b/boost/beast/core/impl/file_posix.ipp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2015-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)
@@ -10,8 +10,21 @@
#ifndef BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
+#include <boost/beast/core/file_posix.hpp>
+
+#if BOOST_BEAST_USE_POSIX_FILE
+
+#include <boost/core/exchange.hpp>
+#include <limits>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+
#if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
-# if defined(__APPLE__) || (defined(ANDROID) && (__ANDROID_API__ < 21))
+# if defined(__APPLE__) || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
# define BOOST_BEAST_NO_POSIX_FADVISE
# endif
#endif
@@ -24,112 +37,92 @@
# endif
#endif
-#include <boost/core/exchange.hpp>
-#include <limits>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <limits.h>
-
namespace boost {
namespace beast {
-namespace detail {
-
-inline
int
-file_posix_close(int fd)
+file_posix::
+native_close(native_handle_type& fd)
{
- for(;;)
+/* https://github.com/boostorg/beast/issues/1445
+
+ This function is tuned for Linux / Mac OS:
+
+ * only calls close() once
+ * returns the error directly to the caller
+ * does not loop on EINTR
+
+ If this is incorrect for the platform, then the
+ caller will need to implement their own type
+ meeting the File requirements and use the correct
+ behavior.
+
+ See:
+ http://man7.org/linux/man-pages/man2/close.2.html
+*/
+ int ev = 0;
+ if(fd != -1)
{
- if(! ::close(fd))
- break;
- int const ev = errno;
- if(errno != EINTR)
- return ev;
+ if(::close(fd) != 0)
+ ev = errno;
+ fd = -1;
}
- return 0;
+ return ev;
}
-} // detail
-
-inline
file_posix::
~file_posix()
{
- if(fd_ != -1)
- detail::file_posix_close(fd_);
+ native_close(fd_);
}
-inline
file_posix::
file_posix(file_posix&& other)
: fd_(boost::exchange(other.fd_, -1))
{
}
-inline
file_posix&
file_posix::
operator=(file_posix&& other)
{
if(&other == this)
return *this;
- if(fd_ != -1)
- detail::file_posix_close(fd_);
+ native_close(fd_);
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
-inline
void
file_posix::
native_handle(native_handle_type fd)
{
- if(fd_ != -1)
- detail::file_posix_close(fd_);
+ native_close(fd_);
fd_ = fd;
}
-inline
void
file_posix::
close(error_code& ec)
{
- if(fd_ != -1)
- {
- auto const ev =
- detail::file_posix_close(fd_);
- if(ev)
- ec.assign(ev, generic_category());
- else
- ec.assign(0, ec.category());
- fd_ = -1;
- }
+ auto const ev = native_close(fd_);
+ if(ev)
+ ec.assign(ev, system_category());
else
- {
- ec.assign(0, ec.category());
- }
+ ec = {};
}
-inline
void
file_posix::
open(char const* path, file_mode mode, error_code& ec)
{
- if(fd_ != -1)
- {
- auto const ev =
- detail::file_posix_close(fd_);
- if(ev)
- ec.assign(ev, generic_category());
- else
- ec.assign(0, ec.category());
- fd_ = -1;
- }
+ auto const ev = native_close(fd_);
+ if(ev)
+ ec.assign(ev, system_category());
+ else
+ ec = {};
+
int f = 0;
#if BOOST_BEAST_USE_POSIX_FADVISE
int advise = 0;
@@ -172,21 +165,14 @@ open(char const* path, file_mode mode, error_code& ec)
break;
case file_mode::append:
- f = O_RDWR | O_CREAT | O_TRUNC;
- #if BOOST_BEAST_USE_POSIX_FADVISE
- advise = POSIX_FADV_SEQUENTIAL;
- #endif
- break;
-
- case file_mode::append_new:
- f = O_RDWR | O_CREAT | O_EXCL;
+ f = O_WRONLY | O_CREAT | O_TRUNC;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
break;
case file_mode::append_existing:
- f = O_RDWR | O_EXCL;
+ f = O_WRONLY;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
@@ -200,7 +186,7 @@ open(char const* path, file_mode mode, error_code& ec)
auto const ev = errno;
if(ev != EINTR)
{
- ec.assign(ev, generic_category());
+ ec.assign(ev, system_category());
return;
}
}
@@ -208,82 +194,77 @@ open(char const* path, file_mode mode, error_code& ec)
if(::posix_fadvise(fd_, 0, 0, advise))
{
auto const ev = errno;
- detail::file_posix_close(fd_);
- fd_ = -1;
- ec.assign(ev, generic_category());
+ native_close(fd_);
+ ec.assign(ev, system_category());
return;
}
#endif
- ec.assign(0, ec.category());
+ ec = {};
}
-inline
std::uint64_t
file_posix::
size(error_code& ec) const
{
if(fd_ == -1)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
struct stat st;
if(::fstat(fd_, &st) != 0)
{
- ec.assign(errno, generic_category());
+ ec.assign(errno, system_category());
return 0;
}
- ec.assign(0, ec.category());
+ ec = {};
return st.st_size;
}
-inline
std::uint64_t
file_posix::
pos(error_code& ec) const
{
if(fd_ == -1)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto const result = ::lseek(fd_, 0, SEEK_CUR);
if(result == (off_t)-1)
{
- ec.assign(errno, generic_category());
+ ec.assign(errno, system_category());
return 0;
}
- ec.assign(0, ec.category());
+ ec = {};
return result;
}
-inline
void
file_posix::
seek(std::uint64_t offset, error_code& ec)
{
if(fd_ == -1)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return;
}
auto const result = ::lseek(fd_, offset, SEEK_SET);
if(result == static_cast<off_t>(-1))
{
- ec.assign(errno, generic_category());
+ ec.assign(errno, system_category());
return;
}
- ec.assign(0, ec.category());
+ ec = {};
}
-inline
std::size_t
file_posix::
read(void* buffer, std::size_t n, error_code& ec) const
{
if(fd_ == -1)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nread = 0;
@@ -297,7 +278,7 @@ read(void* buffer, std::size_t n, error_code& ec) const
auto const ev = errno;
if(ev == EINTR)
continue;
- ec.assign(ev, generic_category());
+ ec.assign(ev, system_category());
return nread;
}
if(result == 0)
@@ -312,14 +293,13 @@ read(void* buffer, std::size_t n, error_code& ec) const
return nread;
}
-inline
std::size_t
file_posix::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(fd_ == -1)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nwritten = 0;
@@ -333,7 +313,7 @@ write(void const* buffer, std::size_t n, error_code& ec)
auto const ev = errno;
if(ev == EINTR)
continue;
- ec.assign(ev, generic_category());
+ ec.assign(ev, system_category());
return nwritten;
}
n -= result;
@@ -347,3 +327,5 @@ write(void const* buffer, std::size_t n, error_code& ec)
} // boost
#endif
+
+#endif
diff --git a/boost/beast/core/impl/file_stdio.ipp b/boost/beast/core/impl/file_stdio.ipp
index 531a8b4748..30adae621b 100644
--- a/boost/beast/core/impl/file_stdio.ipp
+++ b/boost/beast/core/impl/file_stdio.ipp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2015-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)
@@ -10,13 +10,14 @@
#ifndef BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
+#include <boost/beast/core/file_stdio.hpp>
+#include <boost/config/workaround.hpp>
#include <boost/core/exchange.hpp>
#include <limits>
namespace boost {
namespace beast {
-inline
file_stdio::
~file_stdio()
{
@@ -24,14 +25,12 @@ file_stdio::
fclose(f_);
}
-inline
file_stdio::
file_stdio(file_stdio&& other)
: f_(boost::exchange(other.f_, nullptr))
{
}
-inline
file_stdio&
file_stdio::
operator=(file_stdio&& other)
@@ -45,7 +44,6 @@ operator=(file_stdio&& other)
return *this;
}
-inline
void
file_stdio::
native_handle(FILE* f)
@@ -55,7 +53,6 @@ native_handle(FILE* f)
f_ = f;
}
-inline
void
file_stdio::
close(error_code& ec)
@@ -70,10 +67,9 @@ close(error_code& ec)
return;
}
}
- ec.assign(0, ec.category());
+ ec = {};
}
-inline
void
file_stdio::
open(char const* path, file_mode mode, error_code& ec)
@@ -87,17 +83,83 @@ open(char const* path, file_mode mode, error_code& ec)
switch(mode)
{
default:
- case file_mode::read: s = "rb"; break;
- case file_mode::scan: s = "rb"; break;
- case file_mode::write: s = "wb"; break;
- case file_mode::write_new: s = "wbx"; break;
- case file_mode::write_existing: s = "wb"; break;
- case file_mode::append: s = "ab"; break;
- case file_mode::append_new: s = "abx"; break;
- case file_mode::append_existing: s = "ab"; break;
- }
-#if BOOST_MSVC
- auto const ev = fopen_s(&f_, path, s);
+ case file_mode::read:
+ s = "rb";
+ break;
+
+ case file_mode::scan:
+ #ifdef BOOST_MSVC
+ s = "rbS";
+ #else
+ s = "rb";
+ #endif
+ break;
+
+ case file_mode::write:
+ s = "wb+";
+ break;
+
+ case file_mode::write_new:
+ {
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+ FILE* f0;
+ auto const ev = ::fopen_s(&f0, path, "rb");
+ if(! ev)
+ {
+ std::fclose(f0);
+ ec = make_error_code(errc::file_exists);
+ return;
+ }
+ else if(ev !=
+ errc::no_such_file_or_directory)
+ {
+ ec.assign(ev, generic_category());
+ return;
+ }
+ s = "wb";
+#else
+
+ s = "wbx";
+#endif
+ break;
+ }
+
+ case file_mode::write_existing:
+ s = "rb+";
+ break;
+
+ case file_mode::append:
+ s = "ab";
+ break;
+
+ case file_mode::append_existing:
+ {
+#ifdef BOOST_MSVC
+ FILE* f0;
+ auto const ev =
+ ::fopen_s(&f0, path, "rb+");
+ if(ev)
+ {
+ ec.assign(ev, generic_category());
+ return;
+ }
+#else
+ auto const f0 =
+ std::fopen(path, "rb+");
+ if(! f0)
+ {
+ ec.assign(errno, generic_category());
+ return;
+ }
+#endif
+ std::fclose(f0);
+ s = "ab";
+ break;
+ }
+ }
+
+#ifdef BOOST_MSVC
+ auto const ev = ::fopen_s(&f_, path, s);
if(ev)
{
f_ = nullptr;
@@ -112,17 +174,16 @@ open(char const* path, file_mode mode, error_code& ec)
return;
}
#endif
- ec.assign(0, ec.category());
+ ec = {};
}
-inline
std::uint64_t
file_stdio::
size(error_code& ec) const
{
if(! f_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
long pos = std::ftell(f_);
@@ -148,18 +209,17 @@ size(error_code& ec) const
if(result != 0)
ec.assign(errno, generic_category());
else
- ec.assign(0, ec.category());
+ ec = {};
return size;
}
-inline
std::uint64_t
file_stdio::
pos(error_code& ec) const
{
if(! f_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
long pos = std::ftell(f_);
@@ -168,18 +228,17 @@ pos(error_code& ec) const
ec.assign(errno, generic_category());
return 0;
}
- ec.assign(0, ec.category());
+ ec = {};
return pos;
}
-inline
void
file_stdio::
seek(std::uint64_t offset, error_code& ec)
{
if(! f_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return;
}
if(offset > (std::numeric_limits<long>::max)())
@@ -192,17 +251,16 @@ seek(std::uint64_t offset, error_code& ec)
if(result != 0)
ec.assign(errno, generic_category());
else
- ec.assign(0, ec.category());
+ ec = {};
}
-inline
std::size_t
file_stdio::
read(void* buffer, std::size_t n, error_code& ec) const
{
if(! f_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto nread = std::fread(buffer, 1, n, f_);
@@ -214,14 +272,13 @@ read(void* buffer, std::size_t n, error_code& ec) const
return nread;
}
-inline
std::size_t
file_stdio::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(! f_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto nwritten = std::fwrite(buffer, 1, n, f_);
diff --git a/boost/beast/core/impl/file_win32.ipp b/boost/beast/core/impl/file_win32.ipp
index 1183e3853f..8944a6bb45 100644
--- a/boost/beast/core/impl/file_win32.ipp
+++ b/boost/beast/core/impl/file_win32.ipp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2015-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)
@@ -10,6 +10,10 @@
#ifndef BOOST_BEAST_CORE_IMPL_FILE_WIN32_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_WIN32_IPP
+#include <boost/beast/core/file_win32.hpp>
+
+#if BOOST_BEAST_USE_WIN32_FILE
+
#include <boost/core/exchange.hpp>
#include <boost/winapi/access_rights.hpp>
#include <boost/winapi/error_codes.hpp>
@@ -25,7 +29,7 @@ namespace detail {
// VFALCO Can't seem to get boost/detail/winapi to work with
// this so use the non-Ex version for now.
-inline
+BOOST_BEAST_DECL
boost::winapi::BOOL_
set_file_pointer_ex(
boost::winapi::HANDLE_ hFile,
@@ -51,7 +55,6 @@ set_file_pointer_ex(
} // detail
-inline
file_win32::
~file_win32()
{
@@ -59,14 +62,13 @@ file_win32::
boost::winapi::CloseHandle(h_);
}
-inline
file_win32::
file_win32(file_win32&& other)
- : h_(boost::exchange(other.h_, boost::winapi::INVALID_HANDLE_VALUE_))
+ : h_(boost::exchange(other.h_,
+ boost::winapi::INVALID_HANDLE_VALUE_))
{
}
-inline
file_win32&
file_win32::
operator=(file_win32&& other)
@@ -80,7 +82,6 @@ operator=(file_win32&& other)
return *this;
}
-inline
void
file_win32::
native_handle(native_handle_type h)
@@ -90,7 +91,6 @@ native_handle(native_handle_type h)
h_ = h;
}
-inline
void
file_win32::
close(error_code& ec)
@@ -101,16 +101,15 @@ close(error_code& ec)
ec.assign(boost::winapi::GetLastError(),
system_category());
else
- ec.assign(0, ec.category());
+ ec = {};
h_ = boost::winapi::INVALID_HANDLE_VALUE_;
}
else
{
- ec.assign(0, ec.category());
+ ec = {};
}
}
-inline
void
file_win32::
open(char const* path, file_mode mode, error_code& ec)
@@ -180,13 +179,6 @@ open(char const* path, file_mode mode, error_code& ec)
flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
break;
- case file_mode::append_new:
- desired_access = boost::winapi::GENERIC_READ_ |
- boost::winapi::GENERIC_WRITE_;
- creation_disposition = boost::winapi::CREATE_NEW_;
- flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
- break;
-
case file_mode::append_existing:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
@@ -206,17 +198,16 @@ open(char const* path, file_mode mode, error_code& ec)
ec.assign(boost::winapi::GetLastError(),
system_category());
else
- ec.assign(0, ec.category());
+ ec = {};
}
-inline
std::uint64_t
file_win32::
size(error_code& ec) const
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
boost::winapi::LARGE_INTEGER_ fileSize;
@@ -226,18 +217,17 @@ size(error_code& ec) const
system_category());
return 0;
}
- ec.assign(0, ec.category());
+ ec = {};
return fileSize.QuadPart;
}
-inline
std::uint64_t
file_win32::
pos(error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
boost::winapi::LARGE_INTEGER_ in;
@@ -250,18 +240,17 @@ pos(error_code& ec)
system_category());
return 0;
}
- ec.assign(0, ec.category());
+ ec = {};
return out.QuadPart;
}
-inline
void
file_win32::
seek(std::uint64_t offset, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return;
}
boost::winapi::LARGE_INTEGER_ in;
@@ -273,17 +262,16 @@ seek(std::uint64_t offset, error_code& ec)
system_category());
return;
}
- ec.assign(0, ec.category());
+ ec = {};
}
-inline
std::size_t
file_win32::
read(void* buffer, std::size_t n, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nread = 0;
@@ -304,7 +292,7 @@ read(void* buffer, std::size_t n, error_code& ec)
if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
ec.assign(dwError, system_category());
else
- ec.assign(0, ec.category());
+ ec = {};
return nread;
}
if(bytesRead == 0)
@@ -313,18 +301,17 @@ read(void* buffer, std::size_t n, error_code& ec)
nread += bytesRead;
buffer = static_cast<char*>(buffer) + bytesRead;
}
- ec.assign(0, ec.category());
+ ec = {};
return nread;
}
-inline
std::size_t
file_win32::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec = make_error_code(errc::invalid_argument);
+ ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nwritten = 0;
@@ -345,7 +332,7 @@ write(void const* buffer, std::size_t n, error_code& ec)
if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
ec.assign(dwError, system_category());
else
- ec.assign(0, ec.category());
+ ec = {};
return nwritten;
}
if(bytesWritten == 0)
@@ -354,7 +341,7 @@ write(void const* buffer, std::size_t n, error_code& ec)
nwritten += bytesWritten;
buffer = static_cast<char const*>(buffer) + bytesWritten;
}
- ec.assign(0, ec.category());
+ ec = {};
return nwritten;
}
@@ -362,3 +349,5 @@ write(void const* buffer, std::size_t n, error_code& ec)
} // boost
#endif
+
+#endif
diff --git a/boost/beast/core/impl/flat_buffer.ipp b/boost/beast/core/impl/flat_buffer.hpp
index afc843ac0d..f7fd51673d 100644
--- a/boost/beast/core/impl/flat_buffer.ipp
+++ b/boost/beast/core/impl/flat_buffer.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -13,40 +13,46 @@
#include <boost/core/exchange.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
+#include <memory>
#include <stdexcept>
namespace boost {
namespace beast {
-/* Memory is laid out thusly:
+/* Layout:
- begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
+ begin_ in_ out_ last_ end_
+ |<------->|<---------->|<---------->|<------->|
+ | readable | writable |
*/
template<class Allocator>
basic_flat_buffer<Allocator>::
~basic_flat_buffer()
{
- if(begin_)
- alloc_traits::deallocate(
- this->get(), begin_, dist(begin_, end_));
+ if(! begin_)
+ return;
+ alloc_traits::deallocate(
+ this->get(), begin_, capacity());
}
template<class Allocator>
basic_flat_buffer<Allocator>::
-basic_flat_buffer()
+basic_flat_buffer() noexcept(default_nothrow)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
- , max_((std::numeric_limits<std::size_t>::max)())
+ , max_(alloc_traits::max_size(
+ this->get()))
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
-basic_flat_buffer(std::size_t limit)
+basic_flat_buffer(
+ std::size_t limit) noexcept(default_nothrow)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
@@ -58,21 +64,26 @@ basic_flat_buffer(std::size_t limit)
template<class Allocator>
basic_flat_buffer<Allocator>::
-basic_flat_buffer(Allocator const& alloc)
- : boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc)
+basic_flat_buffer(Allocator const& alloc) noexcept
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
- , max_((std::numeric_limits<std::size_t>::max)())
+ , max_(alloc_traits::max_size(
+ this->get()))
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
-basic_flat_buffer(std::size_t limit, Allocator const& alloc)
- : boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc)
+basic_flat_buffer(
+ std::size_t limit,
+ Allocator const& alloc) noexcept
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
@@ -84,24 +95,25 @@ basic_flat_buffer(std::size_t limit, Allocator const& alloc)
template<class Allocator>
basic_flat_buffer<Allocator>::
-basic_flat_buffer(basic_flat_buffer&& other)
- : boost::empty_value<base_alloc_type>(boost::empty_init_t(),
- std::move(other.get()))
+basic_flat_buffer(basic_flat_buffer&& other) noexcept
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t{}, std::move(other.get()))
, begin_(boost::exchange(other.begin_, nullptr))
, in_(boost::exchange(other.in_, nullptr))
, out_(boost::exchange(other.out_, nullptr))
- , last_(out_)
+ , last_(boost::exchange(other.last_, nullptr))
, end_(boost::exchange(other.end_, nullptr))
, max_(other.max_)
{
- other.last_ = nullptr;
}
template<class Allocator>
basic_flat_buffer<Allocator>::
-basic_flat_buffer(basic_flat_buffer&& other,
- Allocator const& alloc)
- : boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc)
+basic_flat_buffer(
+ basic_flat_buffer&& other,
+ Allocator const& alloc)
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t{}, alloc)
{
if(this->get() != other.get())
{
@@ -112,28 +124,31 @@ basic_flat_buffer(basic_flat_buffer&& other,
end_ = nullptr;
max_ = other.max_;
copy_from(other);
- other.reset();
- }
- else
- {
- begin_ = other.begin_;
- in_ = other.in_;
- out_ = other.out_;
- last_ = out_;
- end_ = other.end_;
- max_ = other.max_;
- other.begin_ = nullptr;
- other.in_ = nullptr;
- other.out_ = nullptr;
- other.last_ = nullptr;
- other.end_ = nullptr;
+ other.clear();
+ other.shrink_to_fit();
+ return;
}
+
+ begin_ = other.begin_;
+ in_ = other.in_;
+ out_ = other.out_;
+ last_ = other.out_; // invalidate
+ end_ = other.end_;
+ max_ = other.max_;
+ BOOST_ASSERT(
+ alloc_traits::max_size(this->get()) ==
+ alloc_traits::max_size(other.get()));
+ other.begin_ = nullptr;
+ other.in_ = nullptr;
+ other.out_ = nullptr;
+ other.last_ = nullptr;
+ other.end_ = nullptr;
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer const& other)
- : boost::empty_value<base_alloc_type>(boost::empty_init_t(),
+ : boost::empty_value<base_alloc_type>(boost::empty_init_t{},
alloc_traits::select_on_container_copy_construction(
other.get()))
, begin_(nullptr)
@@ -148,9 +163,11 @@ basic_flat_buffer(basic_flat_buffer const& other)
template<class Allocator>
basic_flat_buffer<Allocator>::
-basic_flat_buffer(basic_flat_buffer const& other,
- Allocator const& alloc)
- : boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc)
+basic_flat_buffer(
+ basic_flat_buffer const& other,
+ Allocator const& alloc)
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
@@ -165,7 +182,8 @@ template<class Allocator>
template<class OtherAlloc>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
- basic_flat_buffer<OtherAlloc> const& other)
+ basic_flat_buffer<OtherAlloc> const& other)
+ noexcept(default_nothrow)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
@@ -179,9 +197,11 @@ basic_flat_buffer(
template<class Allocator>
template<class OtherAlloc>
basic_flat_buffer<Allocator>::
-basic_flat_buffer(basic_flat_buffer<OtherAlloc> const& other,
- Allocator const& alloc)
- : boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc)
+basic_flat_buffer(
+ basic_flat_buffer<OtherAlloc> const& other,
+ Allocator const& alloc)
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
@@ -195,12 +215,12 @@ basic_flat_buffer(basic_flat_buffer<OtherAlloc> const& other,
template<class Allocator>
auto
basic_flat_buffer<Allocator>::
-operator=(basic_flat_buffer&& other) ->
+operator=(basic_flat_buffer&& other) noexcept ->
basic_flat_buffer&
{
- if(this != &other)
- move_assign(other, std::integral_constant<bool,
- alloc_traits::propagate_on_container_move_assignment::value>{});
+ if(this == &other)
+ return *this;
+ move_assign(other, pocma{});
return *this;
}
@@ -210,9 +230,9 @@ basic_flat_buffer<Allocator>::
operator=(basic_flat_buffer const& other) ->
basic_flat_buffer&
{
- if(this != &other)
- copy_assign(other, std::integral_constant<bool,
- alloc_traits::propagate_on_container_copy_assignment::value>{});
+ if(this == &other)
+ return *this;
+ copy_assign(other, pocca{});
return *this;
}
@@ -220,15 +240,64 @@ template<class Allocator>
template<class OtherAlloc>
auto
basic_flat_buffer<Allocator>::
-operator=(basic_flat_buffer<OtherAlloc> const& other) ->
+operator=(
+ basic_flat_buffer<OtherAlloc> const& other) ->
basic_flat_buffer&
{
- reset();
- max_ = other.max_;
copy_from(other);
return *this;
}
+template<class Allocator>
+void
+basic_flat_buffer<Allocator>::
+reserve(std::size_t n)
+{
+ if(max_ < n)
+ max_ = n;
+ if(n > capacity())
+ prepare(n - size());
+}
+
+template<class Allocator>
+void
+basic_flat_buffer<Allocator>::
+shrink_to_fit()
+{
+ auto const len = size();
+ if(len == capacity())
+ return;
+ char* p;
+ if(len > 0)
+ {
+ BOOST_ASSERT(begin_);
+ BOOST_ASSERT(in_);
+ p = alloc(len);
+ std::memcpy(p, in_, len);
+ }
+ else
+ {
+ p = nullptr;
+ }
+ alloc_traits::deallocate(
+ this->get(), begin_, this->capacity());
+ begin_ = p;
+ in_ = begin_;
+ out_ = begin_ + len;
+ last_ = out_;
+ end_ = out_;
+}
+
+template<class Allocator>
+void
+basic_flat_buffer<Allocator>::
+clear() noexcept
+{
+ in_ = begin_;
+ out_ = begin_;
+ last_ = begin_;
+}
+
//------------------------------------------------------------------------------
template<class Allocator>
@@ -237,34 +306,36 @@ basic_flat_buffer<Allocator>::
prepare(std::size_t n) ->
mutable_buffers_type
{
+ auto const len = size();
+ if(len > max_ || n > (max_ - len))
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "basic_flat_buffer too long"});
if(n <= dist(out_, end_))
{
// existing capacity is sufficient
last_ = out_ + n;
return{out_, n};
}
- auto const len = size();
if(n <= capacity() - len)
{
// after a memmove,
// existing capacity is sufficient
if(len > 0)
+ {
+ BOOST_ASSERT(begin_);
+ BOOST_ASSERT(in_);
std::memmove(begin_, in_, len);
+ }
in_ = begin_;
out_ = in_ + len;
last_ = out_ + n;
return {out_, n};
}
- // enforce maximum capacity
- if(n > max_ - len)
- BOOST_THROW_EXCEPTION(std::length_error{
- "basic_flat_buffer overflow"});
// allocate a new buffer
auto const new_size = (std::min<std::size_t>)(
max_,
(std::max<std::size_t>)(2 * len, len + n));
- auto const p = alloc_traits::allocate(
- this->get(), new_size);
+ auto const p = alloc(new_size);
if(begin_)
{
BOOST_ASSERT(p);
@@ -284,7 +355,7 @@ prepare(std::size_t n) ->
template<class Allocator>
void
basic_flat_buffer<Allocator>::
-consume(std::size_t n)
+consume(std::size_t n) noexcept
{
if(n >= dist(in_, out_))
{
@@ -295,69 +366,54 @@ consume(std::size_t n)
in_ += n;
}
+//------------------------------------------------------------------------------
+
template<class Allocator>
+template<class OtherAlloc>
void
basic_flat_buffer<Allocator>::
-shrink_to_fit()
+copy_from(
+ basic_flat_buffer<OtherAlloc> const& other)
{
- auto const len = size();
- if(len == capacity())
- return;
- char* p;
- if(len > 0)
+ std::size_t const n = other.size();
+ if(n == 0 || n > capacity())
{
- BOOST_ASSERT(begin_);
- BOOST_ASSERT(in_);
- p = alloc_traits::allocate(
- this->get(), len);
- std::memcpy(p, in_, len);
+ if(begin_ != nullptr)
+ {
+ alloc_traits::deallocate(
+ this->get(), begin_,
+ this->capacity());
+ begin_ = nullptr;
+ in_ = nullptr;
+ out_ = nullptr;
+ last_ = nullptr;
+ end_ = nullptr;
+ }
+ if(n == 0)
+ return;
+ begin_ = alloc(n);
+ in_ = begin_;
+ out_ = begin_ + n;
+ last_ = begin_ + n;
+ end_ = begin_ + n;
}
- else
+ in_ = begin_;
+ out_ = begin_ + n;
+ last_ = begin_ + n;
+ if(begin_)
{
- p = nullptr;
+ BOOST_ASSERT(other.begin_);
+ std::memcpy(begin_, other.begin_, n);
}
- alloc_traits::deallocate(
- this->get(), begin_, dist(begin_, end_));
- begin_ = p;
- in_ = begin_;
- out_ = begin_ + len;
- last_ = out_;
- end_ = out_;
-}
-
-//------------------------------------------------------------------------------
-
-template<class Allocator>
-inline
-void
-basic_flat_buffer<Allocator>::
-reset()
-{
- consume(size());
- shrink_to_fit();
}
template<class Allocator>
-template<class DynamicBuffer>
-inline
-void
-basic_flat_buffer<Allocator>::
-copy_from(DynamicBuffer const& buffer)
-{
- if(buffer.size() == 0)
- return;
- using boost::asio::buffer_copy;
- commit(buffer_copy(
- prepare(buffer.size()), buffer.data()));
-}
-
-template<class Allocator>
-inline
void
basic_flat_buffer<Allocator>::
move_assign(basic_flat_buffer& other, std::true_type)
{
- reset();
+ clear();
+ shrink_to_fit();
this->get() = std::move(other.get());
begin_ = other.begin_;
in_ = other.in_;
@@ -373,16 +429,15 @@ move_assign(basic_flat_buffer& other, std::true_type)
}
template<class Allocator>
-inline
void
basic_flat_buffer<Allocator>::
move_assign(basic_flat_buffer& other, std::false_type)
{
- reset();
if(this->get() != other.get())
{
copy_from(other);
- other.reset();
+ other.clear();
+ other.shrink_to_fit();
}
else
{
@@ -391,30 +446,27 @@ move_assign(basic_flat_buffer& other, std::false_type)
}
template<class Allocator>
-inline
void
basic_flat_buffer<Allocator>::
copy_assign(basic_flat_buffer const& other, std::true_type)
{
- reset();
max_ = other.max_;
this->get() = other.get();
copy_from(other);
}
template<class Allocator>
-inline
void
basic_flat_buffer<Allocator>::
copy_assign(basic_flat_buffer const& other, std::false_type)
{
- reset();
+ clear();
+ shrink_to_fit();
max_ = other.max_;
copy_from(other);
}
template<class Allocator>
-inline
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other)
@@ -424,7 +476,6 @@ swap(basic_flat_buffer& other)
}
template<class Allocator>
-inline
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other, std::true_type)
@@ -441,7 +492,6 @@ swap(basic_flat_buffer& other, std::true_type)
}
template<class Allocator>
-inline
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other, std::false_type)
@@ -466,6 +516,17 @@ swap(
lhs.swap(rhs);
}
+template<class Allocator>
+char*
+basic_flat_buffer<Allocator>::
+alloc(std::size_t n)
+{
+ if(n > alloc_traits::max_size(this->get()))
+ BOOST_THROW_EXCEPTION(std::length_error(
+ "A basic_flat_buffer exceeded the allocator's maximum size"));
+ return alloc_traits::allocate(this->get(), n);
+}
+
} // beast
} // boost
diff --git a/boost/beast/core/impl/flat_static_buffer.hpp b/boost/beast/core/impl/flat_static_buffer.hpp
new file mode 100644
index 0000000000..c812dd0cfc
--- /dev/null
+++ b/boost/beast/core/impl/flat_static_buffer.hpp
@@ -0,0 +1,43 @@
+//
+// 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_IMPL_FLAT_STATIC_BUFFER_HPP
+#define BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_HPP
+
+namespace boost {
+namespace beast {
+
+template<std::size_t N>
+flat_static_buffer<N>::
+flat_static_buffer(
+ flat_static_buffer const& other)
+ : flat_static_buffer_base(buf_, N)
+{
+ this->commit(net::buffer_copy(
+ this->prepare(other.size()), other.data()));
+}
+
+template<std::size_t N>
+auto
+flat_static_buffer<N>::
+operator=(flat_static_buffer const& other) ->
+ flat_static_buffer<N>&
+{
+ if(this == &other)
+ return *this;
+ this->consume(this->size());
+ this->commit(net::buffer_copy(
+ this->prepare(other.size()), other.data()));
+ return *this;
+}
+
+} // beast
+} // boost
+
+#endif \ No newline at end of file
diff --git a/boost/beast/core/impl/flat_static_buffer.ipp b/boost/beast/core/impl/flat_static_buffer.ipp
index 54bf292116..31f158ebe7 100644
--- a/boost/beast/core/impl/flat_static_buffer.ipp
+++ b/boost/beast/core/impl/flat_static_buffer.ipp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -10,82 +10,36 @@
#ifndef BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_IPP
#define BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_IPP
-#include <boost/beast/core/detail/type_traits.hpp>
-#include <boost/asio/buffer.hpp>
+#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
+#include <memory>
#include <stdexcept>
namespace boost {
namespace beast {
-/* Memory is laid out thusly:
+/* Layout:
- begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
+ begin_ in_ out_ last_ end_
+ |<------->|<---------->|<---------->|<------->|
+ | readable | writable |
*/
-inline
-auto
-flat_static_buffer_base::
-data() const ->
- const_buffers_type
-{
- return {in_, dist(in_, out_)};
-}
-
-inline
void
flat_static_buffer_base::
-reset()
-{
- reset_impl();
-}
-
-inline
-auto
-flat_static_buffer_base::
-prepare(std::size_t n) ->
- mutable_buffers_type
-{
- return prepare_impl(n);
-}
-
-inline
-void
-flat_static_buffer_base::
-reset(void* p, std::size_t n)
-{
- reset_impl(p, n);
-}
-
-template<class>
-void
-flat_static_buffer_base::
-reset_impl()
+clear() noexcept
{
in_ = begin_;
out_ = begin_;
last_ = begin_;
}
-template<class>
-void
-flat_static_buffer_base::
-reset_impl(void* p, std::size_t n)
-{
- begin_ = static_cast<char*>(p);
- in_ = begin_;
- out_ = begin_;
- last_ = begin_;
- end_ = begin_ + n;
-}
-
-template<class>
auto
flat_static_buffer_base::
-prepare_impl(std::size_t n) ->
+prepare(std::size_t n) ->
mutable_buffers_type
{
if(n <= dist(out_, end_))
@@ -105,10 +59,9 @@ prepare_impl(std::size_t n) ->
return {out_, n};
}
-template<class>
void
flat_static_buffer_base::
-consume_impl(std::size_t n)
+consume(std::size_t n) noexcept
{
if(n >= size())
{
@@ -119,32 +72,18 @@ consume_impl(std::size_t n)
in_ += n;
}
-//------------------------------------------------------------------------------
-
-template<std::size_t N>
-flat_static_buffer<N>::
-flat_static_buffer(flat_static_buffer const& other)
- : flat_static_buffer_base(buf_, N)
-{
- using boost::asio::buffer_copy;
- this->commit(buffer_copy(
- this->prepare(other.size()), other.data()));
-}
-
-template<std::size_t N>
-auto
-flat_static_buffer<N>::
-operator=(flat_static_buffer const& other) ->
- flat_static_buffer<N>&
+void
+flat_static_buffer_base::
+reset(void* p, std::size_t n) noexcept
{
- using boost::asio::buffer_copy;
- this->consume(this->size());
- this->commit(buffer_copy(
- this->prepare(other.size()), other.data()));
- return *this;
+ begin_ = static_cast<char*>(p);
+ in_ = begin_;
+ out_ = begin_;
+ last_ = begin_;
+ end_ = begin_ + n;
}
} // beast
} // boost
-#endif
+#endif \ No newline at end of file
diff --git a/boost/beast/core/impl/flat_stream.hpp b/boost/beast/core/impl/flat_stream.hpp
new file mode 100644
index 0000000000..2972131198
--- /dev/null
+++ b/boost/beast/core/impl/flat_stream.hpp
@@ -0,0 +1,276 @@
+//
+// 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_CORE_IMPL_FLAT_STREAM_HPP
+#define BOOST_BEAST_CORE_IMPL_FLAT_STREAM_HPP
+
+#include <boost/beast/core/async_base.hpp>
+#include <boost/beast/core/buffers_prefix.hpp>
+#include <boost/beast/core/static_buffer.hpp>
+#include <boost/beast/core/stream_traits.hpp>
+#include <boost/beast/websocket/teardown.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/coroutine.hpp>
+#include <memory>
+
+namespace boost {
+namespace beast {
+
+template<class NextLayer>
+struct flat_stream<NextLayer>::ops
+{
+
+template<class Handler>
+class write_op
+ : public async_base<Handler,
+ beast::executor_type<flat_stream>>
+ , public net::coroutine
+{
+public:
+ template<
+ class ConstBufferSequence,
+ class Handler_>
+ write_op(
+ Handler_&& h,
+ flat_stream<NextLayer>& s,
+ ConstBufferSequence const& b)
+ : async_base<Handler,
+ beast::executor_type<flat_stream>>(
+ std::forward<Handler_>(h),
+ s.get_executor())
+ {
+ auto const result =
+ flatten(b, max_size);
+ if(result.flatten)
+ {
+ s.buffer_.clear();
+ s.buffer_.commit(net::buffer_copy(
+ s.buffer_.prepare(result.size),
+ b, result.size));
+ s.stream_.async_write_some(
+ s.buffer_.data(), std::move(*this));
+ }
+ else
+ {
+ s.buffer_.clear();
+ s.buffer_.shrink_to_fit();
+ s.stream_.async_write_some(
+ beast::buffers_prefix(
+ result.size, b), std::move(*this));
+ }
+ }
+
+ void
+ operator()(
+ boost::system::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ this->complete_now(ec, bytes_transferred);
+ }
+};
+
+struct run_write_op
+{
+ template<class WriteHandler, class Buffers>
+ void
+ operator()(
+ WriteHandler&& h,
+ flat_stream* s,
+ Buffers const& b)
+ {
+ // 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<WriteHandler,
+ void(error_code, std::size_t)>::value,
+ "WriteHandler type requirements not met");
+
+ write_op<
+ typename std::decay<WriteHandler>::type>(
+ std::forward<WriteHandler>(h), *s, b);
+ }
+};
+
+};
+
+//------------------------------------------------------------------------------
+
+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 type requirements not met");
+ static_assert(net::is_mutable_buffer_sequence<
+ MutableBufferSequence>::value,
+ "MutableBufferSequence type 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)
+{
+ static_assert(boost::beast::is_sync_read_stream<next_layer_type>::value,
+ "SyncReadStream type requirements not met");
+ static_assert(net::is_mutable_buffer_sequence<
+ MutableBufferSequence>::value,
+ "MutableBufferSequence type requirements not met");
+ return stream_.read_some(buffers, ec);
+}
+
+template<class NextLayer>
+template<
+ class MutableBufferSequence,
+ class ReadHandler>
+BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
+flat_stream<NextLayer>::
+async_read_some(
+ MutableBufferSequence const& buffers,
+ ReadHandler&& handler)
+{
+ static_assert(boost::beast::is_async_read_stream<next_layer_type>::value,
+ "AsyncReadStream type requirements not met");
+ static_assert(net::is_mutable_buffer_sequence<
+ MutableBufferSequence >::value,
+ "MutableBufferSequence type 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 type requirements not met");
+ static_assert(net::is_const_buffer_sequence<
+ ConstBufferSequence>::value,
+ "ConstBufferSequence type requirements not met");
+ error_code ec;
+ auto n = write_some(buffers, ec);
+ if(ec)
+ BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
+ return n;
+}
+
+template<class NextLayer>
+template<class ConstBufferSequence>
+std::size_t
+flat_stream<NextLayer>::
+stack_write_some(
+ std::size_t size,
+ ConstBufferSequence const& buffers,
+ error_code& ec)
+{
+ static_buffer<max_stack> b;
+ b.commit(net::buffer_copy(
+ b.prepare(size), buffers));
+ return stream_.write_some(b.data(), ec);
+}
+
+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 type requirements not met");
+ static_assert(net::is_const_buffer_sequence<
+ ConstBufferSequence>::value,
+ "ConstBufferSequence type requirements not met");
+ auto const result = flatten(buffers, max_size);
+ if(result.flatten)
+ {
+ if(result.size <= max_stack)
+ return stack_write_some(result.size, buffers, ec);
+
+ buffer_.clear();
+ buffer_.commit(net::buffer_copy(
+ buffer_.prepare(result.size),
+ buffers));
+ return stream_.write_some(buffer_.data(), ec);
+ }
+ buffer_.clear();
+ buffer_.shrink_to_fit();
+ return stream_.write_some(
+ boost::beast::buffers_prefix(result.size, buffers), ec);
+}
+
+template<class NextLayer>
+template<
+ class ConstBufferSequence,
+ class WriteHandler>
+BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
+flat_stream<NextLayer>::
+async_write_some(
+ ConstBufferSequence const& buffers,
+ WriteHandler&& handler)
+{
+ static_assert(boost::beast::is_async_write_stream<next_layer_type>::value,
+ "AsyncWriteStream type requirements not met");
+ static_assert(net::is_const_buffer_sequence<
+ ConstBufferSequence>::value,
+ "ConstBufferSequence type requirements not met");
+ return net::async_initiate<
+ WriteHandler,
+ void(error_code, std::size_t)>(
+ typename ops::run_write_op{},
+ handler,
+ this,
+ buffers);
+}
+
+template<class NextLayer>
+void
+teardown(
+ boost::beast::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::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
diff --git a/boost/beast/core/impl/handler_ptr.ipp b/boost/beast/core/impl/handler_ptr.hpp
index 06bdd81c40..48260abc2b 100644
--- a/boost/beast/core/impl/handler_ptr.ipp
+++ b/boost/beast/core/impl/handler_ptr.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -22,15 +22,15 @@ void
handler_ptr<T, Handler>::
clear()
{
- typename beast::detail::allocator_traits<
- boost::asio::associated_allocator_t<
- Handler>>::template rebind_alloc<T> alloc(
- boost::asio::get_associated_allocator(
- handler()));
- beast::detail::allocator_traits<
- decltype(alloc)>::destroy(alloc, t_);
- beast::detail::allocator_traits<
- decltype(alloc)>::deallocate(alloc, t_, 1);
+ using A = typename detail::allocator_traits<
+ net::associated_allocator_t<
+ Handler>>::template rebind_alloc<T>;
+ using alloc_traits =
+ beast::detail::allocator_traits<A>;
+ A alloc(
+ net::get_associated_allocator(handler()));
+ alloc_traits::destroy(alloc, t_);
+ alloc_traits::deallocate(alloc, t_, 1);
t_ = nullptr;
}
@@ -41,7 +41,7 @@ handler_ptr<T, Handler>::
if(t_)
{
clear();
- handler().~Handler();
+ h_.~Handler();
}
}
@@ -52,8 +52,9 @@ handler_ptr(handler_ptr&& other)
{
if(other.t_)
{
- new(&h_) Handler(std::move(other.handler()));
- other.handler().~Handler();
+ ::new(static_cast<void*>(std::addressof(h_)))
+ Handler(std::move(other.h_));
+ other.h_.~Handler();
other.t_ = nullptr;
}
}
@@ -64,25 +65,27 @@ handler_ptr<T, Handler>::
handler_ptr(DeducedHandler&& h, Args&&... args)
{
BOOST_STATIC_ASSERT(! std::is_array<T>::value);
- typename beast::detail::allocator_traits<
- boost::asio::associated_allocator_t<
- Handler>>::template rebind_alloc<T> alloc{
- boost::asio::get_associated_allocator(h)};
- using A = decltype(alloc);
+ using A = typename detail::allocator_traits<
+ net::associated_allocator_t<
+ Handler>>::template rebind_alloc<T>;
+ using alloc_traits =
+ beast::detail::allocator_traits<A>;
+ A alloc{net::get_associated_allocator(h)};
bool destroy = false;
auto deleter = [&alloc, &destroy](T* p)
{
if(destroy)
- beast::detail::allocator_traits<A>::destroy(alloc, p);
- beast::detail::allocator_traits<A>::deallocate(alloc, p, 1);
+ alloc_traits::destroy(alloc, p);
+ alloc_traits::deallocate(alloc, p, 1);
};
std::unique_ptr<T, decltype(deleter)> t{
- beast::detail::allocator_traits<A>::allocate(alloc, 1), deleter};
- beast::detail::allocator_traits<A>::construct(alloc, t.get(),
+ alloc_traits::allocate(alloc, 1), deleter};
+ alloc_traits::construct(alloc, t.get(),
static_cast<DeducedHandler const&>(h),
std::forward<Args>(args)...);
destroy = true;
- new(&h_) Handler(std::forward<DeducedHandler>(h));
+ ::new(static_cast<void*>(std::addressof(h_)))
+ Handler(std::forward<DeducedHandler>(h));
t_ = t.release();
}
@@ -100,8 +103,8 @@ release_handler() ->
};
std::unique_ptr<
Handler, decltype(deleter)> destroyer{
- &handler(), deleter};
- return std::move(handler());
+ std::addressof(h_), deleter};
+ return std::move(h_);
}
template<class T, class Handler>
@@ -119,8 +122,8 @@ invoke(Args&&... args)
};
std::unique_ptr<
Handler, decltype(deleter)> destroyer{
- &handler(), deleter};
- handler()(std::forward<Args>(args)...);
+ std::addressof(h_), deleter};
+ h_(std::forward<Args>(args)...);
}
} // beast
diff --git a/boost/beast/core/impl/multi_buffer.ipp b/boost/beast/core/impl/multi_buffer.hpp
index fb48424a3a..643f60ce2b 100644
--- a/boost/beast/core/impl/multi_buffer.ipp
+++ b/boost/beast/core/impl/multi_buffer.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -7,10 +7,12 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_IMPL_MULTI_BUFFER_IPP
-#define BOOST_BEAST_IMPL_MULTI_BUFFER_IPP
+#ifndef BOOST_BEAST_IMPL_MULTI_BUFFER_HPP
+#define BOOST_BEAST_IMPL_MULTI_BUFFER_HPP
+#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/config/workaround.hpp>
#include <boost/core/exchange.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
@@ -18,6 +20,7 @@
#include <exception>
#include <sstream>
#include <string>
+#include <type_traits>
#include <utility>
namespace boost {
@@ -27,40 +30,39 @@ namespace beast {
1 Input and output contained entirely in one element:
- 0 out_
- |<-------------+------------------------------------------->|
- in_pos_ out_pos_ out_end_
+ 0 out_
+ |<------+-----------+--------------------------------+----->|
+ in_pos_ out_pos_ out_end_
2 Output contained in first and second elements:
- out_
- |<------+----------+------->| |<----------+-------------->|
- in_pos_ out_pos_ out_end_
+ out_
+ |<------+-----------+------>| |<-------------------+----->|
+ in_pos_ out_pos_ out_end_
3 Output contained in the second element:
- out_
- |<------------+------------>| |<----+-------------------->|
- in_pos_ out_pos_ out_end_
+ out_
+ |<------+------------------>| |<----+--------------+----->|
+ in_pos_ out_pos_ out_end_
4 Output contained in second and third elements:
- out_
- |<-----+-------->| |<-------+------>| |<--------------->|
- in_pos_ out_pos_ out_end_
+ out_
+ |<------+------->| |<-------+------>| |<---------+----->|
+ in_pos_ out_pos_ out_end_
5 Input sequence is empty:
- out_
- |<------+------------------>| |<-----------+------------->|
- out_pos_ out_end_
+ out_
+ |<------+------------------>| |<-------------------+----->|
+ out_pos_ out_end_
in_pos_
-
6 Output sequence is empty:
out_
@@ -86,6 +88,7 @@ namespace beast {
in_pos_ out_pos_ == 0
out_end_ == 0
*/
+//------------------------------------------------------------------------------
template<class Allocator>
class basic_multi_buffer<Allocator>::element
@@ -93,105 +96,131 @@ class basic_multi_buffer<Allocator>::element
boost::intrusive::link_mode<
boost::intrusive::normal_link>>
{
- using size_type =
- typename detail::allocator_traits<Allocator>::size_type;
+ using size_type = typename
+ detail::allocator_traits<Allocator>::size_type;
size_type const size_;
public:
element(element const&) = delete;
- element& operator=(element const&) = delete;
explicit
- element(size_type n)
+ element(size_type n) noexcept
: size_(n)
{
}
size_type
- size() const
+ size() const noexcept
{
return size_;
}
char*
- data() const
+ data() const noexcept
{
return const_cast<char*>(
reinterpret_cast<char const*>(this + 1));
}
};
+//------------------------------------------------------------------------------
+
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+# pragma warning (push)
+# pragma warning (disable: 4521) // multiple copy constructors specified
+# pragma warning (disable: 4522) // multiple assignment operators specified
+#endif
+
template<class Allocator>
-class basic_multi_buffer<Allocator>::const_buffers_type
+template<bool isMutable>
+class basic_multi_buffer<Allocator>::readable_bytes
{
basic_multi_buffer const* b_;
friend class basic_multi_buffer;
explicit
- const_buffers_type(basic_multi_buffer const& b);
+ readable_bytes(
+ basic_multi_buffer const& b) noexcept
+ : b_(&b)
+ {
+ }
public:
- using value_type = boost::asio::const_buffer;
+ using value_type = typename
+ std::conditional<
+ isMutable,
+ net::mutable_buffer,
+ net::const_buffer>::type;
class const_iterator;
- const_buffers_type() = delete;
- const_buffers_type(const_buffers_type const&) = default;
- const_buffers_type& operator=(const_buffers_type const&) = default;
-
- const_iterator
- begin() const;
-
- const_iterator
- end() const;
-
- friend
- std::size_t
- buffer_size(const_buffers_type const& buffers)
+ readable_bytes() = delete;
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+ readable_bytes(readable_bytes const& other)
+ : b_(other.b_)
{
- return buffers.b_->size();
}
-};
-
-template<class Allocator>
-class basic_multi_buffer<Allocator>::mutable_buffers_type
-{
- basic_multi_buffer const* b_;
- friend class basic_multi_buffer;
-
- explicit
- mutable_buffers_type(basic_multi_buffer const& b);
+ readable_bytes& operator=(readable_bytes const& other)
+ {
+ b_ = other.b_;
+ return *this;
+ }
+#else
+ readable_bytes(readable_bytes const&) = default;
+ readable_bytes& operator=(readable_bytes const&) = default;
+#endif
-public:
- using value_type = mutable_buffer;
+ template<
+ bool isMutable_ = isMutable,
+ class = typename std::enable_if<! isMutable_>::type>
+ readable_bytes(
+ readable_bytes<true> const& other) noexcept
+ : b_(other.b_)
+ {
+ }
- class const_iterator;
+ template<
+ bool isMutable_ = isMutable,
+ class = typename std::enable_if<! isMutable_>::type>
+ readable_bytes& operator=(
+ readable_bytes<true> const& other) noexcept
+ {
+ b_ = other.b_;
+ return *this;
+ }
- mutable_buffers_type() = delete;
- mutable_buffers_type(mutable_buffers_type const&) = default;
- mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
+ const_iterator begin() const noexcept;
+ const_iterator end() const noexcept;
- const_iterator
- begin() const;
-
- const_iterator
- end() const;
+ std::size_t
+ buffer_bytes() const noexcept
+ {
+ return b_->size();
+ }
};
+#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
+# pragma warning (pop)
+#endif
+
//------------------------------------------------------------------------------
template<class Allocator>
-class basic_multi_buffer<Allocator>::const_buffers_type::const_iterator
+template<bool isMutable>
+class
+ basic_multi_buffer<Allocator>::
+ readable_bytes<isMutable>::
+ const_iterator
{
basic_multi_buffer const* b_ = nullptr;
typename list_type::const_iterator it_;
public:
using value_type =
- typename const_buffers_type::value_type;
+ typename readable_bytes::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
@@ -199,32 +228,33 @@ public:
std::bidirectional_iterator_tag;
const_iterator() = default;
- const_iterator(const_iterator&& other) = default;
- const_iterator(const_iterator const& other) = default;
- const_iterator& operator=(const_iterator&& other) = default;
- const_iterator& operator=(const_iterator const& other) = default;
-
- const_iterator(basic_multi_buffer const& b,
- typename list_type::const_iterator const& it)
+ const_iterator(
+ const_iterator const& other) = default;
+ const_iterator& operator=(
+ const_iterator const& other) = default;
+
+ const_iterator(
+ basic_multi_buffer const& b, typename
+ list_type::const_iterator const& it) noexcept
: b_(&b)
, it_(it)
{
}
bool
- operator==(const_iterator const& other) const
+ operator==(const_iterator const& other) const noexcept
{
return b_ == other.b_ && it_ == other.it_;
}
bool
- operator!=(const_iterator const& other) const
+ operator!=(const_iterator const& other) const noexcept
{
return !(*this == other);
}
reference
- operator*() const
+ operator*() const noexcept
{
auto const& e = *it_;
return value_type{e.data(),
@@ -237,14 +267,14 @@ public:
operator->() const = delete;
const_iterator&
- operator++()
+ operator++() noexcept
{
++it_;
return *this;
}
const_iterator
- operator++(int)
+ operator++(int) noexcept
{
auto temp = *this;
++(*this);
@@ -252,14 +282,14 @@ public:
}
const_iterator&
- operator--()
+ operator--() noexcept
{
--it_;
return *this;
}
const_iterator
- operator--(int)
+ operator--(int) noexcept
{
auto temp = *this;
--(*this);
@@ -267,36 +297,34 @@ public:
}
};
-template<class Allocator>
-basic_multi_buffer<Allocator>::
-const_buffers_type::
-const_buffers_type(
- basic_multi_buffer const& b)
- : b_(&b)
-{
-}
+//------------------------------------------------------------------------------
template<class Allocator>
-auto
-basic_multi_buffer<Allocator>::
-const_buffers_type::
-begin() const ->
- const_iterator
+class basic_multi_buffer<Allocator>::mutable_buffers_type
{
- return const_iterator{*b_, b_->list_.begin()};
-}
+ basic_multi_buffer const* b_;
-template<class Allocator>
-auto
-basic_multi_buffer<Allocator>::
-const_buffers_type::
-end() const ->
- const_iterator
-{
- return const_iterator{*b_, b_->out_ ==
- b_->list_.end() ? b_->list_.end() :
- std::next(b_->out_)};
-}
+ friend class basic_multi_buffer;
+
+ explicit
+ mutable_buffers_type(
+ basic_multi_buffer const& b) noexcept
+ : b_(&b)
+ {
+ }
+
+public:
+ using value_type = net::mutable_buffer;
+
+ class const_iterator;
+
+ mutable_buffers_type() = delete;
+ mutable_buffers_type(mutable_buffers_type const&) = default;
+ mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
+
+ const_iterator begin() const noexcept;
+ const_iterator end() const noexcept;
+};
//------------------------------------------------------------------------------
@@ -307,8 +335,8 @@ class basic_multi_buffer<Allocator>::mutable_buffers_type::const_iterator
typename list_type::const_iterator it_;
public:
- using value_type =
- typename mutable_buffers_type::value_type;
+ using value_type = typename
+ mutable_buffers_type::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
@@ -316,32 +344,31 @@ public:
std::bidirectional_iterator_tag;
const_iterator() = default;
- const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
- const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
- const_iterator(basic_multi_buffer const& b,
- typename list_type::const_iterator const& it)
+ const_iterator(
+ basic_multi_buffer const& b,
+ typename list_type::const_iterator const& it) noexcept
: b_(&b)
, it_(it)
{
}
bool
- operator==(const_iterator const& other) const
+ operator==(const_iterator const& other) const noexcept
{
return b_ == other.b_ && it_ == other.it_;
}
bool
- operator!=(const_iterator const& other) const
+ operator!=(const_iterator const& other) const noexcept
{
return !(*this == other);
}
reference
- operator*() const
+ operator*() const noexcept
{
auto const& e = *it_;
return value_type{e.data(),
@@ -354,14 +381,14 @@ public:
operator->() const = delete;
const_iterator&
- operator++()
+ operator++() noexcept
{
++it_;
return *this;
}
const_iterator
- operator++(int)
+ operator++(int) noexcept
{
auto temp = *this;
++(*this);
@@ -369,14 +396,14 @@ public:
}
const_iterator&
- operator--()
+ operator--() noexcept
{
--it_;
return *this;
}
const_iterator
- operator--(int)
+ operator--(int) noexcept
{
auto temp = *this;
--(*this);
@@ -384,20 +411,37 @@ public:
}
};
+//------------------------------------------------------------------------------
+
template<class Allocator>
+template<bool isMutable>
+auto
basic_multi_buffer<Allocator>::
-mutable_buffers_type::
-mutable_buffers_type(
- basic_multi_buffer const& b)
- : b_(&b)
+readable_bytes<isMutable>::
+begin() const noexcept ->
+ const_iterator
{
+ return const_iterator{*b_, b_->list_.begin()};
+}
+
+template<class Allocator>
+template<bool isMutable>
+auto
+basic_multi_buffer<Allocator>::
+readable_bytes<isMutable>::
+end() const noexcept ->
+ const_iterator
+{
+ return const_iterator{*b_, b_->out_ ==
+ b_->list_.end() ? b_->list_.end() :
+ std::next(b_->out_)};
}
template<class Allocator>
auto
basic_multi_buffer<Allocator>::
mutable_buffers_type::
-begin() const ->
+begin() const noexcept ->
const_iterator
{
return const_iterator{*b_, b_->out_};
@@ -407,7 +451,7 @@ template<class Allocator>
auto
basic_multi_buffer<Allocator>::
mutable_buffers_type::
-end() const ->
+end() const noexcept ->
const_iterator
{
return const_iterator{*b_, b_->list_.end()};
@@ -419,19 +463,21 @@ template<class Allocator>
basic_multi_buffer<Allocator>::
~basic_multi_buffer()
{
- delete_list();
+ destroy(list_);
}
template<class Allocator>
basic_multi_buffer<Allocator>::
-basic_multi_buffer()
- : out_(list_.end())
+basic_multi_buffer() noexcept(default_nothrow)
+ : max_(alloc_traits::max_size(this->get()))
+ , out_(list_.end())
{
}
template<class Allocator>
basic_multi_buffer<Allocator>::
-basic_multi_buffer(std::size_t limit)
+basic_multi_buffer(
+ std::size_t limit) noexcept(default_nothrow)
: max_(limit)
, out_(list_.end())
{
@@ -439,17 +485,20 @@ basic_multi_buffer(std::size_t limit)
template<class Allocator>
basic_multi_buffer<Allocator>::
-basic_multi_buffer(Allocator const& alloc)
- : boost::empty_value<
- base_alloc_type>(boost::empty_init_t(), alloc)
+basic_multi_buffer(
+ Allocator const& alloc) noexcept
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t(), alloc)
+ , max_(alloc_traits::max_size(this->get()))
, out_(list_.end())
{
}
template<class Allocator>
basic_multi_buffer<Allocator>::
-basic_multi_buffer(std::size_t limit,
- Allocator const& alloc)
+basic_multi_buffer(
+ std::size_t limit,
+ Allocator const& alloc) noexcept
: boost::empty_value<
base_alloc_type>(boost::empty_init_t(), alloc)
, max_(limit)
@@ -459,9 +508,10 @@ basic_multi_buffer(std::size_t limit,
template<class Allocator>
basic_multi_buffer<Allocator>::
-basic_multi_buffer(basic_multi_buffer&& other)
- : boost::empty_value<
- base_alloc_type>(boost::empty_init_t(), std::move(other.get()))
+basic_multi_buffer(
+ basic_multi_buffer&& other) noexcept
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t(), std::move(other.get()))
, max_(other.max_)
, in_size_(boost::exchange(other.in_size_, 0))
, in_pos_(boost::exchange(other.in_pos_, 0))
@@ -477,8 +527,9 @@ basic_multi_buffer(basic_multi_buffer&& other)
template<class Allocator>
basic_multi_buffer<Allocator>::
-basic_multi_buffer(basic_multi_buffer&& other,
- Allocator const& alloc)
+basic_multi_buffer(
+ basic_multi_buffer&& other,
+ Allocator const& alloc)
: boost::empty_value<
base_alloc_type>(boost::empty_init_t(), alloc)
, max_(other.max_)
@@ -487,33 +538,34 @@ basic_multi_buffer(basic_multi_buffer&& other,
{
out_ = list_.end();
copy_from(other);
- other.reset();
- }
- else
- {
- auto const at_end =
- other.out_ == other.list_.end();
- list_ = std::move(other.list_);
- out_ = at_end ? list_.end() : other.out_;
- in_size_ = other.in_size_;
- in_pos_ = other.in_pos_;
- out_pos_ = other.out_pos_;
- out_end_ = other.out_end_;
- other.in_size_ = 0;
- other.out_ = other.list_.end();
- other.in_pos_ = 0;
- other.out_pos_ = 0;
- other.out_end_ = 0;
+ other.clear();
+ other.shrink_to_fit();
+ return;
}
+
+ auto const at_end =
+ other.out_ == other.list_.end();
+ list_ = std::move(other.list_);
+ out_ = at_end ? list_.end() : other.out_;
+ in_size_ = other.in_size_;
+ in_pos_ = other.in_pos_;
+ out_pos_ = other.out_pos_;
+ out_end_ = other.out_end_;
+ other.in_size_ = 0;
+ other.out_ = other.list_.end();
+ other.in_pos_ = 0;
+ other.out_pos_ = 0;
+ other.out_end_ = 0;
}
template<class Allocator>
basic_multi_buffer<Allocator>::
-basic_multi_buffer(basic_multi_buffer const& other)
- : boost::empty_value<
- base_alloc_type>(boost::empty_init_t(), alloc_traits::
- select_on_container_copy_construction(
- other.get()))
+basic_multi_buffer(
+ basic_multi_buffer const& other)
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t(), alloc_traits::
+ select_on_container_copy_construction(
+ other.get()))
, max_(other.max_)
, out_(list_.end())
{
@@ -522,10 +574,11 @@ basic_multi_buffer(basic_multi_buffer const& other)
template<class Allocator>
basic_multi_buffer<Allocator>::
-basic_multi_buffer(basic_multi_buffer const& other,
- Allocator const& alloc)
- : boost::empty_value<
- base_alloc_type>(boost::empty_init_t(), alloc)
+basic_multi_buffer(
+ basic_multi_buffer const& other,
+ Allocator const& alloc)
+ : boost::empty_value<base_alloc_type>(
+ boost::empty_init_t(), alloc)
, max_(other.max_)
, out_(list_.end())
{
@@ -564,10 +617,9 @@ operator=(basic_multi_buffer&& other) ->
{
if(this == &other)
return *this;
- reset();
+ clear();
max_ = other.max_;
- move_assign(other, std::integral_constant<bool,
- alloc_traits::propagate_on_container_move_assignment::value>{});
+ move_assign(other, pocma{});
return *this;
}
@@ -579,8 +631,7 @@ basic_multi_buffer&
{
if(this == &other)
return *this;
- copy_assign(other, std::integral_constant<bool,
- alloc_traits::propagate_on_container_copy_assignment::value>{});
+ copy_assign(other, pocca{});
return *this;
}
@@ -592,16 +643,16 @@ operator=(
basic_multi_buffer<OtherAlloc> const& other) ->
basic_multi_buffer&
{
- reset();
- max_ = other.max_;
copy_from(other);
return *this;
}
+//------------------------------------------------------------------------------
+
template<class Allocator>
std::size_t
basic_multi_buffer<Allocator>::
-capacity() const
+capacity() const noexcept
{
auto pos = out_;
if(pos == list_.end())
@@ -615,7 +666,7 @@ capacity() const
template<class Allocator>
auto
basic_multi_buffer<Allocator>::
-data() const ->
+data() const noexcept ->
const_buffers_type
{
return const_buffers_type(*this);
@@ -624,12 +675,190 @@ data() const ->
template<class Allocator>
auto
basic_multi_buffer<Allocator>::
+data() noexcept ->
+ mutable_data_type
+{
+ return mutable_data_type(*this);
+}
+
+template<class Allocator>
+void
+basic_multi_buffer<Allocator>::
+reserve(std::size_t n)
+{
+ // VFALCO The amount needs to be adjusted for
+ // the sizeof(element) plus padding
+ if(n > alloc_traits::max_size(this->get()))
+ BOOST_THROW_EXCEPTION(std::length_error(
+ "A basic_multi_buffer exceeded the allocator's maximum size"));
+ std::size_t total = in_size_;
+ if(n <= total)
+ return;
+ if(out_ != list_.end())
+ {
+ total += out_->size() - out_pos_;
+ if(n <= total)
+ return;
+ for(auto it = out_;;)
+ {
+ if(++it == list_.end())
+ break;
+ total += it->size();
+ if(n <= total)
+ return;
+ }
+ }
+ BOOST_ASSERT(n > total);
+ (void)prepare(n - size());
+}
+
+template<class Allocator>
+void
+basic_multi_buffer<Allocator>::
+shrink_to_fit()
+{
+ // empty list
+ if(list_.empty())
+ return;
+
+ // zero readable bytes
+ if(in_size_ == 0)
+ {
+ destroy(list_);
+ list_.clear();
+ out_ = list_.end();
+ in_size_ = 0;
+ in_pos_ = 0;
+ out_pos_ = 0;
+ out_end_ = 0;
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ return;
+ }
+
+ // one or more unused output buffers
+ if(out_ != list_.end())
+ {
+ if(out_ != list_.iterator_to(list_.back()))
+ {
+ // unused list
+ list_type extra;
+ extra.splice(
+ extra.end(),
+ list_,
+ std::next(out_),
+ list_.end());
+ destroy(extra);
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+
+ // unused out_
+ BOOST_ASSERT(out_ ==
+ list_.iterator_to(list_.back()));
+ if(out_pos_ == 0)
+ {
+ BOOST_ASSERT(out_ != list_.begin());
+ auto& e = *out_;
+ list_.erase(out_);
+ out_ = list_.end();
+ destroy(e);
+ out_end_ = 0;
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+ }
+
+ auto const replace =
+ [&](iter pos, element& e)
+ {
+ auto it =
+ list_.insert(pos, e);
+ auto& e0 = *pos;
+ list_.erase(pos);
+ destroy(e0);
+ return it;
+ };
+
+ // partial last buffer
+ if(list_.size() > 1 && out_ != list_.end())
+ {
+ BOOST_ASSERT(out_ ==
+ list_.iterator_to(list_.back()));
+ BOOST_ASSERT(out_pos_ != 0);
+ auto& e = alloc(out_pos_);
+ std::memcpy(
+ e.data(),
+ out_->data(),
+ out_pos_);
+ replace(out_, e);
+ out_ = list_.end();
+ out_pos_ = 0;
+ out_end_ = 0;
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+
+ // partial first buffer
+ if(in_pos_ != 0)
+ {
+ if(out_ != list_.begin())
+ {
+ auto const n =
+ list_.front().size() - in_pos_;
+ auto& e = alloc(n);
+ std::memcpy(
+ e.data(),
+ list_.front().data() + in_pos_,
+ n);
+ replace(list_.begin(), e);
+ in_pos_ = 0;
+ }
+ else
+ {
+ BOOST_ASSERT(list_.size() == 1);
+ BOOST_ASSERT(out_pos_ > in_pos_);
+ auto const n = out_pos_ - in_pos_;
+ auto& e = alloc(n);
+ std::memcpy(
+ e.data(),
+ list_.front().data() + in_pos_,
+ n);
+ replace(list_.begin(), e);
+ in_pos_ = 0;
+ out_ = list_.end();
+ }
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+}
+
+template<class Allocator>
+void
+basic_multi_buffer<Allocator>::
+clear() noexcept
+{
+ out_ = list_.begin();
+ in_size_ = 0;
+ in_pos_ = 0;
+ out_pos_ = 0;
+ out_end_ = 0;
+}
+
+template<class Allocator>
+auto
+basic_multi_buffer<Allocator>::
prepare(size_type n) ->
mutable_buffers_type
{
- if(in_size_ + n > max_)
+ if(in_size_ > max_ || n > (max_ - in_size_))
BOOST_THROW_EXCEPTION(std::length_error{
- "dynamic buffer overflow"});
+ "basic_multi_buffer too long"});
list_type reuse;
std::size_t total = in_size_;
// put all empty buffers on reuse list
@@ -684,15 +913,7 @@ prepare(size_type n) ->
BOOST_ASSERT(total <= max_);
if(! reuse.empty() || n > 0)
{
- for(auto it = reuse.begin(); it != reuse.end();)
- {
- auto& e = *it++;
- reuse.erase(list_.iterator_to(e));
- auto const len = sizeof(e) + e.size();
- alloc_traits::destroy(this->get(), &e);
- alloc_traits::deallocate(this->get(),
- reinterpret_cast<char*>(&e), len);
- }
+ destroy(reuse);
if(n > 0)
{
static auto const growth_factor = 2.0f;
@@ -704,10 +925,7 @@ prepare(size_type n) ->
in_size_ * growth_factor - in_size_),
512,
n}));
- auto& e = *reinterpret_cast<element*>(static_cast<
- void*>(alloc_traits::allocate(this->get(),
- sizeof(element) + size)));
- alloc_traits::construct(this->get(), &e, size);
+ auto& e = alloc(size);
list_.push_back(e);
if(out_ == list_.end())
out_ = list_.iterator_to(e);
@@ -723,7 +941,7 @@ prepare(size_type n) ->
template<class Allocator>
void
basic_multi_buffer<Allocator>::
-commit(size_type n)
+commit(size_type n) noexcept
{
if(list_.empty())
return;
@@ -770,7 +988,7 @@ commit(size_type n)
template<class Allocator>
void
basic_multi_buffer<Allocator>::
-consume(size_type n)
+consume(size_type n) noexcept
{
if(list_.empty())
return;
@@ -795,7 +1013,7 @@ consume(size_type n)
auto& e = list_.front();
list_.erase(list_.iterator_to(e));
auto const len = sizeof(e) + e.size();
- alloc_traits::destroy(this->get(), &e);
+ e.~element();
alloc_traits::deallocate(this->get(),
reinterpret_cast<char*>(&e), len);
#if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
@@ -836,72 +1054,23 @@ consume(size_type n)
}
template<class Allocator>
-inline
-void
-basic_multi_buffer<Allocator>::
-delete_list()
-{
- for(auto iter = list_.begin(); iter != list_.end();)
- {
- auto& e = *iter++;
- auto const len = sizeof(e) + e.size();
- alloc_traits::destroy(this->get(), &e);
- alloc_traits::deallocate(this->get(),
- reinterpret_cast<char*>(&e), len);
- }
-}
-
-template<class Allocator>
-inline
-void
-basic_multi_buffer<Allocator>::
-reset()
-{
- delete_list();
- list_.clear();
- out_ = list_.end();
- in_size_ = 0;
- in_pos_ = 0;
- out_pos_ = 0;
- out_end_ = 0;
-}
-
-template<class Allocator>
-template<class DynamicBuffer>
-inline
+template<class OtherAlloc>
void
basic_multi_buffer<Allocator>::
-copy_from(DynamicBuffer const& buffer)
+copy_from(basic_multi_buffer<OtherAlloc> const& other)
{
- if(buffer.size() == 0)
+ clear();
+ max_ = other.max_;
+ if(other.size() == 0)
return;
- using boost::asio::buffer_copy;
- commit(buffer_copy(
- prepare(buffer.size()), buffer.data()));
+ commit(net::buffer_copy(
+ prepare(other.size()), other.data()));
}
template<class Allocator>
-inline
void
basic_multi_buffer<Allocator>::
-move_assign(basic_multi_buffer& other, std::false_type)
-{
- if(this->get() != other.get())
- {
- copy_from(other);
- other.reset();
- }
- else
- {
- move_assign(other, std::true_type{});
- }
-}
-
-template<class Allocator>
-inline
-void
-basic_multi_buffer<Allocator>::
-move_assign(basic_multi_buffer& other, std::true_type)
+move_assign(basic_multi_buffer& other, std::true_type) noexcept
{
this->get() = std::move(other.get());
auto const at_end =
@@ -913,6 +1082,7 @@ move_assign(basic_multi_buffer& other, std::true_type)
in_pos_ = other.in_pos_;
out_pos_ = other.out_pos_;
out_end_ = other.out_end_;
+ max_ = other.max_;
other.in_size_ = 0;
other.out_ = other.list_.end();
@@ -922,45 +1092,55 @@ move_assign(basic_multi_buffer& other, std::true_type)
}
template<class Allocator>
-inline
+void
+basic_multi_buffer<Allocator>::
+move_assign(basic_multi_buffer& other, std::false_type)
+{
+ if(this->get() != other.get())
+ {
+ copy_from(other);
+ other.clear();
+ other.shrink_to_fit();
+ }
+ else
+ {
+ move_assign(other, std::true_type{});
+ }
+}
+
+template<class Allocator>
void
basic_multi_buffer<Allocator>::
copy_assign(
basic_multi_buffer const& other, std::false_type)
{
- reset();
- max_ = other.max_;
copy_from(other);
}
template<class Allocator>
-inline
void
basic_multi_buffer<Allocator>::
copy_assign(
basic_multi_buffer const& other, std::true_type)
{
- reset();
- max_ = other.max_;
+ clear();
this->get() = other.get();
copy_from(other);
}
template<class Allocator>
-inline
void
basic_multi_buffer<Allocator>::
-swap(basic_multi_buffer& other)
+swap(basic_multi_buffer& other) noexcept
{
swap(other, typename
alloc_traits::propagate_on_container_swap{});
}
template<class Allocator>
-inline
void
basic_multi_buffer<Allocator>::
-swap(basic_multi_buffer& other, std::true_type)
+swap(basic_multi_buffer& other, std::true_type) noexcept
{
using std::swap;
auto const at_end0 =
@@ -981,10 +1161,9 @@ swap(basic_multi_buffer& other, std::true_type)
}
template<class Allocator>
-inline
void
basic_multi_buffer<Allocator>::
-swap(basic_multi_buffer& other, std::false_type)
+swap(basic_multi_buffer& other, std::false_type) noexcept
{
BOOST_ASSERT(this->get() == other.get());
using std::swap;
@@ -1008,7 +1187,7 @@ template<class Allocator>
void
swap(
basic_multi_buffer<Allocator>& lhs,
- basic_multi_buffer<Allocator>& rhs)
+ basic_multi_buffer<Allocator>& rhs) noexcept
{
lhs.swap(rhs);
}
@@ -1016,11 +1195,54 @@ swap(
template<class Allocator>
void
basic_multi_buffer<Allocator>::
+destroy(list_type& list) noexcept
+{
+ for(auto it = list.begin();
+ it != list.end();)
+ destroy(*it++);
+}
+
+template<class Allocator>
+void
+basic_multi_buffer<Allocator>::
+destroy(const_iter it)
+{
+ auto& e = list_.erase(it);
+ destroy(e);
+}
+
+template<class Allocator>
+void
+basic_multi_buffer<Allocator>::
+destroy(element& e)
+{
+ auto const len = sizeof(e) + e.size();
+ e.~element();
+ alloc_traits::deallocate(this->get(),
+ reinterpret_cast<char*>(&e), len);
+}
+
+template<class Allocator>
+auto
+basic_multi_buffer<Allocator>::
+alloc(std::size_t size) ->
+ element&
+{
+ if(size > alloc_traits::max_size(this->get()))
+ BOOST_THROW_EXCEPTION(std::length_error(
+ "A basic_multi_buffer exceeded the allocator's maximum size"));
+ return *::new(alloc_traits::allocate(
+ this->get(),
+ sizeof(element) + size)) element(size);
+}
+
+template<class Allocator>
+void
+basic_multi_buffer<Allocator>::
debug_check() const
{
#ifndef NDEBUG
- using boost::asio::buffer_size;
- BOOST_ASSERT(buffer_size(data()) == in_size_);
+ BOOST_ASSERT(buffer_bytes(data()) == in_size_);
if(list_.empty())
{
BOOST_ASSERT(in_pos_ == 0);
diff --git a/boost/beast/core/impl/read_size.ipp b/boost/beast/core/impl/read_size.hpp
index fa52571e09..1896c014b8 100644
--- a/boost/beast/core/impl/read_size.ipp
+++ b/boost/beast/core/impl/read_size.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -7,9 +7,10 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_IMPL_READ_SIZE_IPP
-#define BOOST_BEAST_IMPL_READ_SIZE_IPP
+#ifndef BOOST_BEAST_IMPL_READ_SIZE_HPP
+#define BOOST_BEAST_IMPL_READ_SIZE_HPP
+#include <boost/asio/buffer.hpp>
#include <boost/assert.hpp>
#include <stdexcept>
#include <type_traits>
@@ -43,21 +44,20 @@ read_size(DynamicBuffer& buffer,
std::size_t max_size, std::false_type)
{
static_assert(
- boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
- "DynamicBuffer requirements not met");
+ net::is_dynamic_buffer<DynamicBuffer>::value,
+ "DynamicBuffer type requirements not met");
BOOST_ASSERT(max_size >= 1);
auto const size = buffer.size();
auto const limit = buffer.max_size() - size;
BOOST_ASSERT(size <= buffer.max_size());
- return (std::min<std::size_t>)(
- (std::max<std::size_t>)(512, buffer.capacity() - size),
- (std::min<std::size_t>)(max_size, limit));
+ return std::min<std::size_t>(
+ std::max<std::size_t>(512, buffer.capacity() - size),
+ std::min<std::size_t>(max_size, limit));
}
} // detail
template<class DynamicBuffer>
-inline
std::size_t
read_size(
DynamicBuffer& buffer, std::size_t max_size)
diff --git a/boost/beast/core/impl/saved_handler.hpp b/boost/beast/core/impl/saved_handler.hpp
new file mode 100644
index 0000000000..a2642f59da
--- /dev/null
+++ b/boost/beast/core/impl/saved_handler.hpp
@@ -0,0 +1,151 @@
+//
+// 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_CORE_IMPL_SAVED_HANDLER_HPP
+#define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
+
+#include <boost/beast/core/detail/allocator.hpp>
+#include <boost/asio/associated_allocator.hpp>
+#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/executor_work_guard.hpp>
+#include <boost/assert.hpp>
+#include <boost/core/empty_value.hpp>
+#include <boost/core/exchange.hpp>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+//------------------------------------------------------------------------------
+
+class saved_handler::base
+{
+protected:
+ ~base() = default;
+
+public:
+ base() = default;
+ virtual void destroy() = 0;
+ virtual void invoke() = 0;
+};
+
+//------------------------------------------------------------------------------
+
+template<class Handler, class Alloc>
+class saved_handler::impl final : public base
+{
+ using alloc_type = typename
+ beast::detail::allocator_traits<
+ Alloc>::template rebind_alloc<impl>;
+
+ using alloc_traits =
+ beast::detail::allocator_traits<alloc_type>;
+
+ struct ebo_pair : boost::empty_value<alloc_type>
+ {
+ Handler h;
+
+ template<class Handler_>
+ ebo_pair(
+ alloc_type const& a,
+ Handler_&& h_)
+ : boost::empty_value<alloc_type>(
+ boost::empty_init_t{}, a)
+ , h(std::forward<Handler_>(h_))
+ {
+ }
+ };
+
+ ebo_pair v_;
+ net::executor_work_guard<
+ net::associated_executor_t<Handler>> wg2_;
+
+public:
+ template<class Handler_>
+ impl(alloc_type const& a, Handler_&& h)
+ : v_(a, std::forward<Handler_>(h))
+ , wg2_(net::get_associated_executor(v_.h))
+ {
+ }
+
+ void
+ destroy() override
+ {
+ auto v = std::move(v_);
+ alloc_traits::destroy(v.get(), this);
+ alloc_traits::deallocate(v.get(), this, 1);
+ }
+
+ void
+ invoke() override
+ {
+ auto v = std::move(v_);
+ alloc_traits::destroy(v.get(), this);
+ alloc_traits::deallocate(v.get(), this, 1);
+ v.h();
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template<class Handler, class Allocator>
+void
+saved_handler::
+emplace(Handler&& handler, Allocator const& alloc)
+{
+ // Can't delete a handler before invoking
+ BOOST_ASSERT(! has_value());
+ using handler_type =
+ typename std::decay<Handler>::type;
+ using alloc_type = typename
+ detail::allocator_traits<Allocator>::
+ template rebind_alloc<impl<
+ handler_type, Allocator>>;
+ using alloc_traits =
+ beast::detail::allocator_traits<alloc_type>;
+ struct storage
+ {
+ alloc_type a;
+ impl<Handler, Allocator>* p;
+
+ explicit
+ storage(Allocator const& a_)
+ : a(a_)
+ , p(alloc_traits::allocate(a, 1))
+ {
+ }
+
+ ~storage()
+ {
+ if(p)
+ alloc_traits::deallocate(a, p, 1);
+ }
+ };
+ storage s(alloc);
+ alloc_traits::construct(s.a, s.p,
+ s.a, std::forward<Handler>(handler));
+ p_ = boost::exchange(s.p, nullptr);
+}
+
+template<class Handler>
+void
+saved_handler::
+emplace(Handler&& handler)
+{
+ // Can't delete a handler before invoking
+ BOOST_ASSERT(! has_value());
+ emplace(
+ std::forward<Handler>(handler),
+ net::get_associated_allocator(handler));
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/saved_handler.ipp b/boost/beast/core/impl/saved_handler.ipp
new file mode 100644
index 0000000000..30ecbc8e15
--- /dev/null
+++ b/boost/beast/core/impl/saved_handler.ipp
@@ -0,0 +1,76 @@
+//
+// 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_CORE_IMPL_SAVED_HANDLER_IPP
+#define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_IPP
+
+#include <boost/beast/core/saved_handler.hpp>
+#include <boost/core/exchange.hpp>
+
+namespace boost {
+namespace beast {
+
+saved_handler::
+~saved_handler()
+{
+ if(p_)
+ p_->destroy();
+}
+
+saved_handler::
+saved_handler(saved_handler&& other) noexcept
+ : p_(boost::exchange(other.p_, nullptr))
+{
+}
+
+saved_handler&
+saved_handler::
+operator=(saved_handler&& other) noexcept
+{
+ // Can't delete a handler before invoking
+ BOOST_ASSERT(! has_value());
+ p_ = boost::exchange(other.p_, nullptr);
+ return *this;
+}
+
+bool
+saved_handler::
+reset() noexcept
+{
+ if(! p_)
+ return false;
+ boost::exchange(p_, nullptr)->destroy();
+ return true;
+}
+
+void
+saved_handler::
+invoke()
+{
+ // Can't invoke without a value
+ BOOST_ASSERT(has_value());
+ boost::exchange(
+ p_, nullptr)->invoke();
+}
+
+bool
+saved_handler::
+maybe_invoke()
+{
+ if(! p_)
+ return false;
+ boost::exchange(
+ p_, nullptr)->invoke();
+ return true;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/static_buffer.hpp b/boost/beast/core/impl/static_buffer.hpp
new file mode 100644
index 0000000000..dee13bfbe5
--- /dev/null
+++ b/boost/beast/core/impl/static_buffer.hpp
@@ -0,0 +1,50 @@
+//
+// 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_IMPL_STATIC_BUFFER_HPP
+#define BOOST_BEAST_IMPL_STATIC_BUFFER_HPP
+
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/throw_exception.hpp>
+#include <algorithm>
+#include <cstring>
+#include <iterator>
+#include <stdexcept>
+
+namespace boost {
+namespace beast {
+
+template<std::size_t N>
+static_buffer<N>::
+static_buffer(static_buffer const& other) noexcept
+ : static_buffer_base(buf_, N)
+{
+ this->commit(net::buffer_copy(
+ this->prepare(other.size()), other.data()));
+}
+
+template<std::size_t N>
+auto
+static_buffer<N>::
+operator=(static_buffer const& other) noexcept ->
+ static_buffer<N>&
+{
+ if(this == &other)
+ return *this;
+ this->consume(this->size());
+ this->commit(net::buffer_copy(
+ this->prepare(other.size()), other.data()));
+ return *this;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/static_buffer.ipp b/boost/beast/core/impl/static_buffer.ipp
index bd498c97a1..c26ff429b8 100644
--- a/boost/beast/core/impl/static_buffer.ipp
+++ b/boost/beast/core/impl/static_buffer.ipp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -10,6 +10,7 @@
#ifndef BOOST_BEAST_IMPL_STATIC_BUFFER_IPP
#define BOOST_BEAST_IMPL_STATIC_BUFFER_IPP
+#include <boost/beast/core/static_buffer.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/throw_exception.hpp>
@@ -21,148 +22,111 @@
namespace boost {
namespace beast {
-inline
static_buffer_base::
-static_buffer_base(void* p, std::size_t size)
+static_buffer_base(
+ void* p, std::size_t size) noexcept
: begin_(static_cast<char*>(p))
, capacity_(size)
{
}
-inline
+void
+static_buffer_base::
+clear() noexcept
+{
+ in_off_ = 0;
+ in_size_ = 0;
+ out_size_ = 0;
+}
+
auto
static_buffer_base::
-data() const ->
+data() const noexcept ->
const_buffers_type
{
- using boost::asio::const_buffer;
- const_buffers_type result;
if(in_off_ + in_size_ <= capacity_)
- {
- result[0] = const_buffer{begin_ + in_off_, in_size_};
- result[1] = const_buffer{begin_, 0};
- }
- else
- {
- result[0] = const_buffer{begin_ + in_off_, capacity_ - in_off_};
- result[1] = const_buffer{begin_, in_size_ - (capacity_ - in_off_)};
- }
- return result;
+ return {
+ net::const_buffer{
+ begin_ + in_off_, in_size_},
+ net::const_buffer{
+ begin_, 0}};
+ return {
+ net::const_buffer{
+ begin_ + in_off_, capacity_ - in_off_},
+ net::const_buffer{
+ begin_, in_size_ - (capacity_ - in_off_)}};
}
-inline
auto
static_buffer_base::
-mutable_data() ->
- mutable_buffers_type
+data() noexcept ->
+ mutable_data_type
{
- using boost::asio::mutable_buffer;
- mutable_buffers_type result;
if(in_off_ + in_size_ <= capacity_)
- {
- result[0] = mutable_buffer{begin_ + in_off_, in_size_};
- result[1] = mutable_buffer{begin_, 0};
- }
- else
- {
- result[0] = mutable_buffer{begin_ + in_off_, capacity_ - in_off_};
- result[1] = mutable_buffer{begin_, in_size_ - (capacity_ - in_off_)};
- }
- return result;
+ return {
+ net::mutable_buffer{
+ begin_ + in_off_, in_size_},
+ net::mutable_buffer{
+ begin_, 0}};
+ return {
+ net::mutable_buffer{
+ begin_ + in_off_, capacity_ - in_off_},
+ net::mutable_buffer{
+ begin_, in_size_ - (capacity_ - in_off_)}};
}
-inline
auto
static_buffer_base::
-prepare(std::size_t size) ->
+prepare(std::size_t n) ->
mutable_buffers_type
{
- using boost::asio::mutable_buffer;
- if(size > capacity_ - in_size_)
+ using net::mutable_buffer;
+ if(n > capacity_ - in_size_)
BOOST_THROW_EXCEPTION(std::length_error{
- "buffer overflow"});
- out_size_ = size;
- auto const out_off = (in_off_ + in_size_) % capacity_;
- mutable_buffers_type result;
+ "static_buffer overflow"});
+ out_size_ = n;
+ auto const out_off =
+ (in_off_ + in_size_) % capacity_;
if(out_off + out_size_ <= capacity_ )
- {
- result[0] = mutable_buffer{begin_ + out_off, out_size_};
- result[1] = mutable_buffer{begin_, 0};
- }
- else
- {
- result[0] = mutable_buffer{begin_ + out_off, capacity_ - out_off};
- result[1] = mutable_buffer{begin_, out_size_ - (capacity_ - out_off)};
- }
- return result;
+ return {
+ net::mutable_buffer{
+ begin_ + out_off, out_size_},
+ net::mutable_buffer{
+ begin_, 0}};
+ return {
+ net::mutable_buffer{
+ begin_ + out_off, capacity_ - out_off},
+ net::mutable_buffer{
+ begin_, out_size_ - (capacity_ - out_off)}};
}
-inline
void
static_buffer_base::
-commit(std::size_t size)
+commit(std::size_t n) noexcept
{
- in_size_ += (std::min)(size, out_size_);
+ in_size_ += (std::min)(n, out_size_);
out_size_ = 0;
}
-inline
void
static_buffer_base::
-consume(std::size_t size)
+consume(std::size_t n) noexcept
{
- if(size < in_size_)
+ if(n < in_size_)
{
- in_off_ = (in_off_ + size) % capacity_;
- in_size_ -= size;
+ in_off_ = (in_off_ + n) % capacity_;
+ in_size_ -= n;
}
else
{
// rewind the offset, so the next call to prepare
// can have a longer contiguous segment. this helps
- // algorithms optimized for larger buffesr.
+ // algorithms optimized for larger buffers.
in_off_ = 0;
in_size_ = 0;
}
}
-inline
-void
-static_buffer_base::
-reset(void* p, std::size_t size)
-{
- begin_ = static_cast<char*>(p);
- capacity_ = size;
- in_off_ = 0;
- in_size_ = 0;
- out_size_ = 0;
-}
-
-//------------------------------------------------------------------------------
-
-template<std::size_t N>
-static_buffer<N>::
-static_buffer(static_buffer const& other)
- : static_buffer_base(buf_, N)
-{
- using boost::asio::buffer_copy;
- this->commit(buffer_copy(
- this->prepare(other.size()), other.data()));
-}
-
-template<std::size_t N>
-auto
-static_buffer<N>::
-operator=(static_buffer const& other) ->
- static_buffer<N>&
-{
- using boost::asio::buffer_copy;
- this->consume(this->size());
- this->commit(buffer_copy(
- this->prepare(other.size()), other.data()));
- return *this;
-}
-
} // beast
} // boost
diff --git a/boost/beast/core/impl/static_string.ipp b/boost/beast/core/impl/static_string.hpp
index 29571dfeee..c668b837fa 100644
--- a/boost/beast/core/impl/static_string.ipp
+++ b/boost/beast/core/impl/static_string.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -7,8 +7,8 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_IMPL_STATIC_STRING_IPP
-#define BOOST_BEAST_IMPL_STATIC_STRING_IPP
+#ifndef BOOST_BEAST_IMPL_STATIC_STRING_HPP
+#define BOOST_BEAST_IMPL_STATIC_STRING_HPP
#include <boost/beast/core/detail/static_string.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
@@ -65,7 +65,12 @@ template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(CharT const* s)
{
- assign(s);
+ auto const count = Traits::length(s);
+ if(count > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "count > max_size()"});
+ n_ = count;
+ Traits::copy(&s_[0], s, n_ + 1);
}
template<std::size_t N, class CharT, class Traits>
@@ -120,6 +125,21 @@ static_string(T const& t, size_type pos, size_type n)
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
+operator=(CharT const* s) ->
+ static_string&
+{
+ auto const count = Traits::length(s);
+ if(count > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "count > max_size()"});
+ n_ = count;
+ Traits::copy(&s_[0], s, n_ + 1);
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
assign(size_type count, CharT ch) ->
static_string&
{
@@ -139,7 +159,9 @@ assign(static_string const& str) ->
static_string&
{
n_ = str.n_;
- Traits::copy(&s_[0], &str.s_[0], n_ + 1);
+ auto const n = n_ + 1;
+ BOOST_BEAST_ASSUME(n != 0);
+ Traits::copy(&s_[0], &str.s_[0], n);
return *this;
}
@@ -463,6 +485,8 @@ resize(std::size_t n)
if(n > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"n > max_size()"});
+ if(n > n_)
+ Traits::assign(&s_[n_], n - n_, CharT{});
n_ = n;
term();
}
@@ -593,7 +617,7 @@ to_static_string(Integer x, std::false_type)
} // detail
-template<class Integer>
+template<class Integer, class>
static_string<detail::max_digits(sizeof(Integer))>
to_static_string(Integer x)
{
diff --git a/boost/beast/core/impl/string_param.ipp b/boost/beast/core/impl/string_param.hpp
index a60771cc12..9d9278382a 100644
--- a/boost/beast/core/impl/string_param.ipp
+++ b/boost/beast/core/impl/string_param.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -7,8 +7,8 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_IMPL_STRING_PARAM_IPP
-#define BOOST_BEAST_IMPL_STRING_PARAM_IPP
+#ifndef BOOST_BEAST_IMPL_STRING_PARAM_HPP
+#define BOOST_BEAST_IMPL_STRING_PARAM_HPP
namespace boost {
namespace beast {
diff --git a/boost/beast/core/make_printable.hpp b/boost/beast/core/make_printable.hpp
new file mode 100644
index 0000000000..cead41a96b
--- /dev/null
+++ b/boost/beast/core/make_printable.hpp
@@ -0,0 +1,107 @@
+//
+// 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_MAKE_PRINTABLE_HPP
+#define BOOST_BEAST_MAKE_PRINTABLE_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/buffer_traits.hpp>
+#include <boost/asio/buffer.hpp>
+#include <ostream>
+
+namespace boost {
+namespace beast {
+
+namespace detail {
+
+template<class Buffers>
+class make_printable_adaptor
+{
+ Buffers b_;
+
+public:
+ explicit
+ make_printable_adaptor(Buffers const& b)
+ : b_(b)
+ {
+ }
+
+ template<class B>
+ friend
+ std::ostream&
+ operator<<(std::ostream& os,
+ make_printable_adaptor<B> const& v);
+};
+
+template<class Buffers>
+std::ostream&
+operator<<(std::ostream& os,
+ make_printable_adaptor<Buffers> const& v)
+{
+ for(
+ auto it = net::buffer_sequence_begin(v.b_),
+ end = net::buffer_sequence_end(v.b_);
+ it != end;
+ ++it)
+ {
+ net::const_buffer cb = *it;
+ os.write(static_cast<char const*>(
+ cb.data()), cb.size());
+ }
+ return os;
+}
+
+} // detail
+
+/** Helper to permit a buffer sequence to be printed to a std::ostream
+
+ This function is used to wrap a buffer sequence to allow it to
+ be interpreted as characters and written to a `std::ostream` such
+ as `std::cout`. No character translation is performed; unprintable
+ and null characters will be transferred as-is to the output stream.
+
+ @par Example
+ This function prints the size and contents of a buffer sequence
+ to standard output:
+ @code
+ template <class ConstBufferSequence>
+ void
+ print (ConstBufferSequence const& buffers)
+ {
+ std::cout <<
+ "Buffer size: " << buffer_bytes(buffers) << " bytes\n"
+ "Buffer data: '" << make_printable(buffers) << "'\n";
+ }
+ @endcode
+
+ @param buffers An object meeting the requirements of
+ <em>ConstBufferSequence</em> to be streamed. The implementation
+ will make a copy of this object. Ownership of the underlying
+ memory is not transferred, the application is still responsible
+ for managing its lifetime.
+*/
+template<class ConstBufferSequence>
+#if BOOST_BEAST_DOXYGEN
+__implementation_defined__
+#else
+detail::make_printable_adaptor<ConstBufferSequence>
+#endif
+make_printable(ConstBufferSequence const& buffers)
+{
+ static_assert(net::is_const_buffer_sequence<
+ ConstBufferSequence>::value,
+ "ConstBufferSequence type requirements not met");
+ return detail::make_printable_adaptor<
+ ConstBufferSequence>{buffers};
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/multi_buffer.hpp b/boost/beast/core/multi_buffer.hpp
index 046ed83a29..2cf477a83b 100644
--- a/boost/beast/core/multi_buffer.hpp
+++ b/boost/beast/core/multi_buffer.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -23,14 +23,39 @@
namespace boost {
namespace beast {
-/** A @b DynamicBuffer that uses multiple buffers internally.
+/** A dynamic buffer providing sequences of variable length.
- The implementation uses a sequence of one or more character arrays
- of varying sizes. Additional character array objects are appended to
- the sequence to accommodate changes in the size of the character
- sequence.
+ A dynamic buffer encapsulates memory storage that may be
+ automatically resized as required, where the memory is
+ divided into two regions: readable bytes followed by
+ writable bytes. These memory regions are internal to
+ the dynamic buffer, but direct access to the elements
+ is provided to permit them to be efficiently used with
+ I/O operations.
- @note Meets the requirements of @b DynamicBuffer.
+ The implementation uses a sequence of one or more byte
+ arrays of varying sizes to represent the readable and
+ writable bytes. Additional byte array objects are
+ appended to the sequence to accommodate changes in the
+ desired size. The behavior and implementation of this
+ container is most similar to `std::deque`.
+
+ Objects of this type meet the requirements of <em>DynamicBuffer</em>
+ and have the following additional properties:
+
+ @li A mutable buffer sequence representing the readable
+ bytes is returned by @ref data when `this` is non-const.
+
+ @li Buffer sequences representing the readable and writable
+ bytes, returned by @ref data and @ref prepare, may have
+ length greater than one.
+
+ @li A configurable maximum size may be set upon construction
+ and adjusted afterwards. Calls to @ref prepare that would
+ exceed this size will throw `std::length_error`.
+
+ @li Sequences previously obtained using @ref data remain
+ valid after calls to @ref prepare or @ref commit.
@tparam Allocator The allocator to use for managing memory.
*/
@@ -46,31 +71,41 @@ class basic_multi_buffer
detail::allocator_traits<Allocator>::
template rebind_alloc<char>;
+ static bool constexpr default_nothrow =
+ std::is_nothrow_default_constructible<Allocator>::value;
+
// Storage for the list of buffers representing the input
// and output sequences. The allocation for each element
// contains `element` followed by raw storage bytes.
class element;
- using alloc_traits = detail::allocator_traits<base_alloc_type>;
+ template<bool>
+ class readable_bytes;
+
+ using alloc_traits =
+ beast::detail::allocator_traits<base_alloc_type>;
using list_type = typename boost::intrusive::make_list<element,
boost::intrusive::constant_time_size<true>>::type;
using iter = typename list_type::iterator;
using const_iter = typename list_type::const_iterator;
using size_type = typename alloc_traits::size_type;
- using const_buffer = boost::asio::const_buffer;
- using mutable_buffer = boost::asio::mutable_buffer;
+
+ using pocma = typename
+ alloc_traits::propagate_on_container_move_assignment;
+
+ using pocca = typename
+ alloc_traits::propagate_on_container_copy_assignment;
static_assert(std::is_base_of<std::bidirectional_iterator_tag,
typename std::iterator_traits<iter>::iterator_category>::value,
- "BidirectionalIterator requirements not met");
+ "BidirectionalIterator type requirements not met");
static_assert(std::is_base_of<std::bidirectional_iterator_tag,
typename std::iterator_traits<const_iter>::iterator_category>::value,
- "BidirectionalIterator requirements not met");
+ "BidirectionalIterator type requirements not met");
- std::size_t max_ =
- (std::numeric_limits<std::size_t>::max)();
+ std::size_t max_;
list_type list_; // list of allocated buffers
iter out_; // element that contains out_pos_
size_type in_size_ = 0; // size of the input sequence
@@ -82,233 +117,431 @@ public:
/// The type of allocator used.
using allocator_type = Allocator;
-#if BOOST_BEAST_DOXYGEN
- /// The type used to represent the input sequence as a list of buffers.
- using const_buffers_type = implementation_defined;
-
- /// The type used to represent the output sequence as a list of buffers.
- using mutable_buffers_type = implementation_defined;
-
-#else
- class const_buffers_type;
-
- class mutable_buffers_type;
-
-#endif
-
/// Destructor
~basic_multi_buffer();
/** Constructor
- Upon construction, capacity will be zero.
+ After construction, @ref capacity will return zero, and
+ @ref max_size will return the largest value which may
+ be passed to the allocator's `allocate` function.
*/
- basic_multi_buffer();
+ basic_multi_buffer() noexcept(default_nothrow);
+
+ /** Constructor
- /** Constructor.
+ After construction, @ref capacity will return zero, and
+ @ref max_size will return the specified value of `limit`.
- @param limit The setting for @ref max_size.
+ @param limit The desired maximum size.
*/
explicit
- basic_multi_buffer(std::size_t limit);
+ basic_multi_buffer(
+ std::size_t limit) noexcept(default_nothrow);
- /** Constructor.
+ /** Constructor
- @param alloc The allocator to use.
+ After construction, @ref capacity will return zero, and
+ @ref max_size will return the largest value which may
+ be passed to the allocator's `allocate` function.
+
+ @param alloc The allocator to use for the object.
+
+ @esafe
+
+ No-throw guarantee.
*/
explicit
- basic_multi_buffer(Allocator const& alloc);
+ basic_multi_buffer(Allocator const& alloc) noexcept;
- /** Constructor.
+ /** Constructor
- @param limit The setting for @ref max_size.
+ After construction, @ref capacity will return zero, and
+ @ref max_size will return the specified value of `limit`.
- @param alloc The allocator to use.
+ @param limit The desired maximum size.
+
+ @param alloc The allocator to use for the object.
+
+ @esafe
+
+ No-throw guarantee.
*/
basic_multi_buffer(
- std::size_t limit, Allocator const& alloc);
+ std::size_t limit, Allocator const& alloc) noexcept;
- /** Move constructor
+ /** Move Constructor
- After the move, `*this` will have an empty output sequence.
+ The container is constructed with the contents of `other`
+ using move semantics. The maximum size will be the same
+ as the moved-from object.
- @param other The object to move from. After the move,
- The object's state will be as if constructed using
- its current allocator and limit.
+ Buffer sequences previously obtained from `other` using
+ @ref data or @ref prepare remain valid after the move.
+
+ @param other The object to move from. After the move, the
+ moved-from object will have zero capacity, zero readable
+ bytes, and zero writable bytes.
+
+ @esafe
+
+ No-throw guarantee.
*/
- basic_multi_buffer(basic_multi_buffer&& other);
+ basic_multi_buffer(basic_multi_buffer&& other) noexcept;
+
+ /** Move Constructor
- /** Move constructor
+ Using `alloc` as the allocator for the new container, the
+ contents of `other` are moved. If `alloc != other.get_allocator()`,
+ this results in a copy. The maximum size will be the same
+ as the moved-from object.
- After the move, `*this` will have an empty output sequence.
+ Buffer sequences previously obtained from `other` using
+ @ref data or @ref prepare become invalid after the move.
@param other The object to move from. After the move,
- The object's state will be as if constructed using
- its current allocator and limit.
+ the moved-from object will have zero capacity, zero readable
+ bytes, and zero writable bytes.
- @param alloc The allocator to use.
+ @param alloc The allocator to use for the object.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of `alloc`.
*/
- basic_multi_buffer(basic_multi_buffer&& other,
+ basic_multi_buffer(
+ basic_multi_buffer&& other,
Allocator const& alloc);
- /** Copy constructor.
+ /** Copy Constructor
+
+ This container is constructed with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
@param other The object to copy from.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of the allocator.
*/
basic_multi_buffer(basic_multi_buffer const& other);
- /** Copy constructor
+ /** Copy Constructor
+
+ This container is constructed with the contents of `other`
+ using copy semantics and the specified allocator. The maximum
+ size will be the same as the copied object.
@param other The object to copy from.
- @param alloc The allocator to use.
+ @param alloc The allocator to use for the object.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of `alloc`.
*/
basic_multi_buffer(basic_multi_buffer const& other,
Allocator const& alloc);
- /** Copy constructor.
+ /** Copy Constructor
+
+ This container is constructed with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
@param other The object to copy from.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of the allocator.
*/
template<class OtherAlloc>
basic_multi_buffer(basic_multi_buffer<
OtherAlloc> const& other);
- /** Copy constructor.
+ /** Copy Constructor
+
+ This container is constructed with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
@param other The object to copy from.
- @param alloc The allocator to use.
+ @param alloc The allocator to use for the object.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of `alloc`.
*/
template<class OtherAlloc>
- basic_multi_buffer(basic_multi_buffer<
- OtherAlloc> const& other, allocator_type const& alloc);
+ basic_multi_buffer(
+ basic_multi_buffer<OtherAlloc> const& other,
+ allocator_type const& alloc);
+
+ /** Move Assignment
- /** Move assignment
+ The container is assigned with the contents of `other`
+ using move semantics. The maximum size will be the same
+ as the moved-from object.
- After the move, `*this` will have an empty output sequence.
+ Buffer sequences previously obtained from `other` using
+ @ref data or @ref prepare remain valid after the move.
@param other The object to move from. After the move,
- The object's state will be as if constructed using
- its current allocator and limit.
+ the moved-from object will have zero capacity, zero readable
+ bytes, and zero writable bytes.
*/
basic_multi_buffer&
operator=(basic_multi_buffer&& other);
- /** Copy assignment
+ /** Copy Assignment
- After the copy, `*this` will have an empty output sequence.
+ The container is assigned with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
+
+ After the copy, `this` will have zero writable bytes.
@param other The object to copy from.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of the allocator.
*/
- basic_multi_buffer& operator=(basic_multi_buffer const& other);
+ basic_multi_buffer& operator=(
+ basic_multi_buffer const& other);
+
+ /** Copy Assignment
- /** Copy assignment
+ The container is assigned with the contents of `other`
+ using copy semantics. The maximum size will be the same
+ as the copied object.
- After the copy, `*this` will have an empty output sequence.
+ After the copy, `this` will have zero writable bytes.
@param other The object to copy from.
+
+ @throws std::length_error if `other.size()` exceeds the
+ maximum allocation size of the allocator.
*/
template<class OtherAlloc>
basic_multi_buffer& operator=(
basic_multi_buffer<OtherAlloc> const& other);
- /// Returns a copy of the associated allocator.
+ /// Returns a copy of the allocator used.
allocator_type
get_allocator() const
{
return this->get();
}
- /// Returns the size of the input sequence.
+ /** Set the maximum allowed capacity
+
+ This function changes the currently configured upper limit
+ on capacity to the specified value.
+
+ @param n The maximum number of bytes ever allowed for capacity.
+
+ @esafe
+
+ No-throw guarantee.
+ */
+ void
+ max_size(std::size_t n) noexcept
+ {
+ max_ = n;
+ }
+
+ /** Guarantee a minimum capacity
+
+ This function adjusts the internal storage (if necessary)
+ to guarantee space for at least `n` bytes.
+
+ Buffer sequences previously obtained using @ref data remain
+ valid, while buffer sequences previously obtained using
+ @ref prepare become invalid.
+
+ @param n The minimum number of byte for the new capacity.
+ If this value is greater than the maximum size, then the
+ maximum size will be adjusted upwards to this value.
+
+ @throws std::length_error if n is larger than the maximum
+ allocation size of the allocator.
+
+ @esafe
+
+ Strong guarantee.
+ */
+ void
+ reserve(std::size_t n);
+
+ /** Reallocate the buffer to fit the readable bytes exactly.
+
+ Buffer sequences previously obtained using @ref data or
+ @ref prepare become invalid.
+
+ @esafe
+
+ Strong guarantee.
+ */
+ void
+ shrink_to_fit();
+
+ /** Set the size of the readable and writable bytes to zero.
+
+ This clears the buffer without changing capacity.
+ Buffer sequences previously obtained using @ref data or
+ @ref prepare become invalid.
+
+ @esafe
+
+ No-throw guarantee.
+ */
+ void
+ clear() noexcept;
+
+ /// Exchange two dynamic buffers
+ template<class Alloc>
+ friend
+ void
+ swap(
+ basic_multi_buffer<Alloc>& lhs,
+ basic_multi_buffer<Alloc>& rhs) noexcept;
+
+ //--------------------------------------------------------------------------
+
+#if BOOST_BEAST_DOXYGEN
+ /// The ConstBufferSequence used to represent the readable bytes.
+ using const_buffers_type = __implementation_defined__;
+
+ /// The MutableBufferSequence used to represent the readable bytes.
+ using mutable_data_type = __implementation_defined__;
+
+ /// The MutableBufferSequence used to represent the writable bytes.
+ using mutable_buffers_type = __implementation_defined__;
+#else
+ using const_buffers_type = readable_bytes<false>;
+ using mutable_data_type = readable_bytes<true>;
+ class mutable_buffers_type;
+#endif
+
+ /// Returns the number of readable bytes.
size_type
- size() const
+ size() const noexcept
{
return in_size_;
}
- /// Returns the permitted maximum sum of the sizes of the input and output sequence.
+ /// Return the maximum number of bytes, both readable and writable, that can ever be held.
size_type
- max_size() const
+ max_size() const noexcept
{
return max_;
}
- /// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
+ /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
std::size_t
- capacity() const;
+ capacity() const noexcept;
- /** Get a list of buffers that represents the input sequence.
+ /** Returns a constant buffer sequence representing the readable bytes
- @note These buffers remain valid across subsequent calls to `prepare`.
+ @note The sequence may contain multiple contiguous memory regions.
*/
const_buffers_type
- data() const;
+ data() const noexcept;
- /** Get a list of buffers that represents the output sequence, with the given size.
+ /** Returns a constant buffer sequence representing the readable bytes
- @note Buffers representing the input sequence acquired prior to
- this call remain valid.
+ @note The sequence may contain multiple contiguous memory regions.
*/
- mutable_buffers_type
- prepare(size_type n);
+ const_buffers_type
+ cdata() const noexcept
+ {
+ return data();
+ }
- /** Move bytes from the output sequence to the input sequence.
+ /** Returns a mutable buffer sequence representing the readable bytes.
- @note Buffers representing the input sequence acquired prior to
- this call remain valid.
+ @note The sequence may contain multiple contiguous memory regions.
*/
- void
- commit(size_type n);
+ mutable_data_type
+ data() noexcept;
- /// Remove bytes from the input sequence.
- void
- consume(size_type n);
+ /** Returns a mutable buffer sequence representing writable bytes.
+
+ Returns a mutable buffer sequence representing the writable
+ bytes containing exactly `n` bytes of storage. Memory may be
+ reallocated as needed.
- template<class Alloc>
- friend
- void
- swap(
- basic_multi_buffer<Alloc>& lhs,
- basic_multi_buffer<Alloc>& rhs);
+ All buffer sequences previously obtained using @ref prepare are
+ invalidated. Buffer sequences previously obtained using @ref data
+ remain valid.
-private:
- template<class OtherAlloc>
- friend class basic_multi_buffer;
+ @param n The desired number of bytes in the returned buffer
+ sequence.
- void
- delete_list();
+ @throws std::length_error if `size() + n` exceeds `max_size()`.
- void
- reset();
+ @esafe
- template<class DynamicBuffer>
- void
- copy_from(DynamicBuffer const& other);
+ Strong guarantee.
+ */
+ mutable_buffers_type
+ prepare(size_type n);
- void
- move_assign(basic_multi_buffer& other, std::false_type);
+ /** Append writable bytes to the readable bytes.
- void
- move_assign(basic_multi_buffer& other, std::true_type);
+ Appends n bytes from the start of the writable bytes to the
+ end of the readable bytes. The remainder of the writable bytes
+ are discarded. If n is greater than the number of writable
+ bytes, all writable bytes are appended to the readable bytes.
- void
- copy_assign(basic_multi_buffer const& other, std::false_type);
+ All buffer sequences previously obtained using @ref prepare are
+ invalidated. Buffer sequences previously obtained using @ref data
+ remain valid.
- void
- copy_assign(basic_multi_buffer const& other, std::true_type);
+ @param n The number of bytes to append. If this number
+ is greater than the number of writable bytes, all
+ writable bytes are appended.
- void
- swap(basic_multi_buffer&);
+ @esafe
+ No-throw guarantee.
+ */
void
- swap(basic_multi_buffer&, std::true_type);
+ commit(size_type n) noexcept;
- void
- swap(basic_multi_buffer&, std::false_type);
+ /** Remove bytes from beginning of the readable bytes.
+
+ Removes n bytes from the beginning of the readable bytes.
+
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare are invalidated.
+
+ @param n The number of bytes to remove. If this number
+ is greater than the number of readable bytes, all
+ readable bytes are removed.
+
+ @esafe
+ No-throw guarantee.
+ */
void
- debug_check() const;
+ consume(size_type n) noexcept;
+
+private:
+ template<class OtherAlloc>
+ friend class basic_multi_buffer;
+
+ template<class OtherAlloc>
+ void copy_from(basic_multi_buffer<OtherAlloc> const&);
+ void move_assign(basic_multi_buffer& other, std::false_type);
+ void move_assign(basic_multi_buffer& other, std::true_type) noexcept;
+ void copy_assign(basic_multi_buffer const& other, std::false_type);
+ void copy_assign(basic_multi_buffer const& other, std::true_type);
+ void swap(basic_multi_buffer&) noexcept;
+ void swap(basic_multi_buffer&, std::true_type) noexcept;
+ void swap(basic_multi_buffer&, std::false_type) noexcept;
+ void destroy(list_type& list) noexcept;
+ void destroy(const_iter it);
+ void destroy(element& e);
+ element& alloc(std::size_t size);
+ void debug_check() const;
};
/// A typical multi buffer
@@ -317,6 +550,6 @@ using multi_buffer = basic_multi_buffer<std::allocator<char>>;
} // beast
} // boost
-#include <boost/beast/core/impl/multi_buffer.ipp>
+#include <boost/beast/core/impl/multi_buffer.hpp>
-#endif
+#endif \ No newline at end of file
diff --git a/boost/beast/core/ostream.hpp b/boost/beast/core/ostream.hpp
index 1f00289bd1..46899b6041 100644
--- a/boost/beast/core/ostream.hpp
+++ b/boost/beast/core/ostream.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,54 +11,21 @@
#define BOOST_BEAST_WRITE_OSTREAM_HPP
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/detail/ostream.hpp>
#include <type_traits>
#include <streambuf>
#include <utility>
+#ifdef BOOST_BEAST_ALLOW_DEPRECATED
+#include <boost/beast/core/make_printable.hpp>
+#endif
+
namespace boost {
namespace beast {
-/** Return an object representing a @b ConstBufferSequence.
-
- This function wraps a reference to a buffer sequence and permits
- the following operation:
-
- @li `operator<<` to `std::ostream`. No character translation is
- performed; unprintable and null characters will be transferred
- as-is to the output stream.
+/** Return an output stream that formats values into a <em>DynamicBuffer</em>.
- @par Example
- @code
- multi_buffer b;
- ...
- std::cout << buffers(b.data()) << std::endl;
- @endcode
-
- @param b An object meeting the requirements of @b ConstBufferSequence
- to be streamed. The implementation will make a copy of this object.
- Ownership of the underlying memory is not transferred, the application
- is still responsible for managing its lifetime.
-*/
-template<class ConstBufferSequence>
-#if BOOST_BEAST_DOXYGEN
-implementation_defined
-#else
-detail::buffers_helper<ConstBufferSequence>
-#endif
-buffers(ConstBufferSequence const& b)
-{
- static_assert(boost::asio::is_const_buffer_sequence<
- ConstBufferSequence>::value,
- "ConstBufferSequence requirements not met");
- return detail::buffers_helper<
- ConstBufferSequence>{b};
-}
-
-/** Return an output stream that formats values into a @b DynamicBuffer.
-
- This function wraps the caller provided @b DynamicBuffer into
+ This function wraps the caller provided <em>DynamicBuffer</em> into
a `std::ostream` derived class, to allow `operator<<` stream style
formatting operations.
@@ -70,7 +37,7 @@ buffers(ConstBufferSequence const& b)
@note Calling members of the underlying buffer before the output
stream is destroyed results in undefined behavior.
- @param buffer An object meeting the requirements of @b DynamicBuffer
+ @param buffer An object meeting the requirements of <em>DynamicBuffer</em>
into which the formatted output will be placed.
@return An object derived from `std::ostream` which redirects output
@@ -82,7 +49,7 @@ buffers(ConstBufferSequence const& b)
*/
template<class DynamicBuffer>
#if BOOST_BEAST_DOXYGEN
-implementation_defined
+__implementation_defined__
#else
detail::ostream_helper<
DynamicBuffer, char, std::char_traits<char>,
@@ -91,13 +58,32 @@ detail::ostream_helper<
ostream(DynamicBuffer& buffer)
{
static_assert(
- boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
- "DynamicBuffer requirements not met");
+ net::is_dynamic_buffer<DynamicBuffer>::value,
+ "DynamicBuffer type requirements not met");
return detail::ostream_helper<
DynamicBuffer, char, std::char_traits<char>,
detail::basic_streambuf_movable::value>{buffer};
}
+//------------------------------------------------------------------------------
+
+#ifdef BOOST_BEAST_ALLOW_DEPRECATED
+template<class T>
+detail::make_printable_adaptor<T>
+buffers(T const& t)
+{
+ return make_printable(t);
+}
+#else
+template<class T>
+void buffers(T const&)
+{
+ static_assert(sizeof(T) == 0,
+ "The function buffers() is deprecated, use make_printable() instead, "
+ "or define BOOST_BEAST_ALLOW_DEPRECATED to silence this error.");
+}
+#endif
+
} // beast
} // boost
diff --git a/boost/beast/core/rate_policy.hpp b/boost/beast/core/rate_policy.hpp
new file mode 100644
index 0000000000..1f8abb9b6a
--- /dev/null
+++ b/boost/beast/core/rate_policy.hpp
@@ -0,0 +1,220 @@
+//
+// 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_CORE_RATE_POLICY_HPP
+#define BOOST_BEAST_CORE_RATE_POLICY_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <cstdint>
+#include <limits>
+
+namespace boost {
+namespace beast {
+
+/** Helper class to assist implementing a <em>RatePolicy</em>.
+
+ This class is used by the implementation to gain access to the
+ private members of a user-defined object meeting the requirements
+ of <em>RatePolicy</em>. To use it, simply declare it as a friend
+ in your class:
+
+ @par Example
+ @code
+ class custom_rate_policy
+ {
+ friend class beast::rate_policy_access;
+ ...
+ @endcode
+
+ @par Concepts
+
+ @li <em>RatePolicy</em>
+
+ @see beast::basic_stream
+*/
+class rate_policy_access
+{
+private:
+ template<class, class, class>
+ friend class basic_stream;
+
+ template<class Policy>
+ static
+ std::size_t
+ available_read_bytes(Policy& policy)
+ {
+ return policy.available_read_bytes();
+ }
+
+ template<class Policy>
+ static
+ std::size_t
+ available_write_bytes(Policy& policy)
+ {
+ return policy.available_write_bytes();
+ }
+
+ template<class Policy>
+ static
+ void
+ transfer_read_bytes(
+ Policy& policy, std::size_t n)
+ {
+ return policy.transfer_read_bytes(n);
+ }
+
+ template<class Policy>
+ static
+ void
+ transfer_write_bytes(
+ Policy& policy, std::size_t n)
+ {
+ return policy.transfer_write_bytes(n);
+ }
+
+ template<class Policy>
+ static
+ void
+ on_timer(Policy& policy)
+ {
+ return policy.on_timer();
+ }
+};
+
+//------------------------------------------------------------------------------
+
+/** A rate policy with unlimited throughput.
+
+ This rate policy object does not apply any rate limit.
+
+ @par Concepts
+
+ @li <em>RatePolicy</em>
+
+ @see beast::basic_stream, beast::tcp_stream
+*/
+class unlimited_rate_policy
+{
+ friend class rate_policy_access;
+
+ static std::size_t constexpr all =
+ (std::numeric_limits<std::size_t>::max)();
+
+ std::size_t
+ available_read_bytes() const noexcept
+ {
+ return all;
+ }
+
+ std::size_t
+ available_write_bytes() const noexcept
+ {
+ return all;
+ }
+
+ void
+ transfer_read_bytes(std::size_t) const noexcept
+ {
+ }
+
+ void
+ transfer_write_bytes(std::size_t) const noexcept
+ {
+ }
+
+ void
+ on_timer() const noexcept
+ {
+ }
+};
+
+//------------------------------------------------------------------------------
+
+/** A rate policy with simple, configurable limits on reads and writes.
+
+ This rate policy allows for simple individual limits on the amount
+ of bytes per second allowed for reads and writes.
+
+ @par Concepts
+
+ @li <em>RatePolicy</em>
+
+ @see beast::basic_stream
+*/
+class simple_rate_policy
+{
+ friend class rate_policy_access;
+
+ static std::size_t constexpr all =
+ std::numeric_limits<std::size_t>::max();
+
+ std::size_t rd_remain_ = all;
+ std::size_t wr_remain_ = all;
+ std::size_t rd_limit_ = all;
+ std::size_t wr_limit_ = all;
+
+ std::size_t
+ available_read_bytes() const noexcept
+ {
+ return rd_remain_;
+ }
+
+ std::size_t
+ available_write_bytes() const noexcept
+ {
+ return wr_remain_;
+ }
+
+ void
+ transfer_read_bytes(std::size_t n) noexcept
+ {
+ if( rd_remain_ != all)
+ rd_remain_ =
+ (n < rd_remain_) ? rd_remain_ - n : 0;
+ }
+
+ void
+ transfer_write_bytes(std::size_t n) noexcept
+ {
+ if( wr_remain_ != all)
+ wr_remain_ =
+ (n < wr_remain_) ? wr_remain_ - n : 0;
+ }
+
+ void
+ on_timer() noexcept
+ {
+ rd_remain_ = rd_limit_;
+ wr_remain_ = wr_limit_;
+ }
+
+public:
+ /// Set the limit of bytes per second to read
+ void
+ read_limit(std::size_t bytes_per_second) noexcept
+ {
+ rd_limit_ = bytes_per_second;
+ if( rd_remain_ > bytes_per_second)
+ rd_remain_ = bytes_per_second;
+ }
+
+ /// Set the limit of bytes per second to write
+ void
+ write_limit(std::size_t bytes_per_second) noexcept
+ {
+ wr_limit_ = bytes_per_second;
+ if( wr_remain_ > bytes_per_second)
+ wr_remain_ = bytes_per_second;
+ }
+};
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/read_size.hpp b/boost/beast/core/read_size.hpp
index d9aaaa61ab..7d33d38f0b 100644
--- a/boost/beast/core/read_size.hpp
+++ b/boost/beast/core/read_size.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,7 +11,6 @@
#define BOOST_BEAST_READ_SIZE_HELPER_HPP
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/type_traits.hpp>
#include <boost/throw_exception.hpp>
namespace boost {
@@ -59,6 +58,6 @@ read_size_or_throw(DynamicBuffer& buffer,
} // beast
} // boost
-#include <boost/beast/core/impl/read_size.ipp>
+#include <boost/beast/core/impl/read_size.hpp>
#endif
diff --git a/boost/beast/core/role.hpp b/boost/beast/core/role.hpp
new file mode 100644
index 0000000000..2301417244
--- /dev/null
+++ b/boost/beast/core/role.hpp
@@ -0,0 +1,50 @@
+//
+// 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_ROLE_HPP
+#define BOOST_BEAST_ROLE_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+
+namespace boost {
+namespace beast {
+
+/** The role of local or remote peer.
+
+ Whether the endpoint is a client or server affects the
+ behavior of teardown.
+ The teardown behavior also depends on the type of the stream
+ being torn down.
+
+ The default implementation of teardown for regular
+ TCP/IP sockets is as follows:
+
+ @li In the client role, a TCP/IP shutdown is sent after
+ reading all remaining data on the connection.
+
+ @li In the server role, a TCP/IP shutdown is sent before
+ reading all remaining data on the connection.
+
+ When the next layer type is a `net::ssl::stream`,
+ the connection is closed by performing the SSL closing
+ handshake corresponding to the role type, client or server.
+*/
+enum class role_type
+{
+ /// The stream is operating as a client.
+ client,
+
+ /// The stream is operating as a server.
+ server
+};
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/saved_handler.hpp b/boost/beast/core/saved_handler.hpp
new file mode 100644
index 0000000000..a4599d429f
--- /dev/null
+++ b/boost/beast/core/saved_handler.hpp
@@ -0,0 +1,137 @@
+//
+// 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_CORE_SAVED_HANDLER_HPP
+#define BOOST_BEAST_CORE_SAVED_HANDLER_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+
+namespace boost {
+namespace beast {
+
+/** An invocable, nullary function object which holds a completion handler.
+
+ This container can hold a type-erased instance of any completion
+ handler, or it can be empty. When the container holds a value,
+ the implementation maintains an instance of `net::executor_work_guard`
+ for the handler's associated executor. Memory is dynamically allocated
+ to store the completion handler, and the allocator may optionally
+ be specified. Otherwise, the implementation uses the handler's
+ associated allocator.
+*/
+class saved_handler
+{
+ class base;
+
+ template<class, class>
+ class impl;
+
+ base* p_ = nullptr;
+
+public:
+ /// Default Constructor
+ saved_handler() = default;
+
+ /// Copy Constructor (deleted)
+ saved_handler(saved_handler const&) = delete;
+
+ /// Copy Assignment (deleted)
+ saved_handler& operator=(saved_handler const&) = delete;
+
+ /// Destructor
+ BOOST_BEAST_DECL
+ ~saved_handler();
+
+ /// Move Constructor
+ BOOST_BEAST_DECL
+ saved_handler(saved_handler&& other) noexcept;
+
+ /// Move Assignment
+ BOOST_BEAST_DECL
+ saved_handler&
+ operator=(saved_handler&& other) noexcept;
+
+ /// Returns `true` if `*this` contains a completion handler.
+ bool
+ has_value() const noexcept
+ {
+ return p_ != nullptr;
+ }
+
+ /** Store a completion handler in the container.
+
+ Requires `this->has_value() == false`.
+
+ @param handler The completion handler to store.
+ The implementation takes ownership of the handler by performing a decay-copy.
+
+ @param alloc The allocator to use.
+ */
+ template<class Handler, class Allocator>
+ void
+ emplace(Handler&& handler, Allocator const& alloc);
+
+ /** Store a completion handler in the container.
+
+ Requires `this->has_value() == false`. The
+ implementation will use the handler's associated
+ allocator to obtian storage.
+
+ @param handler The completion handler to store.
+ The implementation takes ownership of the handler by performing a decay-copy.
+ */
+ template<class Handler>
+ void
+ emplace(Handler&& handler);
+
+ /** Discard the saved handler, if one exists.
+
+ If `*this` contains an object, it is destroyed.
+
+ @returns `true` if an object was destroyed.
+ */
+ BOOST_BEAST_DECL
+ bool
+ reset() noexcept;
+
+ /** Unconditionally invoke the stored completion handler.
+
+ Requires `this->has_value() == true`. Any dynamic memory
+ used is deallocated before the stored completion handler
+ is invoked. The executor work guard is also reset before
+ the invocation.
+ */
+ BOOST_BEAST_DECL
+ void
+ invoke();
+
+ /** Conditionally invoke the stored completion handler.
+
+ Invokes the stored completion handler if
+ `this->has_value() == true`, otherwise does nothing. Any
+ dynamic memory used is deallocated before the stored completion
+ handler is invoked. The executor work guard is also reset before
+ the invocation.
+
+ @return `true` if the invocation took place.
+ */
+ BOOST_BEAST_DECL
+ bool
+ maybe_invoke();
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/saved_handler.hpp>
+#ifdef BOOST_BEAST_HEADER_ONLY
+#include <boost/beast/core/impl/saved_handler.ipp>
+#endif
+
+#endif
diff --git a/boost/beast/core/span.hpp b/boost/beast/core/span.hpp
index 4aa7788501..e170729472 100644
--- a/boost/beast/core/span.hpp
+++ b/boost/beast/core/span.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
diff --git a/boost/beast/core/static_buffer.hpp b/boost/beast/core/static_buffer.hpp
index fa59638bb7..1e44237164 100644
--- a/boost/beast/core/static_buffer.hpp
+++ b/boost/beast/core/static_buffer.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -11,7 +11,9 @@
#define BOOST_BEAST_STATIC_BUFFER_HPP
#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/buffers_pair.hpp>
#include <boost/asio/buffer.hpp>
+#include <boost/assert.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
@@ -20,23 +22,36 @@
namespace boost {
namespace beast {
-/** A circular @b DynamicBuffer with a fixed size internal buffer.
+/** A dynamic buffer providing a fixed size, circular buffer.
- This implements a circular dynamic buffer. Calls to @ref prepare
- never require moving memory. The buffer sequences returned may
- be up to length two.
- Ownership of the underlying storage belongs to the derived class.
+ A dynamic buffer encapsulates memory storage that may be
+ automatically resized as required, where the memory is
+ divided into two regions: readable bytes followed by
+ writable bytes. These memory regions are internal to
+ the dynamic buffer, but direct access to the elements
+ is provided to permit them to be efficiently used with
+ I/O operations.
- @note Variables are usually declared using the template class
- @ref static_buffer; however, to reduce the number of instantiations
- of template functions receiving static stream buffer arguments in a
- deduced context, the signature of the receiving function should use
- @ref static_buffer_base.
+ Objects of this type meet the requirements of <em>DynamicBuffer</em>
+ and have the following additional properties:
+
+ @li A mutable buffer sequence representing the readable
+ bytes is returned by @ref data when `this` is non-const.
+
+ @li Buffer sequences representing the readable and writable
+ bytes, returned by @ref data and @ref prepare, may have
+ length up to two.
- When used with @ref static_buffer this implements a dynamic
- buffer using no memory allocations.
+ @li All operations execute in constant time.
+
+ @li Ownership of the underlying storage belongs to the
+ derived class.
+
+ @note Variables are usually declared using the template class
+ @ref static_buffer; however, to reduce the number of template
+ instantiations, objects should be passed `static_buffer_base&`.
- @see @ref static_buffer
+ @see static_buffer
*/
class static_buffer_base
{
@@ -50,14 +65,6 @@ class static_buffer_base
static_buffer_base& operator=(static_buffer_base const&) = delete;
public:
- /// The type used to represent the input sequence as a list of buffers.
- using const_buffers_type =
- std::array<boost::asio::const_buffer, 2>;
-
- /// The type used to represent the output sequence as a list of buffers.
- using mutable_buffers_type =
- std::array<boost::asio::mutable_buffer, 2>;
-
/** Constructor
This creates a dynamic buffer using the provided storage area.
@@ -66,98 +73,167 @@ public:
@param size The number of valid bytes pointed to by `p`.
*/
- static_buffer_base(void* p, std::size_t size);
+ BOOST_BEAST_DECL
+ static_buffer_base(void* p, std::size_t size) noexcept;
+
+ /** Clear the readable and writable bytes to zero.
+
+ This function causes the readable and writable bytes
+ to become empty. The capacity is not changed.
+
+ Buffer sequences previously obtained using @ref data or
+ @ref prepare become invalid.
+
+ @esafe
+
+ No-throw guarantee.
+ */
+ BOOST_BEAST_DECL
+ void
+ clear() noexcept;
+
+ //--------------------------------------------------------------------------
+
+#if BOOST_BEAST_DOXYGEN
+ /// The ConstBufferSequence used to represent the readable bytes.
+ using const_buffers_type = __implementation_defined__;
+
+ /// The MutableBufferSequence used to represent the readable bytes.
+ using mutable_data_type = __implementation_defined__;
- /// Return the size of the input sequence.
+ /// The MutableBufferSequence used to represent the writable bytes.
+ using mutable_buffers_type = __implementation_defined__;
+#else
+ using const_buffers_type = detail::buffers_pair<false>;
+ using mutable_data_type = detail::buffers_pair<true>;
+ using mutable_buffers_type = detail::buffers_pair<true>;
+#endif
+
+ /// Returns the number of readable bytes.
std::size_t
- size() const
+ size() const noexcept
{
return in_size_;
}
- /// Return the maximum sum of the input and output sequence sizes.
+ /// Return the maximum number of bytes, both readable and writable, that can ever be held.
std::size_t
- max_size() const
+ max_size() const noexcept
{
return capacity_;
}
- /// Return the maximum sum of input and output sizes that can be held without an allocation.
+ /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
std::size_t
- capacity() const
+ capacity() const noexcept
{
return capacity_;
}
- /** Get a list of buffers that represent the input sequence.
- */
+ /// Returns a constant buffer sequence representing the readable bytes
+ BOOST_BEAST_DECL
+ const_buffers_type
+ data() const noexcept;
+
+ /// Returns a constant buffer sequence representing the readable bytes
const_buffers_type
- data() const;
+ cdata() const noexcept
+ {
+ return data();
+ }
- /** Get a mutable list of buffers that represent the input sequence.
- */
- mutable_buffers_type
- mutable_data();
+ /// Returns a mutable buffer sequence representing the readable bytes
+ BOOST_BEAST_DECL
+ mutable_data_type
+ data() noexcept;
+
+ /** Returns a mutable buffer sequence representing writable bytes.
+
+ Returns a mutable buffer sequence representing the writable
+ bytes containing exactly `n` bytes of storage. Memory may be
+ reallocated as needed.
+
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare are invalidated.
- /** Get a list of buffers that represent the output sequence, with the given size.
+ @param n The desired number of bytes in the returned buffer
+ sequence.
- @param size The number of bytes to request.
+ @throws std::length_error if `size() + n` exceeds `max_size()`.
- @throws std::length_error if the size would exceed the capacity.
+ @esafe
+
+ Strong guarantee.
*/
+ BOOST_BEAST_DECL
mutable_buffers_type
- prepare(std::size_t size);
+ prepare(std::size_t n);
- /** Move bytes from the output sequence to the input sequence.
+ /** Append writable bytes to the readable bytes.
- @param size The number of bytes to commit. If this is greater
- than the size of the output sequence, the entire output
- sequence is committed.
- */
- void
- commit(std::size_t size);
+ Appends n bytes from the start of the writable bytes to the
+ end of the readable bytes. The remainder of the writable bytes
+ are discarded. If n is greater than the number of writable
+ bytes, all writable bytes are appended to the readable bytes.
- /** Remove bytes from the input sequence.
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare are invalidated.
- @param size The number of bytes to consume. If this is greater
- than the size of the input sequence, the entire input sequence
- is consumed.
+ @param n The number of bytes to append. If this number
+ is greater than the number of writable bytes, all
+ writable bytes are appended.
+
+ @esafe
+
+ No-throw guarantee.
*/
+ BOOST_BEAST_DECL
void
- consume(std::size_t size);
+ commit(std::size_t n) noexcept;
-protected:
- /** Constructor
+ /** Remove bytes from beginning of the readable bytes.
- The buffer will be in an undefined state. It is necessary
- for the derived class to call @ref reset in order to
- initialize the object.
- */
- static_buffer_base() = default;
+ Removes n bytes from the beginning of the readable bytes.
- /** Reset the pointed-to buffer.
+ All buffers sequences previously obtained using
+ @ref data or @ref prepare are invalidated.
- This function resets the internal state to the buffer provided.
- All input and output sequences are invalidated. This function
- allows the derived class to construct its members before
- initializing the static buffer.
+ @param n The number of bytes to remove. If this number
+ is greater than the number of readable bytes, all
+ readable bytes are removed.
- @param p A pointer to valid storage of at least `n` bytes.
+ @esafe
- @param size The number of valid bytes pointed to by `p`.
+ No-throw guarantee.
*/
+ BOOST_BEAST_DECL
void
- reset(void* p, std::size_t size);
+ consume(std::size_t n) noexcept;
};
//------------------------------------------------------------------------------
-/** A circular @b DynamicBuffer with a fixed size internal buffer.
+/** A dynamic buffer providing a fixed size, circular buffer.
+
+ A dynamic buffer encapsulates memory storage that may be
+ automatically resized as required, where the memory is
+ divided into two regions: readable bytes followed by
+ writable bytes. These memory regions are internal to
+ the dynamic buffer, but direct access to the elements
+ is provided to permit them to be efficiently used with
+ I/O operations.
+
+ Objects of this type meet the requirements of <em>DynamicBuffer</em>
+ and have the following additional properties:
+
+ @li A mutable buffer sequence representing the readable
+ bytes is returned by @ref data when `this` is non-const.
- This implements a circular dynamic buffer. Calls to @ref prepare
- never require moving memory. The buffer sequences returned may
- be up to length two.
- Ownership of the underlying storage belongs to the derived class.
+ @li Buffer sequences representing the readable and writable
+ bytes, returned by @ref data and @ref prepare, may have
+ length up to two.
+
+ @li All operations execute in constant time.
@tparam N The number of bytes in the internal buffer.
@@ -165,7 +241,7 @@ protected:
objects of this type in a deduced context, the signature of the
receiving function should use @ref static_buffer_base instead.
- @see @ref static_buffer_base
+ @see static_buffer_base
*/
template<std::size_t N>
class static_buffer : public static_buffer_base
@@ -174,41 +250,41 @@ class static_buffer : public static_buffer_base
public:
/// Constructor
- static_buffer(static_buffer const&);
-
- /// Constructor
- static_buffer()
+ static_buffer() noexcept
: static_buffer_base(buf_, N)
{
}
+ /// Constructor
+ static_buffer(static_buffer const&) noexcept;
+
/// Assignment
- static_buffer& operator=(static_buffer const&);
+ static_buffer& operator=(static_buffer const&) noexcept;
/// Returns the @ref static_buffer_base portion of this object
static_buffer_base&
- base()
+ base() noexcept
{
return *this;
}
/// Returns the @ref static_buffer_base portion of this object
static_buffer_base const&
- base() const
+ base() const noexcept
{
return *this;
}
/// Return the maximum sum of the input and output sequence sizes.
std::size_t constexpr
- max_size() const
+ max_size() const noexcept
{
return N;
}
/// Return the maximum sum of input and output sizes that can be held without an allocation.
std::size_t constexpr
- capacity() const
+ capacity() const noexcept
{
return N;
}
@@ -217,6 +293,9 @@ public:
} // beast
} // boost
+#include <boost/beast/core/impl/static_buffer.hpp>
+#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/beast/core/impl/static_buffer.ipp>
+#endif
#endif
diff --git a/boost/beast/core/static_string.hpp b/boost/beast/core/static_string.hpp
index 991c2e64a5..fc60a72e7d 100644
--- a/boost/beast/core/static_string.hpp
+++ b/boost/beast/core/static_string.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -35,7 +35,7 @@ namespace beast {
@note The stored string is always null-terminated.
- @see @ref to_static_string
+ @see to_static_string
*/
template<
std::size_t N,
@@ -171,10 +171,7 @@ public:
/// Assign from null-terminated string.
static_string&
- operator=(CharT const* s)
- {
- return assign(s);
- }
+ operator=(CharT const* s);
/// Assign from single character.
static_string&
@@ -1100,13 +1097,19 @@ operator<<(std::basic_ostream<CharT, Traits>& os,
maximum size large enough to hold the longest possible decimal
representation of any integer of the given type.
*/
-template<class Integer>
+template<
+ class Integer
+#ifndef BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ std::is_integral<Integer>::value>::type
+#endif
+>
static_string<detail::max_digits(sizeof(Integer))>
to_static_string(Integer x);
} // beast
} // boost
-#include <boost/beast/core/impl/static_string.ipp>
+#include <boost/beast/core/impl/static_string.hpp>
#endif
diff --git a/boost/beast/core/stream_traits.hpp b/boost/beast/core/stream_traits.hpp
new file mode 100644
index 0000000000..f1945ea93a
--- /dev/null
+++ b/boost/beast/core/stream_traits.hpp
@@ -0,0 +1,544 @@
+//
+// 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_STREAM_TRAITS_HPP
+#define BOOST_BEAST_STREAM_TRAITS_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/static_const.hpp>
+#include <boost/beast/core/detail/stream_traits.hpp>
+#include <boost/asio/basic_socket.hpp>
+
+namespace boost {
+namespace beast {
+
+/** A trait to determine the lowest layer type of a stack of stream layers.
+
+ If `t.next_layer()` is well-defined for an object `t` of type `T`,
+ then `lowest_layer_type<T>` will be an alias for
+ `lowest_layer_type<decltype(t.next_layer())>`,
+ otherwise it will be the type
+ `std::remove_reference<T>`.
+
+ @param T The type to determine the lowest layer type of.
+
+ @return The type of the lowest layer.
+*/
+template<class T>
+#if BOOST_BEAST_DOXYGEN
+using lowest_layer_type = __see_below__;
+#else
+using lowest_layer_type = detail::lowest_layer_type<T>;
+#endif
+
+/** Return the lowest layer in a stack of stream layers.
+
+ If `t.next_layer()` is well-defined, returns
+ `get_lowest_layer(t.next_layer())`. Otherwise, it returns `t`.
+
+ A stream layer is an object of class type which wraps another object through
+ composition, and meets some or all of the named requirements of the wrapped
+ type while optionally changing behavior. Examples of stream layers include
+ `net::ssl::stream` or @ref beast::websocket::stream. The owner of a stream
+ layer can interact directly with the wrapper, by passing it to stream
+ algorithms. Or, the owner can obtain a reference to the wrapped object by
+ calling `next_layer()` and accessing its members. This is necessary when it is
+ desired to access functionality in the next layer which is not available
+ in the wrapper. For example, @ref websocket::stream permits reading and
+ writing, but in order to establish the underlying connection, members
+ of the wrapped stream (such as `connect`) must be invoked directly.
+
+ Usually the last object in the chain of composition is the concrete socket
+ object (for example, a `net::basic_socket` or a class derived from it).
+ The function @ref get_lowest_layer exists to easily obtain the concrete
+ socket when it is desired to perform an action that is not prescribed by
+ a named requirement, such as changing a socket option, cancelling all
+ pending asynchronous I/O, or closing the socket (perhaps by using
+ @ref close_socket).
+
+ @par Example
+ @code
+ // Set non-blocking mode on a stack of stream
+ // layers with a regular socket at the lowest layer.
+ template <class Stream>
+ void set_non_blocking (Stream& stream)
+ {
+ error_code ec;
+ // A compile error here means your lowest layer is not the right type!
+ get_lowest_layer(stream).non_blocking(true, ec);
+ if(ec)
+ throw system_error{ec};
+ }
+ @endcode
+
+ @param t The layer in a stack of layered objects for which the lowest layer is returned.
+
+ @see close_socket, lowest_layer_type
+*/
+template<class T>
+lowest_layer_type<T>&
+get_lowest_layer(T& t) noexcept
+{
+ return detail::get_lowest_layer_impl(
+ t, detail::has_next_layer<T>{});
+}
+
+//------------------------------------------------------------------------------
+
+/** A trait to determine the return type of get_executor.
+
+ This type alias will be the type of values returned by
+ by calling member `get_exector` on an object of type `T&`.
+
+ @param T The type to query
+
+ @return The type of values returned from `get_executor`.
+*/
+// Workaround for ICE on gcc 4.8
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+using executor_type = __see_below__;
+#elif BOOST_WORKAROUND(BOOST_GCC, < 40900)
+template<class T>
+using executor_type =
+ typename std::decay<T>::type::executor_type;
+#else
+template<class T>
+using executor_type =
+ decltype(std::declval<T&>().get_executor());
+#endif
+
+/** Determine if `T` has the `get_executor` member function.
+
+ Metafunctions are used to perform compile time checking of template
+ types. This type will be `std::true_type` if `T` has the member
+ function with the correct signature, else type will be `std::false_type`.
+
+ @par Example
+
+ Use with tag dispatching:
+
+ @code
+ template<class T>
+ void maybe_hello(T const& t, std::true_type)
+ {
+ net::post(
+ t.get_executor(),
+ []
+ {
+ std::cout << "Hello, world!" << std::endl;
+ });
+ }
+
+ template<class T>
+ void maybe_hello(T const&, std::false_type)
+ {
+ // T does not have get_executor
+ }
+
+ template<class T>
+ void maybe_hello(T const& t)
+ {
+ maybe_hello(t, has_get_executor<T>{});
+ }
+ @endcode
+
+ Use with `static_assert`:
+
+ @code
+ struct stream
+ {
+ using executor_type = net::io_context::executor_type;
+ executor_type get_executor() noexcept;
+ };
+
+ static_assert(has_get_executor<stream>::value, "Missing get_executor member");
+ @endcode
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+using has_get_executor = __see_below__;
+#else
+template<class T, class = void>
+struct has_get_executor : std::false_type {};
+
+template<class T>
+struct has_get_executor<T, boost::void_t<decltype(
+ std::declval<T&>().get_executor())>> : std::true_type {};
+#endif
+
+//------------------------------------------------------------------------------
+
+/** Determine if at type meets the requirements of <em>SyncReadStream</em>.
+
+ Metafunctions are used to perform compile time checking of template
+ types. This type will be `std::true_type` if `T` meets the requirements,
+ else the type will be `std::false_type`.
+
+ @par Example
+ Use with `static_assert`:
+ @code
+ template<class SyncReadStream>
+ void f(SyncReadStream& stream)
+ {
+ static_assert(is_sync_read_stream<SyncReadStream>::value,
+ "SyncReadStream type requirements not met");
+ ...
+ @endcode
+
+ Use with `std::enable_if` (SFINAE):
+ @code
+ template<class SyncReadStream>
+ typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
+ f(SyncReadStream& stream);
+ @endcode
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+using is_sync_read_stream = __see_below__;
+#else
+template<class T, class = void>
+struct is_sync_read_stream : std::false_type {};
+
+template<class T>
+struct is_sync_read_stream<T, boost::void_t<decltype(
+ std::declval<std::size_t&>() = std::declval<T&>().read_some(
+ std::declval<detail::MutableBufferSequence>()),
+ std::declval<std::size_t&>() = std::declval<T&>().read_some(
+ std::declval<detail::MutableBufferSequence>(),
+ std::declval<boost::system::error_code&>())
+ )>> : std::true_type {};
+#endif
+
+/** Determine if `T` meets the requirements of <em>SyncWriteStream</em>.
+
+ Metafunctions are used to perform compile time checking of template
+ types. This type will be `std::true_type` if `T` meets the requirements,
+ else the type will be `std::false_type`.
+
+ @par Example
+
+ Use with `static_assert`:
+
+ @code
+ template<class SyncReadStream>
+ void f(SyncReadStream& stream)
+ {
+ static_assert(is_sync_read_stream<SyncReadStream>::value,
+ "SyncReadStream type requirements not met");
+ ...
+ @endcode
+
+ Use with `std::enable_if` (SFINAE):
+
+ @code
+ template<class SyncReadStream>
+ typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
+ f(SyncReadStream& stream);
+ @endcode
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+using is_sync_write_stream = __see_below__;
+#else
+template<class T, class = void>
+struct is_sync_write_stream : std::false_type {};
+
+template<class T>
+struct is_sync_write_stream<T, boost::void_t<decltype(
+ (
+ std::declval<std::size_t&>() = std::declval<T&>().write_some(
+ std::declval<detail::ConstBufferSequence>()))
+ ,std::declval<std::size_t&>() = std::declval<T&>().write_some(
+ std::declval<detail::ConstBufferSequence>(),
+ std::declval<boost::system::error_code&>())
+ )>> : std::true_type {};
+#endif
+
+/** Determine if `T` meets the requirements of @b SyncStream.
+
+ Metafunctions are used to perform compile time checking of template
+ types. This type will be `std::true_type` if `T` meets the requirements,
+ else the type will be `std::false_type`.
+
+ @par Example
+
+ Use with `static_assert`:
+
+ @code
+ template<class SyncStream>
+ void f(SyncStream& stream)
+ {
+ static_assert(is_sync_stream<SyncStream>::value,
+ "SyncStream type requirements not met");
+ ...
+ @endcode
+
+ Use with `std::enable_if` (SFINAE):
+
+ @code
+ template<class SyncStream>
+ typename std::enable_if<is_sync_stream<SyncStream>::value>::type
+ f(SyncStream& stream);
+ @endcode
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+using is_sync_stream = __see_below__;
+#else
+template<class T>
+using is_sync_stream = std::integral_constant<bool,
+ is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
+#endif
+
+//------------------------------------------------------------------------------
+
+/** Determine if `T` meets the requirements of <em>AsyncReadStream</em>.
+
+ Metafunctions are used to perform compile time checking of template
+ types. This type will be `std::true_type` if `T` meets the requirements,
+ else the type will be `std::false_type`.
+
+ @par Example
+
+ Use with `static_assert`:
+
+ @code
+ template<class AsyncReadStream>
+ void f(AsyncReadStream& stream)
+ {
+ static_assert(is_async_read_stream<AsyncReadStream>::value,
+ "AsyncReadStream type requirements not met");
+ ...
+ @endcode
+
+ Use with `std::enable_if` (SFINAE):
+
+ @code
+ template<class AsyncReadStream>
+ typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
+ f(AsyncReadStream& stream);
+ @endcode
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+using is_async_read_stream = __see_below__;
+#else
+template<class T, class = void>
+struct is_async_read_stream : std::false_type {};
+
+template<class T>
+struct is_async_read_stream<T, boost::void_t<decltype(
+ std::declval<T&>().async_read_some(
+ std::declval<detail::MutableBufferSequence>(),
+ std::declval<detail::ReadHandler>())
+ )>> : std::integral_constant<bool,
+ has_get_executor<T>::value
+ > {};
+#endif
+
+/** Determine if `T` meets the requirements of <em>AsyncWriteStream</em>.
+
+ Metafunctions are used to perform compile time checking of template
+ types. This type will be `std::true_type` if `T` meets the requirements,
+ else the type will be `std::false_type`.
+
+ @par Example
+
+ Use with `static_assert`:
+
+ @code
+ template<class AsyncWriteStream>
+ void f(AsyncWriteStream& stream)
+ {
+ static_assert(is_async_write_stream<AsyncWriteStream>::value,
+ "AsyncWriteStream type requirements not met");
+ ...
+ @endcode
+
+ Use with `std::enable_if` (SFINAE):
+
+ @code
+ template<class AsyncWriteStream>
+ typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
+ f(AsyncWriteStream& stream);
+ @endcode
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+using is_async_write_stream = __see_below__;
+#else
+template<class T, class = void>
+struct is_async_write_stream : std::false_type {};
+
+template<class T>
+struct is_async_write_stream<T, boost::void_t<decltype(
+ std::declval<T&>().async_write_some(
+ std::declval<detail::ConstBufferSequence>(),
+ std::declval<detail::WriteHandler>())
+ )>> : std::integral_constant<bool,
+ has_get_executor<T>::value
+ > {};
+#endif
+
+/** Determine if `T` meets the requirements of @b AsyncStream.
+
+ Metafunctions are used to perform compile time checking of template
+ types. This type will be `std::true_type` if `T` meets the requirements,
+ else the type will be `std::false_type`.
+
+ @par Example
+
+ Use with `static_assert`:
+
+ @code
+ template<class AsyncStream>
+ void f(AsyncStream& stream)
+ {
+ static_assert(is_async_stream<AsyncStream>::value,
+ "AsyncStream type requirements not met");
+ ...
+ @endcode
+
+ Use with `std::enable_if` (SFINAE):
+
+ @code
+ template<class AsyncStream>
+ typename std::enable_if<is_async_stream<AsyncStream>::value>::type
+ f(AsyncStream& stream);
+ @endcode
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+using is_async_stream = __see_below__;
+#else
+template<class T>
+using is_async_stream = std::integral_constant<bool,
+ is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
+#endif
+
+//------------------------------------------------------------------------------
+
+/** Default socket close function.
+
+ This function is not meant to be called directly. Instead, it
+ is called automatically when using @ref close_socket. To enable
+ closure of user-defined types or classes derived from a particular
+ user-defined type, this function should be overloaded in the
+ corresponding namespace for the type in question.
+
+ @see close_socket
+*/
+template<
+ class Protocol,
+ class Executor>
+void
+beast_close_socket(
+ net::basic_socket<
+ Protocol, Executor>& sock)
+{
+ boost::system::error_code ec;
+ sock.close(ec);
+}
+
+namespace detail {
+
+struct close_socket_impl
+{
+ template<class T>
+ void
+ operator()(T& t) const
+ {
+ using beast::beast_close_socket;
+ beast_close_socket(t);
+ }
+};
+
+} // detail
+
+/** Close a socket or socket-like object.
+
+ This function attempts to close an object representing a socket.
+ In this context, a socket is an object for which an unqualified
+ call to the function `void beast_close_socket(Socket&)` is
+ well-defined. The function `beast_close_socket` is a
+ <em>customization point</em>, allowing user-defined types to
+ provide an algorithm for performing the close operation by
+ overloading this function for the type in question.
+
+ Since the customization point is a function call, the normal
+ rules for finding the correct overload are applied including
+ the rules for argument-dependent lookup ("ADL"). This permits
+ classes derived from a type for which a customization is provided
+ to inherit the customization point.
+
+ An overload for the networking class template `net::basic_socket`
+ is provided, which implements the close algorithm for all socket-like
+ objects (hence the name of this customization point). When used
+ in conjunction with @ref get_lowest_layer, a generic algorithm
+ operating on a layered stream can perform a closure of the underlying
+ socket without knowing the exact list of concrete types.
+
+ @par Example 1
+ The following generic function synchronously sends a message
+ on the stream, then closes the socket.
+ @code
+ template <class WriteStream>
+ void hello_and_close (WriteStream& stream)
+ {
+ net::write(stream, net::const_buffer("Hello, world!", 13));
+ close_socket(get_lowest_layer(stream));
+ }
+ @endcode
+
+ To enable closure of user defined types, it is necessary to provide
+ an overload of the function `beast_close_socket` for the type.
+
+ @par Example 2
+ The following code declares a user-defined type which contains a
+ private socket, and provides an overload of the customization
+ point which closes the private socket.
+ @code
+ class my_socket
+ {
+ net::ip::tcp::socket sock_;
+
+ public:
+ my_socket(net::io_context& ioc)
+ : sock_(ioc)
+ {
+ }
+
+ friend void beast_close_socket(my_socket& s)
+ {
+ error_code ec;
+ s.sock_.close(ec);
+ // ignore the error
+ }
+ };
+ @endcode
+
+ @param sock The socket to close. If the customization point is not
+ defined for the type of this object, or one of its base classes,
+ then a compiler error results.
+
+ @see beast_close_socket
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class Socket>
+void
+close_socket(Socket& sock);
+#else
+BOOST_BEAST_INLINE_VARIABLE(close_socket, detail::close_socket_impl)
+#endif
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/string.hpp b/boost/beast/core/string.hpp
index de94d2e639..976bfca48a 100644
--- a/boost/beast/core/string.hpp
+++ b/boost/beast/core/string.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -64,24 +64,24 @@ iequals(
auto p1 = lhs.data();
auto p2 = rhs.data();
char a, b;
+ // fast loop
while(n--)
{
a = *p1++;
b = *p2++;
if(a != b)
- {
- // slow loop
- do
- {
- if(ascii_tolower(a) != ascii_tolower(b))
- return false;
- a = *p1++;
- b = *p2++;
- }
- while(n--);
- return true;
- }
+ goto slow;
+ }
+ return true;
+slow:
+ do
+ {
+ if(ascii_tolower(a) != ascii_tolower(b))
+ return false;
+ a = *p1++;
+ b = *p2++;
}
+ while(n--);
return true;
}
diff --git a/boost/beast/core/string_param.hpp b/boost/beast/core/string_param.hpp
index a068cc4091..67ef69469c 100644
--- a/boost/beast/core/string_param.hpp
+++ b/boost/beast/core/string_param.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -125,6 +125,6 @@ public:
} // beast
} // boost
-#include <boost/beast/core/impl/string_param.ipp>
+#include <boost/beast/core/impl/string_param.hpp>
#endif
diff --git a/boost/beast/core/tcp_stream.hpp b/boost/beast/core/tcp_stream.hpp
new file mode 100644
index 0000000000..a96dd2aed1
--- /dev/null
+++ b/boost/beast/core/tcp_stream.hpp
@@ -0,0 +1,34 @@
+//
+// 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_CORE_TCP_STREAM_HPP
+#define BOOST_BEAST_CORE_TCP_STREAM_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/basic_stream.hpp>
+#include <boost/beast/core/rate_policy.hpp>
+#include <boost/asio/executor.hpp>
+#include <boost/asio/ip/tcp.hpp>
+
+namespace boost {
+namespace beast {
+
+/** A TCP/IP stream socket with timeouts and a polymorphic executor.
+
+ @see basic_stream
+*/
+using tcp_stream = basic_stream<
+ net::ip::tcp,
+ net::executor,
+ unlimited_rate_policy>;
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/type_traits.hpp b/boost/beast/core/type_traits.hpp
index d400e7f615..2f42301800 100644
--- a/boost/beast/core/type_traits.hpp
+++ b/boost/beast/core/type_traits.hpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// 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)
@@ -10,22 +10,19 @@
#ifndef BOOST_BEAST_TYPE_TRAITS_HPP
#define BOOST_BEAST_TYPE_TRAITS_HPP
+#ifndef BOOST_BEAST_DOXYGEN
+
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/file_base.hpp>
-#include <boost/beast/core/detail/type_traits.hpp>
-#include <boost/asio/buffer.hpp>
-#include <type_traits>
+#include <boost/beast/core/detail/is_invocable.hpp>
+#include <boost/config/pragma_message.hpp>
+#include <type_traits.hpp>
+
+BOOST_PRAGMA_MESSAGE("<boost/beast/core/type_traits.hpp> is DEPRECATED and will be removed in a future release.")
namespace boost {
namespace beast {
-//------------------------------------------------------------------------------
-//
-// Handler concepts
-//
-//------------------------------------------------------------------------------
-
-/** Determine if `T` meets the requirements of @b CompletionHandler.
+/** Determine if `T` meets the requirements of <em>CompletionHandler</em>.
This trait checks whether a type meets the requirements for a completion
handler, and is also callable with the specified signature.
@@ -34,446 +31,28 @@ namespace beast {
else the type will be `std::false_type`.
@par Example
-
Use with `static_assert`:
-
@code
struct handler
{
void operator()(error_code&);
};
-
static_assert(is_completion_handler<handler, void(error_code&)>::value,
"Not a completion handler");
@endcode
*/
template<class T, class Signature>
#if BOOST_BEAST_DOXYGEN
-using is_completion_handler = std::integral_constant<bool, ...>;
+using is_completion_handler = __see_below__
#else
using is_completion_handler = std::integral_constant<bool,
std::is_move_constructible<typename std::decay<T>::type>::value &&
detail::is_invocable<T, Signature>::value>;
#endif
-//------------------------------------------------------------------------------
-//
-// Stream concepts
-//
-//------------------------------------------------------------------------------
-
-/** Determine if `T` has the `get_executor` member function.
-
- Metafunctions are used to perform compile time checking of template
- types. This type will be `std::true_type` if `T` has the member
- function with the correct signature, else type will be `std::false_type`.
-
- @par Example
-
- Use with tag dispatching:
-
- @code
- template<class T>
- void maybe_hello(T& t, std::true_type)
- {
- boost::asio::post(
- t.get_executor(),
- []
- {
- std::cout << "Hello, world!" << std::endl;
- });
- }
-
- template<class T>
- void maybe_hello(T&, std::false_type)
- {
- // T does not have get_executor
- }
-
- template<class T>
- void maybe_hello(T& t)
- {
- maybe_hello(t, has_get_executor<T>{});
- }
- @endcode
-
- Use with `static_assert`:
-
- @code
- struct stream
- {
- using executor_type = boost::asio::io_context::executor_type;
- executor_type get_executor() noexcept;
- };
-
- static_assert(has_get_executor<stream>::value, "Missing get_executor member");
- @endcode
-*/
-#if BOOST_BEAST_DOXYGEN
-template<class T>
-struct has_get_executor : std::integral_constant<bool, ...>{};
-#else
-template<class T, class = void>
-struct has_get_executor : std::false_type {};
-
-template<class T>
-struct has_get_executor<T, beast::detail::void_t<decltype(
- std::declval<T&>().get_executor())>> : std::true_type {};
-#endif
-
-/** Alias for `T::lowest_layer_type` if it exists, else `T`
-
- This will be a type alias for `T::lowest_layer_type`
- if it exists, else it will be an alias for `T`.
-
- @par Example
-
- Declaring a wrapper:
-
- @code
- template<class Stream>
- struct stream_wrapper
- {
- using next_layer_type = typename std::remove_reference<Stream>::type;
- using lowest_layer_type = get_lowest_layer<stream_type>;
- };
- @endcode
-
- Defining a metafunction:
-
- @code
- /// Alias for `std::true_type` if `T` wraps another stream
- template<class T>
- using is_stream_wrapper : std::integral_constant<bool,
- ! std::is_same<T, get_lowest_layer<T>>::value> {};
- @endcode
-*/
-#if BOOST_BEAST_DOXYGEN
-template<class T>
-struct get_lowest_layer;
-#else
-template<class T>
-using get_lowest_layer = typename detail::get_lowest_layer_helper<T>::type;
-#endif
-
-/** Determine if `T` meets the requirements of @b AsyncReadStream.
-
- Metafunctions are used to perform compile time checking of template
- types. This type will be `std::true_type` if `T` meets the requirements,
- else the type will be `std::false_type`.
-
- @par Example
-
- Use with `static_assert`:
-
- @code
- template<class AsyncReadStream>
- void f(AsyncReadStream& stream)
- {
- static_assert(is_async_read_stream<AsyncReadStream>::value,
- "AsyncReadStream requirements not met");
- ...
- @endcode
-
- Use with `std::enable_if` (SFINAE):
-
- @code
- template<class AsyncReadStream>
- typename std::enable_if<is_async_read_stream<AsyncReadStream>::value>::type
- f(AsyncReadStream& stream);
- @endcode
-*/
-#if BOOST_BEAST_DOXYGEN
-template<class T>
-struct is_async_read_stream : std::integral_constant<bool, ...>{};
-#else
-template<class T, class = void>
-struct is_async_read_stream : std::false_type {};
-
-template<class T>
-struct is_async_read_stream<T, detail::void_t<decltype(
- std::declval<T>().async_read_some(
- std::declval<detail::MutableBufferSequence>(),
- std::declval<detail::ReadHandler>())
- )>> : std::integral_constant<bool,
- has_get_executor<T>::value
- > {};
-#endif
-
-/** Determine if `T` meets the requirements of @b AsyncWriteStream.
-
- Metafunctions are used to perform compile time checking of template
- types. This type will be `std::true_type` if `T` meets the requirements,
- else the type will be `std::false_type`.
-
- @par Example
-
- Use with `static_assert`:
-
- @code
- template<class AsyncWriteStream>
- void f(AsyncWriteStream& stream)
- {
- static_assert(is_async_write_stream<AsyncWriteStream>::value,
- "AsyncWriteStream requirements not met");
- ...
- @endcode
-
- Use with `std::enable_if` (SFINAE):
-
- @code
- template<class AsyncWriteStream>
- typename std::enable_if<is_async_write_stream<AsyncWriteStream>::value>::type
- f(AsyncWriteStream& stream);
- @endcode
-*/
-#if BOOST_BEAST_DOXYGEN
-template<class T>
-struct is_async_write_stream : std::integral_constant<bool, ...>{};
-#else
-template<class T, class = void>
-struct is_async_write_stream : std::false_type {};
-
-template<class T>
-struct is_async_write_stream<T, detail::void_t<decltype(
- std::declval<T>().async_write_some(
- std::declval<detail::ConstBufferSequence>(),
- std::declval<detail::WriteHandler>())
- )>> : std::integral_constant<bool,
- has_get_executor<T>::value
- > {};
-#endif
-
-/** Determine if `T` meets the requirements of @b SyncReadStream.
-
- Metafunctions are used to perform compile time checking of template
- types. This type will be `std::true_type` if `T` meets the requirements,
- else the type will be `std::false_type`.
-
- @par Example
-
- Use with `static_assert`:
-
- @code
- template<class SyncReadStream>
- void f(SyncReadStream& stream)
- {
- static_assert(is_sync_read_stream<SyncReadStream>::value,
- "SyncReadStream requirements not met");
- ...
- @endcode
-
- Use with `std::enable_if` (SFINAE):
-
- @code
- template<class SyncReadStream>
- typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
- f(SyncReadStream& stream);
- @endcode
-*/
-#if BOOST_BEAST_DOXYGEN
-template<class T>
-struct is_sync_read_stream : std::integral_constant<bool, ...>{};
-#else
-template<class T, class = void>
-struct is_sync_read_stream : std::false_type {};
-
-template<class T>
-struct is_sync_read_stream<T, detail::void_t<decltype(
- std::declval<std::size_t&>() = std::declval<T>().read_some(
- std::declval<detail::MutableBufferSequence>()),
- std::declval<std::size_t&>() = std::declval<T>().read_some(
- std::declval<detail::MutableBufferSequence>(),
- std::declval<boost::system::error_code&>())
- )>> : std::true_type {};
-#endif
-
-/** Determine if `T` meets the requirements of @b SyncWriteStream.
-
- Metafunctions are used to perform compile time checking of template
- types. This type will be `std::true_type` if `T` meets the requirements,
- else the type will be `std::false_type`.
-
- @par Example
-
- Use with `static_assert`:
-
- @code
- template<class SyncReadStream>
- void f(SyncReadStream& stream)
- {
- static_assert(is_sync_read_stream<SyncReadStream>::value,
- "SyncReadStream requirements not met");
- ...
- @endcode
-
- Use with `std::enable_if` (SFINAE):
-
- @code
- template<class SyncReadStream>
- typename std::enable_if<is_sync_read_stream<SyncReadStream>::value>::type
- f(SyncReadStream& stream);
- @endcode
-*/
-#if BOOST_BEAST_DOXYGEN
-template<class T>
-struct is_sync_write_stream : std::integral_constant<bool, ...>{};
-#else
-template<class T, class = void>
-struct is_sync_write_stream : std::false_type {};
-
-template<class T>
-struct is_sync_write_stream<T, detail::void_t<decltype(
- std::declval<std::size_t&>() = std::declval<T&>().write_some(
- std::declval<detail::ConstBufferSequence>()),
- std::declval<std::size_t&>() = std::declval<T&>().write_some(
- std::declval<detail::ConstBufferSequence>(),
- std::declval<boost::system::error_code&>())
- )>> : std::true_type {};
-#endif
-
-/** Determine if `T` meets the requirements of @b AsyncStream.
-
- Metafunctions are used to perform compile time checking of template
- types. This type will be `std::true_type` if `T` meets the requirements,
- else the type will be `std::false_type`.
-
- @par Example
-
- Use with `static_assert`:
-
- @code
- template<class AsyncStream>
- void f(AsyncStream& stream)
- {
- static_assert(is_async_stream<AsyncStream>::value,
- "AsyncStream requirements not met");
- ...
- @endcode
-
- Use with `std::enable_if` (SFINAE):
-
- @code
- template<class AsyncStream>
- typename std::enable_if<is_async_stream<AsyncStream>::value>::type
- f(AsyncStream& stream);
- @endcode
-*/
-#if BOOST_BEAST_DOXYGEN
-template<class T>
-struct is_async_stream : std::integral_constant<bool, ...>{};
-#else
-template<class T>
-using is_async_stream = std::integral_constant<bool,
- is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
-#endif
-
-/** Determine if `T` meets the requirements of @b SyncStream.
-
- Metafunctions are used to perform compile time checking of template
- types. This type will be `std::true_type` if `T` meets the requirements,
- else the type will be `std::false_type`.
-
- @par Example
-
- Use with `static_assert`:
-
- @code
- template<class SyncStream>
- void f(SyncStream& stream)
- {
- static_assert(is_sync_stream<SyncStream>::value,
- "SyncStream requirements not met");
- ...
- @endcode
-
- Use with `std::enable_if` (SFINAE):
-
- @code
- template<class SyncStream>
- typename std::enable_if<is_sync_stream<SyncStream>::value>::type
- f(SyncStream& stream);
- @endcode
-*/
-#if BOOST_BEAST_DOXYGEN
-template<class T>
-struct is_sync_stream : std::integral_constant<bool, ...>{};
-#else
-template<class T>
-using is_sync_stream = std::integral_constant<bool,
- is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
-#endif
-
-//------------------------------------------------------------------------------
-//
-// File concepts
-//
-//------------------------------------------------------------------------------
-
-/** Determine if `T` meets the requirements of @b File.
-
- Metafunctions are used to perform compile time checking of template
- types. This type will be `std::true_type` if `T` meets the requirements,
- else the type will be `std::false_type`.
-
- @par Example
-
- Use with `static_assert`:
-
- @code
- template<class File>
- void f(File& file)
- {
- static_assert(is_file<File>::value,
- "File requirements not met");
- ...
- @endcode
-
- Use with `std::enable_if` (SFINAE):
-
- @code
- template<class File>
- typename std::enable_if<is_file<File>::value>::type
- f(File& file);
- @endcode
-*/
-#if BOOST_BEAST_DOXYGEN
-template<class T>
-struct is_file : std::integral_constant<bool, ...>{};
-#else
-template<class T, class = void>
-struct is_file : std::false_type {};
-
-template<class T>
-struct is_file<T, detail::void_t<decltype(
- std::declval<bool&>() = std::declval<T const&>().is_open(),
- std::declval<T&>().close(std::declval<error_code&>()),
- std::declval<T&>().open(
- std::declval<char const*>(),
- std::declval<file_mode>(),
- std::declval<error_code&>()),
- std::declval<std::uint64_t&>() = std::declval<T&>().size(
- std::declval<error_code&>()),
- std::declval<std::uint64_t&>() = std::declval<T&>().pos(
- std::declval<error_code&>()),
- std::declval<T&>().seek(
- std::declval<std::uint64_t>(),
- std::declval<error_code&>()),
- std::declval<std::size_t&>() = std::declval<T&>().read(
- std::declval<void*>(),
- std::declval<std::size_t>(),
- std::declval<error_code&>()),
- std::declval<std::size_t&>() = std::declval<T&>().write(
- std::declval<void const*>(),
- std::declval<std::size_t>(),
- std::declval<error_code&>())
- )>> : std::integral_constant<bool,
- std::is_default_constructible<T>::value &&
- std::is_destructible<T>::value
- > {};
-#endif
-
} // beast
} // boost
#endif
+
+#endif