summaryrefslogtreecommitdiff
path: root/boost/beast/core
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/core')
-rw-r--r--boost/beast/core/bind_handler.hpp80
-rw-r--r--boost/beast/core/buffered_read_stream.hpp373
-rw-r--r--boost/beast/core/buffers_adapter.hpp164
-rw-r--r--boost/beast/core/buffers_cat.hpp119
-rw-r--r--boost/beast/core/buffers_prefix.hpp237
-rw-r--r--boost/beast/core/buffers_suffix.hpp161
-rw-r--r--boost/beast/core/buffers_to_string.hpp59
-rw-r--r--boost/beast/core/detail/allocator.hpp42
-rw-r--r--boost/beast/core/detail/base64.hpp251
-rw-r--r--boost/beast/core/detail/bind_handler.hpp189
-rw-r--r--boost/beast/core/detail/buffers_ref.hpp67
-rw-r--r--boost/beast/core/detail/clamp.hpp59
-rw-r--r--boost/beast/core/detail/config.hpp57
-rw-r--r--boost/beast/core/detail/cpu_info.hpp99
-rw-r--r--boost/beast/core/detail/empty_base_optimization.hpp100
-rw-r--r--boost/beast/core/detail/in_place_init.hpp43
-rw-r--r--boost/beast/core/detail/integer_sequence.hpp143
-rw-r--r--boost/beast/core/detail/ostream.hpp319
-rw-r--r--boost/beast/core/detail/sha1.hpp313
-rw-r--r--boost/beast/core/detail/static_ostream.hpp142
-rw-r--r--boost/beast/core/detail/static_string.hpp135
-rw-r--r--boost/beast/core/detail/type_traits.hpp353
-rw-r--r--boost/beast/core/detail/variant.hpp195
-rw-r--r--boost/beast/core/detail/varint.hpp79
-rw-r--r--boost/beast/core/error.hpp58
-rw-r--r--boost/beast/core/file.hpp45
-rw-r--r--boost/beast/core/file_base.hpp89
-rw-r--r--boost/beast/core/file_posix.hpp175
-rw-r--r--boost/beast/core/file_stdio.hpp158
-rw-r--r--boost/beast/core/file_win32.hpp177
-rw-r--r--boost/beast/core/flat_buffer.hpp342
-rw-r--r--boost/beast/core/flat_static_buffer.hpp254
-rw-r--r--boost/beast/core/handler_ptr.hpp213
-rw-r--r--boost/beast/core/impl/buffered_read_stream.ipp248
-rw-r--r--boost/beast/core/impl/buffers_adapter.ipp517
-rw-r--r--boost/beast/core/impl/buffers_cat.ipp503
-rw-r--r--boost/beast/core/impl/buffers_prefix.ipp258
-rw-r--r--boost/beast/core/impl/buffers_suffix.ipp249
-rw-r--r--boost/beast/core/impl/file_posix.ipp349
-rw-r--r--boost/beast/core/impl/file_stdio.ipp239
-rw-r--r--boost/beast/core/impl/file_win32.ipp364
-rw-r--r--boost/beast/core/impl/flat_buffer.ipp475
-rw-r--r--boost/beast/core/impl/flat_static_buffer.ipp151
-rw-r--r--boost/beast/core/impl/handler_ptr.ipp147
-rw-r--r--boost/beast/core/impl/multi_buffer.ipp1063
-rw-r--r--boost/beast/core/impl/read_size.ipp80
-rw-r--r--boost/beast/core/impl/static_buffer.ipp148
-rw-r--r--boost/beast/core/impl/static_string.ipp618
-rw-r--r--boost/beast/core/impl/string_param.ipp108
-rw-r--r--boost/beast/core/multi_buffer.hpp322
-rw-r--r--boost/beast/core/ostream.hpp104
-rw-r--r--boost/beast/core/read_size.hpp64
-rw-r--r--boost/beast/core/span.hpp215
-rw-r--r--boost/beast/core/static_buffer.hpp217
-rw-r--r--boost/beast/core/static_string.hpp1112
-rw-r--r--boost/beast/core/string.hpp155
-rw-r--r--boost/beast/core/string_param.hpp130
-rw-r--r--boost/beast/core/type_traits.hpp490
58 files changed, 13616 insertions, 0 deletions
diff --git a/boost/beast/core/bind_handler.hpp b/boost/beast/core/bind_handler.hpp
new file mode 100644
index 0000000000..0756bc5aaa
--- /dev/null
+++ b/boost/beast/core/bind_handler.hpp
@@ -0,0 +1,80 @@
+//
+// 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_BIND_HANDLER_HPP
+#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>
+
+namespace boost {
+namespace beast {
+
+/** 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 subtituted for
+ placeholders present in the list of bound arguments. Parameters
+ which are not matched to placeholders are silently discarded.
+ The passed handler and arguments are forwarded into the returned
+ handler, which provides the same `io_context` execution guarantees
+ as the original handler.
+
+ Unlike `boost::asio::io_context::wrap`, the returned handler can
+ be used in a subsequent call to `boost::asio::io_context::post`
+ instead of `boost::asio::io_context::dispatch`, to ensure that
+ the handler will not be invoked immediately by the calling
+ function.
+
+ Example:
+
+ @code
+ template<class AsyncReadStream, class ReadHandler>
+ void
+ signal_aborted(AsyncReadStream& stream, ReadHandler&& handler)
+ {
+ boost::asio::post(
+ stream.get_executor(),
+ bind_handler(std::forward<ReadHandler>(handler),
+ boost::asio::error::operation_aborted, 0));
+ }
+ @endcode
+
+ @param handler The handler to wrap.
+
+ @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
+detail::bound_handler<
+ typename std::decay<Handler>::type, Args...>
+#endif
+bind_handler(Handler&& handler, Args&&... args)
+{
+#if 0
+ static_assert(is_completion_handler<
+ Handler, void(Args...)>::value,
+ "Handler requirements not met");
+#endif
+ return detail::bound_handler<typename std::decay<
+ Handler>::type, Args...>(std::forward<
+ Handler>(handler), std::forward<Args>(args)...);
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/buffered_read_stream.hpp b/boost/beast/core/buffered_read_stream.hpp
new file mode 100644
index 0000000000..e683a40953
--- /dev/null
+++ b/boost/beast/core/buffered_read_stream.hpp
@@ -0,0 +1,373 @@
+//
+// 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_BUFFERED_READ_STREAM_HPP
+#define BOOST_BEAST_BUFFERED_READ_STREAM_HPP
+
+#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/asio/async_result.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/io_context.hpp>
+#include <cstdint>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+/** A @b Stream with attached @b DynamicBuffer to buffer reads.
+
+ This wraps a @b Stream 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
+ 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
+ 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`
+ could make use of this wrapper.
+
+ Uses:
+
+ @li Transparently leave untouched input acquired in calls
+ to `boost::asio::read_until` behind for subsequent callers.
+
+ @li "Preload" a stream with handshake input data acquired
+ from other sources.
+
+ Example:
+ @code
+ // Process the next HTTP header on the stream,
+ // leaving excess bytes behind for the next call.
+ //
+ template<class DynamicBuffer>
+ void process_http_message(
+ buffered_read_stream<DynamicBuffer>& stream)
+ {
+ // Read up to and including the end of the HTTP
+ // header, leaving the sequence in the stream's
+ // buffer. read_until may read past the end of the
+ // headers; the return value will include only the
+ // part up to the end of the delimiter.
+ //
+ std::size_t bytes_transferred =
+ boost::asio::read_until(
+ stream.next_layer(), stream.buffer(), "\r\n\r\n");
+
+ // Use buffers_prefix() to limit the input
+ // sequence to only the data up to and including
+ // the trailing "\r\n\r\n".
+ //
+ auto header_buffers = buffers_prefix(
+ bytes_transferred, stream.buffer().data());
+
+ ...
+
+ // Discard the portion of the input corresponding
+ // to the HTTP headers.
+ //
+ stream.buffer().consume(bytes_transferred);
+
+ // Everything we read from the stream
+ // is part of the content-body.
+ }
+ @endcode
+
+ @tparam Stream The type of stream to wrap.
+
+ @tparam DynamicBuffer The type of stream buffer to use.
+*/
+template<class Stream, class DynamicBuffer>
+class buffered_read_stream
+{
+ static_assert(
+ boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
+ "DynamicBuffer requirements not met");
+
+ template<class Buffers, class Handler>
+ class read_some_op;
+
+ DynamicBuffer buffer_;
+ std::size_t capacity_ = 0;
+ Stream next_layer_;
+
+public:
+ /// The type of the internal buffer
+ using buffer_type = DynamicBuffer;
+
+ /// The type of the next layer.
+ using next_layer_type =
+ typename std::remove_reference<Stream>::type;
+
+ /// The type of the lowest layer.
+ using lowest_layer_type =
+ typename get_lowest_layer<next_layer_type>::type;
+
+ /** Move constructor.
+
+ @note The behavior of move assignment on or from streams
+ with active or pending operations is undefined.
+ */
+ buffered_read_stream(buffered_read_stream&&) = default;
+
+ /** Move assignment.
+
+ @note The behavior of move assignment on or from streams
+ with active or pending operations is undefined.
+ */
+ buffered_read_stream& operator=(buffered_read_stream&&) = default;
+
+ /** Construct the wrapping stream.
+
+ @param args Parameters forwarded to the `Stream` constructor.
+ */
+ template<class... Args>
+ explicit
+ buffered_read_stream(Args&&... args);
+
+ /// Get a reference to the next layer.
+ next_layer_type&
+ next_layer()
+ {
+ return next_layer_;
+ }
+
+ /// Get a const reference to the next layer.
+ next_layer_type const&
+ next_layer() const
+ {
+ 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();
+ }
+
+ /** 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.
+
+ @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())
+ {
+ return next_layer_.get_executor();
+ }
+
+ /** Access the internal buffer.
+
+ The internal buffer is returned. It is possible for the
+ caller to break invariants with this function. For example,
+ by causing the internal buffer size to increase beyond
+ the caller defined maximum.
+ */
+ DynamicBuffer&
+ buffer()
+ {
+ return buffer_;
+ }
+
+ /// Access the internal buffer
+ DynamicBuffer const&
+ buffer() const
+ {
+ return buffer_;
+ }
+
+ /** Set the maximum buffer size.
+
+ This changes the maximum size of the internal buffer used
+ to hold read data. No bytes are discarded by this call. If
+ the buffer size is set to zero, no more data will be buffered.
+
+ Thread safety:
+ The caller is responsible for making sure the call is
+ made from the same implicit or explicit strand.
+
+ @param size The number of bytes in the read buffer.
+
+ @note This is a soft limit. If the new maximum size is smaller
+ than the amount of data in the buffer, no bytes are discarded.
+ */
+ void
+ capacity(std::size_t size)
+ {
+ capacity_ = size;
+ }
+
+ /** 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 One or more buffers into which the data will be read.
+
+ @return The number of bytes read.
+
+ @throws system_error Thrown on failure.
+ */
+ 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 One or more buffers into which the data will be read.
+
+ @param ec Set to the error, if any occurred.
+
+ @return The number of bytes read, or 0 on error.
+ */
+ 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 data from
+ the stream. The function call always returns immediately.
+
+ @param buffers One or more buffers into which the data
+ will be read. 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 handler to be called when the operation
+ completes. Copies will be made of the handler as required.
+ 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
+ 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`.
+ */
+ template<class MutableBufferSequence, class ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(
+ ReadHandler, void(error_code, std::size_t))
+ async_read_some(MutableBufferSequence const& buffers,
+ ReadHandler&& handler);
+
+ /** Write some data to the stream.
+
+ This function is used to write data to the stream.
+ The function call will block until one or more bytes of the
+ data has been written successfully, or until an error occurs.
+
+ @param buffers One or more data buffers to be written to the stream.
+
+ @return The number of bytes written.
+
+ @throws system_error Thrown on failure.
+ */
+ template<class ConstBufferSequence>
+ std::size_t
+ write_some(ConstBufferSequence const& buffers)
+ {
+ static_assert(is_sync_write_stream<next_layer_type>::value,
+ "SyncWriteStream requirements not met");
+ return next_layer_.write_some(buffers);
+ }
+
+ /** Write some data to the stream.
+
+ This function is used to write data to the stream.
+ The function call will block until one or more bytes of the
+ data has been written successfully, or until an error occurs.
+
+ @param buffers One or more data buffers to be written to the stream.
+
+ @param ec Set to the error, if any occurred.
+
+ @return The number of bytes written.
+ */
+ template<class ConstBufferSequence>
+ std::size_t
+ write_some(ConstBufferSequence const& buffers,
+ error_code& ec)
+ {
+ static_assert(is_sync_write_stream<next_layer_type>::value,
+ "SyncWriteStream requirements not met");
+ return next_layer_.write_some(buffers, ec);
+ }
+
+ /** Start an asynchronous write.
+
+ This function is used to asynchronously write data from
+ the stream. The function call always returns immediately.
+
+ @param buffers One or more data buffers to be written to
+ the stream. 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 handler to be called when the operation
+ completes. Copies will be made of the handler as required.
+ 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
+ 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`.
+ */
+ template<class ConstBufferSequence, class WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(
+ WriteHandler, void(error_code, std::size_t))
+ async_write_some(ConstBufferSequence const& buffers,
+ WriteHandler&& handler);
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/buffered_read_stream.ipp>
+
+#endif
diff --git a/boost/beast/core/buffers_adapter.hpp b/boost/beast/core/buffers_adapter.hpp
new file mode 100644
index 0000000000..826183ed06
--- /dev/null
+++ b/boost/beast/core/buffers_adapter.hpp
@@ -0,0 +1,164 @@
+//
+// 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_BUFFERS_ADAPTER_HPP
+#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 <type_traits>
+
+namespace boost {
+namespace beast {
+
+/** Adapts a @b MutableBufferSequence into a @b DynamicBuffer.
+
+ 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.
+
+ 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 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_)
+ {
+ }
+
+public:
+#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
+
+ /// 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);
+
+ /// 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_;
+ }
+
+ /** 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_cat.hpp b/boost/beast/core/buffers_cat.hpp
new file mode 100644
index 0000000000..1d711b3b30
--- /dev/null
+++ b/boost/beast/core/buffers_cat.hpp
@@ -0,0 +1,119 @@
+//
+// 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_BUFFERS_CAT_HPP
+#define BOOST_BEAST_BUFFERS_CAT_HPP
+
+#include <boost/beast/core/detail/config.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
+*/
+template<class... Buffers>
+class buffers_cat_view
+{
+ std::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 BOOST_BEAST_DOXYGEN
+ using value_type = implementation_defined;
+#else
+ using value_type = typename
+ detail::common_buffers_type<Buffers...>::type;
+#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;
+
+ /// 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.
+ */
+ explicit
+ buffers_cat_view(Buffers const&... buffers);
+
+ //-----
+
+ /// Required for @b BufferSequence
+ buffers_cat_view(buffers_cat_view const&) = default;
+
+ /// Required for @b BufferSequence
+ const_iterator
+ begin() const;
+
+ /// Required for @b BufferSequence
+ const_iterator
+ end() const;
+};
+
+/** Concatenate 2 or more buffer sequences.
+
+ This function returns a constant or mutable buffer sequence which,
+ when iterated, efficiently concatenates the input buffer sequences.
+ Copies of the arguments passed will be made; however, the returned
+ object does not take ownership of the underlying memory. The
+ application is still responsible for managing the lifetime of the
+ referenced memory.
+
+ @param buffers The list of buffer sequences to concatenate.
+
+ @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.
+
+ @see @ref buffers_cat_view
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class... BufferSequence>
+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");
+ return buffers_cat_view<B1, B2, Bn...>{b1, b2, bn...};
+}
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/buffers_cat.ipp>
+
+#endif
diff --git a/boost/beast/core/buffers_prefix.hpp b/boost/beast/core/buffers_prefix.hpp
new file mode 100644
index 0000000000..67d58b5c58
--- /dev/null
+++ b/boost/beast/core/buffers_prefix.hpp
@@ -0,0 +1,237 @@
+//
+// 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_BUFFERS_PREFIX_HPP
+#define BOOST_BEAST_BUFFERS_PREFIX_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/type_traits.hpp>
+#include <boost/beast/core/detail/in_place_init.hpp>
+#include <boost/asio/buffer.hpp>
+#include <cstdint>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+
+/** A buffer sequence adapter that shortens the sequence size.
+
+ The class adapts a buffer sequence to efficiently represent
+ a shorter subset of the original list of buffers starting
+ with the first byte of the original sequence.
+
+ @tparam BufferSequence The buffer sequence to adapt.
+*/
+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;
+
+ BufferSequence bs_;
+ std::size_t size_;
+ iter_type end_;
+
+ template<class Deduced>
+ buffers_prefix_view(
+ Deduced&& other, std::size_t dist)
+ : bs_(std::forward<Deduced>(other).bs_)
+ , size_(other.size_)
+ , end_(std::next(bs_.begin(), dist))
+ {
+ }
+
+ void
+ setup(std::size_t size);
+
+public:
+ /// The type for each element in the list of buffers.
+ 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;
+
+#if BOOST_BEAST_DOXYGEN
+ /// A bidirectional iterator type that may be used to read elements.
+ using const_iterator = implementation_defined;
+
+#else
+ class const_iterator;
+
+#endif
+
+ /// Move constructor.
+ buffers_prefix_view(buffers_prefix_view&&);
+
+ /// Copy constructor.
+ buffers_prefix_view(buffers_prefix_view const&);
+
+ /// Move assignment.
+ buffers_prefix_view& operator=(buffers_prefix_view&&);
+
+ /// 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,
+ 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.
+ */
+ buffers_prefix_view(
+ std::size_t size,
+ BufferSequence const& buffers);
+
+ /** 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,
+ the resulting sequence will represent the entire
+ input sequence.
+
+ @param args Arguments forwarded to the contained buffers constructor.
+ */
+ template<class... Args>
+ buffers_prefix_view(
+ std::size_t size,
+ boost::in_place_init_t,
+ Args&&... args);
+
+ /// Get a bidirectional iterator to the first element.
+ const_iterator
+ begin() const;
+
+ /// Get a bidirectional iterator to one past the last element.
+ 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.
+
+ @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 buffer sequence.
+
+ 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 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 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.
+*/
+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)
+{
+ static_assert(
+ boost::asio::is_const_buffer_sequence<BufferSequence>::value ||
+ boost::asio::is_mutable_buffer_sequence<BufferSequence>::value,
+ "BufferSequence requirements not met");
+ return buffers_prefix_view<BufferSequence>(size, buffers);
+}
+
+/** Returns the first buffer in a buffer sequence
+
+ This returns the first buffer in the buffer sequence.
+ If the buffer sequence is an empty range, the returned
+ buffer will have a zero buffer size.
+
+ @param buffers The buffer sequence. If the sequence is
+ mutable, the returned buffer sequence will also be mutable.
+ 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_front(BufferSequence const& buffers)
+{
+ auto const first =
+ boost::asio::buffer_sequence_begin(buffers);
+ if(first == boost::asio::buffer_sequence_end(buffers))
+ return {};
+ return *first;
+}
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/buffers_prefix.ipp>
+
+#endif
diff --git a/boost/beast/core/buffers_suffix.hpp b/boost/beast/core/buffers_suffix.hpp
new file mode 100644
index 0000000000..81eb5a6ba7
--- /dev/null
+++ b/boost/beast/core/buffers_suffix.hpp
@@ -0,0 +1,161 @@
+//
+// 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_BUFFERS_SUFFIX_HPP
+#define BOOST_BEAST_BUFFERS_SUFFIX_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/in_place_init.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/optional.hpp>
+#include <cstdint>
+#include <iterator>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+/** Adapter to trim the front of a `BufferSequence`.
+
+ This adapter 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
+ the buffers wrapped.
+
+ The wrapped buffer is not modified, a copy is made instead.
+ Ownership of the underlying memory is not transferred, the application
+ is still responsible for managing its lifetime.
+
+ @tparam BufferSequence The buffer sequence to wrap.
+
+ @par Example
+
+ This function writes the entire contents of a buffer sequence
+ to the specified stream.
+
+ @code
+ template<class SyncWriteStream, class ConstBufferSequence>
+ void send(SyncWriteStream& stream, ConstBufferSequence const& buffers)
+ {
+ buffers_suffix<ConstBufferSequence> bs{buffers};
+ while(boost::asio::buffer_size(bs) > 0)
+ bs.consume(stream.write_some(bs));
+ }
+ @endcode
+*/
+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;
+
+ BufferSequence bs_;
+ 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_),
+ dist))
+ , skip_(other.skip_)
+ {
+ }
+
+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 BOOST_BEAST_DOXYGEN
+ using value_type = implementation_defined;
+#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;
+#endif
+
+#if BOOST_BEAST_DOXYGEN
+ /// A bidirectional iterator type that may be used to read elements.
+ using const_iterator = implementation_defined;
+
+#else
+ class const_iterator;
+
+#endif
+
+ /// Constructor
+ buffers_suffix();
+
+ /// Constructor
+ buffers_suffix(buffers_suffix&&);
+
+ /// Constructor
+ buffers_suffix(buffers_suffix const&);
+
+ /** Constructor
+
+ A copy of the buffer sequence is made. Ownership of the
+ underlying memory is not transferred or copied.
+ */
+ explicit
+ buffers_suffix(BufferSequence const& buffers);
+
+ /** Constructor
+
+ This constructs the buffer sequence in-place from
+ a list of arguments.
+
+ @param args Arguments forwarded to the buffers constructor.
+ */
+ template<class... Args>
+ buffers_suffix(boost::in_place_init_t, Args&&... args);
+
+ /// Assignment
+ buffers_suffix& operator=(buffers_suffix&&);
+
+ /// Assignment
+ buffers_suffix& operator=(buffers_suffix const&);
+
+ /// Get a bidirectional iterator to the first element.
+ const_iterator
+ begin() const;
+
+ /// Get a bidirectional iterator to one past the last element.
+ const_iterator
+ end() const;
+
+ /** Remove bytes from the beginning of the sequence.
+
+ @param amount The number of bytes to remove. If this is
+ larger than the number of bytes remaining, all the
+ bytes remaining are removed.
+ */
+ void
+ consume(std::size_t amount);
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/buffers_suffix.ipp>
+
+#endif
diff --git a/boost/beast/core/buffers_to_string.hpp b/boost/beast/core/buffers_to_string.hpp
new file mode 100644
index 0000000000..aae3d3aa57
--- /dev/null
+++ b/boost/beast/core/buffers_to_string.hpp
@@ -0,0 +1,59 @@
+//
+// 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_BUFFERS_TO_STRING_HPP
+#define BOOST_BEAST_BUFFERS_TO_STRING_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/asio/buffer.hpp>
+#include <string>
+
+namespace boost {
+namespace beast {
+
+/** Return a string representing the contents of a buffer sequence.
+
+ This function returns a string representing an entire buffer
+ sequence. Nulls and unprintable characters in the buffer
+ sequence are inserted to the resulting string as-is. No
+ character conversions are performed.
+
+ @param buffers The buffer sequence to convert
+
+ @par Example
+
+ This function writes a buffer sequence converted to a string
+ to `std::cout`.
+
+ @code
+ template<class ConstBufferSequence>
+ void print(ConstBufferSequence const& buffers)
+ {
+ std::cout << buffers_to_string(buffers) << std::endl;
+ }
+ @endcode
+*/
+template<class ConstBufferSequence>
+std::string
+buffers_to_string(ConstBufferSequence const& buffers)
+{
+ std::string result;
+ result.reserve(boost::asio::buffer_size(buffers));
+ for(boost::asio::const_buffer buffer :
+ detail::buffers_range(buffers))
+ result.append(reinterpret_cast<
+ char const*>(buffer.data()), buffer.size());
+ return result;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/allocator.hpp b/boost/beast/core/detail/allocator.hpp
new file mode 100644
index 0000000000..39b2aa5f12
--- /dev/null
+++ b/boost/beast/core/detail/allocator.hpp
@@ -0,0 +1,42 @@
+//
+// 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_ALLOCATOR_HPP
+#define BOOST_BEAST_DETAIL_ALLOCATOR_HPP
+
+#include <boost/config.hpp>
+#if BOOST_NO_CXX11_ALLOCATOR
+#include <boost/container/allocator_traits.hpp>
+#else
+#include <memory>
+#endif
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+// This is a workaround for allocator_traits
+// implementations which falsely claim C++11
+// compatibility.
+
+#if BOOST_NO_CXX11_ALLOCATOR
+template<class Alloc>
+using allocator_traits = boost::container::allocator_traits<Alloc>;
+
+#else
+template<class Alloc>
+using allocator_traits = std::allocator_traits<Alloc>;
+
+#endif
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/base64.hpp b/boost/beast/core/detail/base64.hpp
new file mode 100644
index 0000000000..ece03dfa34
--- /dev/null
+++ b/boost/beast/core/detail/base64.hpp
@@ -0,0 +1,251 @@
+//
+// 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
+//
+
+/*
+ Portions from http://www.adp-gmbh.ch/cpp/common/base64.html
+ Copyright notice:
+
+ base64.cpp and base64.h
+
+ Copyright (C) 2004-2008 René 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.
+
+ René Nyffenegger rene.nyffenegger@adp-gmbh.ch
+
+*/
+
+#ifndef BOOST_BEAST_DETAIL_BASE64_HPP
+#define BOOST_BEAST_DETAIL_BASE64_HPP
+
+#include <cctype>
+#include <string>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+namespace base64 {
+
+inline
+char const*
+get_alphabet()
+{
+ static char constexpr tab[] = {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+ };
+ return &tab[0];
+}
+
+inline
+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];
+}
+
+
+/// Returns max chars needed to encode a base64 string
+inline
+std::size_t constexpr
+encoded_size(std::size_t n)
+{
+ return 4 * ((n + 2) / 3);
+}
+
+/// Returns max bytes needed to decode a base64 string
+inline
+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.
+
+ 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.
+*/
+template<class = void>
+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.
+*/
+template<class = void>
+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
+
+template<class = void>
+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;
+}
+
+inline
+std::string
+base64_encode(std::string const& s)
+{
+ return base64_encode (reinterpret_cast <
+ std::uint8_t const*> (s.data()), s.size());
+}
+
+template<class = void>
+std::string
+base64_decode(std::string const& data)
+{
+ std::string dest;
+ dest.resize(base64::decoded_size(data.size()));
+ auto const result = base64::decode(
+ &dest[0], data.data(), data.size());
+ dest.resize(result.first);
+ return dest;
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/bind_handler.hpp b/boost/beast/core/detail/bind_handler.hpp
new file mode 100644
index 0000000000..5a9059b8e3
--- /dev/null
+++ b/boost/beast/core/detail/bind_handler.hpp
@@ -0,0 +1,189 @@
+//
+// 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_BIND_HANDLER_HPP
+#define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP
+
+#include <boost/beast/core/detail/integer_sequence.hpp>
+#include <boost/asio/associated_allocator.hpp>
+#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/core/ignore_unused.hpp>
+#include <functional>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+/* Nullary handler that calls Handler with bound arguments.
+
+ The bound handler provides the same io_context execution
+ guarantees as the original handler.
+*/
+template<class Handler, class... Args>
+class bound_handler
+{
+ // 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...>;
+
+ Handler h_;
+ args_type args_;
+
+ template<class Arg, class Vals>
+ static
+ typename std::enable_if<
+ std::is_placeholder<typename
+ std::decay<Arg>::type>::value == 0,
+ Arg&&>::type
+ extract(Arg&& arg, Vals& vals)
+ {
+ boost::ignore_unused(vals);
+ return arg;
+ }
+
+ template<class Arg, class Vals>
+ static
+ 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
+ extract(Arg&&, Vals&& vals)
+ {
+ return std::get<std::is_placeholder<
+ typename std::decay<Arg>::type>::value - 1>(
+ std::forward<Vals>(vals));
+ }
+
+ template<
+ class ArgsTuple,
+ std::size_t... S>
+ static
+ void
+ invoke(
+ Handler& h,
+ ArgsTuple& args,
+ std::tuple<>&&,
+ index_sequence<S...>)
+ {
+ boost::ignore_unused(args);
+ h(std::get<S>(args)...);
+ }
+
+ template<
+ class ArgsTuple,
+ class ValsTuple,
+ std::size_t... S>
+ static
+ void
+ invoke(
+ Handler& h,
+ ArgsTuple& args,
+ ValsTuple&& vals,
+ index_sequence<S...>)
+ {
+ boost::ignore_unused(args);
+ boost::ignore_unused(vals);
+ h(extract(std::get<S>(args),
+ std::forward<ValsTuple>(vals))...);
+ }
+
+public:
+ using result_type = void;
+
+ using allocator_type =
+ boost::asio::associated_allocator_t<Handler>;
+
+ bound_handler(bound_handler&&) = default;
+ bound_handler(bound_handler const&) = default;
+
+ template<class DeducedHandler>
+ explicit
+ bound_handler(
+ DeducedHandler&& handler, Args&&... args)
+ : h_(std::forward<DeducedHandler>(handler))
+ , args_(std::forward<Args>(args)...)
+ {
+ }
+
+ allocator_type
+ get_allocator() const noexcept
+ {
+ return boost::asio::get_associated_allocator(h_);
+ }
+
+ friend
+ bool
+ asio_handler_is_continuation(bound_handler* h)
+ {
+ using boost::asio::asio_handler_is_continuation;
+ return asio_handler_is_continuation(std::addressof(h->h_));
+ }
+
+ template<class... Values>
+ void
+ operator()(Values&&... values)
+ {
+ invoke(h_, args_,
+ std::forward_as_tuple(
+ std::forward<Values>(values)...),
+ index_sequence_for<Args...>());
+ }
+
+ template<class... Values>
+ void
+ operator()(Values&&... values) const
+ {
+ invoke(h_, args_,
+ std::forward_as_tuple(
+ std::forward<Values>(values)...),
+ index_sequence_for<Args...>());
+ }
+};
+
+} // detail
+} // beast
+
+namespace asio {
+template<class Handler, class... Args, class Executor>
+struct associated_executor<
+ beast::detail::bound_handler<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
+ {
+ return associated_executor<
+ Handler, Executor>::get(h.h_, ex);
+ }
+};
+} // asio
+
+} // boost
+
+namespace std {
+template<class Handler, class... Args>
+void
+bind(boost::beast::detail::bound_handler<
+ Handler, Args...>, ...) = delete;
+} // std
+
+#endif
diff --git a/boost/beast/core/detail/buffers_ref.hpp b/boost/beast/core/detail/buffers_ref.hpp
new file mode 100644
index 0000000000..e56a9764fd
--- /dev/null
+++ b/boost/beast/core/detail/buffers_ref.hpp
@@ -0,0 +1,67 @@
+//
+// 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_BUFFERS_REF_HPP
+#define BOOST_BEAST_DETAIL_BUFFERS_REF_HPP
+
+#include <boost/beast/core/type_traits.hpp>
+#include <iterator>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+// A very lightweight reference to a buffer sequence
+template<class BufferSequence>
+class buffers_ref
+{
+ BufferSequence const* buffers_;
+
+public:
+ using const_iterator = typename
+ buffer_sequence_iterator<BufferSequence>::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;
+
+ explicit
+ buffers_ref(BufferSequence const& buffers)
+ : buffers_(std::addressof(buffers))
+ {
+ }
+
+ const_iterator
+ begin() const
+ {
+ return boost::asio::buffer_sequence_begin(*buffers_);
+ }
+
+ const_iterator
+ end() const
+ {
+ return boost::asio::buffer_sequence_end(*buffers_);
+ }
+};
+
+// Return a reference to a buffer sequence
+template<class BufferSequence>
+buffers_ref<BufferSequence>
+make_buffers_ref(BufferSequence const& buffers)
+{
+ return buffers_ref<BufferSequence>(buffers);
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/clamp.hpp b/boost/beast/core/detail/clamp.hpp
new file mode 100644
index 0000000000..95a8fab425
--- /dev/null
+++ b/boost/beast/core/detail/clamp.hpp
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_CORE_DETAIL_CLAMP_HPP
+#define BOOST_BEAST_CORE_DETAIL_CLAMP_HPP
+
+#include <cstdlib>
+#include <limits>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<class UInt>
+static
+std::size_t
+clamp(UInt x)
+{
+ if(x >= (std::numeric_limits<std::size_t>::max)())
+ return (std::numeric_limits<std::size_t>::max)();
+ return static_cast<std::size_t>(x);
+}
+
+template<class UInt>
+static
+std::size_t
+clamp(UInt x, std::size_t limit)
+{
+ if(x >= limit)
+ return limit;
+ return static_cast<std::size_t>(x);
+}
+
+// return `true` if x + y > z, which are unsigned
+template<
+ class U1, class U2, class U3>
+constexpr
+bool
+sum_exceeds(U1 x, U2 y, U3 z)
+{
+ static_assert(
+ std::is_unsigned<U1>::value &&
+ std::is_unsigned<U2>::value &&
+ std::is_unsigned<U3>::value, "");
+ return y > z || x > z - y;
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/config.hpp b/boost/beast/core/detail/config.hpp
new file mode 100644
index 0000000000..48f97e377f
--- /dev/null
+++ b/boost/beast/core/detail/config.hpp
@@ -0,0 +1,57 @@
+//
+// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_CORE_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/core/ignore_unused.hpp>
+#include <boost/static_assert.hpp>
+
+/*
+ _MSC_VER and _MSC_FULL_VER by version:
+
+ 14.0 (2015) 1900 190023026
+ 14.0 (2015 Update 1) 1900 190023506
+ 14.0 (2015 Update 2) 1900 190023918
+ 14.0 (2015 Update 3) 1900 190024210
+*/
+
+#if defined(BOOST_MSVC)
+# if BOOST_MSVC_FULL_VER < 190024210
+# error Beast requires C++11: Visual Studio 2015 Update 3 or later needed
+# endif
+
+#elif defined(BOOST_GCC)
+# if(BOOST_GCC < 40801)
+# error Beast requires C++11: gcc version 4.8 or later needed
+# endif
+
+#else
+# if \
+ defined(BOOST_NO_CXX11_DECLTYPE) || \
+ defined(BOOST_NO_CXX11_HDR_TUPLE) || \
+ defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || \
+ defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
+# error Beast requires C++11: a conforming compiler is needed
+# endif
+
+#endif
+
+#if BOOST_VERSION >= 106500 || ! defined(BOOST_GCC) || BOOST_GCC < 70000
+# define BOOST_BEAST_FALLTHROUGH BOOST_FALLTHROUGH
+#else
+# define BOOST_BEAST_FALLTHROUGH __attribute__((fallthrough))
+#endif
+
+#endif
diff --git a/boost/beast/core/detail/cpu_info.hpp b/boost/beast/core/detail/cpu_info.hpp
new file mode 100644
index 0000000000..579589fa8e
--- /dev/null
+++ b/boost/beast/core/detail/cpu_info.hpp
@@ -0,0 +1,99 @@
+//
+// Copyright (c) 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_CPU_INFO_HPP
+#define BOOST_BEAST_DETAIL_CPU_INFO_HPP
+
+#include <boost/config.hpp>
+
+#ifndef BOOST_BEAST_NO_INTRINSICS
+# if defined(BOOST_MSVC) || ((defined(BOOST_GCC) || defined(BOOST_CLANG)) && defined(__SSE4_2__))
+# define BOOST_BEAST_NO_INTRINSICS 0
+# else
+# define BOOST_BEAST_NO_INTRINSICS 1
+# endif
+#endif
+
+#if ! BOOST_BEAST_NO_INTRINSICS
+
+#ifdef BOOST_MSVC
+#include <intrin.h> // __cpuid
+#else
+#include <cpuid.h> // __get_cpuid
+#endif
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+/* Portions from Boost,
+ Copyright Andrey Semashev 2007 - 2015.
+*/
+template<class = void>
+void
+cpuid(
+ std::uint32_t id,
+ std::uint32_t& eax,
+ std::uint32_t& ebx,
+ std::uint32_t& ecx,
+ std::uint32_t& edx)
+{
+#ifdef BOOST_MSVC
+ int regs[4];
+ __cpuid(regs, id);
+ eax = regs[0];
+ ebx = regs[1];
+ ecx = regs[2];
+ edx = regs[3];
+#else
+ __get_cpuid(id, &eax, &ebx, &ecx, &edx);
+#endif
+}
+
+struct cpu_info
+{
+ bool sse42 = false;
+
+ cpu_info();
+};
+
+inline
+cpu_info::
+cpu_info()
+{
+ constexpr std::uint32_t SSE42 = 1 << 20;
+
+ std::uint32_t eax = 0;
+ std::uint32_t ebx = 0;
+ std::uint32_t ecx = 0;
+ std::uint32_t edx = 0;
+
+ cpuid(0, eax, ebx, ecx, edx);
+ if(eax >= 1)
+ {
+ cpuid(1, eax, ebx, ecx, edx);
+ sse42 = (ecx & SSE42) != 0;
+ }
+}
+
+template<class = void>
+cpu_info const&
+get_cpu_info()
+{
+ static cpu_info const ci;
+ return ci;
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
+
+#endif
diff --git a/boost/beast/core/detail/empty_base_optimization.hpp b/boost/beast/core/detail/empty_base_optimization.hpp
new file mode 100644
index 0000000000..b1e728b674
--- /dev/null
+++ b/boost/beast/core/detail/empty_base_optimization.hpp
@@ -0,0 +1,100 @@
+//
+// 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_EMPTY_BASE_OPTIMIZATION_HPP
+#define BOOST_BEAST_DETAIL_EMPTY_BASE_OPTIMIZATION_HPP
+
+#include <boost/type_traits/is_final.hpp>
+#include <type_traits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<class T>
+struct is_empty_base_optimization_derived
+ : std::integral_constant<bool,
+ std::is_empty<T>::value &&
+ ! boost::is_final<T>::value>
+{
+};
+
+template<class T, int UniqueID = 0,
+ bool isDerived =
+ is_empty_base_optimization_derived<T>::value>
+class empty_base_optimization : private T
+{
+public:
+ empty_base_optimization() = default;
+ empty_base_optimization(empty_base_optimization&&) = default;
+ empty_base_optimization(empty_base_optimization const&) = default;
+ empty_base_optimization& operator=(empty_base_optimization&&) = default;
+ empty_base_optimization& operator=(empty_base_optimization const&) = default;
+
+ template<class Arg1, class... ArgN>
+ explicit
+ empty_base_optimization(Arg1&& arg1, ArgN&&... argn)
+ : T(std::forward<Arg1>(arg1),
+ std::forward<ArgN>(argn)...)
+ {
+ }
+
+ T& member() noexcept
+ {
+ return *this;
+ }
+
+ T const& member() const noexcept
+ {
+ return *this;
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template<
+ class T,
+ int UniqueID
+>
+class empty_base_optimization <T, UniqueID, false>
+{
+ T t_;
+
+public:
+ empty_base_optimization() = default;
+ empty_base_optimization(empty_base_optimization&&) = default;
+ empty_base_optimization(empty_base_optimization const&) = default;
+ empty_base_optimization& operator=(empty_base_optimization&&) = default;
+ empty_base_optimization& operator=(empty_base_optimization const&) = default;
+
+ template<class Arg1, class... ArgN>
+ explicit
+ empty_base_optimization(Arg1&& arg1, ArgN&&... argn)
+ : t_(std::forward<Arg1>(arg1),
+ std::forward<ArgN>(argn)...)
+ {
+ }
+
+ T& member() noexcept
+ {
+ return t_;
+ }
+
+ T const& member() const noexcept
+ {
+ return t_;
+ }
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/in_place_init.hpp b/boost/beast/core/detail/in_place_init.hpp
new file mode 100644
index 0000000000..d3a33becd5
--- /dev/null
+++ b/boost/beast/core/detail/in_place_init.hpp
@@ -0,0 +1,43 @@
+//
+// 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_IN_PLACE_INIT_HPP
+#define BOOST_BEAST_DETAIL_IN_PLACE_INIT_HPP
+
+#include <boost/version.hpp>
+#include <boost/optional/optional.hpp>
+
+// Provide boost::in_place_init_t and boost::in_place_init
+// for Boost versions earlier than 1.63.0.
+
+#if BOOST_VERSION < 106300
+
+namespace boost {
+
+namespace optional_ns {
+
+// a tag for in-place initialization of contained value
+struct in_place_init_t
+{
+ struct init_tag{};
+ explicit in_place_init_t(init_tag){}
+};
+const in_place_init_t in_place_init ((in_place_init_t::init_tag()));
+
+} // namespace optional_ns
+
+using optional_ns::in_place_init_t;
+using optional_ns::in_place_init;
+
+}
+
+#endif
+
+#endif
+
diff --git a/boost/beast/core/detail/integer_sequence.hpp b/boost/beast/core/detail/integer_sequence.hpp
new file mode 100644
index 0000000000..71664229af
--- /dev/null
+++ b/boost/beast/core/detail/integer_sequence.hpp
@@ -0,0 +1,143 @@
+//
+// 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/ostream.hpp b/boost/beast/core/detail/ostream.hpp
new file mode 100644
index 0000000000..8d6eb94f51
--- /dev/null
+++ b/boost/beast/core/detail/ostream.hpp
@@ -0,0 +1,319 @@
+//
+// 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_OSTREAM_HPP
+#define BOOST_BEAST_DETAIL_OSTREAM_HPP
+
+#include <boost/beast/core/buffers_prefix.hpp>
+#include <boost/beast/core/read_size.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/asio/buffer.hpp>
+#include <memory>
+#include <iosfwd>
+#include <streambuf>
+#include <type_traits>
+#include <utility>
+
+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(
+ reinterpret_cast<char const*>(b.data()),
+ b.size());
+ return os;
+}
+
+//------------------------------------------------------------------------------
+
+struct basic_streambuf_movable_helper :
+ std::basic_streambuf<char, std::char_traits<char>>
+{
+ basic_streambuf_movable_helper(
+ basic_streambuf_movable_helper&&) = default;
+};
+
+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>
+ : public std::basic_streambuf<CharT, Traits>
+{
+ using int_type = typename
+ std::basic_streambuf<CharT, Traits>::int_type;
+
+ using traits_type = typename
+ std::basic_streambuf<CharT, Traits>::traits_type;
+
+ static std::size_t constexpr max_size = 512;
+
+ DynamicBuffer& buf_;
+
+public:
+ ostream_buffer(ostream_buffer&&) = default;
+ ostream_buffer(ostream_buffer const&) = delete;
+
+ ~ostream_buffer() noexcept
+ {
+ sync();
+ }
+
+ explicit
+ ostream_buffer(DynamicBuffer& buf)
+ : buf_(buf)
+ {
+ 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;
+ }
+
+private:
+ void
+ prepare()
+ {
+ auto bs = buf_.prepare(
+ read_size_or_throw(buf_, max_size));
+ auto const b = buffers_front(bs);
+ auto const p = reinterpret_cast<CharT*>(b.data());
+ this->setp(p,
+ p + b.size() / sizeof(CharT) - 1);
+ }
+
+ void
+ flush(int extra = 0)
+ {
+ buf_.commit(
+ (this->pptr() - this->pbase() + extra) *
+ sizeof(CharT));
+ }
+};
+
+// 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
+
+template<class DynamicBuffer, class CharT, class Traits>
+class ostream_buffer
+ <DynamicBuffer, CharT, Traits, false>
+ : public std::basic_streambuf<CharT, Traits>
+{
+ using int_type = typename
+ std::basic_streambuf<CharT, Traits>::int_type;
+
+ using traits_type = typename
+ std::basic_streambuf<CharT, Traits>::traits_type;
+
+ static std::size_t constexpr max_size = 512;
+
+ DynamicBuffer& buf_;
+
+public:
+ ostream_buffer(ostream_buffer&&) = delete;
+ ostream_buffer(ostream_buffer const&) = delete;
+
+ ~ostream_buffer() noexcept
+ {
+ sync();
+ }
+
+ explicit
+ ostream_buffer(DynamicBuffer& buf)
+ : buf_(buf)
+ {
+ 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;
+ }
+
+private:
+ void
+ prepare()
+ {
+ auto bs = buf_.prepare(
+ read_size_or_throw(buf_, max_size));
+ auto const b = buffers_front(bs);
+ auto const p = reinterpret_cast<CharT*>(b.data());
+ this->setp(p,
+ p + b.size() / sizeof(CharT) - 1);
+ }
+
+ void
+ flush(int extra = 0)
+ {
+ buf_.commit(
+ (this->pptr() - this->pbase() + extra) *
+ sizeof(CharT));
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template<class DynamicBuffer,
+ class CharT, class Traits, bool isMovable>
+class ostream_helper;
+
+template<class DynamicBuffer, class CharT, class Traits>
+class ostream_helper<
+ DynamicBuffer, CharT, Traits, true>
+ : public std::basic_ostream<CharT, Traits>
+{
+ ostream_buffer<
+ DynamicBuffer, CharT, Traits, true> osb_;
+
+public:
+ explicit
+ ostream_helper(DynamicBuffer& buf);
+
+ 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)
+{
+}
+
+template<class DynamicBuffer, class CharT, class Traits>
+ostream_helper<DynamicBuffer, CharT, Traits, true>::
+ostream_helper(
+ ostream_helper&& other)
+ : std::basic_ostream<CharT, Traits>(&osb_)
+ , osb_(std::move(other.osb_))
+{
+}
+
+// This work-around is for libstdc++ versions that
+// don't have a movable std::basic_streambuf
+
+template<class T>
+class ostream_helper_base
+{
+protected:
+ std::unique_ptr<T> member;
+
+ ostream_helper_base(
+ ostream_helper_base&&) = default;
+
+ explicit
+ ostream_helper_base(T* t)
+ : member(t)
+ {
+ }
+};
+
+template<class DynamicBuffer, class CharT, class Traits>
+class ostream_helper<
+ DynamicBuffer, CharT, Traits, false>
+ : private ostream_helper_base<ostream_buffer<
+ DynamicBuffer, CharT, Traits, false>>
+ , public std::basic_ostream<CharT, Traits>
+{
+public:
+ explicit
+ ostream_helper(DynamicBuffer& buf)
+ : 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())
+ {
+ }
+
+ ostream_helper(ostream_helper&& other)
+ : ostream_helper_base<ostream_buffer<
+ DynamicBuffer, CharT, Traits, false>>(
+ std::move(other))
+ , std::basic_ostream<CharT, Traits>(this->member.get())
+ {
+ }
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/sha1.hpp b/boost/beast/core/detail/sha1.hpp
new file mode 100644
index 0000000000..336da2a0f2
--- /dev/null
+++ b/boost/beast/core/detail/sha1.hpp
@@ -0,0 +1,313 @@
+//
+// 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_SHA1_HPP
+#define BOOST_BEAST_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 {
+
+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
+{
+ static unsigned int constexpr block_size = sha1::BLOCK_BYTES;
+ static unsigned int constexpr digest_size = 20;
+
+ std::size_t buflen;
+ std::size_t blocks;
+ std::uint32_t digest[5];
+ std::uint8_t buf[block_size];
+};
+
+template<class = void>
+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;
+}
+
+template<class = void>
+void
+update(sha1_context& ctx,
+ void const* message, std::size_t size) noexcept
+{
+ auto p = reinterpret_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;
+ }
+}
+
+template<class = void>
+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 =
+ reinterpret_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_ostream.hpp b/boost/beast/core/detail/static_ostream.hpp
new file mode 100644
index 0000000000..cb5a00b3da
--- /dev/null
+++ b/boost/beast/core/detail/static_ostream.hpp
@@ -0,0 +1,142 @@
+//
+// 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_STATIC_OSTREAM_HPP
+#define BOOST_BEAST_DETAIL_STATIC_OSTREAM_HPP
+
+#include <locale>
+#include <ostream>
+#include <streambuf>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+// http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
+
+class static_ostream_buffer
+ : public std::basic_streambuf<char>
+{
+ using CharT = char;
+ using Traits = std::char_traits<CharT>;
+ using int_type = typename
+ std::basic_streambuf<CharT, Traits>::int_type;
+ using traits_type = typename
+ std::basic_streambuf<CharT, Traits>::traits_type;
+
+ char* data_;
+ std::size_t size_;
+ std::size_t len_ = 0;
+ std::string s_;
+
+public:
+ static_ostream_buffer(static_ostream_buffer&&) = delete;
+ static_ostream_buffer(static_ostream_buffer const&) = delete;
+
+ static_ostream_buffer(char* data, std::size_t size)
+ : data_(data)
+ , size_(size)
+ {
+ this->setp(data_, data_ + size - 1);
+ }
+
+ ~static_ostream_buffer() noexcept
+ {
+ }
+
+ string_view
+ str() const
+ {
+ if(! s_.empty())
+ return {s_.data(), len_};
+ return {data_, len_};
+ }
+
+ 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;
+ }
+
+private:
+ void
+ prepare()
+ {
+ static auto const growth_factor = 1.5;
+
+ if(len_ < size_ - 1)
+ {
+ this->setp(
+ data_ + len_, data_ + size_ - 2);
+ return;
+ }
+ if(s_.empty())
+ {
+ s_.resize(static_cast<std::size_t>(
+ growth_factor * len_));
+ Traits::copy(&s_[0], data_, len_);
+ }
+ else
+ {
+ s_.resize(static_cast<std::size_t>(
+ growth_factor * len_));
+ }
+ this->setp(&s_[len_], &s_[len_] +
+ s_.size() - len_ - 1);
+ }
+
+ void
+ flush(int extra = 0)
+ {
+ len_ += static_cast<std::size_t>(
+ this->pptr() - this->pbase() + extra);
+ }
+};
+
+class static_ostream : public std::basic_ostream<char>
+{
+ static_ostream_buffer osb_;
+
+public:
+ static_ostream(char* data, std::size_t size)
+ : std::basic_ostream<char>(&this->osb_)
+ , osb_(data, size)
+ {
+ imbue(std::locale::classic());
+ }
+
+ string_view
+ str() const
+ {
+ return osb_.str();
+ }
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/static_string.hpp b/boost/beast/core/detail/static_string.hpp
new file mode 100644
index 0000000000..a5384591ff
--- /dev/null
+++ b/boost/beast/core/detail/static_string.hpp
@@ -0,0 +1,135 @@
+//
+// 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_STATIC_STRING_HPP
+#define BOOST_BEAST_DETAIL_STATIC_STRING_HPP
+
+#include <boost/beast/core/string.hpp>
+#include <boost/assert.hpp>
+#include <iterator>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+// Because k-ballo said so
+template<class T>
+using is_input_iterator =
+ std::integral_constant<bool,
+ ! std::is_integral<T>::value>;
+
+template<class CharT, class Traits>
+int
+lexicographical_compare(
+ CharT const* s1, std::size_t n1,
+ CharT const* s2, std::size_t n2)
+{
+ if(n1 < n2)
+ return Traits::compare(
+ s1, s2, n1) <= 0 ? -1 : 1;
+ if(n1 > n2)
+ return Traits::compare(
+ s1, s2, n2) >= 0 ? 1 : -1;
+ return Traits::compare(s1, s2, n1);
+}
+
+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);
+}
+
+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>(
+ s1.data(), s1.size(), s2.data(), s2.size());
+}
+
+// Maximum number of characters in the decimal
+// representation of a binary number. This includes
+// the potential minus sign.
+//
+inline
+std::size_t constexpr
+max_digits(std::size_t bytes)
+{
+ return static_cast<std::size_t>(
+ bytes * 2.41) + 1 + 1;
+}
+
+template<class CharT, class Integer, class Traits>
+CharT*
+raw_to_string(
+ CharT* buf, Integer x, std::true_type)
+{
+ if(x == 0)
+ {
+ Traits::assign(*--buf, '0');
+ return buf;
+ }
+ if(x < 0)
+ {
+ x = -x;
+ for(;x > 0; x /= 10)
+ Traits::assign(*--buf ,
+ "0123456789"[x % 10]);
+ Traits::assign(*--buf, '-');
+ return buf;
+ }
+ for(;x > 0; x /= 10)
+ Traits::assign(*--buf ,
+ "0123456789"[x % 10]);
+ return buf;
+}
+
+template<class CharT, class Integer, class Traits>
+CharT*
+raw_to_string(
+ CharT* buf, Integer x, std::false_type)
+{
+ if(x == 0)
+ {
+ *--buf = '0';
+ return buf;
+ }
+ for(;x > 0; x /= 10)
+ Traits::assign(*--buf ,
+ "0123456789"[x % 10]);
+ return buf;
+}
+
+template<
+ class CharT,
+ class Integer,
+ class Traits = std::char_traits<CharT>>
+CharT*
+raw_to_string(CharT* last, std::size_t size, Integer i)
+{
+ boost::ignore_unused(size);
+ BOOST_ASSERT(size >= max_digits(sizeof(Integer)));
+ return raw_to_string<CharT, Integer, Traits>(
+ last, i, std::is_signed<Integer>{});
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/type_traits.hpp b/boost/beast/core/detail/type_traits.hpp
new file mode 100644
index 0000000000..06fbda291d
--- /dev/null
+++ b/boost/beast/core/detail/type_traits.hpp
@@ -0,0 +1,353 @@
+//
+// 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_TYPE_TRAITS_HPP
+#define BOOST_BEAST_DETAIL_TYPE_TRAITS_HPP
+
+#include <boost/beast/core/error.hpp>
+#include <boost/asio/buffer.hpp>
+#include <iterator>
+#include <tuple>
+#include <type_traits>
+#include <string>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+//
+// utilities
+//
+
+template<class... Ts>
+struct make_void
+{
+ using type = void;
+};
+
+template<class... Ts>
+using void_t = typename make_void<Ts...>::type;
+
+template<class T>
+inline
+void
+accept_rv(T){}
+
+template<class U>
+std::size_t constexpr
+max_sizeof()
+{
+ return sizeof(U);
+}
+
+template<class U0, class U1, class... Us>
+std::size_t constexpr
+max_sizeof()
+{
+ return
+ max_sizeof<U0>() > max_sizeof<U1, Us...>() ?
+ max_sizeof<U0>() : max_sizeof<U1, Us...>();
+}
+
+template<class U>
+std::size_t constexpr
+max_alignof()
+{
+ return alignof(U);
+}
+
+template<class U0, class U1, class... Us>
+std::size_t constexpr
+max_alignof()
+{
+ return
+ max_alignof<U0>() > max_alignof<U1, Us...>() ?
+ max_alignof<U0>() : max_alignof<U1, Us...>();
+}
+
+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 {};
+
+template<class T, class E>
+struct is_contiguous_container<T, E, void_t<
+ decltype(
+ std::declval<std::size_t&>() = std::declval<T const&>().size(),
+ std::declval<E*&>() = std::declval<T&>().data(),
+ (void)0),
+ typename std::enable_if<
+ std::is_same<
+ typename std::remove_cv<E>::type,
+ typename std::remove_cv<
+ typename std::remove_pointer<
+ decltype(std::declval<T&>().data())
+ >::type
+ >::type
+ >::value
+ >::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...);
+}
+
+//------------------------------------------------------------------------------
+
+//
+// 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<
+ std::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_adapter
+{
+ Buffers const& b_;
+
+public:
+ using value_type = typename std::conditional<
+ std::is_convertible<typename std::iterator_traits<
+ typename buffer_sequence_iterator<Buffers>::type>::value_type,
+ boost::asio::const_buffer>::value,
+ boost::asio::const_buffer,
+ boost::asio::mutable_buffer>::type;
+
+ /* VFALCO This isn't right, because range-for will pick up the iterator's
+ value_type which might not be const_buffer or mutable_buffer. We
+ need to declare our own iterator wrapper that converts the underlying
+ iterator's value_type to const_buffer or mutable_buffer so that
+ range-for sees one of those types.
+ */
+ using const_iterator = typename
+ buffer_sequence_iterator<Buffers>::type;
+
+ explicit
+ buffers_range_adapter(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_adapter<Buffers>
+buffers_range(Buffers const& buffers)
+{
+ return buffers_range_adapter<Buffers>{buffers};
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/variant.hpp b/boost/beast/core/detail/variant.hpp
new file mode 100644
index 0000000000..cba6ba63c0
--- /dev/null
+++ b/boost/beast/core/detail/variant.hpp
@@ -0,0 +1,195 @@
+//
+// 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_VARIANT_HPP
+#define BOOST_BEAST_DETAIL_VARIANT_HPP
+
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/assert.hpp>
+#include <cstddef>
+#include <tuple>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+// This simple variant gets the job done without
+// causing too much trouble with template depth:
+//
+// * Always allows an empty state I==0
+// * emplace() and get() support 1-based indexes only
+// * Basic exception guarantee
+// * Max 255 types
+//
+template<class... TN>
+class variant
+{
+ typename std::aligned_storage<
+ max_sizeof<TN...>(),
+ max_alignof<TN...>()
+ >::type buf_;
+ unsigned char i_ = 0;
+
+ template<std::size_t I>
+ using type = typename std::tuple_element<
+ I , std::tuple<TN...>>::type;
+
+ template<std::size_t I>
+ using C = std::integral_constant<std::size_t, I>;
+
+public:
+ variant() = default;
+
+ ~variant()
+ {
+ if(i_)
+ destroy(C<0>{});
+ }
+
+ // 0 = empty
+ unsigned char
+ index() const
+ {
+ return i_;
+ }
+
+ // moved-from object becomes empty
+ variant(variant&& other)
+ {
+ i_ = other.move(&buf_, C<0>{});
+ }
+
+ variant(variant const& other)
+ {
+ i_ = other.copy(&buf_, C<0>{});
+ }
+
+ // moved-from object becomes empty
+ variant& operator=(variant&& other)
+ {
+ if(i_ != 0)
+ destroy(C<0>{});
+ i_ = other.move(&buf_, C<0>{});
+ return *this;
+ }
+
+ variant& operator=(variant const& other)
+ {
+ if(i_ != 0)
+ destroy(C<0>{});
+ i_ = other.copy(&buf_, C<0>{});
+ return *this;
+ }
+
+ template<std::size_t I, class... Args>
+ void
+ emplace(Args&&... args)
+ {
+ if(i_ != 0)
+ destroy(C<0>{});
+ new(&buf_) type<I-1>(
+ std::forward<Args>(args)...);
+ i_ = I;
+ }
+
+ template<std::size_t I>
+ type<I-1>&
+ get()
+ {
+ BOOST_ASSERT(i_ == I);
+ return *reinterpret_cast<
+ type<I-1>*>(&buf_);
+ }
+
+ template<std::size_t I>
+ type<I-1> const&
+ get() const
+ {
+ BOOST_ASSERT(i_ == I);
+ return *reinterpret_cast<
+ type<I-1> const*>(&buf_);
+ }
+
+ void
+ reset()
+ {
+ if(i_ == 0)
+ return;
+ destroy(C<0>{});
+ }
+
+private:
+ void
+ destroy(C<sizeof...(TN)>)
+ {
+ return;
+ }
+
+ template<std::size_t I>
+ void
+ destroy(C<I>)
+ {
+ if(i_ == I+1)
+ {
+ using T = type<I>;
+ get<I+1>().~T();
+ i_ = 0;
+ return;
+ }
+ destroy(C<I+1>{});
+ }
+
+ unsigned char
+ move(void*, C<sizeof...(TN)>)
+ {
+ return 0;
+ }
+
+ template<std::size_t I>
+ unsigned char
+ move(void* dest, C<I>)
+ {
+ if(i_ == I+1)
+ {
+ using T = type<I>;
+ new(dest) T{std::move(get<I+1>())};
+ get<I+1>().~T();
+ i_ = 0;
+ return I+1;
+ }
+ return move(dest, C<I+1>{});
+ }
+
+ unsigned char
+ copy(void*, C<sizeof...(TN)>) const
+ {
+ return 0;
+ }
+
+ template<std::size_t I>
+ unsigned char
+ copy(void* dest, C<I>) const
+ {
+ if(i_ == I+1)
+ {
+ using T = type<I>;
+ auto const& t = get<I+1>();
+ new(dest) T{t};
+ return I+1;
+ }
+ return copy(dest, C<I+1>{});
+ }
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/detail/varint.hpp b/boost/beast/core/detail/varint.hpp
new file mode 100644
index 0000000000..37f0b9d1c1
--- /dev/null
+++ b/boost/beast/core/detail/varint.hpp
@@ -0,0 +1,79 @@
+//
+// Copyright (c) 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_VARINT_HPP
+#define BOOST_BEAST_DETAIL_VARINT_HPP
+
+#include <boost/static_assert.hpp>
+#include <cstdlib>
+#include <iterator>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+// https://developers.google.com/protocol-buffers/docs/encoding#varints
+
+inline
+std::size_t
+varint_size(std::size_t value)
+{
+ std::size_t n = 1;
+ while(value > 127)
+ {
+ ++n;
+ value /= 128;
+ }
+ return n;
+}
+
+template<class FwdIt>
+std::size_t
+varint_read(FwdIt& first)
+{
+ using value_type = typename
+ std::iterator_traits<FwdIt>::value_type;
+ BOOST_STATIC_ASSERT(
+ std::is_integral<value_type>::value &&
+ sizeof(value_type) == 1);
+ std::size_t value = 0;
+ std::size_t factor = 1;
+ while((*first & 0x80) != 0)
+ {
+ value += (*first++ & 0x7f) * factor;
+ factor *= 128;
+ }
+ value += *first++ * factor;
+ return value;
+}
+
+template<class FwdIt>
+void
+varint_write(FwdIt& first, std::size_t value)
+{
+ using value_type = typename
+ std::iterator_traits<FwdIt>::value_type;
+ BOOST_STATIC_ASSERT(
+ std::is_integral<value_type>::value &&
+ sizeof(value_type) == 1);
+ while(value > 127)
+ {
+ *first++ = static_cast<value_type>(
+ 0x80 | value);
+ value /= 128;
+ }
+ *first++ = static_cast<value_type>(value);
+}
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/error.hpp b/boost/beast/core/error.hpp
new file mode 100644
index 0000000000..f034f7a404
--- /dev/null
+++ b/boost/beast/core/error.hpp
@@ -0,0 +1,58 @@
+//
+// 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_ERROR_HPP
+#define BOOST_BEAST_ERROR_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+
+namespace boost {
+namespace beast {
+
+/// The type of error code used by the library
+using error_code = boost::system::error_code;
+
+/// The type of system error thrown by the library
+using system_error = boost::system::system_error;
+
+/// The type of error category used by the library
+using error_category = boost::system::error_category;
+
+/// A function to return the generic error category used by the library
+#if BOOST_BEAST_DOXYGEN
+error_category const&
+generic_category();
+#else
+using boost::system::generic_category;
+#endif
+
+/// A function to return the system error category used by the library
+#if BOOST_BEAST_DOXYGEN
+error_category const&
+system_category();
+#else
+using boost::system::system_category;
+#endif
+
+/// The type of error condition used by the library
+using error_condition = boost::system::error_condition;
+
+/// The set of constants used for cross-platform error codes
+#if BOOST_BEAST_DOXYGEN
+enum errc{};
+#else
+namespace errc = boost::system::errc;
+#endif
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/file.hpp b/boost/beast/core/file.hpp
new file mode 100644
index 0000000000..09c8e82081
--- /dev/null
+++ b/boost/beast/core/file.hpp
@@ -0,0 +1,45 @@
+//
+// Copyright (c) 2015-2016 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_FILE_HPP
+#define BOOST_BEAST_CORE_FILE_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/file_base.hpp>
+#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 {
+
+/** An implementation of File.
+
+ This alias is set to the best available implementation
+ of @b File given the platform and build settings.
+*/
+#if BOOST_BEAST_DOXYGEN
+struct file : file_stdio
+{
+};
+#else
+#if BOOST_BEAST_USE_WIN32_FILE
+using file = file_win32;
+#elif BOOST_BEAST_USE_POSIX_FILE
+using file = file_posix;
+#else
+using file = file_stdio;
+#endif
+#endif
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/file_base.hpp b/boost/beast/core/file_base.hpp
new file mode 100644
index 0000000000..c2b3c53a53
--- /dev/null
+++ b/boost/beast/core/file_base.hpp
@@ -0,0 +1,89 @@
+//
+// Copyright (c) 2015-2016 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_FILE_BASE_HPP
+#define BOOST_BEAST_CORE_FILE_BASE_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/string.hpp>
+
+namespace boost {
+namespace beast {
+
+/** File open modes
+
+ These modes are used when opening files using
+ instances of the @b File concept.
+
+ @see file_stdio
+*/
+enum class file_mode
+{
+ /// Random reading
+ read,
+
+ /// Sequential reading
+ scan,
+
+ /** Random writing to a new or truncated file
+
+ @li If the file does not exist, it is created.
+
+ @li If the file exists, it is truncated to
+ zero size upon opening.
+ */
+ write,
+
+ /** Random writing to new file only
+
+ If the file exists, an error is generated.
+ */
+ write_new,
+
+ /** Random writing to existing file
+
+ If the file does not exist, an error is generated.
+ */
+ write_existing,
+
+ /** Appending to a new or truncated file
+
+ The current file position shall be set to the end of
+ the file prior to each write.
+
+ @li If the file does not exist, it is created.
+
+ @li If the file exists, it is truncated to
+ zero size upon opening.
+ */
+ 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
+ the file prior to each write.
+
+ If the file does not exist, an error is generated.
+ */
+ append_existing
+};
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/file_posix.hpp b/boost/beast/core/file_posix.hpp
new file mode 100644
index 0000000000..65bac2065d
--- /dev/null
+++ b/boost/beast/core/file_posix.hpp
@@ -0,0 +1,175 @@
+//
+// Copyright (c) 2015-2016 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_FILE_POSIX_HPP
+#define BOOST_BEAST_CORE_FILE_POSIX_HPP
+
+#include <boost/config.hpp>
+
+#if ! defined(BOOST_BEAST_NO_POSIX_FILE)
+# if ! defined(__APPLE__) && ! defined(__linux__)
+# define BOOST_BEAST_NO_POSIX_FILE
+# endif
+#endif
+
+#if ! defined(BOOST_BEAST_USE_POSIX_FILE)
+# if ! defined(BOOST_BEAST_NO_POSIX_FILE)
+# define BOOST_BEAST_USE_POSIX_FILE 1
+# else
+# define BOOST_BEAST_USE_POSIX_FILE 0
+# endif
+#endif
+
+#if BOOST_BEAST_USE_POSIX_FILE
+
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/file_base.hpp>
+#include <cstdint>
+
+namespace boost {
+namespace beast {
+
+/** An implementation of File for POSIX systems.
+
+ This class implements a @b File using POSIX interfaces.
+*/
+class file_posix
+{
+ int fd_ = -1;
+
+public:
+ /** The type of the underlying file handle.
+
+ This is platform-specific.
+ */
+ using native_handle_type = int;
+
+ /** Destructor
+
+ If the file is open it is first closed.
+ */
+ ~file_posix();
+
+ /** Constructor
+
+ There is no open file initially.
+ */
+ file_posix() = default;
+
+ /** Constructor
+
+ The moved-from object behaves as if default constructed.
+ */
+ file_posix(file_posix&& other);
+
+ /** Assignment
+
+ The moved-from object behaves as if default constructed.
+ */
+ file_posix& operator=(file_posix&& other);
+
+ /// Returns the native handle associated with the file.
+ native_handle_type
+ native_handle() const
+ {
+ return fd_;
+ }
+
+ /** Set the native handle associated with the file.
+
+ If the file is open it is first closed.
+
+ @param fd The native file handle to assign.
+ */
+ void
+ native_handle(native_handle_type fd);
+
+ /// Returns `true` if the file is open
+ bool
+ is_open() const
+ {
+ return fd_ != -1;
+ }
+
+ /** Close the file if open
+
+ @param ec Set to the error, if any occurred.
+ */
+ void
+ close(error_code& ec);
+
+ /** Open a file at the given path with the specified mode
+
+ @param path The utf-8 encoded path to the file
+
+ @param mode The file mode to use
+
+ @param ec Set to the error, if any occurred
+ */
+ void
+ open(char const* path, file_mode mode, error_code& ec);
+
+ /** Return the size of the open file
+
+ @param ec Set to the error, if any occurred
+
+ @return The size in bytes
+ */
+ std::uint64_t
+ size(error_code& ec) const;
+
+ /** Return the current position in the open file
+
+ @param ec Set to the error, if any occurred
+
+ @return The offset in bytes from the beginning of the file
+ */
+ std::uint64_t
+ pos(error_code& ec) const;
+
+ /** Adjust the current position in the open file
+
+ @param offset The offset in bytes from the beginning of the file
+
+ @param ec Set to the error, if any occurred
+ */
+ void
+ seek(std::uint64_t offset, error_code& ec);
+
+ /** Read from the open file
+
+ @param buffer The buffer for storing the result of the read
+
+ @param n The number of bytes to read
+
+ @param ec Set to the error, if any occurred
+ */
+ std::size_t
+ read(void* buffer, std::size_t n, error_code& ec) const;
+
+ /** Write to the open file
+
+ @param buffer The buffer holding the data to write
+
+ @param n The number of bytes to write
+
+ @param ec Set to the error, if any occurred
+ */
+ std::size_t
+ write(void const* buffer, std::size_t n, error_code& ec);
+};
+
+} // beast
+} // boost
+
+#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
new file mode 100644
index 0000000000..09ca0c42de
--- /dev/null
+++ b/boost/beast/core/file_stdio.hpp
@@ -0,0 +1,158 @@
+//
+// Copyright (c) 2015-2016 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_FILE_STDIO_HPP
+#define BOOST_BEAST_CORE_FILE_STDIO_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/file_base.hpp>
+#include <cstdio>
+#include <cstdint>
+
+namespace boost {
+namespace beast {
+
+/** An implementation of File which uses cstdio.
+
+ This class implements a file using the interfaces present
+ in the C++ Standard Library, in `<stdio>`.
+*/
+class file_stdio
+{
+ FILE* f_ = nullptr;
+
+public:
+ /** The type of the underlying file handle.
+
+ This is platform-specific.
+ */
+ using native_handle_type = FILE*;
+
+ /** Destructor
+
+ If the file is open it is first closed.
+ */
+ ~file_stdio();
+
+ /** Constructor
+
+ There is no open file initially.
+ */
+ file_stdio() = default;
+
+ /** Constructor
+
+ The moved-from object behaves as if default constructed.
+ */
+ file_stdio(file_stdio&& other);
+
+ /** Assignment
+
+ The moved-from object behaves as if default constructed.
+ */
+ file_stdio& operator=(file_stdio&& other);
+
+ /// Returns the native handle associated with the file.
+ FILE*
+ native_handle() const
+ {
+ return f_;
+ }
+
+ /** Set the native handle associated with the file.
+
+ If the file is open it is first closed.
+
+ @param f The native file handle to assign.
+ */
+ void
+ native_handle(FILE* f);
+
+ /// Returns `true` if the file is open
+ bool
+ is_open() const
+ {
+ return f_ != nullptr;
+ }
+
+ /** Close the file if open
+
+ @param ec Set to the error, if any occurred.
+ */
+ void
+ close(error_code& ec);
+
+ /** Open a file at the given path with the specified mode
+
+ @param path The utf-8 encoded path to the file
+
+ @param mode The file mode to use
+
+ @param ec Set to the error, if any occurred
+ */
+ void
+ open(char const* path, file_mode mode, error_code& ec);
+
+ /** Return the size of the open file
+
+ @param ec Set to the error, if any occurred
+
+ @return The size in bytes
+ */
+ std::uint64_t
+ size(error_code& ec) const;
+
+ /** Return the current position in the open file
+
+ @param ec Set to the error, if any occurred
+
+ @return The offset in bytes from the beginning of the file
+ */
+ std::uint64_t
+ pos(error_code& ec) const;
+
+ /** Adjust the current position in the open file
+
+ @param offset The offset in bytes from the beginning of the file
+
+ @param ec Set to the error, if any occurred
+ */
+ void
+ seek(std::uint64_t offset, error_code& ec);
+
+ /** Read from the open file
+
+ @param buffer The buffer for storing the result of the read
+
+ @param n The number of bytes to read
+
+ @param ec Set to the error, if any occurred
+ */
+ std::size_t
+ read(void* buffer, std::size_t n, error_code& ec) const;
+
+ /** Write to the open file
+
+ @param buffer The buffer holding the data to write
+
+ @param n The number of bytes to write
+
+ @param ec Set to the error, if any occurred
+ */
+ std::size_t
+ write(void const* buffer, std::size_t n, error_code& ec);
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/file_stdio.ipp>
+
+#endif
diff --git a/boost/beast/core/file_win32.hpp b/boost/beast/core/file_win32.hpp
new file mode 100644
index 0000000000..3e9a18abaa
--- /dev/null
+++ b/boost/beast/core/file_win32.hpp
@@ -0,0 +1,177 @@
+//
+// Copyright (c) 2015-2016 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_FILE_WIN32_HPP
+#define BOOST_BEAST_CORE_FILE_WIN32_HPP
+
+#include <boost/config.hpp>
+
+#if ! defined(BOOST_BEAST_USE_WIN32_FILE)
+# ifdef BOOST_MSVC
+# define BOOST_BEAST_USE_WIN32_FILE 1
+# else
+# define BOOST_BEAST_USE_WIN32_FILE 0
+# endif
+#endif
+
+#if BOOST_BEAST_USE_WIN32_FILE
+
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/file_base.hpp>
+#include <boost/winapi/basic_types.hpp>
+#include <boost/winapi/handles.hpp>
+#include <cstdio>
+#include <cstdint>
+
+namespace boost {
+namespace beast {
+
+/** An implementation of File for Win32.
+
+ This class implements a @b File using Win32 native interfaces.
+*/
+class file_win32
+{
+ boost::winapi::HANDLE_ h_ =
+ boost::winapi::INVALID_HANDLE_VALUE_;
+
+public:
+ /** The type of the underlying file handle.
+
+ This is platform-specific.
+ */
+#if BOOST_BEAST_DOXYGEN
+ using native_handle_type = HANDLE;
+#else
+ using native_handle_type = boost::winapi::HANDLE_;
+#endif
+
+ /** Destructor
+
+ If the file is open it is first closed.
+ */
+ ~file_win32();
+
+ /** Constructor
+
+ There is no open file initially.
+ */
+ file_win32() = default;
+
+ /** Constructor
+
+ The moved-from object behaves as if default constructed.
+ */
+ file_win32(file_win32&& other);
+
+ /** Assignment
+
+ The moved-from object behaves as if default constructed.
+ */
+ file_win32& operator=(file_win32&& other);
+
+ /// Returns the native handle associated with the file.
+ native_handle_type
+ native_handle()
+ {
+ return h_;
+ }
+
+ /** Set the native handle associated with the file.
+
+ If the file is open it is first closed.
+
+ @param h The native file handle to assign.
+ */
+ void
+ native_handle(native_handle_type h);
+
+ /// Returns `true` if the file is open
+ bool
+ is_open() const
+ {
+ return h_ != boost::winapi::INVALID_HANDLE_VALUE_;
+ }
+
+ /** Close the file if open
+
+ @param ec Set to the error, if any occurred.
+ */
+ void
+ close(error_code& ec);
+
+ /** Open a file at the given path with the specified mode
+
+ @param path The utf-8 encoded path to the file
+
+ @param mode The file mode to use
+
+ @param ec Set to the error, if any occurred
+ */
+ void
+ open(char const* path, file_mode mode, error_code& ec);
+
+ /** Return the size of the open file
+
+ @param ec Set to the error, if any occurred
+
+ @return The size in bytes
+ */
+ std::uint64_t
+ size(error_code& ec) const;
+
+ /** Return the current position in the open file
+
+ @param ec Set to the error, if any occurred
+
+ @return The offset in bytes from the beginning of the file
+ */
+ std::uint64_t
+ pos(error_code& ec);
+
+ /** Adjust the current position in the open file
+
+ @param offset The offset in bytes from the beginning of the file
+
+ @param ec Set to the error, if any occurred
+ */
+ void
+ seek(std::uint64_t offset, error_code& ec);
+
+ /** Read from the open file
+
+ @param buffer The buffer for storing the result of the read
+
+ @param n The number of bytes to read
+
+ @param ec Set to the error, if any occurred
+ */
+ std::size_t
+ read(void* buffer, std::size_t n, error_code& ec);
+
+ /** Write to the open file
+
+ @param buffer The buffer holding the data to write
+
+ @param n The number of bytes to write
+
+ @param ec Set to the error, if any occurred
+ */
+ std::size_t
+ write(void const* buffer, std::size_t n, error_code& ec);
+};
+
+} // beast
+} // boost
+
+#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
new file mode 100644
index 0000000000..0ccd16bc64
--- /dev/null
+++ b/boost/beast/core/flat_buffer.hpp
@@ -0,0 +1,342 @@
+//
+// 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_FLAT_BUFFER_HPP
+#define BOOST_BEAST_FLAT_BUFFER_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/allocator.hpp>
+#include <boost/beast/core/detail/empty_base_optimization.hpp>
+#include <boost/asio/buffer.hpp>
+#include <limits>
+#include <memory>
+
+namespace boost {
+namespace beast {
+
+/** A linear dynamic buffer.
+
+ 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.
+
+ @li A configurable maximum buffer size may be set upon
+ construction. Attempts to exceed the buffer size will throw
+ `std::length_error`.
+
+ Upon construction, a maximum size for the buffer may be
+ specified. If this limit is exceeded, the `std::length_error`
+ exception will be thrown.
+
+ @note This class is designed for use with algorithms that
+ take dynamic buffers as parameters, and are optimized
+ for the case where the input sequence or output sequence
+ is stored in a single contiguous buffer.
+*/
+template<class Allocator>
+class basic_flat_buffer
+#if ! BOOST_BEAST_DOXYGEN
+ : private detail::empty_base_optimization<
+ typename detail::allocator_traits<Allocator>::
+ template rebind_alloc<char>>
+#endif
+{
+ enum
+ {
+ min_size = 512
+ };
+
+ template<class OtherAlloc>
+ friend class basic_flat_buffer;
+
+ using base_alloc_type = typename
+ detail::allocator_traits<Allocator>::
+ template rebind_alloc<char>;
+
+ using alloc_traits =
+ detail::allocator_traits<base_alloc_type>;
+
+ static
+ inline
+ std::size_t
+ dist(char const* first, char const* last)
+ {
+ return static_cast<std::size_t>(last - first);
+ }
+
+ char* begin_;
+ char* in_;
+ char* out_;
+ char* last_;
+ char* end_;
+ std::size_t max_;
+
+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::mutable_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.
+ */
+ basic_flat_buffer();
+
+ /** Constructor
+
+ Upon construction, capacity will be zero.
+
+ @param limit The setting for @ref max_size.
+ */
+ explicit
+ basic_flat_buffer(std::size_t limit);
+
+ /** Constructor
+
+ Upon construction, capacity will be zero.
+
+ @param alloc The allocator to construct with.
+ */
+ explicit
+ basic_flat_buffer(Allocator const& alloc);
+
+ /** Constructor
+
+ Upon construction, capacity will be zero.
+
+ @param limit The setting for @ref max_size.
+
+ @param alloc The allocator to use.
+ */
+ basic_flat_buffer(
+ std::size_t limit, Allocator const& alloc);
+
+ /** Constructor
+
+ After the move, `*this` will have an empty output sequence.
+
+ @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.
+ */
+ basic_flat_buffer(basic_flat_buffer&& other);
+
+ /** Constructor
+
+ After the move, `*this` will have an empty output sequence.
+
+ @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.
+
+ @param alloc The allocator to use.
+ */
+ basic_flat_buffer(
+ basic_flat_buffer&& other, Allocator const& alloc);
+
+ /** Constructor
+
+ @param other The object to copy from.
+ */
+ basic_flat_buffer(basic_flat_buffer const& other);
+
+ /** Constructor
+
+ @param other The object to copy from.
+
+ @param alloc The allocator to use.
+ */
+ basic_flat_buffer(basic_flat_buffer const& other,
+ Allocator const& alloc);
+
+ /** Constructor
+
+ @param other The object to copy from.
+ */
+ template<class OtherAlloc>
+ basic_flat_buffer(
+ basic_flat_buffer<OtherAlloc> const& other);
+
+ /** Constructor
+
+ @param other The object to copy from.
+
+ @param alloc The allocator to use.
+ */
+ template<class OtherAlloc>
+ basic_flat_buffer(
+ basic_flat_buffer<OtherAlloc> const& other,
+ Allocator const& alloc);
+
+ /** Assignment
+
+ After the move, `*this` will have an empty output sequence.
+
+ @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.
+ */
+ basic_flat_buffer&
+ operator=(basic_flat_buffer&& other);
+
+ /** Assignment
+
+ After the copy, `*this` will have an empty output sequence.
+
+ @param other The object to copy from.
+ */
+ basic_flat_buffer&
+ operator=(basic_flat_buffer const& other);
+
+ /** Copy assignment
+
+ After the copy, `*this` will have an empty output sequence.
+
+ @param other The object to copy from.
+ */
+ template<class OtherAlloc>
+ basic_flat_buffer&
+ operator=(basic_flat_buffer<OtherAlloc> const& other);
+
+ /// Returns a copy of the associated allocator.
+ allocator_type
+ get_allocator() const
+ {
+ return this->member();
+ }
+
+ /// Returns the size of the input sequence.
+ std::size_t
+ size() const
+ {
+ return dist(in_, out_);
+ }
+
+ /// Return the maximum sum of the input and output sequence sizes.
+ std::size_t
+ max_size() const
+ {
+ return max_;
+ }
+
+ /// Return the maximum sum of input and output sizes that can be held without an allocation.
+ std::size_t
+ capacity() const
+ {
+ return dist(begin_, end_);
+ }
+
+ /// Get a list of buffers that represent the input sequence.
+ const_buffers_type
+ data() const
+ {
+ 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()`.
+
+ @note All previous buffers sequences obtained from
+ calls to @ref data or @ref prepare are invalidated.
+ */
+ mutable_buffers_type
+ prepare(std::size_t n);
+
+ /** Move bytes from the output sequence to the input sequence.
+
+ @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.
+
+ @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_));
+ }
+
+ /** Remove bytes from the input sequence.
+
+ If `n` is greater than the number of bytes in the input
+ sequence, all bytes in the input sequence are removed.
+
+ @note All previous buffers sequences obtained from
+ calls to @ref data or @ref prepare are invalidated.
+ */
+ void
+ consume(std::size_t n);
+
+ /** Reallocate the buffer to fit the input sequence.
+
+ @note All previous buffers sequences obtained from
+ calls to @ref data or @ref prepare are invalidated.
+ */
+ void
+ shrink_to_fit();
+
+ /// Exchange two flat buffers
+ template<class Alloc>
+ friend
+ void
+ swap(
+ basic_flat_buffer<Alloc>& lhs,
+ basic_flat_buffer<Alloc>& rhs);
+
+private:
+ void
+ reset();
+
+ template<class DynamicBuffer>
+ void
+ copy_from(DynamicBuffer 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);
+};
+
+using flat_buffer =
+ basic_flat_buffer<std::allocator<char>>;
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/flat_buffer.ipp>
+
+#endif
diff --git a/boost/beast/core/flat_static_buffer.hpp b/boost/beast/core/flat_static_buffer.hpp
new file mode 100644
index 0000000000..141ae552c1
--- /dev/null
+++ b/boost/beast/core/flat_static_buffer.hpp
@@ -0,0 +1,254 @@
+//
+// 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_FLAT_STATIC_BUFFER_HPP
+#define BOOST_BEAST_FLAT_STATIC_BUFFER_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/asio/buffer.hpp>
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+
+namespace boost {
+namespace beast {
+
+/** A flat @b DynamicBuffer with 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.
+
+ @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.
+
+ When used with @ref flat_static_buffer this implements a dynamic
+ buffer using no memory allocations.
+
+ @see @ref flat_static_buffer
+*/
+class flat_static_buffer_base
+{
+ char* begin_;
+ char* in_;
+ char* out_;
+ 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;
+
+public:
+ /** The type used to represent the input sequence as a list of buffers.
+
+ This buffer sequence is guaranteed to have length 1.
+ */
+ using const_buffers_type = boost::asio::mutable_buffer;
+
+ /** The type used to represent the output sequence as a list of buffers.
+
+ This buffer sequence is guaranteed to have length 1.
+ */
+ using mutable_buffers_type = boost::asio::mutable_buffer;
+
+ /** Constructor
+
+ This creates a dynamic buffer using the provided storage area.
+
+ @param p A pointer to valid storage of at least `n` bytes.
+
+ @param n The number of valid bytes pointed to by `p`.
+ */
+ flat_static_buffer_base(void* p, std::size_t n)
+ {
+ reset_impl(p, n);
+ }
+
+ /// Return the size of the input sequence.
+ std::size_t
+ size() const
+ {
+ return out_ - in_;
+ }
+
+ /// Return the maximum sum of the input and output sequence sizes.
+ std::size_t
+ max_size() const
+ {
+ return dist(begin_, end_);
+ }
+
+ /// Return the maximum sum of input and output sizes that can be held without an allocation.
+ std::size_t
+ capacity() const
+ {
+ return max_size();
+ }
+
+ /** Get a list of buffers that represent the input sequence.
+
+ @note These buffers remain valid across subsequent calls to `prepare`.
+ */
+ const_buffers_type
+ data() const;
+
+ /// Set the input and output sequences to size 0
+ void
+ reset();
+
+ /** Get a list of buffers that represent 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)
+ {
+ out_ += (std::min<std::size_t>)(n, last_ - out_);
+ }
+
+ /// Remove bytes from the input sequence.
+ void
+ consume(std::size_t n)
+ {
+ consume_impl(n);
+ }
+
+protected:
+ /** Constructor
+
+ The buffer will be in an undefined state. It is necessary
+ for the derived class to call @ref reset with a pointer
+ and size in order to initialize the object.
+ */
+ flat_static_buffer_base() = default;
+
+ /** Reset the pointed-to buffer.
+
+ 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 p A pointer to valid storage of at least `n` bytes.
+
+ @param n The number of valid bytes pointed to by `p`.
+ */
+ void
+ reset(void* p, std::size_t n);
+
+private:
+ static
+ inline
+ std::size_t
+ dist(char const* first, char const* last)
+ {
+ 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.
+
+ Buffer sequences returned by @ref data and @ref prepare
+ will always be of length one.
+ This implements a dynamic buffer using no memory allocations.
+
+ @tparam N The number of bytes in the internal buffer.
+
+ @note To reduce the number of template instantiations when passing
+ 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
+*/
+template<std::size_t N>
+class flat_static_buffer : public flat_static_buffer_base
+{
+ char buf_[N];
+
+public:
+ /// Constructor
+ flat_static_buffer(flat_static_buffer const&);
+
+ /// Constructor
+ flat_static_buffer()
+ : flat_static_buffer_base(buf_, N)
+ {
+ }
+
+ /// Assignment
+ flat_static_buffer& operator=(flat_static_buffer const&);
+
+ /// Returns the @ref flat_static_buffer_base portion of this object
+ flat_static_buffer_base&
+ base()
+ {
+ return *this;
+ }
+
+ /// Returns the @ref flat_static_buffer_base portion of this object
+ flat_static_buffer_base const&
+ base() const
+ {
+ return *this;
+ }
+
+ /// Return the maximum sum of the input and output sequence sizes.
+ std::size_t constexpr
+ max_size() const
+ {
+ return N;
+ }
+
+ /// Return the maximum sum of input and output sizes that can be held without an allocation.
+ std::size_t constexpr
+ capacity() const
+ {
+ return N;
+ }
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/flat_static_buffer.ipp>
+
+#endif
diff --git a/boost/beast/core/handler_ptr.hpp b/boost/beast/core/handler_ptr.hpp
new file mode 100644
index 0000000000..f08a815c16
--- /dev/null
+++ b/boost/beast/core/handler_ptr.hpp
@@ -0,0 +1,213 @@
+//
+// 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_HANDLER_PTR_HPP
+#define BOOST_BEAST_HANDLER_PTR_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <atomic>
+#include <cstdint>
+#include <type_traits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+/** A smart pointer container with associated completion handler.
+
+ This is a smart pointer that retains shared ownership of an
+ object through a pointer. Memory is managed using the allocation
+ and deallocation functions associated with a completion handler,
+ which is also stored in the object. The managed object is
+ destroyed and its memory deallocated when one of the following
+ happens:
+
+ @li The function @ref invoke is called.
+
+ @li The function @ref release_handler is called.
+
+ @li The last remaining container owning the object is destroyed.
+
+ Objects of this type are used in the implementation of
+ composed operations. Typically the composed operation's shared
+ state is managed by the @ref handler_ptr and an allocator
+ associated with the final handler is used to create the managed
+ object.
+
+ @note The reference count is stored using a 16 bit unsigned
+ integer. Making more than 2^16 copies of one object results
+ in undefined behavior.
+
+ @tparam T The type of the owned object.
+
+ @tparam Handler The type of the completion handler.
+*/
+template<class T, class Handler>
+class handler_ptr
+{
+ struct P
+ {
+ T* t;
+ std::atomic<std::uint16_t> n;
+
+ // There's no way to put the handler anywhere else
+ // without exposing ourselves to race conditions
+ // and all sorts of ugliness.
+ // See:
+ // https://github.com/boostorg/beast/issues/215
+ Handler handler;
+
+ template<class DeducedHandler, class... Args>
+ P(DeducedHandler&& handler, Args&&... args);
+ };
+
+ P* p_;
+
+public:
+ /// The type of element this object stores
+ using element_type = T;
+
+ /// The type of handler this object stores
+ using handler_type = Handler;
+
+ /// Copy assignment (disallowed).
+ handler_ptr& operator=(handler_ptr const&) = delete;
+
+ /** Destructs the owned object if no more @ref handler_ptr link to it.
+
+ If `*this` owns an object and it is the last @ref handler_ptr
+ owning it, the object is destroyed and the memory deallocated
+ using the associated deallocator.
+ */
+ ~handler_ptr();
+
+ /** Move constructor.
+
+ When this call returns, the moved-from container
+ will have no owned object.
+ */
+ handler_ptr(handler_ptr&& other);
+
+ /// Copy constructor
+ handler_ptr(handler_ptr const& other);
+
+ /** Construct a new @ref handler_ptr
+
+ This creates a new @ref handler_ptr with an owned object
+ of type `T`. The allocator associated with the handler will
+ be used to allocate memory for the owned object. The constructor
+ for the owned object will be called thusly:
+
+ @code
+ T(handler, std::forward<Args>(args)...)
+ @endcode
+
+ @param handler The handler to associate with the owned
+ object. The argument will be moved.
+
+ @param args Optional arguments forwarded to
+ the owned object's constructor.
+ */
+ template<class... Args>
+ handler_ptr(Handler&& handler, Args&&... args);
+
+ /** Construct a new @ref handler_ptr
+
+ This creates a new @ref handler_ptr with an owned object
+ of type `T`. The allocator associated with the handler will
+ be used to allocate memory for the owned object. The constructor
+ for the owned object will be called thusly:
+
+ @code
+ T(handler, std::forward<Args>(args)...)
+ @endcode
+
+ @param handler The handler to associate with the owned
+ object. The argument will be copied.
+
+ @param args Optional arguments forwarded to
+ the owned object's constructor.
+ */
+ template<class... Args>
+ handler_ptr(Handler const& handler, Args&&... args);
+
+ /// Returns a reference to the handler
+ handler_type&
+ handler() const
+ {
+ return p_->handler;
+ }
+
+ /// Returns `true` if `*this` owns an object.
+ explicit
+ operator bool() const
+ {
+ return p_ && p_->t;
+ }
+
+ /** Returns a pointer to the owned object.
+
+ If `*this` owns an object, a pointer to the
+ object is returned, else `nullptr` is returned.
+ */
+ T*
+ get() const
+ {
+ return p_ ? p_->t : nullptr;
+ }
+
+ /// Return a reference to the owned object.
+ T&
+ operator*() const
+ {
+ return *p_->t;
+ }
+
+ /// Return a pointer to the owned object.
+ T*
+ operator->() const
+ {
+ return p_->t;
+ }
+
+ /** Release ownership of the handler
+
+ If `*this` owns an object, it is first destroyed.
+
+ @return The released handler.
+ */
+ handler_type
+ release_handler();
+
+ /** Invoke the handler in the owned object.
+
+ This function invokes the handler in the owned object
+ with a forwarded argument list. Before the invocation,
+ the owned object is destroyed, satisfying the
+ deallocation-before-invocation Asio guarantee. All
+ instances of @ref handler_ptr which refer to the
+ same owned object will be reset, including this instance.
+
+ @note Care must be taken when the arguments are themselves
+ stored in the owned object. Such arguments must first be
+ moved to the stack or elsewhere, and then passed, or else
+ undefined behavior will result.
+ */
+ template<class... Args>
+ void
+ invoke(Args&&... args);
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/handler_ptr.ipp>
+
+#endif
diff --git a/boost/beast/core/impl/buffered_read_stream.ipp b/boost/beast/core/impl/buffered_read_stream.ipp
new file mode 100644
index 0000000000..9e9fa53065
--- /dev/null
+++ b/boost/beast/core/impl/buffered_read_stream.ipp
@@ -0,0 +1,248 @@
+//
+// 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/handler_continuation_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
+{
+ int step_ = 0;
+ buffered_read_stream& s_;
+ MutableBufferSequence b_;
+ Handler h_;
+
+public:
+ read_some_op(read_some_op&&) = default;
+ read_some_op(read_some_op const&) = default;
+
+ template<class DeducedHandler, class... Args>
+ read_some_op(DeducedHandler&& h,
+ buffered_read_stream& s,
+ MutableBufferSequence const& b)
+ : s_(s)
+ , 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 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_BEAST_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::asio::async_completion<ReadHandler,
+ void(error_code, std::size_t)> init{handler};
+ read_some_op<MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
+ ReadHandler, void(error_code, std::size_t))>{
+ 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_adapter.ipp
new file mode 100644
index 0000000000..e16d2a9b32
--- /dev/null
+++ b/boost/beast/core/impl/buffers_adapter.ipp
@@ -0,0 +1,517 @@
+//
+// 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_ADAPTER_IPP
+#define BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP
+
+#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<class MutableBufferSequence>
+class buffers_adapter<MutableBufferSequence>::
+ const_buffers_type
+{
+ buffers_adapter const* ba_;
+
+public:
+ using value_type = boost::asio::mutable_buffer;
+
+ 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;
+
+private:
+ friend class buffers_adapter;
+
+ const_buffers_type(buffers_adapter const& ba)
+ : ba_(&ba)
+ {
+ }
+};
+
+template<class MutableBufferSequence>
+class buffers_adapter<MutableBufferSequence>::
+ const_buffers_type::const_iterator
+{
+ iter_type it_;
+ buffers_adapter const* ba_ = nullptr;
+
+public:
+ using value_type = boost::asio::const_buffer;
+ 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 ba_ == other.ba_ &&
+ it_ == other.it_;
+ }
+
+ bool
+ operator!=(const_iterator const& other) const
+ {
+ return !(*this == other);
+ }
+
+ reference
+ operator*() const
+ {
+ value_type const b = *it_;
+ return value_type{b.data(),
+ (ba_->out_ == boost::asio::buffer_sequence_end(ba_->bs_) ||
+ it_ != ba_->out_) ? b.size() : ba_->out_pos_} +
+ (it_ == ba_->begin_ ? ba_->in_pos_ : 0);
+ }
+
+ 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;
+ }
+
+private:
+ friend class const_buffers_type;
+
+ const_iterator(buffers_adapter const& ba,
+ iter_type iter)
+ : it_(iter)
+ , ba_(&ba)
+ {
+ }
+};
+
+template<class MutableBufferSequence>
+inline
+auto
+buffers_adapter<MutableBufferSequence>::const_buffers_type::begin() const ->
+ const_iterator
+{
+ return const_iterator{*ba_, ba_->begin_};
+}
+
+template<class MutableBufferSequence>
+inline
+auto
+buffers_adapter<MutableBufferSequence>::const_buffers_type::end() const ->
+ const_iterator
+{
+ return const_iterator{*ba_, ba_->out_ ==
+ ba_->end_ ? ba_->end_ : std::next(ba_->out_)};
+}
+
+//------------------------------------------------------------------------------
+
+template<class MutableBufferSequence>
+class buffers_adapter<MutableBufferSequence>::
+mutable_buffers_type
+{
+ buffers_adapter const* ba_;
+
+public:
+ using value_type = boost::asio::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;
+
+ const_iterator
+ end() const;
+
+private:
+ friend class buffers_adapter;
+
+ mutable_buffers_type(
+ buffers_adapter const& ba)
+ : ba_(&ba)
+ {
+ }
+};
+
+template<class MutableBufferSequence>
+class buffers_adapter<MutableBufferSequence>::
+mutable_buffers_type::const_iterator
+{
+ iter_type it_;
+ buffers_adapter const* ba_ = nullptr;
+
+public:
+ using value_type = boost::asio::mutable_buffer;
+ 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 ba_ == other.ba_ &&
+ it_ == other.it_;
+ }
+
+ bool
+ operator!=(const_iterator const& other) const
+ {
+ return !(*this == other);
+ }
+
+ reference
+ operator*() const
+ {
+ value_type const b = *it_;
+ return value_type{b.data(),
+ it_ == std::prev(ba_->end_) ?
+ ba_->out_end_ : b.size()} +
+ (it_ == ba_->out_ ? ba_->out_pos_ : 0);
+ }
+
+ 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;
+ }
+
+private:
+ friend class mutable_buffers_type;
+
+ const_iterator(buffers_adapter const& ba,
+ iter_type iter)
+ : it_(iter)
+ , ba_(&ba)
+ {
+ }
+};
+
+template<class MutableBufferSequence>
+inline
+auto
+buffers_adapter<MutableBufferSequence>::
+mutable_buffers_type::
+begin() const ->
+ const_iterator
+{
+ return const_iterator{*ba_, ba_->out_};
+}
+
+template<class MutableBufferSequence>
+inline
+auto
+buffers_adapter<MutableBufferSequence>::
+mutable_buffers_type::
+end() const ->
+ const_iterator
+{
+ return const_iterator{*ba_, ba_->end_};
+}
+
+//------------------------------------------------------------------------------
+
+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_))
+{
+}
+
+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_))
+{
+}
+
+template<class MutableBufferSequence>
+auto
+buffers_adapter<MutableBufferSequence>::operator=(
+ buffers_adapter&& other) -> buffers_adapter&
+{
+ 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&
+{
+ 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_ = 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>
+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_))
+{
+}
+
+template<class MutableBufferSequence>
+auto
+buffers_adapter<MutableBufferSequence>::prepare(std::size_t n) ->
+ mutable_buffers_type
+{
+ using boost::asio::buffer_size;
+ end_ = out_;
+ if(end_ != boost::asio::buffer_sequence_end(bs_))
+ {
+ auto size = buffer_size(*end_) - out_pos_;
+ if(n > size)
+ {
+ n -= size;
+ while(++end_ !=
+ boost::asio::buffer_sequence_end(bs_))
+ {
+ size = buffer_size(*end_);
+ if(n < size)
+ {
+ out_end_ = n;
+ n = 0;
+ ++end_;
+ break;
+ }
+ n -= size;
+ out_end_ = size;
+ }
+ }
+ else
+ {
+ ++end_;
+ out_end_ = out_pos_ + n;
+ n = 0;
+ }
+ }
+ if(n > 0)
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "buffer overflow"});
+ return mutable_buffers_type{*this};
+}
+
+template<class MutableBufferSequence>
+void
+buffers_adapter<MutableBufferSequence>::commit(std::size_t n)
+{
+ 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_;
+ if(n < avail)
+ {
+ out_pos_ += n;
+ in_size_ += n;
+ max_size_ -= n;
+ return;
+ }
+ ++out_;
+ n -= avail;
+ out_pos_ = 0;
+ in_size_ += avail;
+ max_size_ -= avail;
+ }
+
+ n = (std::min)(n, out_end_ - out_pos_);
+ out_pos_ += n;
+ in_size_ += n;
+ max_size_ -= n;
+ if(out_pos_ == buffer_size(*out_))
+ {
+ ++out_;
+ out_pos_ = 0;
+ out_end_ = 0;
+ }
+}
+
+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)
+{
+ using boost::asio::buffer_size;
+ while(begin_ != out_)
+ {
+ auto const avail =
+ buffer_size(*begin_) - in_pos_;
+ if(n < avail)
+ {
+ in_size_ -= n;
+ in_pos_ += n;
+ return;
+ }
+ n -= avail;
+ in_size_ -= avail;
+ in_pos_ = 0;
+ ++begin_;
+ }
+ auto const avail = out_pos_ - in_pos_;
+ if(n < avail)
+ {
+ in_size_ -= n;
+ in_pos_ += n;
+ }
+ else
+ {
+ in_size_ -= avail;
+ in_pos_ = out_pos_;
+ }
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/buffers_cat.ipp b/boost/beast/core/impl/buffers_cat.ipp
new file mode 100644
index 0000000000..d92d55233a
--- /dev/null
+++ b/boost/beast/core/impl/buffers_cat.ipp
@@ -0,0 +1,503 @@
+//
+// 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/asio/buffer.hpp>
+#include <boost/throw_exception.hpp>
+#include <array>
+#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
+{
+ std::size_t n_;
+ std::tuple<Bn...> const* bn_;
+ std::array<char, detail::max_sizeof<
+ typename detail::buffer_sequence_iterator<Bn>::type...>()> buf_;
+
+ friend class buffers_cat_view<Bn...>;
+
+ template<std::size_t I>
+ using C = std::integral_constant<std::size_t, I>;
+
+ template<std::size_t I>
+ using iter_t = typename detail::buffer_sequence_iterator<
+ typename std::tuple_element<I, std::tuple<Bn...>>::type>::type;
+
+ template<std::size_t I>
+ iter_t<I>&
+ iter()
+ {
+ // type-pun
+ return *reinterpret_cast<
+ iter_t<I>*>(static_cast<void*>(buf_.data()));
+ }
+
+ template<std::size_t I>
+ iter_t<I> const&
+ iter() const
+ {
+ // type-pun
+ return *reinterpret_cast<
+ iter_t<I> const*>(static_cast<
+ void const*>(buf_.data()));
+ }
+
+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();
+ const_iterator();
+ const_iterator(const_iterator&& other);
+ const_iterator(const_iterator const& other);
+ const_iterator& operator=(const_iterator&& other);
+ const_iterator& operator=(const_iterator const& other);
+
+ 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(
+ std::tuple<Bn...> const& bn, bool at_end);
+
+ void
+ construct(C<sizeof...(Bn)> const&)
+ {
+ auto constexpr I = sizeof...(Bn);
+ n_ = I;
+ }
+
+ template<std::size_t I>
+ void
+ construct(C<I> const&)
+ {
+ if(boost::asio::buffer_size(
+ std::get<I>(*bn_)) != 0)
+ {
+ n_ = I;
+ new(&buf_[0]) iter_t<I>{
+ boost::asio::buffer_sequence_begin(
+ std::get<I>(*bn_))};
+ return;
+ }
+ construct(C<I+1>{});
+ }
+
+ void
+ rconstruct(C<0> const&)
+ {
+ auto constexpr I = 0;
+ if(boost::asio::buffer_size(
+ std::get<I>(*bn_)) != 0)
+ {
+ n_ = I;
+ new(&buf_[0]) iter_t<I>{
+ boost::asio::buffer_sequence_end(
+ std::get<I>(*bn_))};
+ return;
+ }
+ BOOST_THROW_EXCEPTION(std::logic_error{
+ "invalid iterator"});
+ }
+
+ template<std::size_t I>
+ void
+ rconstruct(C<I> const&)
+ {
+ if(boost::asio::buffer_size(
+ std::get<I>(*bn_)) != 0)
+ {
+ n_ = I;
+ new(&buf_[0]) iter_t<I>{
+ boost::asio::buffer_sequence_end(
+ std::get<I>(*bn_))};
+ return;
+ }
+ rconstruct(C<I-1>{});
+ }
+
+ void
+ destroy(C<sizeof...(Bn)> const&)
+ {
+ return;
+ }
+
+ template<std::size_t I>
+ void
+ destroy(C<I> const&)
+ {
+ if(n_ == I)
+ {
+ using Iter = iter_t<I>;
+ iter<I>().~Iter();
+ return;
+ }
+ destroy(C<I+1>{});
+ }
+
+ void
+ move(const_iterator&&,
+ C<sizeof...(Bn)> const&)
+ {
+ }
+
+ template<std::size_t I>
+ void
+ move(const_iterator&& other,
+ C<I> const&)
+ {
+ if(n_ == I)
+ {
+ new(&buf_[0]) iter_t<I>{
+ std::move(other.iter<I>())};
+ return;
+ }
+ move(std::move(other), C<I+1>{});
+ }
+
+ void
+ copy(const_iterator const&,
+ C<sizeof...(Bn)> const&)
+ {
+ }
+
+ template<std::size_t I>
+ void
+ copy(const_iterator const& other,
+ C<I> const&)
+ {
+ if(n_ == I)
+ {
+ new(&buf_[0]) iter_t<I>{
+ other.iter<I>()};
+ return;
+ }
+ copy(other, C<I+1>{});
+ }
+
+ bool
+ equal(const_iterator const&,
+ C<sizeof...(Bn)> const&) const
+ {
+ return true;
+ }
+
+ template<std::size_t I>
+ bool
+ equal(const_iterator const& other,
+ C<I> const&) const
+ {
+ if(n_ == I)
+ return iter<I>() == other.iter<I>();
+ return equal(other, C<I+1>{});
+ }
+
+ [[noreturn]]
+ reference
+ dereference(C<sizeof...(Bn)> const&) const
+ {
+ BOOST_THROW_EXCEPTION(std::logic_error{
+ "invalid iterator"});
+ }
+
+ template<std::size_t I>
+ reference
+ dereference(C<I> const&) const
+ {
+ if(n_ == I)
+ return *iter<I>();
+ return dereference(C<I+1>{});
+ }
+
+ [[noreturn]]
+ void
+ increment(C<sizeof...(Bn)> const&)
+ {
+ BOOST_THROW_EXCEPTION(std::logic_error{
+ "invalid iterator"});
+ }
+
+ template<std::size_t I>
+ void
+ increment(C<I> const&)
+ {
+ if(n_ == I)
+ {
+ if(++iter<I>() !=
+ boost::asio::buffer_sequence_end(
+ std::get<I>(*bn_)))
+ return;
+ using Iter = iter_t<I>;
+ iter<I>().~Iter();
+ return construct(C<I+1>{});
+ }
+ increment(C<I+1>{});
+ }
+
+ void
+ decrement(C<sizeof...(Bn)> const&)
+ {
+ auto constexpr I = sizeof...(Bn);
+ if(n_ == I)
+ rconstruct(C<I-1>{});
+ decrement(C<I-1>{});
+ }
+
+ template<std::size_t I>
+ void
+ decrement(C<I> const&)
+ {
+ if(n_ == I)
+ {
+ if(iter<I>() !=
+ boost::asio::buffer_sequence_begin(
+ std::get<I>(*bn_)))
+ {
+ --iter<I>();
+ return;
+ }
+ --n_;
+ using Iter = iter_t<I>;
+ iter<I>().~Iter();
+ rconstruct(C<I-1>{});
+ }
+ decrement(C<I-1>{});
+ }
+
+ void
+ decrement(C<0> const&)
+ {
+ auto constexpr I = 0;
+ if(iter<I>() !=
+ boost::asio::buffer_sequence_begin(
+ std::get<I>(*bn_)))
+ {
+ --iter<I>();
+ return;
+ }
+ BOOST_THROW_EXCEPTION(std::logic_error{
+ "invalid iterator"});
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template<class... Bn>
+buffers_cat_view<Bn...>::
+const_iterator::~const_iterator()
+{
+ destroy(C<0>{});
+}
+
+template<class... Bn>
+buffers_cat_view<Bn...>::
+const_iterator::const_iterator()
+ : n_(sizeof...(Bn))
+ , bn_(nullptr)
+{
+}
+
+template<class... Bn>
+buffers_cat_view<Bn...>::
+const_iterator::const_iterator(
+ std::tuple<Bn...> const& bn, bool at_end)
+ : bn_(&bn)
+{
+ if(at_end)
+ n_ = sizeof...(Bn);
+ else
+ construct(C<0>{});
+}
+
+template<class... Bn>
+buffers_cat_view<Bn...>::
+const_iterator::const_iterator(const_iterator&& other)
+ : n_(other.n_)
+ , bn_(other.bn_)
+{
+ move(std::move(other), C<0>{});
+}
+
+template<class... Bn>
+buffers_cat_view<Bn...>::
+const_iterator::const_iterator(const_iterator const& other)
+ : n_(other.n_)
+ , bn_(other.bn_)
+{
+ copy(other, C<0>{});
+}
+
+template<class... Bn>
+auto
+buffers_cat_view<Bn...>::
+const_iterator::operator=(const_iterator&& other) ->
+ const_iterator&
+{
+ if(&other == this)
+ return *this;
+ destroy(C<0>{});
+ n_ = other.n_;
+ bn_ = other.bn_;
+ // VFALCO What about exceptions?
+ move(std::move(other), C<0>{});
+ return *this;
+}
+
+template<class... Bn>
+auto
+buffers_cat_view<Bn...>::
+const_iterator::operator=(const_iterator const& other) ->
+const_iterator&
+{
+ if(&other == this)
+ return *this;
+ destroy(C<0>{});
+ n_ = other.n_;
+ bn_ = other.bn_;
+ // VFALCO What about exceptions?
+ copy(other, C<0>{});
+ return *this;
+}
+
+template<class... Bn>
+bool
+buffers_cat_view<Bn...>::
+const_iterator::operator==(const_iterator const& other) const
+{
+ if(bn_ != other.bn_)
+ return false;
+ if(n_ != other.n_)
+ return false;
+ return equal(other, C<0>{});
+}
+
+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.ipp b/boost/beast/core/impl/buffers_prefix.ipp
new file mode 100644
index 0000000000..0bb92cc3ae
--- /dev/null
+++ b/boost/beast/core/impl/buffers_prefix.ipp
@@ -0,0 +1,258 @@
+//
+// 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<
+ 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 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_ == 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_(0)
+ , 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;
+ 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;
+ 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_;
+ 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_;
+ 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.ipp
new file mode 100644
index 0000000000..6356d63e0c
--- /dev/null
+++ b/boost/beast/core/impl/buffers_suffix.ipp
@@ -0,0 +1,249 @@
+//
+// 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_SUFFIX_IPP
+#define BOOST_BEAST_IMPL_BUFFERS_SUFFIX_IPP
+
+#include <boost/beast/core/type_traits.hpp>
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+template<class Buffers>
+class buffers_suffix<Buffers>::const_iterator
+{
+ friend class buffers_suffix<Buffers>;
+
+ using iter_type = typename
+ detail::buffer_sequence_iterator<Buffers>::type;
+
+ iter_type it_;
+ buffers_suffix const* b_ = nullptr;
+
+public:
+ 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 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_ == other.b_ && it_ == other.it_;
+ }
+
+ bool
+ operator!=(const_iterator const& other) const
+ {
+ return !(*this == other);
+ }
+
+ reference
+ operator*() const
+ {
+ return it_ == b_->begin_
+ ? value_type{*it_} + b_->skip_
+ : *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;
+ }
+
+private:
+ const_iterator(buffers_suffix const& b,
+ iter_type it)
+ : it_(it)
+ , b_(&b)
+ {
+ }
+};
+
+//------------------------------------------------------------------------------
+
+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_))
+{
+}
+
+template<class Buffers>
+buffers_suffix<Buffers>::
+buffers_suffix(buffers_suffix const& other)
+ : buffers_suffix(other,
+ std::distance<iter_type>(
+ boost::asio::buffer_sequence_begin(
+ other.bs_), other.begin_))
+{
+}
+
+template<class Buffers>
+buffers_suffix<Buffers>::
+buffers_suffix(Buffers const& bs)
+ : bs_(bs)
+ , begin_(boost::asio::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");
+}
+
+template<class Buffers>
+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_))
+{
+ static_assert(sizeof...(Args) > 0,
+ "Missing constructor arguments");
+ static_assert(
+ std::is_constructible<Buffers, Args...>::value,
+ "Buffers not constructible from arguments");
+}
+
+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_),
+ other.begin_);
+ bs_ = other.bs_;
+ begin_ = std::next(
+ boost::asio::buffer_sequence_begin(bs_), dist);
+ skip_ = other.skip_;
+ return *this;
+}
+
+template<class Buffers>
+inline
+auto
+buffers_suffix<Buffers>::
+begin() const ->
+ const_iterator
+{
+ return const_iterator{*this, begin_};
+}
+
+template<class Buffers>
+inline
+auto
+buffers_suffix<Buffers>::
+end() const ->
+ const_iterator
+{
+ return const_iterator{*this,
+ boost::asio::buffer_sequence_end(bs_)};
+}
+
+template<class Buffers>
+void
+buffers_suffix<Buffers>::
+consume(std::size_t amount)
+{
+ using boost::asio::buffer_size;
+ auto const end =
+ boost::asio::buffer_sequence_end(bs_);
+ for(;amount > 0 && begin_ != end; ++begin_)
+ {
+ auto const len =
+ buffer_size(*begin_) - skip_;
+ if(amount < len)
+ {
+ skip_ += amount;
+ break;
+ }
+ amount -= len;
+ skip_ = 0;
+ }
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/file_posix.ipp b/boost/beast/core/impl/file_posix.ipp
new file mode 100644
index 0000000000..96ccdc3bbe
--- /dev/null
+++ b/boost/beast/core/impl/file_posix.ipp
@@ -0,0 +1,349 @@
+//
+// Copyright (c) 2015-2016 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_FILE_POSIX_IPP
+#define BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
+
+#if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
+# if defined(__APPLE__) || (defined(ANDROID) && (__ANDROID_API__ < 21))
+# define BOOST_BEAST_NO_POSIX_FADVISE
+# endif
+#endif
+
+#if ! defined(BOOST_BEAST_USE_POSIX_FADVISE)
+# if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
+# define BOOST_BEAST_USE_POSIX_FADVISE 1
+# else
+# define BOOST_BEAST_USE_POSIX_FADVISE 0
+# endif
+#endif
+
+#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)
+{
+ for(;;)
+ {
+ if(! ::close(fd))
+ break;
+ int const ev = errno;
+ if(errno != EINTR)
+ return ev;
+ }
+ return 0;
+}
+
+} // detail
+
+inline
+file_posix::
+~file_posix()
+{
+ if(fd_ != -1)
+ detail::file_posix_close(fd_);
+}
+
+inline
+file_posix::
+file_posix(file_posix&& other)
+ : fd_(other.fd_)
+{
+ 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_);
+ 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_);
+ 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;
+ }
+ else
+ {
+ ec.assign(0, ec.category());
+ }
+}
+
+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;
+ }
+ int f = 0;
+#if BOOST_BEAST_USE_POSIX_FADVISE
+ int advise = 0;
+#endif
+ switch(mode)
+ {
+ default:
+ case file_mode::read:
+ f = O_RDONLY;
+ #if BOOST_BEAST_USE_POSIX_FADVISE
+ advise = POSIX_FADV_RANDOM;
+ #endif
+ break;
+ case file_mode::scan:
+ f = O_RDONLY;
+ #if BOOST_BEAST_USE_POSIX_FADVISE
+ advise = POSIX_FADV_SEQUENTIAL;
+ #endif
+ break;
+
+ case file_mode::write:
+ f = O_RDWR | O_CREAT | O_TRUNC;
+ #if BOOST_BEAST_USE_POSIX_FADVISE
+ advise = POSIX_FADV_RANDOM;
+ #endif
+ break;
+
+ case file_mode::write_new:
+ f = O_RDWR | O_CREAT | O_EXCL;
+ #if BOOST_BEAST_USE_POSIX_FADVISE
+ advise = POSIX_FADV_RANDOM;
+ #endif
+ break;
+
+ case file_mode::write_existing:
+ f = O_RDWR | O_EXCL;
+ #if BOOST_BEAST_USE_POSIX_FADVISE
+ advise = POSIX_FADV_RANDOM;
+ #endif
+ 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;
+ #if BOOST_BEAST_USE_POSIX_FADVISE
+ advise = POSIX_FADV_SEQUENTIAL;
+ #endif
+ break;
+
+ case file_mode::append_existing:
+ f = O_RDWR | O_EXCL;
+ #if BOOST_BEAST_USE_POSIX_FADVISE
+ advise = POSIX_FADV_SEQUENTIAL;
+ #endif
+ break;
+ }
+ for(;;)
+ {
+ fd_ = ::open(path, f, 0644);
+ if(fd_ != -1)
+ break;
+ auto const ev = errno;
+ if(ev != EINTR)
+ {
+ ec.assign(ev, generic_category());
+ return;
+ }
+ }
+#if BOOST_BEAST_USE_POSIX_FADVISE
+ if(::posix_fadvise(fd_, 0, 0, advise))
+ {
+ auto const ev = errno;
+ detail::file_posix_close(fd_);
+ fd_ = -1;
+ ec.assign(ev, generic_category());
+ return;
+ }
+#endif
+ ec.assign(0, ec.category());
+}
+
+inline
+std::uint64_t
+file_posix::
+size(error_code& ec) const
+{
+ if(fd_ == -1)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ struct stat st;
+ if(::fstat(fd_, &st) != 0)
+ {
+ ec.assign(errno, generic_category());
+ return 0;
+ }
+ ec.assign(0, ec.category());
+ return st.st_size;
+}
+
+inline
+std::uint64_t
+file_posix::
+pos(error_code& ec) const
+{
+ if(fd_ == -1)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ auto const result = ::lseek(fd_, 0, SEEK_CUR);
+ if(result == (off_t)-1)
+ {
+ ec.assign(errno, generic_category());
+ return 0;
+ }
+ ec.assign(0, ec.category());
+ return result;
+}
+
+inline
+void
+file_posix::
+seek(std::uint64_t offset, error_code& ec)
+{
+ if(fd_ == -1)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return;
+ }
+ auto const result = ::lseek(fd_, offset, SEEK_SET);
+ if(result == static_cast<off_t>(-1))
+ {
+ ec.assign(errno, generic_category());
+ return;
+ }
+ ec.assign(0, ec.category());
+}
+
+inline
+std::size_t
+file_posix::
+read(void* buffer, std::size_t n, error_code& ec) const
+{
+ if(fd_ == -1)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ std::size_t nread = 0;
+ while(n > 0)
+ {
+ auto const amount = static_cast<ssize_t>((std::min)(
+ n, static_cast<std::size_t>(SSIZE_MAX)));
+ auto const result = ::read(fd_, buffer, amount);
+ if(result == -1)
+ {
+ auto const ev = errno;
+ if(ev == EINTR)
+ continue;
+ ec.assign(ev, generic_category());
+ return nread;
+ }
+ if(result == 0)
+ {
+ // short read
+ return nread;
+ }
+ n -= result;
+ nread += result;
+ buffer = reinterpret_cast<char*>(buffer) + result;
+ }
+ return nread;
+}
+
+inline
+std::size_t
+file_posix::
+write(void const* buffer, std::size_t n, error_code& ec)
+{
+ if(fd_ == -1)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ std::size_t nwritten = 0;
+ while(n > 0)
+ {
+ auto const amount = static_cast<ssize_t>((std::min)(
+ n, static_cast<std::size_t>(SSIZE_MAX)));
+ auto const result = ::write(fd_, buffer, amount);
+ if(result == -1)
+ {
+ auto const ev = errno;
+ if(ev == EINTR)
+ continue;
+ ec.assign(ev, generic_category());
+ return nwritten;
+ }
+ n -= result;
+ nwritten += result;
+ buffer = reinterpret_cast<char const*>(buffer) + result;
+ }
+ return nwritten;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/file_stdio.ipp b/boost/beast/core/impl/file_stdio.ipp
new file mode 100644
index 0000000000..ca5cb0cbde
--- /dev/null
+++ b/boost/beast/core/impl/file_stdio.ipp
@@ -0,0 +1,239 @@
+//
+// Copyright (c) 2015-2016 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_FILE_STDIO_IPP
+#define BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
+
+#include <limits>
+
+namespace boost {
+namespace beast {
+
+inline
+file_stdio::
+~file_stdio()
+{
+ if(f_)
+ fclose(f_);
+}
+
+inline
+file_stdio::
+file_stdio(file_stdio&& other)
+ : f_(other.f_)
+{
+ other.f_ = nullptr;
+}
+
+inline
+file_stdio&
+file_stdio::
+operator=(file_stdio&& other)
+{
+ if(&other == this)
+ return *this;
+ if(f_)
+ fclose(f_);
+ f_ = other.f_;
+ other.f_ = nullptr;
+ return *this;
+}
+
+inline
+void
+file_stdio::
+native_handle(FILE* f)
+{
+ if(f_)
+ fclose(f_);
+ f_ = f;
+}
+
+inline
+void
+file_stdio::
+close(error_code& ec)
+{
+ if(f_)
+ {
+ int failed = fclose(f_);
+ f_ = nullptr;
+ if(failed)
+ {
+ ec.assign(errno, generic_category());
+ return;
+ }
+ }
+ ec.assign(0, ec.category());
+}
+
+inline
+void
+file_stdio::
+open(char const* path, file_mode mode, error_code& ec)
+{
+ if(f_)
+ {
+ fclose(f_);
+ f_ = nullptr;
+ }
+ char const* s;
+ 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);
+ if(ev)
+ {
+ f_ = nullptr;
+ ec.assign(ev, generic_category());
+ return;
+ }
+#else
+ f_ = std::fopen(path, s);
+ if(! f_)
+ {
+ ec.assign(errno, generic_category());
+ return;
+ }
+#endif
+ ec.assign(0, ec.category());
+}
+
+inline
+std::uint64_t
+file_stdio::
+size(error_code& ec) const
+{
+ if(! f_)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ long pos = std::ftell(f_);
+ if(pos == -1L)
+ {
+ ec.assign(errno, generic_category());
+ return 0;
+ }
+ int result = std::fseek(f_, 0, SEEK_END);
+ if(result != 0)
+ {
+ ec.assign(errno, generic_category());
+ return 0;
+ }
+ long size = std::ftell(f_);
+ if(size == -1L)
+ {
+ ec.assign(errno, generic_category());
+ std::fseek(f_, pos, SEEK_SET);
+ return 0;
+ }
+ result = std::fseek(f_, pos, SEEK_SET);
+ if(result != 0)
+ ec.assign(errno, generic_category());
+ else
+ ec.assign(0, ec.category());
+ return size;
+}
+
+inline
+std::uint64_t
+file_stdio::
+pos(error_code& ec) const
+{
+ if(! f_)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ long pos = std::ftell(f_);
+ if(pos == -1L)
+ {
+ ec.assign(errno, generic_category());
+ return 0;
+ }
+ ec.assign(0, ec.category());
+ return pos;
+}
+
+inline
+void
+file_stdio::
+seek(std::uint64_t offset, error_code& ec)
+{
+ if(! f_)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return;
+ }
+ if(offset > (std::numeric_limits<long>::max)())
+ {
+ ec = make_error_code(errc::invalid_seek);
+ return;
+ }
+ int result = std::fseek(f_,
+ static_cast<long>(offset), SEEK_SET);
+ if(result != 0)
+ ec.assign(errno, generic_category());
+ else
+ ec.assign(0, ec.category());
+}
+
+inline
+std::size_t
+file_stdio::
+read(void* buffer, std::size_t n, error_code& ec) const
+{
+ if(! f_)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ auto nread = std::fread(buffer, 1, n, f_);
+ if(std::ferror(f_))
+ {
+ ec.assign(errno, generic_category());
+ return 0;
+ }
+ return nread;
+}
+
+inline
+std::size_t
+file_stdio::
+write(void const* buffer, std::size_t n, error_code& ec)
+{
+ if(! f_)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ auto nwritten = std::fwrite(buffer, 1, n, f_);
+ if(std::ferror(f_))
+ {
+ ec.assign(errno, generic_category());
+ return 0;
+ }
+ return nwritten;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/file_win32.ipp b/boost/beast/core/impl/file_win32.ipp
new file mode 100644
index 0000000000..de4abae41f
--- /dev/null
+++ b/boost/beast/core/impl/file_win32.ipp
@@ -0,0 +1,364 @@
+//
+// Copyright (c) 2015-2016 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_FILE_WIN32_IPP
+#define BOOST_BEAST_CORE_IMPL_FILE_WIN32_IPP
+
+#include <boost/winapi/access_rights.hpp>
+#include <boost/winapi/error_codes.hpp>
+#include <boost/winapi/file_management.hpp>
+#include <boost/winapi/get_last_error.hpp>
+#include <limits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+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::winapi::BOOL_
+set_file_pointer_ex(
+ boost::winapi::HANDLE_ hFile,
+ boost::winapi::LARGE_INTEGER_ lpDistanceToMove,
+ boost::winapi::PLARGE_INTEGER_ lpNewFilePointer,
+ boost::winapi::DWORD_ dwMoveMethod)
+{
+ auto dwHighPart = lpDistanceToMove.u.HighPart;
+ auto dwLowPart = boost::winapi::SetFilePointer(
+ hFile,
+ lpDistanceToMove.u.LowPart,
+ &dwHighPart,
+ dwMoveMethod);
+ if(dwLowPart == boost::winapi::INVALID_SET_FILE_POINTER_)
+ return 0;
+ if(lpNewFilePointer)
+ {
+ lpNewFilePointer->u.LowPart = dwLowPart;
+ lpNewFilePointer->u.HighPart = dwHighPart;
+ }
+ return 1;
+}
+
+} // detail
+
+inline
+file_win32::
+~file_win32()
+{
+ if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
+ boost::winapi::CloseHandle(h_);
+}
+
+inline
+file_win32::
+file_win32(file_win32&& other)
+ : h_(other.h_)
+{
+ other.h_ = boost::winapi::INVALID_HANDLE_VALUE_;
+}
+
+inline
+file_win32&
+file_win32::
+operator=(file_win32&& other)
+{
+ if(&other == this)
+ return *this;
+ if(h_)
+ boost::winapi::CloseHandle(h_);
+ h_ = other.h_;
+ other.h_ = boost::winapi::INVALID_HANDLE_VALUE_;
+ return *this;
+}
+
+inline
+void
+file_win32::
+native_handle(native_handle_type h)
+{
+ if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
+ boost::winapi::CloseHandle(h_);
+ h_ = h;
+}
+
+inline
+void
+file_win32::
+close(error_code& ec)
+{
+ if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
+ {
+ if(! boost::winapi::CloseHandle(h_))
+ ec.assign(boost::winapi::GetLastError(),
+ system_category());
+ else
+ ec.assign(0, ec.category());
+ h_ = boost::winapi::INVALID_HANDLE_VALUE_;
+ }
+ else
+ {
+ ec.assign(0, ec.category());
+ }
+}
+
+inline
+void
+file_win32::
+open(char const* path, file_mode mode, error_code& ec)
+{
+ if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
+ {
+ boost::winapi::CloseHandle(h_);
+ h_ = boost::winapi::INVALID_HANDLE_VALUE_;
+ }
+ boost::winapi::DWORD_ share_mode = 0;
+ boost::winapi::DWORD_ desired_access = 0;
+ boost::winapi::DWORD_ creation_disposition = 0;
+ boost::winapi::DWORD_ flags_and_attributes = 0;
+/*
+ | When the file...
+ This argument: | Exists Does not exist
+ -------------------------+------------------------------------------------------
+ CREATE_ALWAYS | Truncates Creates
+ CREATE_NEW +-----------+ Fails Creates
+ OPEN_ALWAYS ===| does this |===> Opens Creates
+ OPEN_EXISTING +-----------+ Opens Fails
+ TRUNCATE_EXISTING | Truncates Fails
+*/
+ switch(mode)
+ {
+ default:
+ case file_mode::read:
+ desired_access = boost::winapi::GENERIC_READ_;
+ share_mode = boost::winapi::FILE_SHARE_READ_;
+ creation_disposition = boost::winapi::OPEN_EXISTING_;
+ flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
+ break;
+
+ case file_mode::scan:
+ desired_access = boost::winapi::GENERIC_READ_;
+ share_mode = boost::winapi::FILE_SHARE_READ_;
+ creation_disposition = boost::winapi::OPEN_EXISTING_;
+ flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
+ break;
+
+ case file_mode::write:
+ desired_access = boost::winapi::GENERIC_READ_ |
+ boost::winapi::GENERIC_WRITE_;
+ creation_disposition = boost::winapi::CREATE_ALWAYS_;
+ flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
+ break;
+
+ case file_mode::write_new:
+ desired_access = boost::winapi::GENERIC_READ_ |
+ boost::winapi::GENERIC_WRITE_;
+ creation_disposition = boost::winapi::CREATE_NEW_;
+ flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
+ break;
+
+ case file_mode::write_existing:
+ desired_access = boost::winapi::GENERIC_READ_ |
+ boost::winapi::GENERIC_WRITE_;
+ creation_disposition = boost::winapi::OPEN_EXISTING_;
+ flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
+ break;
+
+ case file_mode::append:
+ desired_access = boost::winapi::GENERIC_READ_ |
+ boost::winapi::GENERIC_WRITE_;
+
+ creation_disposition = boost::winapi::CREATE_ALWAYS_;
+ 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_;
+ creation_disposition = boost::winapi::OPEN_EXISTING_;
+ flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
+ break;
+ }
+ h_ = ::CreateFileA(
+ path,
+ desired_access,
+ share_mode,
+ NULL,
+ creation_disposition,
+ flags_and_attributes,
+ NULL);
+ if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
+ ec.assign(boost::winapi::GetLastError(),
+ system_category());
+ else
+ ec.assign(0, ec.category());
+}
+
+inline
+std::uint64_t
+file_win32::
+size(error_code& ec) const
+{
+ if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ boost::winapi::LARGE_INTEGER_ fileSize;
+ if(! boost::winapi::GetFileSizeEx(h_, &fileSize))
+ {
+ ec.assign(boost::winapi::GetLastError(),
+ system_category());
+ return 0;
+ }
+ ec.assign(0, ec.category());
+ return fileSize.QuadPart;
+}
+
+inline
+std::uint64_t
+file_win32::
+pos(error_code& ec)
+{
+ if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ boost::winapi::LARGE_INTEGER_ in;
+ boost::winapi::LARGE_INTEGER_ out;
+ in.QuadPart = 0;
+ if(! detail::set_file_pointer_ex(h_, in, &out,
+ boost::winapi::FILE_CURRENT_))
+ {
+ ec.assign(boost::winapi::GetLastError(),
+ system_category());
+ return 0;
+ }
+ ec.assign(0, ec.category());
+ return out.QuadPart;
+}
+
+inline
+void
+file_win32::
+seek(std::uint64_t offset, error_code& ec)
+{
+ if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return;
+ }
+ boost::winapi::LARGE_INTEGER_ in;
+ in.QuadPart = offset;
+ if(! detail::set_file_pointer_ex(h_, in, 0,
+ boost::winapi::FILE_BEGIN_))
+ {
+ ec.assign(boost::winapi::GetLastError(),
+ system_category());
+ return;
+ }
+ ec.assign(0, ec.category());
+}
+
+inline
+std::size_t
+file_win32::
+read(void* buffer, std::size_t n, error_code& ec)
+{
+ if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
+ {
+ ec.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ std::size_t nread = 0;
+ while(n > 0)
+ {
+ boost::winapi::DWORD_ amount;
+ if(n > (std::numeric_limits<
+ boost::winapi::DWORD_>::max)())
+ amount = (std::numeric_limits<
+ boost::winapi::DWORD_>::max)();
+ else
+ amount = static_cast<
+ boost::winapi::DWORD_>(n);
+ boost::winapi::DWORD_ bytesRead;
+ if(! ::ReadFile(h_, buffer, amount, &bytesRead, 0))
+ {
+ auto const dwError = ::GetLastError();
+ if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
+ ec.assign(::GetLastError(), system_category());
+ else
+ ec.assign(0, ec.category());
+ return nread;
+ }
+ if(bytesRead == 0)
+ return nread;
+ n -= bytesRead;
+ nread += bytesRead;
+ buffer = reinterpret_cast<char*>(buffer) + bytesRead;
+ }
+ ec.assign(0, ec.category());
+ 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.assign(errc::invalid_argument, generic_category());
+ return 0;
+ }
+ std::size_t nwritten = 0;
+ while(n > 0)
+ {
+ boost::winapi::DWORD_ amount;
+ if(n > (std::numeric_limits<
+ boost::winapi::DWORD_>::max)())
+ amount = (std::numeric_limits<
+ boost::winapi::DWORD_>::max)();
+ else
+ amount = static_cast<
+ boost::winapi::DWORD_>(n);
+ boost::winapi::DWORD_ bytesWritten;
+ if(! ::WriteFile(h_, buffer, amount, &bytesWritten, 0))
+ {
+ auto const dwError = ::GetLastError();
+ if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
+ ec.assign(::GetLastError(), system_category());
+ else
+ ec.assign(0, ec.category());
+ return nwritten;
+ }
+ if(bytesWritten == 0)
+ return nwritten;
+ n -= bytesWritten;
+ nwritten += bytesWritten;
+ buffer = reinterpret_cast<char const*>(buffer) + bytesWritten;
+ }
+ ec.assign(0, ec.category());
+ return nwritten;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/flat_buffer.ipp b/boost/beast/core/impl/flat_buffer.ipp
new file mode 100644
index 0000000000..ffca651cc9
--- /dev/null
+++ b/boost/beast/core/impl/flat_buffer.ipp
@@ -0,0 +1,475 @@
+//
+// 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_FLAT_BUFFER_HPP
+#define BOOST_BEAST_IMPL_FLAT_BUFFER_HPP
+
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <stdexcept>
+
+namespace boost {
+namespace beast {
+
+/* Memory is laid out thusly:
+
+ begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
+*/
+
+template<class Allocator>
+basic_flat_buffer<Allocator>::
+~basic_flat_buffer()
+{
+ if(begin_)
+ alloc_traits::deallocate(
+ this->member(), begin_, dist(begin_, end_));
+}
+
+template<class Allocator>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer()
+ : begin_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_((std::numeric_limits<std::size_t>::max)())
+{
+}
+
+template<class Allocator>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer(std::size_t limit)
+ : begin_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_(limit)
+{
+}
+
+template<class Allocator>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer(Allocator const& alloc)
+ : detail::empty_base_optimization<base_alloc_type>(alloc)
+ , begin_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_((std::numeric_limits<std::size_t>::max)())
+{
+}
+
+template<class Allocator>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer(std::size_t limit, Allocator const& alloc)
+ : detail::empty_base_optimization<base_alloc_type>(alloc)
+ , begin_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_(limit)
+{
+}
+
+template<class Allocator>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer(basic_flat_buffer&& other)
+ : detail::empty_base_optimization<base_alloc_type>(
+ std::move(other.member()))
+ , 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;
+}
+
+template<class Allocator>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer(basic_flat_buffer&& other,
+ Allocator const& alloc)
+ : detail::empty_base_optimization<base_alloc_type>(alloc)
+{
+ if(this->member() != other.member())
+ {
+ begin_ = nullptr;
+ in_ = nullptr;
+ out_ = nullptr;
+ last_ = nullptr;
+ 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;
+ }
+}
+
+template<class Allocator>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer(basic_flat_buffer const& other)
+ : detail::empty_base_optimization<base_alloc_type>(
+ alloc_traits::select_on_container_copy_construction(
+ other.member()))
+ , begin_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_(other.max_)
+{
+ copy_from(other);
+}
+
+template<class Allocator>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer(basic_flat_buffer const& other,
+ Allocator const& alloc)
+ : detail::empty_base_optimization<base_alloc_type>(alloc)
+ , begin_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_(other.max_)
+{
+ copy_from(other);
+}
+
+template<class Allocator>
+template<class OtherAlloc>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer(
+ basic_flat_buffer<OtherAlloc> const& other)
+ : begin_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_(other.max_)
+{
+ copy_from(other);
+}
+
+template<class Allocator>
+template<class OtherAlloc>
+basic_flat_buffer<Allocator>::
+basic_flat_buffer(basic_flat_buffer<OtherAlloc> const& other,
+ Allocator const& alloc)
+ : detail::empty_base_optimization<base_alloc_type>(alloc)
+ , begin_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_(other.max_)
+{
+ copy_from(other);
+}
+
+template<class Allocator>
+auto
+basic_flat_buffer<Allocator>::
+operator=(basic_flat_buffer&& other) ->
+ basic_flat_buffer&
+{
+ if(this != &other)
+ move_assign(other, std::integral_constant<bool,
+ alloc_traits::propagate_on_container_move_assignment::value>{});
+ return *this;
+}
+
+template<class Allocator>
+auto
+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>{});
+ return *this;
+}
+
+template<class Allocator>
+template<class OtherAlloc>
+auto
+basic_flat_buffer<Allocator>::
+operator=(basic_flat_buffer<OtherAlloc> const& other) ->
+ basic_flat_buffer&
+{
+ reset();
+ max_ = other.max_;
+ copy_from(other);
+ return *this;
+}
+
+//------------------------------------------------------------------------------
+
+template<class Allocator>
+auto
+basic_flat_buffer<Allocator>::
+prepare(std::size_t n) ->
+ mutable_buffers_type
+{
+ 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)
+ 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->member(), new_size);
+ if(begin_)
+ {
+ BOOST_ASSERT(p);
+ BOOST_ASSERT(in_);
+ std::memcpy(p, in_, len);
+ alloc_traits::deallocate(
+ this->member(), begin_, capacity());
+ }
+ begin_ = p;
+ in_ = begin_;
+ out_ = in_ + len;
+ last_ = out_ + n;
+ end_ = begin_ + new_size;
+ return {out_, n};
+}
+
+template<class Allocator>
+void
+basic_flat_buffer<Allocator>::
+consume(std::size_t n)
+{
+ if(n >= dist(in_, out_))
+ {
+ in_ = begin_;
+ out_ = begin_;
+ return;
+ }
+ in_ += n;
+}
+
+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_traits::allocate(
+ this->member(), len);
+ std::memcpy(p, in_, len);
+ }
+ else
+ {
+ p = nullptr;
+ }
+ alloc_traits::deallocate(
+ this->member(), 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();
+ this->member() = std::move(other.member());
+ 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;
+}
+
+template<class Allocator>
+inline
+void
+basic_flat_buffer<Allocator>::
+move_assign(basic_flat_buffer& other, std::false_type)
+{
+ reset();
+ if(this->member() != other.member())
+ {
+ copy_from(other);
+ other.reset();
+ }
+ else
+ {
+ move_assign(other, std::true_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->member() = other.member();
+ copy_from(other);
+}
+
+template<class Allocator>
+inline
+void
+basic_flat_buffer<Allocator>::
+copy_assign(basic_flat_buffer const& other, std::false_type)
+{
+ reset();
+ max_ = other.max_;
+ copy_from(other);
+}
+
+template<class Allocator>
+inline
+void
+basic_flat_buffer<Allocator>::
+swap(basic_flat_buffer& other)
+{
+ swap(other, typename
+ alloc_traits::propagate_on_container_swap{});
+}
+
+template<class Allocator>
+inline
+void
+basic_flat_buffer<Allocator>::
+swap(basic_flat_buffer& other, std::true_type)
+{
+ using std::swap;
+ swap(this->member(), other.member());
+ swap(max_, other.max_);
+ swap(begin_, other.begin_);
+ swap(in_, other.in_);
+ swap(out_, other.out_);
+ last_ = this->out_;
+ other.last_ = other.out_;
+ swap(end_, other.end_);
+}
+
+template<class Allocator>
+inline
+void
+basic_flat_buffer<Allocator>::
+swap(basic_flat_buffer& other, std::false_type)
+{
+ BOOST_ASSERT(this->member() == other.member());
+ using std::swap;
+ swap(max_, other.max_);
+ swap(begin_, other.begin_);
+ swap(in_, other.in_);
+ swap(out_, other.out_);
+ last_ = this->out_;
+ other.last_ = other.out_;
+ swap(end_, other.end_);
+}
+
+template<class Allocator>
+void
+swap(
+ basic_flat_buffer<Allocator>& lhs,
+ basic_flat_buffer<Allocator>& rhs)
+{
+ lhs.swap(rhs);
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/flat_static_buffer.ipp b/boost/beast/core/impl/flat_static_buffer.ipp
new file mode 100644
index 0000000000..3d38b92958
--- /dev/null
+++ b/boost/beast/core/impl/flat_static_buffer.ipp
@@ -0,0 +1,151 @@
+//
+// 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_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/throw_exception.hpp>
+#include <algorithm>
+#include <cstring>
+#include <iterator>
+#include <stdexcept>
+
+namespace boost {
+namespace beast {
+
+/* Memory is laid out thusly:
+
+ begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
+*/
+
+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()
+{
+ in_ = begin_;
+ out_ = begin_;
+ last_ = begin_;
+}
+
+template<class>
+void
+flat_static_buffer_base::
+reset_impl(void* p, std::size_t n)
+{
+ begin_ =
+ reinterpret_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) ->
+ mutable_buffers_type
+{
+ if(n <= dist(out_, end_))
+ {
+ last_ = out_ + n;
+ return {out_, n};
+ }
+ auto const len = size();
+ if(n > capacity() - len)
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "buffer overflow"});
+ if(len > 0)
+ std::memmove(begin_, in_, len);
+ in_ = begin_;
+ out_ = in_ + len;
+ last_ = out_ + n;
+ return {out_, n};
+}
+
+template<class>
+void
+flat_static_buffer_base::
+consume_impl(std::size_t n)
+{
+ if(n >= size())
+ {
+ in_ = begin_;
+ out_ = in_;
+ return;
+ }
+ 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>&
+{
+ using boost::asio::buffer_copy;
+ this->consume(this->size());
+ this->commit(buffer_copy(
+ this->prepare(other.size()), other.data()));
+ return *this;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/handler_ptr.ipp b/boost/beast/core/impl/handler_ptr.ipp
new file mode 100644
index 0000000000..15a159a8fd
--- /dev/null
+++ b/boost/beast/core/impl/handler_ptr.ipp
@@ -0,0 +1,147 @@
+//
+// 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_HANDLER_PTR_HPP
+#define BOOST_BEAST_IMPL_HANDLER_PTR_HPP
+
+#include <boost/asio/associated_allocator.hpp>
+#include <boost/assert.hpp>
+#include <memory>
+
+namespace boost {
+namespace beast {
+
+template<class T, class Handler>
+template<class DeducedHandler, class... Args>
+inline
+handler_ptr<T, Handler>::P::
+P(DeducedHandler&& h, Args&&... args)
+ : n(1)
+ , handler(std::forward<DeducedHandler>(h))
+{
+ typename std::allocator_traits<
+ boost::asio::associated_allocator_t<Handler>>::
+ template rebind_alloc<T> alloc{
+ boost::asio::get_associated_allocator(handler)};
+ t = std::allocator_traits<decltype(alloc)>::allocate(alloc, 1);
+ try
+ {
+ t = new(t) T{handler,
+ std::forward<Args>(args)...};
+ }
+ catch(...)
+ {
+ std::allocator_traits<
+ decltype(alloc)>::deallocate(alloc, t, 1);
+ throw;
+ }
+}
+
+template<class T, class Handler>
+handler_ptr<T, Handler>::
+~handler_ptr()
+{
+ if(! p_)
+ return;
+ if(--p_->n)
+ return;
+ if(p_->t)
+ {
+ p_->t->~T();
+ typename std::allocator_traits<
+ boost::asio::associated_allocator_t<Handler>>::
+ template rebind_alloc<T> alloc{
+ boost::asio::get_associated_allocator(
+ p_->handler)};
+ std::allocator_traits<
+ decltype(alloc)>::deallocate(alloc, p_->t, 1);
+ }
+ delete p_;
+}
+
+template<class T, class Handler>
+handler_ptr<T, Handler>::
+handler_ptr(handler_ptr&& other)
+ : p_(other.p_)
+{
+ other.p_ = nullptr;
+}
+
+template<class T, class Handler>
+handler_ptr<T, Handler>::
+handler_ptr(handler_ptr const& other)
+ : p_(other.p_)
+{
+ if(p_)
+ ++p_->n;
+}
+
+template<class T, class Handler>
+template<class... Args>
+handler_ptr<T, Handler>::
+handler_ptr(Handler&& handler, Args&&... args)
+ : p_(new P{std::move(handler),
+ std::forward<Args>(args)...})
+{
+ BOOST_STATIC_ASSERT(! std::is_array<T>::value);
+}
+
+template<class T, class Handler>
+template<class... Args>
+handler_ptr<T, Handler>::
+handler_ptr(Handler const& handler, Args&&... args)
+ : p_(new P{handler, std::forward<Args>(args)...})
+{
+ BOOST_STATIC_ASSERT(! std::is_array<T>::value);
+}
+
+template<class T, class Handler>
+auto
+handler_ptr<T, Handler>::
+release_handler() ->
+ handler_type
+{
+ BOOST_ASSERT(p_);
+ BOOST_ASSERT(p_->t);
+ p_->t->~T();
+ typename std::allocator_traits<
+ boost::asio::associated_allocator_t<Handler>>::
+ template rebind_alloc<T> alloc{
+ boost::asio::get_associated_allocator(
+ p_->handler)};
+ std::allocator_traits<
+ decltype(alloc)>::deallocate(alloc, p_->t, 1);
+ p_->t = nullptr;
+ return std::move(p_->handler);
+}
+
+template<class T, class Handler>
+template<class... Args>
+void
+handler_ptr<T, Handler>::
+invoke(Args&&... args)
+{
+ BOOST_ASSERT(p_);
+ BOOST_ASSERT(p_->t);
+ p_->t->~T();
+ typename std::allocator_traits<
+ boost::asio::associated_allocator_t<Handler>>::
+ template rebind_alloc<T> alloc{
+ boost::asio::get_associated_allocator(
+ p_->handler)};
+ std::allocator_traits<
+ decltype(alloc)>::deallocate(alloc, p_->t, 1);
+ p_->t = nullptr;
+ p_->handler(std::forward<Args>(args)...);
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/multi_buffer.ipp b/boost/beast/core/impl/multi_buffer.ipp
new file mode 100644
index 0000000000..7b66694cb3
--- /dev/null
+++ b/boost/beast/core/impl/multi_buffer.ipp
@@ -0,0 +1,1063 @@
+//
+// 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_MULTI_BUFFER_IPP
+#define BOOST_BEAST_IMPL_MULTI_BUFFER_IPP
+
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <algorithm>
+#include <exception>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace boost {
+namespace beast {
+
+/* These diagrams illustrate the layout and state variables.
+
+1 Input and output contained entirely in one element:
+
+ 0 out_
+ |<-------------+------------------------------------------->|
+ in_pos_ out_pos_ out_end_
+
+
+2 Output contained in first and second elements:
+
+ out_
+ |<------+----------+------->| |<----------+-------------->|
+ in_pos_ out_pos_ out_end_
+
+
+3 Output contained in the second element:
+
+ out_
+ |<------------+------------>| |<----+-------------------->|
+ in_pos_ out_pos_ out_end_
+
+
+4 Output contained in second and third elements:
+
+ out_
+ |<-----+-------->| |<-------+------>| |<--------------->|
+ in_pos_ out_pos_ out_end_
+
+
+5 Input sequence is empty:
+
+ out_
+ |<------+------------------>| |<-----------+------------->|
+ out_pos_ out_end_
+ in_pos_
+
+
+6 Output sequence is empty:
+
+ out_
+ |<------+------------------>| |<------+------------------>|
+ in_pos_ out_pos_
+ out_end_
+
+
+7 The end of output can point to the end of an element.
+ But out_pos_ should never point to the end:
+
+ out_
+ |<------+------------------>| |<------+------------------>|
+ in_pos_ out_pos_ out_end_
+
+
+8 When the input sequence entirely fills the last element and
+ the output sequence is empty, out_ will point to the end of
+ the list of buffers, and out_pos_ and out_end_ will be 0:
+
+
+ |<------+------------------>| out_ == list_.end()
+ in_pos_ out_pos_ == 0
+ out_end_ == 0
+*/
+
+template<class Allocator>
+class basic_multi_buffer<Allocator>::element
+ : public boost::intrusive::list_base_hook<
+ boost::intrusive::link_mode<
+ boost::intrusive::normal_link>>
+{
+ 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)
+ : size_(n)
+ {
+ }
+
+ size_type
+ size() const
+ {
+ return size_;
+ }
+
+ char*
+ data() const
+ {
+ return const_cast<char*>(
+ reinterpret_cast<char const*>(this+1));
+ }
+};
+
+template<class Allocator>
+class basic_multi_buffer<Allocator>::const_buffers_type
+{
+ basic_multi_buffer const* b_;
+
+ friend class basic_multi_buffer;
+
+ explicit
+ const_buffers_type(basic_multi_buffer const& b);
+
+public:
+ using value_type = boost::asio::mutable_buffer;
+
+ 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)
+ {
+ 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);
+
+public:
+ using value_type = 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;
+
+ const_iterator
+ end() const;
+};
+
+//------------------------------------------------------------------------------
+
+template<class Allocator>
+class basic_multi_buffer<Allocator>::const_buffers_type::const_iterator
+{
+ basic_multi_buffer const* b_ = nullptr;
+ typename list_type::const_iterator it_;
+
+public:
+ using value_type =
+ typename const_buffers_type::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&& 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)
+ : b_(&b)
+ , it_(it)
+ {
+ }
+
+ 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
+ {
+ auto const& e = *it_;
+ return value_type{e.data(),
+ (b_->out_ == b_->list_.end() ||
+ &e != &*b_->out_) ? e.size() : b_->out_pos_} +
+ (&e == &*b_->list_.begin() ? b_->in_pos_ : 0);
+ }
+
+ 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;
+ }
+};
+
+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
+{
+ return const_iterator{*b_, b_->list_.begin()};
+}
+
+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_)};
+}
+
+//------------------------------------------------------------------------------
+
+template<class Allocator>
+class basic_multi_buffer<Allocator>::mutable_buffers_type::const_iterator
+{
+ basic_multi_buffer const* b_ = nullptr;
+ typename list_type::const_iterator it_;
+
+public:
+ using value_type =
+ typename mutable_buffers_type::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&& 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)
+ : b_(&b)
+ , it_(it)
+ {
+ }
+
+ 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
+ {
+ auto const& e = *it_;
+ return value_type{e.data(),
+ &e == &*std::prev(b_->list_.end()) ?
+ b_->out_end_ : e.size()} +
+ (&e == &*b_->out_ ? b_->out_pos_ : 0);
+ }
+
+ 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;
+ }
+};
+
+template<class Allocator>
+basic_multi_buffer<Allocator>::
+mutable_buffers_type::
+mutable_buffers_type(
+ basic_multi_buffer const& b)
+ : b_(&b)
+{
+}
+
+template<class Allocator>
+auto
+basic_multi_buffer<Allocator>::
+mutable_buffers_type::
+begin() const ->
+ const_iterator
+{
+ return const_iterator{*b_, b_->out_};
+}
+
+template<class Allocator>
+auto
+basic_multi_buffer<Allocator>::
+mutable_buffers_type::
+end() const ->
+ const_iterator
+{
+ return const_iterator{*b_, b_->list_.end()};
+}
+
+//------------------------------------------------------------------------------
+
+template<class Allocator>
+basic_multi_buffer<Allocator>::
+~basic_multi_buffer()
+{
+ delete_list();
+}
+
+template<class Allocator>
+basic_multi_buffer<Allocator>::
+basic_multi_buffer()
+ : out_(list_.end())
+{
+}
+
+template<class Allocator>
+basic_multi_buffer<Allocator>::
+basic_multi_buffer(std::size_t limit)
+ : max_(limit)
+ , out_(list_.end())
+{
+}
+
+template<class Allocator>
+basic_multi_buffer<Allocator>::
+basic_multi_buffer(Allocator const& alloc)
+ : detail::empty_base_optimization<
+ base_alloc_type>(alloc)
+ , out_(list_.end())
+{
+}
+
+template<class Allocator>
+basic_multi_buffer<Allocator>::
+basic_multi_buffer(std::size_t limit,
+ Allocator const& alloc)
+ : detail::empty_base_optimization<
+ base_alloc_type>(alloc)
+ , max_(limit)
+ , out_(list_.end())
+{
+}
+
+template<class Allocator>
+basic_multi_buffer<Allocator>::
+basic_multi_buffer(basic_multi_buffer&& other)
+ : detail::empty_base_optimization<
+ base_alloc_type>(std::move(other.member()))
+ , max_(other.max_)
+ , in_size_(other.in_size_)
+ , in_pos_(other.in_pos_)
+ , out_pos_(other.out_pos_)
+ , out_end_(other.out_end_)
+{
+ auto const at_end =
+ other.out_ == other.list_.end();
+ list_ = std::move(other.list_);
+ out_ = at_end ? list_.end() : other.out_;
+ 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&& other,
+ Allocator const& alloc)
+ : detail::empty_base_optimization<
+ base_alloc_type>(alloc)
+ , max_(other.max_)
+{
+ if(this->member() != other.member())
+ {
+ 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;
+ }
+}
+
+template<class Allocator>
+basic_multi_buffer<Allocator>::
+basic_multi_buffer(basic_multi_buffer const& other)
+ : detail::empty_base_optimization<
+ base_alloc_type>(alloc_traits::
+ select_on_container_copy_construction(
+ other.member()))
+ , max_(other.max_)
+ , out_(list_.end())
+{
+ copy_from(other);
+}
+
+template<class Allocator>
+basic_multi_buffer<Allocator>::
+basic_multi_buffer(basic_multi_buffer const& other,
+ Allocator const& alloc)
+ : detail::empty_base_optimization<
+ base_alloc_type>(alloc)
+ , max_(other.max_)
+ , out_(list_.end())
+{
+ copy_from(other);
+}
+
+template<class Allocator>
+template<class OtherAlloc>
+basic_multi_buffer<Allocator>::
+basic_multi_buffer(
+ basic_multi_buffer<OtherAlloc> const& other)
+ : out_(list_.end())
+{
+ copy_from(other);
+}
+
+template<class Allocator>
+template<class OtherAlloc>
+basic_multi_buffer<Allocator>::
+basic_multi_buffer(
+ basic_multi_buffer<OtherAlloc> const& other,
+ allocator_type const& alloc)
+ : detail::empty_base_optimization<
+ base_alloc_type>(alloc)
+ , max_(other.max_)
+ , out_(list_.end())
+{
+ copy_from(other);
+}
+
+template<class Allocator>
+auto
+basic_multi_buffer<Allocator>::
+operator=(basic_multi_buffer&& other) ->
+ basic_multi_buffer&
+{
+ if(this == &other)
+ return *this;
+ reset();
+ max_ = other.max_;
+ move_assign(other, std::integral_constant<bool,
+ alloc_traits::propagate_on_container_move_assignment::value>{});
+ return *this;
+}
+
+template<class Allocator>
+auto
+basic_multi_buffer<Allocator>::
+operator=(basic_multi_buffer const& other) ->
+basic_multi_buffer&
+{
+ if(this == &other)
+ return *this;
+ copy_assign(other, std::integral_constant<bool,
+ alloc_traits::propagate_on_container_copy_assignment::value>{});
+ return *this;
+}
+
+template<class Allocator>
+template<class OtherAlloc>
+auto
+basic_multi_buffer<Allocator>::
+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
+{
+ auto pos = out_;
+ if(pos == list_.end())
+ return in_size_;
+ auto n = pos->size() - out_pos_;
+ while(++pos != list_.end())
+ n += pos->size();
+ return in_size_ + n;
+}
+
+template<class Allocator>
+auto
+basic_multi_buffer<Allocator>::
+data() const ->
+ const_buffers_type
+{
+ return const_buffers_type(*this);
+}
+
+template<class Allocator>
+auto
+basic_multi_buffer<Allocator>::
+prepare(size_type n) ->
+ mutable_buffers_type
+{
+ if(in_size_ + n > max_)
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "dynamic buffer overflow"});
+ list_type reuse;
+ std::size_t total = in_size_;
+ // put all empty buffers on reuse list
+ if(out_ != list_.end())
+ {
+ total += out_->size() - out_pos_;
+ if(out_ != list_.iterator_to(list_.back()))
+ {
+ out_end_ = out_->size();
+ reuse.splice(reuse.end(), list_,
+ std::next(out_), list_.end());
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+ auto const avail = out_->size() - out_pos_;
+ if(n > avail)
+ {
+ out_end_ = out_->size();
+ n -= avail;
+ }
+ else
+ {
+ out_end_ = out_pos_ + n;
+ n = 0;
+ }
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+ // get space from reuse buffers
+ while(n > 0 && ! reuse.empty())
+ {
+ auto& e = reuse.front();
+ reuse.erase(reuse.iterator_to(e));
+ list_.push_back(e);
+ total += e.size();
+ if(n > e.size())
+ {
+ out_end_ = e.size();
+ n -= e.size();
+ }
+ else
+ {
+ out_end_ = n;
+ n = 0;
+ }
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+ 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->member(), &e);
+ alloc_traits::deallocate(this->member(),
+ reinterpret_cast<char*>(&e), len);
+ }
+ if(n > 0)
+ {
+ static auto const growth_factor = 2.0f;
+ auto const size =
+ (std::min<std::size_t>)(
+ max_ - total,
+ (std::max<std::size_t>)({
+ static_cast<std::size_t>(
+ in_size_ * growth_factor - in_size_),
+ 512,
+ n}));
+ auto& e = *reinterpret_cast<element*>(static_cast<
+ void*>(alloc_traits::allocate(this->member(),
+ sizeof(element) + size)));
+ alloc_traits::construct(this->member(), &e, size);
+ list_.push_back(e);
+ if(out_ == list_.end())
+ out_ = list_.iterator_to(e);
+ out_end_ = n;
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+ }
+ return mutable_buffers_type(*this);
+}
+
+template<class Allocator>
+void
+basic_multi_buffer<Allocator>::
+commit(size_type n)
+{
+ if(list_.empty())
+ return;
+ if(out_ == list_.end())
+ return;
+ auto const back =
+ list_.iterator_to(list_.back());
+ while(out_ != back)
+ {
+ auto const avail =
+ out_->size() - out_pos_;
+ if(n < avail)
+ {
+ out_pos_ += n;
+ in_size_ += n;
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ return;
+ }
+ ++out_;
+ n -= avail;
+ out_pos_ = 0;
+ in_size_ += avail;
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+
+ n = (std::min)(n, out_end_ - out_pos_);
+ out_pos_ += n;
+ in_size_ += n;
+ if(out_pos_ == out_->size())
+ {
+ ++out_;
+ out_pos_ = 0;
+ out_end_ = 0;
+ }
+#if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+#endif
+}
+
+template<class Allocator>
+void
+basic_multi_buffer<Allocator>::
+consume(size_type n)
+{
+ if(list_.empty())
+ return;
+ for(;;)
+ {
+ if(list_.begin() != out_)
+ {
+ auto const avail =
+ list_.front().size() - in_pos_;
+ if(n < avail)
+ {
+ in_size_ -= n;
+ in_pos_ += n;
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ break;
+ }
+ n -= avail;
+ in_size_ -= avail;
+ in_pos_ = 0;
+ auto& e = list_.front();
+ list_.erase(list_.iterator_to(e));
+ auto const len = sizeof(e) + e.size();
+ alloc_traits::destroy(this->member(), &e);
+ alloc_traits::deallocate(this->member(),
+ reinterpret_cast<char*>(&e), len);
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ }
+ else
+ {
+ auto const avail = out_pos_ - in_pos_;
+ if(n < avail)
+ {
+ in_size_ -= n;
+ in_pos_ += n;
+ }
+ else
+ {
+ in_size_ = 0;
+ if(out_ != list_.iterator_to(list_.back()) ||
+ out_pos_ != out_end_)
+ {
+ in_pos_ = out_pos_;
+ }
+ else
+ {
+ // Input and output sequences are empty, reuse buffer.
+ // Alternatively we could deallocate it.
+ in_pos_ = 0;
+ out_pos_ = 0;
+ out_end_ = 0;
+ }
+ }
+ #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
+ debug_check();
+ #endif
+ break;
+ }
+ }
+}
+
+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->member(), &e);
+ alloc_traits::deallocate(this->member(),
+ 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
+void
+basic_multi_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_multi_buffer<Allocator>::
+move_assign(basic_multi_buffer& other, std::false_type)
+{
+ if(this->member() != other.member())
+ {
+ 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)
+{
+ this->member() = std::move(other.member());
+ 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>
+inline
+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_;
+ this->member() = other.member();
+ copy_from(other);
+}
+
+template<class Allocator>
+inline
+void
+basic_multi_buffer<Allocator>::
+swap(basic_multi_buffer& other)
+{
+ 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)
+{
+ using std::swap;
+ auto const at_end0 =
+ out_ == list_.end();
+ auto const at_end1 =
+ other.out_ == other.list_.end();
+ swap(this->member(), other.member());
+ swap(list_, other.list_);
+ swap(out_, other.out_);
+ if(at_end1)
+ out_ = list_.end();
+ if(at_end0)
+ other.out_ = other.list_.end();
+ swap(in_size_, other.in_size_);
+ swap(in_pos_, other.in_pos_);
+ swap(out_pos_, other.out_pos_);
+ swap(out_end_, other.out_end_);
+}
+
+template<class Allocator>
+inline
+void
+basic_multi_buffer<Allocator>::
+swap(basic_multi_buffer& other, std::false_type)
+{
+ BOOST_ASSERT(this->member() == other.member());
+ using std::swap;
+ auto const at_end0 =
+ out_ == list_.end();
+ auto const at_end1 =
+ other.out_ == other.list_.end();
+ swap(list_, other.list_);
+ swap(out_, other.out_);
+ if(at_end1)
+ out_ = list_.end();
+ if(at_end0)
+ other.out_ = other.list_.end();
+ swap(in_size_, other.in_size_);
+ swap(in_pos_, other.in_pos_);
+ swap(out_pos_, other.out_pos_);
+ swap(out_end_, other.out_end_);
+}
+
+template<class Allocator>
+void
+swap(
+ basic_multi_buffer<Allocator>& lhs,
+ basic_multi_buffer<Allocator>& rhs)
+{
+ lhs.swap(rhs);
+}
+
+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_);
+ if(list_.empty())
+ {
+ BOOST_ASSERT(in_pos_ == 0);
+ BOOST_ASSERT(in_size_ == 0);
+ BOOST_ASSERT(out_pos_ == 0);
+ BOOST_ASSERT(out_end_ == 0);
+ BOOST_ASSERT(out_ == list_.end());
+ return;
+ }
+
+ auto const& front = list_.front();
+
+ BOOST_ASSERT(in_pos_ < front.size());
+
+ if(out_ == list_.end())
+ {
+ BOOST_ASSERT(out_pos_ == 0);
+ BOOST_ASSERT(out_end_ == 0);
+ }
+ else
+ {
+ auto const& out = *out_;
+ auto const& back = list_.back();
+
+ BOOST_ASSERT(out_end_ <= back.size());
+ BOOST_ASSERT(out_pos_ < out.size());
+ BOOST_ASSERT(&out != &front || out_pos_ >= in_pos_);
+ BOOST_ASSERT(&out != &front || out_pos_ - in_pos_ == in_size_);
+ BOOST_ASSERT(&out != &back || out_pos_ <= out_end_);
+ }
+#endif
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/read_size.ipp b/boost/beast/core/impl/read_size.ipp
new file mode 100644
index 0000000000..ddcaf397a9
--- /dev/null
+++ b/boost/beast/core/impl/read_size.ipp
@@ -0,0 +1,80 @@
+//
+// 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_READ_SIZE_IPP
+#define BOOST_BEAST_IMPL_READ_SIZE_IPP
+
+namespace boost {
+namespace beast {
+
+namespace detail {
+
+template<class T, class = void>
+struct has_read_size_helper : std::false_type {};
+
+template<class T>
+struct has_read_size_helper<T, decltype(
+ read_size_helper(std::declval<T&>(), 512),
+ (void)0)> : std::true_type
+{
+};
+
+template<class DynamicBuffer>
+std::size_t
+read_size(DynamicBuffer& buffer,
+ std::size_t max_size, std::true_type)
+{
+ return read_size_helper(buffer, max_size);
+}
+
+template<class DynamicBuffer>
+std::size_t
+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");
+ 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));
+}
+
+} // detail
+
+template<class DynamicBuffer>
+inline
+std::size_t
+read_size(
+ DynamicBuffer& buffer, std::size_t max_size)
+{
+ return detail::read_size(buffer, max_size,
+ detail::has_read_size_helper<DynamicBuffer>{});
+}
+
+template<class DynamicBuffer>
+std::size_t
+read_size_or_throw(
+ DynamicBuffer& buffer, std::size_t max_size)
+{
+ auto const n = read_size(buffer, max_size);
+ if(n == 0)
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "buffer overflow"});
+ return n;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/static_buffer.ipp b/boost/beast/core/impl/static_buffer.ipp
new file mode 100644
index 0000000000..d93a1e6911
--- /dev/null
+++ b/boost/beast/core/impl/static_buffer.ipp
@@ -0,0 +1,148 @@
+//
+// 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_STATIC_BUFFER_IPP
+#define BOOST_BEAST_IMPL_STATIC_BUFFER_IPP
+
+#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 {
+
+inline
+static_buffer_base::
+static_buffer_base(void* p, std::size_t size)
+ : begin_(reinterpret_cast<char*>(p))
+ , capacity_(size)
+{
+}
+
+inline
+auto
+static_buffer_base::
+data() const ->
+ const_buffers_type
+{
+ using boost::asio::mutable_buffer;
+ const_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;
+}
+
+inline
+auto
+static_buffer_base::
+prepare(std::size_t size) ->
+ mutable_buffers_type
+{
+ using boost::asio::mutable_buffer;
+ if(size > 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;
+ 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;
+}
+
+inline
+void
+static_buffer_base::
+commit(std::size_t size)
+{
+ in_size_ += (std::min)(size, out_size_);
+ out_size_ = 0;
+}
+
+inline
+void
+static_buffer_base::
+consume(std::size_t size)
+{
+ if(size < in_size_)
+ {
+ in_off_ = (in_off_ + size) % capacity_;
+ in_size_ -= size;
+ }
+ else
+ {
+ // rewind the offset, so the next call to prepare
+ // can have a longer continguous segment. this helps
+ // algorithms optimized for larger buffesr.
+ in_off_ = 0;
+ in_size_ = 0;
+ }
+}
+
+inline
+void
+static_buffer_base::
+reset(void* p, std::size_t size)
+{
+ begin_ = reinterpret_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
+
+#endif
diff --git a/boost/beast/core/impl/static_string.ipp b/boost/beast/core/impl/static_string.ipp
new file mode 100644
index 0000000000..29571dfeee
--- /dev/null
+++ b/boost/beast/core/impl/static_string.ipp
@@ -0,0 +1,618 @@
+//
+// 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_STATIC_STRING_IPP
+#define BOOST_BEAST_IMPL_STATIC_STRING_IPP
+
+#include <boost/beast/core/detail/static_string.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/throw_exception.hpp>
+
+namespace boost {
+namespace beast {
+
+//
+// (constructor)
+//
+
+template<std::size_t N, class CharT, class Traits>
+static_string<N, CharT, Traits>::
+static_string()
+{
+ n_ = 0;
+ term();
+}
+
+template<std::size_t N, class CharT, class Traits>
+static_string<N, CharT, Traits>::
+static_string(size_type count, CharT ch)
+{
+ assign(count, ch);
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<std::size_t M>
+static_string<N, CharT, Traits>::
+static_string(static_string<M, CharT, Traits> const& other,
+ size_type pos)
+{
+ assign(other, pos);
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<std::size_t M>
+static_string<N, CharT, Traits>::
+static_string(static_string<M, CharT, Traits> const& other,
+ size_type pos, size_type count)
+{
+ assign(other, pos, count);
+}
+
+template<std::size_t N, class CharT, class Traits>
+static_string<N, CharT, Traits>::
+static_string(CharT const* s, size_type count)
+{
+ assign(s, count);
+}
+
+template<std::size_t N, class CharT, class Traits>
+static_string<N, CharT, Traits>::
+static_string(CharT const* s)
+{
+ assign(s);
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<class InputIt>
+static_string<N, CharT, Traits>::
+static_string(InputIt first, InputIt last)
+{
+ assign(first, last);
+}
+
+template<std::size_t N, class CharT, class Traits>
+static_string<N, CharT, Traits>::
+static_string(static_string const& s)
+{
+ assign(s);
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<std::size_t M>
+static_string<N, CharT, Traits>::
+static_string(static_string<M, CharT, Traits> const& s)
+{
+ assign(s);
+}
+
+template<std::size_t N, class CharT, class Traits>
+static_string<N, CharT, Traits>::
+static_string(std::initializer_list<CharT> init)
+{
+ assign(init.begin(), init.end());
+}
+
+template<std::size_t N, class CharT, class Traits>
+static_string<N, CharT, Traits>::
+static_string(string_view_type sv)
+{
+ assign(sv);
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<class T, class>
+static_string<N, CharT, Traits>::
+static_string(T const& t, size_type pos, size_type n)
+{
+ assign(t, pos, n);
+}
+
+//
+// (assignment)
+//
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+assign(size_type count, CharT ch) ->
+ static_string&
+{
+ if(count > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "count > max_size()"});
+ n_ = count;
+ Traits::assign(&s_[0], n_, ch);
+ term();
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+assign(static_string const& str) ->
+ static_string&
+{
+ n_ = str.n_;
+ Traits::copy(&s_[0], &str.s_[0], n_ + 1);
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<std::size_t M>
+auto
+static_string<N, CharT, Traits>::
+assign(static_string<M, CharT, Traits> const& str,
+ size_type pos, size_type count) ->
+ static_string&
+{
+ auto const ss = str.substr(pos, count);
+ return assign(ss.data(), ss.size());
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+assign(CharT const* s, size_type count) ->
+ static_string&
+{
+ if(count > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "count > max_size()"});
+ n_ = count;
+ Traits::copy(&s_[0], s, n_);
+ term();
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<class InputIt>
+auto
+static_string<N, CharT, Traits>::
+assign(InputIt first, InputIt last) ->
+ static_string&
+{
+ std::size_t const n = std::distance(first, last);
+ if(n > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "n > max_size()"});
+ n_ = n;
+ for(auto it = &s_[0]; first != last; ++it, ++first)
+ Traits::assign(*it, *first);
+ term();
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<class T>
+auto
+static_string<N, CharT, Traits>::
+assign(T const& t, size_type pos, size_type count) ->
+ typename std::enable_if<std::is_convertible<T,
+ string_view_type>::value, static_string&>::type
+{
+ auto const sv = string_view_type(t).substr(pos, count);
+ if(sv.size() > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "sv.size() > max_size()"});
+ n_ = sv.size();
+ Traits::copy(&s_[0], &sv[0], n_);
+ term();
+ return *this;
+}
+
+//
+// Element access
+//
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+at(size_type pos) ->
+ reference
+{
+ if(pos >= size())
+ BOOST_THROW_EXCEPTION(std::out_of_range{
+ "pos >= size()"});
+ return s_[pos];
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+at(size_type pos) const ->
+ const_reference
+{
+ if(pos >= size())
+ BOOST_THROW_EXCEPTION(std::out_of_range{
+ "pos >= size()"});
+ return s_[pos];
+}
+
+//
+// Capacity
+//
+
+template<std::size_t N, class CharT, class Traits>
+void
+static_string<N, CharT, Traits>::
+reserve(std::size_t n)
+{
+ if(n > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "n > max_size()"});
+}
+
+//
+// Operations
+//
+
+template<std::size_t N, class CharT, class Traits>
+void
+static_string<N, CharT, Traits>::
+clear()
+{
+ n_ = 0;
+ term();
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+insert(size_type index, size_type count, CharT ch) ->
+ static_string&
+{
+ if(index > size())
+ BOOST_THROW_EXCEPTION(std::out_of_range{
+ "index > size()"});
+ insert(begin() + index, count, ch);
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+insert(size_type index, CharT const* s, size_type count) ->
+ static_string&
+{
+ if(index > size())
+ BOOST_THROW_EXCEPTION(std::out_of_range{
+ "index > size()"});
+ if(size() + count > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "size() + count > max_size()"});
+ Traits::move(
+ &s_[index + count], &s_[index], size() - index);
+ n_ += count;
+ Traits::copy(&s_[index], s, count);
+ term();
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<std::size_t M>
+auto
+static_string<N, CharT, Traits>::
+insert(size_type index,
+ static_string<M, CharT, Traits> const& str,
+ size_type index_str, size_type count) ->
+ static_string&
+{
+ auto const ss = str.substr(index_str, count);
+ return insert(index, ss.data(), ss.size());
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+insert(const_iterator pos, size_type count, CharT ch) ->
+ iterator
+{
+ if(size() + count > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "size() + count() > max_size()"});
+ auto const index = pos - &s_[0];
+ Traits::move(
+ &s_[index + count], &s_[index], size() - index);
+ n_ += count;
+ Traits::assign(&s_[index], count, ch);
+ term();
+ return &s_[index];
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<class InputIt>
+auto
+static_string<N, CharT, Traits>::
+insert(const_iterator pos, InputIt first, InputIt last) ->
+ typename std::enable_if<
+ detail::is_input_iterator<InputIt>::value,
+ iterator>::type
+{
+ std::size_t const count = std::distance(first, last);
+ if(size() + count > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "size() + count > max_size()"});
+ std::size_t const index = pos - begin();
+ Traits::move(
+ &s_[index + count], &s_[index], size() - index);
+ n_ += count;
+ for(auto it = begin() + index;
+ first != last; ++it, ++first)
+ Traits::assign(*it, *first);
+ term();
+ return begin() + index;
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<class T>
+auto
+static_string<N, CharT, Traits>::
+insert(size_type index, const T& t,
+ size_type index_str, size_type count) ->
+ typename std::enable_if<std::is_convertible<
+ T const&, string_view_type>::value &&
+ ! std::is_convertible<T const&, CharT const*>::value,
+ static_string&>::type
+{
+ auto const str =
+ string_view_type(t).substr(index_str, count);
+ return insert(index, str.data(), str.size());
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+erase(size_type index, size_type count) ->
+ static_string&
+{
+ if(index > size())
+ BOOST_THROW_EXCEPTION(std::out_of_range{
+ "index > size()"});
+ auto const n = (std::min)(count, size() - index);
+ Traits::move(
+ &s_[index], &s_[index + n], size() - (index + n) + 1);
+ n_ -= n;
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+erase(const_iterator pos) ->
+ iterator
+{
+ erase(pos - begin(), 1);
+ return begin() + (pos - begin());
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+erase(const_iterator first, const_iterator last) ->
+ iterator
+{
+ erase(first - begin(),
+ std::distance(first, last));
+ return begin() + (first - begin());
+}
+
+template<std::size_t N, class CharT, class Traits>
+void
+static_string<N, CharT, Traits>::
+push_back(CharT ch)
+{
+ if(size() >= max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "size() >= max_size()"});
+ Traits::assign(s_[n_++], ch);
+ term();
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<std::size_t M>
+auto
+static_string<N, CharT, Traits>::
+append(static_string<M, CharT, Traits> const& str,
+ size_type pos, size_type count) ->
+ static_string&
+{
+ // Valid range is [0, size)
+ if(pos >= str.size())
+ BOOST_THROW_EXCEPTION(std::out_of_range{
+ "pos > str.size()"});
+ string_view_type const ss{&str.s_[pos],
+ (std::min)(count, str.size() - pos)};
+ insert(size(), ss.data(), ss.size());
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+substr(size_type pos, size_type count) const ->
+ string_view_type
+{
+ if(pos > size())
+ BOOST_THROW_EXCEPTION(std::out_of_range{
+ "pos > size()"});
+ return{&s_[pos], (std::min)(count, size() - pos)};
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+copy(CharT* dest, size_type count, size_type pos) const ->
+ size_type
+{
+ auto const str = substr(pos, count);
+ Traits::copy(dest, str.data(), str.size());
+ return str.size();
+}
+
+template<std::size_t N, class CharT, class Traits>
+void
+static_string<N, CharT, Traits>::
+resize(std::size_t n)
+{
+ if(n > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "n > max_size()"});
+ n_ = n;
+ term();
+}
+
+template<std::size_t N, class CharT, class Traits>
+void
+static_string<N, CharT, Traits>::
+resize(std::size_t n, CharT c)
+{
+ if(n > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "n > max_size()"});
+ if(n > n_)
+ Traits::assign(&s_[n_], n - n_, c);
+ n_ = n;
+ term();
+}
+
+template<std::size_t N, class CharT, class Traits>
+void
+static_string<N, CharT, Traits>::
+swap(static_string& str)
+{
+ static_string tmp(str);
+ str.n_ = n_;
+ Traits::copy(&str.s_[0], &s_[0], n_ + 1);
+ n_ = tmp.n_;
+ Traits::copy(&s_[0], &tmp.s_[0], n_ + 1);
+}
+
+template<std::size_t N, class CharT, class Traits>
+template<std::size_t M>
+void
+static_string<N, CharT, Traits>::
+swap(static_string<M, CharT, Traits>& str)
+{
+ if(size() > str.max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "size() > str.max_size()"});
+ if(str.size() > max_size())
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "str.size() > max_size()"});
+ static_string tmp(str);
+ str.n_ = n_;
+ Traits::copy(&str.s_[0], &s_[0], n_ + 1);
+ n_ = tmp.n_;
+ Traits::copy(&s_[0], &tmp.s_[0], n_ + 1);
+}
+
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+assign_char(CharT ch, std::true_type) ->
+ static_string&
+{
+ n_ = 1;
+ Traits::assign(s_[0], ch);
+ term();
+ return *this;
+}
+
+template<std::size_t N, class CharT, class Traits>
+auto
+static_string<N, CharT, Traits>::
+assign_char(CharT, std::false_type) ->
+ static_string&
+{
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "max_size() == 0"});
+}
+
+namespace detail {
+
+template<class Integer>
+static_string<max_digits(sizeof(Integer))>
+to_static_string(Integer x, std::true_type)
+{
+ if(x == 0)
+ return {'0'};
+ static_string<detail::max_digits(
+ sizeof(Integer))> s;
+ if(x < 0)
+ {
+ x = -x;
+ char buf[max_digits(sizeof(x))];
+ char* p = buf;
+ for(;x > 0; x /= 10)
+ *p++ = "0123456789"[x % 10];
+ s.resize(1 + p - buf);
+ s[0] = '-';
+ auto d = &s[1];
+ while(p > buf)
+ *d++ = *--p;
+ }
+ else
+ {
+ char buf[max_digits(sizeof(x))];
+ char* p = buf;
+ for(;x > 0; x /= 10)
+ *p++ = "0123456789"[x % 10];
+ s.resize(p - buf);
+ auto d = &s[0];
+ while(p > buf)
+ *d++ = *--p;
+ }
+ return s;
+}
+
+template<class Integer>
+static_string<max_digits(sizeof(Integer))>
+to_static_string(Integer x, std::false_type)
+{
+ if(x == 0)
+ return {'0'};
+ char buf[max_digits(sizeof(x))];
+ char* p = buf;
+ for(;x > 0; x /= 10)
+ *p++ = "0123456789"[x % 10];
+ static_string<detail::max_digits(
+ sizeof(Integer))> s;
+ s.resize(p - buf);
+ auto d = &s[0];
+ while(p > buf)
+ *d++ = *--p;
+ return s;
+}
+
+} // detail
+
+template<class Integer>
+static_string<detail::max_digits(sizeof(Integer))>
+to_static_string(Integer x)
+{
+ using CharT = char;
+ using Traits = std::char_traits<CharT>;
+ BOOST_STATIC_ASSERT(std::is_integral<Integer>::value);
+ char buf[detail::max_digits(sizeof(Integer))];
+ auto last = buf + sizeof(buf);
+ auto it = detail::raw_to_string<
+ CharT, Integer, Traits>(last, sizeof(buf), x);
+ static_string<detail::max_digits(sizeof(Integer))> s;
+ s.resize(static_cast<std::size_t>(last - it));
+ auto p = s.data();
+ while(it < last)
+ Traits::assign(*p++, *it++);
+ return s;
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/impl/string_param.ipp b/boost/beast/core/impl/string_param.ipp
new file mode 100644
index 0000000000..a60771cc12
--- /dev/null
+++ b/boost/beast/core/impl/string_param.ipp
@@ -0,0 +1,108 @@
+//
+// 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_STRING_PARAM_IPP
+#define BOOST_BEAST_IMPL_STRING_PARAM_IPP
+
+namespace boost {
+namespace beast {
+
+template<class T>
+typename std::enable_if<
+ std::is_integral<T>::value>::type
+string_param::
+print(T const& t)
+{
+ auto const last = buf_ + sizeof(buf_);
+ auto const it = detail::raw_to_string<
+ char, T, std::char_traits<char>>(
+ last, sizeof(buf_), t);
+ sv_ = {it, static_cast<std::size_t>(
+ last - it)};
+}
+
+template<class T>
+typename std::enable_if<
+ ! std::is_integral<T>::value &&
+ ! std::is_convertible<T, string_view>::value
+>::type
+string_param::
+print(T const& t)
+{
+ os_.emplace(buf_, sizeof(buf_));
+ *os_ << t;
+ os_->flush();
+ sv_ = os_->str();
+}
+
+inline
+void
+string_param::
+print(string_view sv)
+{
+ sv_ = sv;
+}
+
+template<class T>
+typename std::enable_if<
+ std::is_integral<T>::value>::type
+string_param::
+print_1(T const& t)
+{
+ char buf[detail::max_digits(sizeof(T))];
+ auto const last = buf + sizeof(buf);
+ auto const it = detail::raw_to_string<
+ char, T, std::char_traits<char>>(
+ last, sizeof(buf), t);
+ *os_ << string_view{it,
+ static_cast<std::size_t>(last - it)};
+}
+
+template<class T>
+typename std::enable_if<
+ ! std::is_integral<T>::value>::type
+string_param::
+print_1(T const& t)
+{
+ *os_ << t;
+}
+
+template<class T0, class... TN>
+void
+string_param::
+print_n(T0 const& t0, TN const&... tn)
+{
+ print_1(t0);
+ print_n(tn...);
+}
+
+template<class T0, class T1, class... TN>
+void
+string_param::
+print(T0 const& t0, T1 const& t1, TN const&... tn)
+{
+ os_.emplace(buf_, sizeof(buf_));
+ print_1(t0);
+ print_1(t1);
+ print_n(tn...);
+ os_->flush();
+ sv_ = os_->str();
+}
+
+template<class... Args>
+string_param::
+string_param(Args const&... args)
+{
+ print(args...);
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/multi_buffer.hpp b/boost/beast/core/multi_buffer.hpp
new file mode 100644
index 0000000000..ee14b419a5
--- /dev/null
+++ b/boost/beast/core/multi_buffer.hpp
@@ -0,0 +1,322 @@
+//
+// 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_MULTI_BUFFER_HPP
+#define BOOST_BEAST_MULTI_BUFFER_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/allocator.hpp>
+#include <boost/beast/core/detail/empty_base_optimization.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/intrusive/list.hpp>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+
+/** A @b DynamicBuffer that uses multiple buffers internally.
+
+ 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.
+
+ @note Meets the requirements of @b DynamicBuffer.
+
+ @tparam Allocator The allocator to use for managing memory.
+*/
+template<class Allocator>
+class basic_multi_buffer
+#if ! BOOST_BEAST_DOXYGEN
+ : private detail::empty_base_optimization<
+ typename detail::allocator_traits<Allocator>::
+ template rebind_alloc<char>>
+#endif
+{
+ using base_alloc_type = typename
+ detail::allocator_traits<Allocator>::
+ template rebind_alloc<char>;
+
+ // 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>;
+ 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;
+
+ static_assert(std::is_base_of<std::bidirectional_iterator_tag,
+ typename std::iterator_traits<iter>::iterator_category>::value,
+ "BidirectionalIterator 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");
+
+ std::size_t max_ =
+ (std::numeric_limits<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
+ size_type in_pos_ = 0; // input offset in list_.front()
+ size_type out_pos_ = 0; // output offset in *out_
+ size_type out_end_ = 0; // output end offset in list_.back()
+
+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.
+ */
+ basic_multi_buffer();
+
+ /** Constructor.
+
+ @param limit The setting for @ref max_size.
+ */
+ explicit
+ basic_multi_buffer(std::size_t limit);
+
+ /** Constructor.
+
+ @param alloc The allocator to use.
+ */
+ explicit
+ basic_multi_buffer(Allocator const& alloc);
+
+ /** Constructor.
+
+ @param limit The setting for @ref max_size.
+
+ @param alloc The allocator to use.
+ */
+ basic_multi_buffer(
+ std::size_t limit, Allocator const& alloc);
+
+ /** Move constructor
+
+ After the move, `*this` will have an empty output sequence.
+
+ @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.
+ */
+ basic_multi_buffer(basic_multi_buffer&& other);
+
+ /** Move constructor
+
+ After the move, `*this` will have an empty output sequence.
+
+ @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.
+
+ @param alloc The allocator to use.
+ */
+ basic_multi_buffer(basic_multi_buffer&& other,
+ Allocator const& alloc);
+
+ /** Copy constructor.
+
+ @param other The object to copy from.
+ */
+ basic_multi_buffer(basic_multi_buffer const& other);
+
+ /** Copy constructor
+
+ @param other The object to copy from.
+
+ @param alloc The allocator to use.
+ */
+ basic_multi_buffer(basic_multi_buffer const& other,
+ Allocator const& alloc);
+
+ /** Copy constructor.
+
+ @param other The object to copy from.
+ */
+ template<class OtherAlloc>
+ basic_multi_buffer(basic_multi_buffer<
+ OtherAlloc> const& other);
+
+ /** Copy constructor.
+
+ @param other The object to copy from.
+
+ @param alloc The allocator to use.
+ */
+ template<class OtherAlloc>
+ basic_multi_buffer(basic_multi_buffer<
+ OtherAlloc> const& other, allocator_type const& alloc);
+
+ /** Move assignment
+
+ After the move, `*this` will have an empty output sequence.
+
+ @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.
+ */
+ basic_multi_buffer&
+ operator=(basic_multi_buffer&& other);
+
+ /** Copy assignment
+
+ After the copy, `*this` will have an empty output sequence.
+
+ @param other The object to copy from.
+ */
+ basic_multi_buffer& operator=(basic_multi_buffer const& other);
+
+ /** Copy assignment
+
+ After the copy, `*this` will have an empty output sequence.
+
+ @param other The object to copy from.
+ */
+ template<class OtherAlloc>
+ basic_multi_buffer& operator=(
+ basic_multi_buffer<OtherAlloc> const& other);
+
+ /// Returns a copy of the associated allocator.
+ allocator_type
+ get_allocator() const
+ {
+ return this->member();
+ }
+
+ /// Returns the size of the input sequence.
+ size_type
+ size() const
+ {
+ return in_size_;
+ }
+
+ /// Returns the permitted maximum sum of the sizes of the input and output sequence.
+ size_type
+ max_size() const
+ {
+ return max_;
+ }
+
+ /// 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;
+
+ /** 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;
+
+ /** Get a list of buffers that represents the output sequence, with the given size.
+
+ @note Buffers representing the input sequence acquired prior to
+ this call remain valid.
+ */
+ mutable_buffers_type
+ prepare(size_type 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(size_type n);
+
+ /// Remove bytes from the input sequence.
+ void
+ consume(size_type n);
+
+ template<class Alloc>
+ friend
+ void
+ swap(
+ basic_multi_buffer<Alloc>& lhs,
+ basic_multi_buffer<Alloc>& rhs);
+
+private:
+ template<class OtherAlloc>
+ friend class basic_multi_buffer;
+
+ void
+ delete_list();
+
+ void
+ reset();
+
+ template<class DynamicBuffer>
+ void
+ copy_from(DynamicBuffer const& other);
+
+ void
+ move_assign(basic_multi_buffer& other, std::false_type);
+
+ void
+ move_assign(basic_multi_buffer& other, std::true_type);
+
+ 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&);
+
+ void
+ swap(basic_multi_buffer&, std::true_type);
+
+ void
+ swap(basic_multi_buffer&, std::false_type);
+
+ void
+ debug_check() const;
+};
+
+/// A typical multi buffer
+using multi_buffer = basic_multi_buffer<std::allocator<char>>;
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/multi_buffer.ipp>
+
+#endif
diff --git a/boost/beast/core/ostream.hpp b/boost/beast/core/ostream.hpp
new file mode 100644
index 0000000000..1f00289bd1
--- /dev/null
+++ b/boost/beast/core/ostream.hpp
@@ -0,0 +1,104 @@
+//
+// 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_WRITE_OSTREAM_HPP
+#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>
+
+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.
+
+ @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
+ a `std::ostream` derived class, to allow `operator<<` stream style
+ formatting operations.
+
+ @par Example
+ @code
+ ostream(buffer) << "Hello, world!" << std::endl;
+ @endcode
+
+ @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
+ into which the formatted output will be placed.
+
+ @return An object derived from `std::ostream` which redirects output
+ The wrapped dynamic buffer is not modified, a copy is made instead.
+ Ownership of the underlying memory is not transferred, the application
+ is still responsible for managing its lifetime. The caller is
+ responsible for ensuring the dynamic buffer is not destroyed for the
+ lifetime of the output stream.
+*/
+template<class DynamicBuffer>
+#if BOOST_BEAST_DOXYGEN
+implementation_defined
+#else
+detail::ostream_helper<
+ DynamicBuffer, char, std::char_traits<char>,
+ detail::basic_streambuf_movable::value>
+#endif
+ostream(DynamicBuffer& buffer)
+{
+ static_assert(
+ boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
+ "DynamicBuffer requirements not met");
+ return detail::ostream_helper<
+ DynamicBuffer, char, std::char_traits<char>,
+ detail::basic_streambuf_movable::value>{buffer};
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/read_size.hpp b/boost/beast/core/read_size.hpp
new file mode 100644
index 0000000000..d9aaaa61ab
--- /dev/null
+++ b/boost/beast/core/read_size.hpp
@@ -0,0 +1,64 @@
+//
+// 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_READ_SIZE_HELPER_HPP
+#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 {
+namespace beast {
+
+/** Returns a natural read size.
+
+ This function inspects the capacity, size, and maximum
+ size of the dynamic buffer. Then it computes a natural
+ read size given the passed-in upper limit. It favors
+ a read size that does not require a reallocation, subject
+ to a reasonable minimum to avoid tiny reads.
+
+ @param buffer The dynamic buffer to inspect.
+
+ @param max_size An upper limit on the returned value.
+
+ @note If the buffer is already at its maximum size, zero
+ is returned.
+*/
+template<class DynamicBuffer>
+std::size_t
+read_size(DynamicBuffer& buffer, std::size_t max_size);
+
+/** Returns a natural read size or throw if the buffer is full.
+
+ This function inspects the capacity, size, and maximum
+ size of the dynamic buffer. Then it computes a natural
+ read size given the passed-in upper limit. It favors
+ a read size that does not require a reallocation, subject
+ to a reasonable minimum to avoid tiny reads.
+
+ @param buffer The dynamic buffer to inspect.
+
+ @param max_size An upper limit on the returned value.
+
+ @throws std::length_error if `max_size > 0` and the buffer
+ is full.
+*/
+template<class DynamicBuffer>
+std::size_t
+read_size_or_throw(DynamicBuffer& buffer,
+ std::size_t max_size);
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/read_size.ipp>
+
+#endif
diff --git a/boost/beast/core/span.hpp b/boost/beast/core/span.hpp
new file mode 100644
index 0000000000..4aa7788501
--- /dev/null
+++ b/boost/beast/core/span.hpp
@@ -0,0 +1,215 @@
+//
+// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_CORE_SPAN_HPP
+#define BOOST_BEAST_CORE_SPAN_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+
+/** A range of bytes expressed as a ContiguousContainer
+
+ This class implements a non-owning reference to a storage
+ area of a certain size and having an underlying integral
+ type with size of 1.
+
+ @tparam T The type pointed to by span iterators
+*/
+template<class T>
+class span
+{
+ T* data_ = nullptr;
+ std::size_t size_ = 0;
+
+public:
+ /// The type of value, including cv qualifiers
+ using element_type = T;
+
+ /// The type of value of each span element
+ using value_type = typename std::remove_const<T>::type;
+
+ /// The type of integer used to index the span
+ using index_type = std::ptrdiff_t;
+
+ /// A pointer to a span element
+ using pointer = T*;
+
+ /// A reference to a span element
+ using reference = T&;
+
+ /// The iterator used by the container
+ using iterator = pointer;
+
+ /// The const pointer used by the container
+ using const_pointer = T const*;
+
+ /// The const reference used by the container
+ using const_reference = T const&;
+
+ /// The const iterator used by the container
+ using const_iterator = const_pointer;
+
+ /// Constructor
+ span() = default;
+
+ /// Constructor
+ span(span const&) = default;
+
+ /// Assignment
+ span& operator=(span const&) = default;
+
+ /** Constructor
+
+ @param data A pointer to the beginning of the range of elements
+
+ @param size The number of elements pointed to by `data`
+ */
+ span(T* data, std::size_t size)
+ : data_(data), size_(size)
+ {
+ }
+
+ /** Constructor
+
+ @param container The container to construct from
+ */
+ template<class ContiguousContainer
+#if ! BOOST_BEAST_DOXYGEN
+ , class = typename std::enable_if<
+ detail::is_contiguous_container<
+ ContiguousContainer, T>::value>::type
+#endif
+ >
+ explicit
+ span(ContiguousContainer&& container)
+ : data_(container.data())
+ , size_(container.size())
+ {
+ }
+
+#if ! BOOST_BEAST_DOXYGEN
+ template<class CharT, class Traits, class Allocator>
+ explicit
+ span(std::basic_string<CharT, Traits, Allocator>& s)
+ : data_(&s[0])
+ , size_(s.size())
+ {
+ }
+
+ template<class CharT, class Traits, class Allocator>
+ explicit
+ span(std::basic_string<CharT, Traits, Allocator> const& s)
+ : data_(s.data())
+ , size_(s.size())
+ {
+ }
+#endif
+
+ /** Assignment
+
+ @param container The container to assign from
+ */
+ template<class ContiguousContainer>
+#if BOOST_BEAST_DOXYGEN
+ span&
+#else
+ typename std::enable_if<detail::is_contiguous_container<
+ ContiguousContainer, T>::value,
+ span&>::type
+#endif
+ operator=(ContiguousContainer&& container)
+ {
+ data_ = container.data();
+ size_ = container.size();
+ return *this;
+ }
+
+#if ! BOOST_BEAST_DOXYGEN
+ template<class CharT, class Traits, class Allocator>
+ span&
+ operator=(std::basic_string<
+ CharT, Traits, Allocator>& s)
+ {
+ data_ = &s[0];
+ size_ = s.size();
+ return *this;
+ }
+
+ template<class CharT, class Traits, class Allocator>
+ span&
+ operator=(std::basic_string<
+ CharT, Traits, Allocator> const& s)
+ {
+ data_ = s.data();
+ size_ = s.size();
+ return *this;
+ }
+#endif
+
+ /// Returns `true` if the span is empty
+ bool
+ empty() const
+ {
+ return size_ == 0;
+ }
+
+ /// Returns a pointer to the beginning of the span
+ T*
+ data() const
+ {
+ return data_;
+ }
+
+ /// Returns the number of elements in the span
+ std::size_t
+ size() const
+ {
+ return size_;
+ }
+
+ /// Returns an iterator to the beginning of the span
+ const_iterator
+ begin() const
+ {
+ return data_;
+ }
+
+ /// Returns an iterator to the beginning of the span
+ const_iterator
+ cbegin() const
+ {
+ return data_;
+ }
+
+ /// Returns an iterator to one past the end of the span
+ const_iterator
+ end() const
+ {
+ return data_ + size_;
+ }
+
+ /// Returns an iterator to one past the end of the span
+ const_iterator
+ cend() const
+ {
+ return data_ + size_;
+ }
+};
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/static_buffer.hpp b/boost/beast/core/static_buffer.hpp
new file mode 100644
index 0000000000..05496c4018
--- /dev/null
+++ b/boost/beast/core/static_buffer.hpp
@@ -0,0 +1,217 @@
+//
+// 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_STATIC_BUFFER_HPP
+#define BOOST_BEAST_STATIC_BUFFER_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/asio/buffer.hpp>
+#include <algorithm>
+#include <array>
+#include <cstddef>
+#include <cstring>
+
+namespace boost {
+namespace beast {
+
+/** A circular @b DynamicBuffer with a fixed size internal 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.
+
+ @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.
+
+ When used with @ref static_buffer this implements a dynamic
+ buffer using no memory allocations.
+
+ @see @ref static_buffer
+*/
+class static_buffer_base
+{
+ char* begin_;
+ std::size_t in_off_ = 0;
+ std::size_t in_size_ = 0;
+ std::size_t out_size_ = 0;
+ std::size_t capacity_;
+
+ static_buffer_base(static_buffer_base const& other) = delete;
+ 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::mutable_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.
+
+ @param p A pointer to valid storage of at least `n` bytes.
+
+ @param size The number of valid bytes pointed to by `p`.
+ */
+ static_buffer_base(void* p, std::size_t size);
+
+ /// Return the size of the input sequence.
+ std::size_t
+ size() const
+ {
+ return in_size_;
+ }
+
+ /// Return the maximum sum of the input and output sequence sizes.
+ std::size_t
+ max_size() const
+ {
+ return capacity_;
+ }
+
+ /// Return the maximum sum of input and output sizes that can be held without an allocation.
+ std::size_t
+ capacity() const
+ {
+ return capacity_;
+ }
+
+ /** Get a list of buffers that represent the input sequence.
+ */
+ const_buffers_type
+ data() const;
+
+ /** Get a list of buffers that represent the output sequence, with the given size.
+
+ @param size The number of bytes to request.
+
+ @throws std::length_error if the size would exceed the capacity.
+ */
+ mutable_buffers_type
+ prepare(std::size_t size);
+
+ /** Move bytes from the output sequence to the input sequence.
+
+ @param size The nubmer 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);
+
+ /** Remove bytes from the input sequence.
+
+ @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.
+ */
+ void
+ consume(std::size_t size);
+
+protected:
+ /** Constructor
+
+ 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;
+
+ /** Reset the pointed-to buffer.
+
+ 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 p A pointer to valid storage of at least `n` bytes.
+
+ @param size The number of valid bytes pointed to by `p`.
+ */
+ void
+ reset(void* p, std::size_t size);
+};
+
+//------------------------------------------------------------------------------
+
+/** A circular @b DynamicBuffer with a fixed size internal 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.
+
+ @tparam N The number of bytes in the internal buffer.
+
+ @note To reduce the number of template instantiations when passing
+ 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
+*/
+template<std::size_t N>
+class static_buffer : public static_buffer_base
+{
+ char buf_[N];
+
+public:
+ /// Constructor
+ static_buffer(static_buffer const&);
+
+ /// Constructor
+ static_buffer()
+ : static_buffer_base(buf_, N)
+ {
+ }
+
+ /// Assignment
+ static_buffer& operator=(static_buffer const&);
+
+ /// Returns the @ref static_buffer_base portion of this object
+ static_buffer_base&
+ base()
+ {
+ return *this;
+ }
+
+ /// Returns the @ref static_buffer_base portion of this object
+ static_buffer_base const&
+ base() const
+ {
+ return *this;
+ }
+
+ /// Return the maximum sum of the input and output sequence sizes.
+ std::size_t constexpr
+ max_size() const
+ {
+ return N;
+ }
+
+ /// Return the maximum sum of input and output sizes that can be held without an allocation.
+ std::size_t constexpr
+ capacity() const
+ {
+ return N;
+ }
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/static_buffer.ipp>
+
+#endif
diff --git a/boost/beast/core/static_string.hpp b/boost/beast/core/static_string.hpp
new file mode 100644
index 0000000000..991c2e64a5
--- /dev/null
+++ b/boost/beast/core/static_string.hpp
@@ -0,0 +1,1112 @@
+//
+// 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_STATIC_STRING_HPP
+#define BOOST_BEAST_STATIC_STRING_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/string.hpp>
+#include <boost/beast/core/detail/static_string.hpp>
+#include <algorithm>
+#include <cstdint>
+#include <initializer_list>
+#include <iterator>
+#include <ostream>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+
+namespace boost {
+namespace beast {
+
+/** A modifiable string with a fixed-size storage area.
+
+ These objects behave like `std::string` except that the storage
+ is not dynamically allocated but rather fixed in size.
+
+ These strings offer performance advantages when a protocol
+ imposes a natural small upper limit on the size of a value.
+
+ @note The stored string is always null-terminated.
+
+ @see @ref to_static_string
+*/
+template<
+ std::size_t N,
+ class CharT = char,
+ class Traits = std::char_traits<CharT>>
+class static_string
+{
+ template<std::size_t, class, class>
+ friend class static_string;
+
+ void
+ term()
+ {
+ Traits::assign(s_[n_], 0);
+ }
+
+ std::size_t n_;
+ CharT s_[N+1];
+
+public:
+ //
+ // Member types
+ //
+
+ using traits_type = Traits;
+ using value_type = typename Traits::char_type;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using pointer = value_type*;
+ using reference = value_type&;
+ using const_pointer = value_type const*;
+ using const_reference = value_type const&;
+ using iterator = value_type*;
+ using const_iterator = value_type const*;
+ using reverse_iterator =
+ std::reverse_iterator<iterator>;
+ using const_reverse_iterator =
+ std::reverse_iterator<const_iterator>;
+
+ /// The type of `string_view` returned by the interface
+ using string_view_type =
+ basic_string_view<CharT, Traits>;
+
+ //
+ // Constants
+ //
+
+ /// Maximum size of the string excluding the null terminator
+ static std::size_t constexpr max_size_n = N;
+
+ /// A special index
+ static constexpr size_type npos = size_type(-1);
+
+ //
+ // (constructor)
+ //
+
+ /// Default constructor (empty string).
+ static_string();
+
+ /** Construct with count copies of character `ch`.
+
+ The behavior is undefined if `count >= npos`
+ */
+ static_string(size_type count, CharT ch);
+
+ /// Construct with a substring (pos, other.size()) of `other`.
+ template<std::size_t M>
+ static_string(static_string<M, CharT, Traits> const& other,
+ size_type pos);
+
+ /// Construct with a substring (pos, count) of `other`.
+ template<std::size_t M>
+ static_string(static_string<M, CharT, Traits> const& other,
+ size_type pos, size_type count);
+
+ /// Construct with the first `count` characters of `s`, including nulls.
+ static_string(CharT const* s, size_type count);
+
+ /// Construct from a null terminated string.
+ static_string(CharT const* s);
+
+ /// Construct from a range of characters
+ template<class InputIt>
+ static_string(InputIt first, InputIt last);
+
+ /// Copy constructor.
+ static_string(static_string const& other);
+
+ /// Copy constructor.
+ template<std::size_t M>
+ static_string(static_string<M, CharT, Traits> const& other);
+
+ /// Construct from an initializer list
+ static_string(std::initializer_list<CharT> init);
+
+ /// Construct from a `string_view`
+ explicit
+ static_string(string_view_type sv);
+
+ /** Construct from any object convertible to `string_view_type`.
+
+ The range (pos, n) is extracted from the value
+ obtained by converting `t` to `string_view_type`,
+ and used to construct the string.
+ */
+#if BOOST_BEAST_DOXYGEN
+ template<class T>
+#else
+ template<class T, class = typename std::enable_if<
+ std::is_convertible<T, string_view_type>::value>::type>
+#endif
+ static_string(T const& t, size_type pos, size_type n);
+
+ //
+ // (assignment)
+ //
+
+ /// Copy assignment.
+ static_string&
+ operator=(static_string const& str)
+ {
+ return assign(str);
+ }
+
+ /// Copy assignment.
+ template<std::size_t M>
+ static_string&
+ operator=(static_string<M, CharT, Traits> const& str)
+ {
+ return assign(str);
+ }
+
+ /// Assign from null-terminated string.
+ static_string&
+ operator=(CharT const* s)
+ {
+ return assign(s);
+ }
+
+ /// Assign from single character.
+ static_string&
+ operator=(CharT ch)
+ {
+ return assign_char(ch,
+ std::integral_constant<bool, (N>0)>{});
+ }
+
+ /// Assign from initializer list.
+ static_string&
+ operator=(std::initializer_list<CharT> init)
+ {
+ return assign(init);
+ }
+
+ /// Assign from `string_view_type`.
+ static_string&
+ operator=(string_view_type sv)
+ {
+ return assign(sv);
+ }
+
+ /// Assign `count` copies of `ch`.
+ static_string&
+ assign(size_type count, CharT ch);
+
+ /// Assign from another `static_string`
+ static_string&
+ assign(static_string const& str);
+
+ // VFALCO NOTE this could come in two flavors,
+ // N>M and N<M, and skip the exception
+ // check when N>M
+
+ /// Assign from another `static_string`
+ template<std::size_t M>
+ static_string&
+ assign(static_string<M, CharT, Traits> const& str)
+ {
+ return assign(str.data(), str.size());
+ }
+
+ /// Assign `count` characterss starting at `npos` from `other`.
+ template<std::size_t M>
+ static_string&
+ assign(static_string<M, CharT, Traits> const& str,
+ size_type pos, size_type count = npos);
+
+ /// Assign the first `count` characters of `s`, including nulls.
+ static_string&
+ assign(CharT const* s, size_type count);
+
+ /// Assign a null terminated string.
+ static_string&
+ assign(CharT const* s)
+ {
+ return assign(s, Traits::length(s));
+ }
+
+ /// Assign from an iterator range of characters.
+ template<class InputIt>
+ static_string&
+ assign(InputIt first, InputIt last);
+
+ /// Assign from initializer list.
+ static_string&
+ assign(std::initializer_list<CharT> init)
+ {
+ return assign(init.begin(), init.end());
+ }
+
+ /// Assign from `string_view_type`.
+ static_string&
+ assign(string_view_type str)
+ {
+ return assign(str.data(), str.size());
+ }
+
+ /** Assign from any object convertible to `string_view_type`.
+
+ The range (pos, n) is extracted from the value
+ obtained by converting `t` to `string_view_type`,
+ and used to assign the string.
+ */
+ template<class T>
+#if BOOST_BEAST_DOXYGEN
+ static_string&
+#else
+ typename std::enable_if<std::is_convertible<T,
+ string_view_type>::value, static_string&>::type
+#endif
+ assign(T const& t,
+ size_type pos, size_type count = npos);
+
+ //
+ // Element access
+ //
+
+ /// Access specified character with bounds checking.
+ reference
+ at(size_type pos);
+
+ /// Access specified character with bounds checking.
+ const_reference
+ at(size_type pos) const;
+
+ /// Access specified character.
+ reference
+ operator[](size_type pos)
+ {
+ return s_[pos];
+ }
+
+ /// Access specified character.
+ const_reference
+ operator[](size_type pos) const
+ {
+ return s_[pos];
+ }
+
+ /// Accesses the first character.
+ CharT&
+ front()
+ {
+ return s_[0];
+ }
+
+ /// Accesses the first character.
+ CharT const&
+ front() const
+ {
+ return s_[0];
+ }
+
+ /// Accesses the last character.
+ CharT&
+ back()
+ {
+ return s_[n_-1];
+ }
+
+ /// Accesses the last character.
+ CharT const&
+ back() const
+ {
+ return s_[n_-1];
+ }
+
+ /// Returns a pointer to the first character of a string.
+ CharT*
+ data()
+ {
+ return &s_[0];
+ }
+
+ /// Returns a pointer to the first character of a string.
+ CharT const*
+ data() const
+ {
+ return &s_[0];
+ }
+
+ /// Returns a non-modifiable standard C character array version of the string.
+ CharT const*
+ c_str() const
+ {
+ return data();
+ }
+
+ /// Convert a static string to a `string_view_type`
+ operator string_view_type() const
+ {
+ return basic_string_view<
+ CharT, Traits>{data(), size()};
+ }
+
+ //
+ // Iterators
+ //
+
+ /// Returns an iterator to the beginning.
+ iterator
+ begin()
+ {
+ return &s_[0];
+ }
+
+ /// Returns an iterator to the beginning.
+ const_iterator
+ begin() const
+ {
+ return &s_[0];
+ }
+
+ /// Returns an iterator to the beginning.
+ const_iterator
+ cbegin() const
+ {
+ return &s_[0];
+ }
+
+ /// Returns an iterator to the end.
+ iterator
+ end()
+ {
+ return &s_[n_];
+ }
+
+ /// Returns an iterator to the end.
+ const_iterator
+ end() const
+ {
+ return &s_[n_];
+ }
+
+ /// Returns an iterator to the end.
+ const_iterator
+ cend() const
+ {
+ return &s_[n_];
+ }
+
+ /// Returns a reverse iterator to the beginning.
+ reverse_iterator
+ rbegin()
+ {
+ return reverse_iterator{end()};
+ }
+
+ /// Returns a reverse iterator to the beginning.
+ const_reverse_iterator
+ rbegin() const
+ {
+ return const_reverse_iterator{cend()};
+ }
+
+ /// Returns a reverse iterator to the beginning.
+ const_reverse_iterator
+ crbegin() const
+ {
+ return const_reverse_iterator{cend()};
+ }
+
+ /// Returns a reverse iterator to the end.
+ reverse_iterator
+ rend()
+ {
+ return reverse_iterator{begin()};
+ }
+
+ /// Returns a reverse iterator to the end.
+ const_reverse_iterator
+ rend() const
+ {
+ return const_reverse_iterator{cbegin()};
+ }
+
+ /// Returns a reverse iterator to the end.
+ const_reverse_iterator
+ crend() const
+ {
+ return const_reverse_iterator{cbegin()};
+ }
+
+ //
+ // Capacity
+ //
+
+ /// Returns `true` if the string is empty.
+ bool
+ empty() const
+ {
+ return n_ == 0;
+ }
+
+ /// Returns the number of characters, excluding the null terminator.
+ size_type
+ size() const
+ {
+ return n_;
+ }
+
+ /// Returns the number of characters, excluding the null terminator.
+ size_type
+ length() const
+ {
+ return size();
+ }
+
+ /// Returns the maximum number of characters that can be stored, excluding the null terminator.
+ size_type constexpr
+ max_size() const
+ {
+ return N;
+ }
+
+ /** Reserves storage.
+
+ This actually just throws an exception if `n > N`,
+ otherwise does nothing since the storage is fixed.
+ */
+ void
+ reserve(std::size_t n);
+
+ /// Returns the number of characters that can be held in currently allocated storage.
+ size_type constexpr
+ capacity() const
+ {
+ return max_size();
+ }
+
+ /** Reduces memory usage by freeing unused memory.
+
+ This actually does nothing, since the storage is fixed.
+ */
+ void
+ shrink_to_fit()
+ {
+ }
+
+ //
+ // Operations
+ //
+
+ /// Clears the contents.
+ void
+ clear();
+
+ static_string&
+ insert(size_type index, size_type count, CharT ch);
+
+ static_string&
+ insert(size_type index, CharT const* s)
+ {
+ return insert(index, s, Traits::length(s));
+ }
+
+ static_string&
+ insert(size_type index, CharT const* s, size_type count);
+
+ template<std::size_t M>
+ static_string&
+ insert(size_type index,
+ static_string<M, CharT, Traits> const& str)
+ {
+ return insert(index, str.data(), str.size());
+ }
+
+ template<std::size_t M>
+ static_string&
+ insert(size_type index,
+ static_string<M, CharT, Traits> const& str,
+ size_type index_str, size_type count = npos);
+
+ iterator
+ insert(const_iterator pos, CharT ch)
+ {
+ return insert(pos, 1, ch);
+ }
+
+ iterator
+ insert(const_iterator pos, size_type count, CharT ch);
+
+ template<class InputIt>
+#if BOOST_BEAST_DOXYGEN
+ iterator
+#else
+ typename std::enable_if<
+ detail::is_input_iterator<InputIt>::value,
+ iterator>::type
+#endif
+ insert(const_iterator pos, InputIt first, InputIt last);
+
+ iterator
+ insert(const_iterator pos, std::initializer_list<CharT> init)
+ {
+ return insert(pos, init.begin(), init.end());
+ }
+
+ static_string&
+ insert(size_type index, string_view_type str)
+ {
+ return insert(index, str.data(), str.size());
+ }
+
+ template<class T>
+#if BOOST_BEAST_DOXYGEN
+ static_string&
+#else
+ typename std::enable_if<
+ std::is_convertible<T const&, string_view_type>::value &&
+ ! std::is_convertible<T const&, CharT const*>::value,
+ static_string&>::type
+#endif
+ insert(size_type index, T const& t,
+ size_type index_str, size_type count = npos);
+
+ static_string&
+ erase(size_type index = 0, size_type count = npos);
+
+ iterator
+ erase(const_iterator pos);
+
+ iterator
+ erase(const_iterator first, const_iterator last);
+
+ void
+ push_back(CharT ch);
+
+ void
+ pop_back()
+ {
+ Traits::assign(s_[--n_], 0);
+ }
+
+ static_string&
+ append(size_type count, CharT ch)
+ {
+ insert(end(), count, ch);
+ return *this;
+ }
+
+ template<std::size_t M>
+ static_string&
+ append(static_string<M, CharT, Traits> const& str)
+ {
+ insert(size(), str);
+ return *this;
+ }
+
+ template<std::size_t M>
+ static_string&
+ append(static_string<M, CharT, Traits> const& str,
+ size_type pos, size_type count = npos);
+
+ static_string&
+ append(CharT const* s, size_type count)
+ {
+ insert(size(), s, count);
+ return *this;
+ }
+
+ static_string&
+ append(CharT const* s)
+ {
+ insert(size(), s);
+ return *this;
+ }
+
+ template<class InputIt>
+#if BOOST_BEAST_DOXYGEN
+ static_string&
+#else
+ typename std::enable_if<
+ detail::is_input_iterator<InputIt>::value,
+ static_string&>::type
+#endif
+ append(InputIt first, InputIt last)
+ {
+ insert(end(), first, last);
+ return *this;
+ }
+
+ static_string&
+ append(std::initializer_list<CharT> init)
+ {
+ insert(end(), init);
+ return *this;
+ }
+
+ static_string&
+ append(string_view_type sv)
+ {
+ insert(size(), sv);
+ return *this;
+ }
+
+ template<class T>
+ typename std::enable_if<
+ std::is_convertible<T const&, string_view_type>::value &&
+ ! std::is_convertible<T const&, CharT const*>::value,
+ static_string&>::type
+ append(T const& t, size_type pos, size_type count = npos)
+ {
+ insert(size(), t, pos, count);
+ return *this;
+ }
+
+ template<std::size_t M>
+ static_string&
+ operator+=(static_string<M, CharT, Traits> const& str)
+ {
+ return append(str.data(), str.size());
+ }
+
+ static_string&
+ operator+=(CharT ch)
+ {
+ push_back(ch);
+ return *this;
+ }
+
+ static_string&
+ operator+=(CharT const* s)
+ {
+ return append(s);
+ }
+
+ static_string&
+ operator+=(std::initializer_list<CharT> init)
+ {
+ return append(init);
+ }
+
+ static_string&
+ operator+=(string_view_type const& str)
+ {
+ return append(str);
+ }
+
+ template<std::size_t M>
+ int
+ compare(static_string<M, CharT, Traits> const& str) const
+ {
+ return detail::lexicographical_compare<CharT, Traits>(
+ &s_[0], n_, &str.s_[0], str.n_);
+ }
+
+ template<std::size_t M>
+ int
+ compare(size_type pos1, size_type count1,
+ static_string<M, CharT, Traits> const& str) const
+ {
+ return detail::lexicographical_compare<CharT, Traits>(
+ substr(pos1, count1), str.data(), str.size());
+ }
+
+ template<std::size_t M>
+ int
+ compare(size_type pos1, size_type count1,
+ static_string<M, CharT, Traits> const& str,
+ size_type pos2, size_type count2 = npos) const
+ {
+ return detail::lexicographical_compare(
+ substr(pos1, count1), str.substr(pos2, count2));
+ }
+
+ int
+ compare(CharT const* s) const
+ {
+ return detail::lexicographical_compare<CharT, Traits>(
+ &s_[0], n_, s, Traits::length(s));
+ }
+
+ int
+ compare(size_type pos1, size_type count1,
+ CharT const* s) const
+ {
+ return detail::lexicographical_compare<CharT, Traits>(
+ substr(pos1, count1), s, Traits::length(s));
+ }
+
+ int
+ compare(size_type pos1, size_type count1,
+ CharT const*s, size_type count2) const
+ {
+ return detail::lexicographical_compare<CharT, Traits>(
+ substr(pos1, count1), s, count2);
+ }
+
+ int
+ compare(string_view_type str) const
+ {
+ return detail::lexicographical_compare<CharT, Traits>(
+ &s_[0], n_, str.data(), str.size());
+ }
+
+ int
+ compare(size_type pos1, size_type count1,
+ string_view_type str) const
+ {
+ return detail::lexicographical_compare<CharT, Traits>(
+ substr(pos1, count1), str);
+ }
+
+ template<class T>
+#if BOOST_BEAST_DOXYGEN
+ int
+#else
+ typename std::enable_if<
+ std::is_convertible<T const&, string_view_type>::value &&
+ ! std::is_convertible<T const&, CharT const*>::value,
+ int>::type
+#endif
+ compare(size_type pos1, size_type count1,
+ T const& t, size_type pos2,
+ size_type count2 = npos) const
+ {
+ return compare(pos1, count1,
+ string_view_type(t).substr(pos2, count2));
+ }
+
+ string_view_type
+ substr(size_type pos = 0, size_type count = npos) const;
+
+ /// Copy a substring (pos, pos+count) to character string pointed to by `dest`.
+ size_type
+ copy(CharT* dest, size_type count, size_type pos = 0) const;
+
+ /** Changes the number of characters stored.
+
+ If the resulting string is larger, the new
+ characters are uninitialized.
+ */
+ void
+ resize(std::size_t n);
+
+ /** Changes the number of characters stored.
+
+ If the resulting string is larger, the new
+ characters are initialized to the value of `c`.
+ */
+ void
+ resize(std::size_t n, CharT c);
+
+ /// Exchange the contents of this string with another.
+ void
+ swap(static_string& str);
+
+ /// Exchange the contents of this string with another.
+ template<std::size_t M>
+ void
+ swap(static_string<M, CharT, Traits>& str);
+
+ //
+ // Search
+ //
+
+private:
+ static_string&
+ assign_char(CharT ch, std::true_type);
+
+ static_string&
+ assign_char(CharT ch, std::false_type);
+};
+
+//
+// Disallowed operations
+//
+
+// These operations are explicitly deleted since
+// there is no reasonable implementation possible.
+
+template<std::size_t N, std::size_t M, class CharT, class Traits>
+void
+operator+(
+ static_string<N, CharT, Traits>const& lhs,
+ static_string<M, CharT, Traits>const& rhs) = delete;
+
+template<std::size_t N, class CharT, class Traits>
+void
+operator+(CharT const* lhs,
+ static_string<N, CharT, Traits>const& rhs) = delete;
+
+template<std::size_t N, class CharT, class Traits>
+void
+operator+(CharT lhs,
+ static_string<N, CharT, Traits> const& rhs) = delete;
+
+template<std::size_t N, class CharT, class Traits>
+void
+operator+(static_string<N, CharT, Traits> const& lhs,
+ CharT const* rhs) = delete;
+
+template<std::size_t N, class CharT, class Traits>
+void
+operator+(static_string<N, CharT, Traits> const& lhs,
+ CharT rhs) = delete;
+
+//
+// Non-member functions
+//
+
+template<std::size_t N, std::size_t M,
+ class CharT, class Traits>
+bool
+operator==(
+ static_string<N, CharT, Traits> const& lhs,
+ static_string<M, CharT, Traits> const& rhs)
+{
+ return lhs.compare(rhs) == 0;
+}
+
+template<std::size_t N, std::size_t M,
+ class CharT, class Traits>
+bool
+operator!=(
+ static_string<N, CharT, Traits> const& lhs,
+ static_string<M, CharT, Traits> const& rhs)
+{
+ return lhs.compare(rhs) != 0;
+}
+
+template<std::size_t N, std::size_t M,
+ class CharT, class Traits>
+bool
+operator<(
+ static_string<N, CharT, Traits> const& lhs,
+ static_string<M, CharT, Traits> const& rhs)
+{
+ return lhs.compare(rhs) < 0;
+}
+
+template<std::size_t N, std::size_t M,
+ class CharT, class Traits>
+bool
+operator<=(
+ static_string<N, CharT, Traits> const& lhs,
+ static_string<M, CharT, Traits> const& rhs)
+{
+ return lhs.compare(rhs) <= 0;
+}
+
+template<std::size_t N, std::size_t M,
+ class CharT, class Traits>
+bool
+operator>(
+ static_string<N, CharT, Traits> const& lhs,
+ static_string<M, CharT, Traits> const& rhs)
+{
+ return lhs.compare(rhs) > 0;
+}
+
+template<std::size_t N, std::size_t M,
+ class CharT, class Traits>
+bool
+operator>=(
+ static_string<N, CharT, Traits> const& lhs,
+ static_string<M, CharT, Traits> const& rhs)
+{
+ return lhs.compare(rhs) >= 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator==(
+ CharT const* lhs,
+ static_string<N, CharT, Traits> const& rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs, Traits::length(lhs),
+ rhs.data(), rhs.size()) == 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator==(
+ static_string<N, CharT, Traits> const& lhs,
+ CharT const* rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs.data(), lhs.size(),
+ rhs, Traits::length(rhs)) == 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator!=(
+ CharT const* lhs,
+ static_string<N, CharT, Traits> const& rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs, Traits::length(lhs),
+ rhs.data(), rhs.size()) != 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator!=(
+ static_string<N, CharT, Traits> const& lhs,
+ CharT const* rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs.data(), lhs.size(),
+ rhs, Traits::length(rhs)) != 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator<(
+ CharT const* lhs,
+ static_string<N, CharT, Traits> const& rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs, Traits::length(lhs),
+ rhs.data(), rhs.size()) < 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator<(
+ static_string<N, CharT, Traits> const& lhs,
+ CharT const* rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs.data(), lhs.size(),
+ rhs, Traits::length(rhs)) < 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator<=(
+ CharT const* lhs,
+ static_string<N, CharT, Traits> const& rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs, Traits::length(lhs),
+ rhs.data(), rhs.size()) <= 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator<=(
+ static_string<N, CharT, Traits> const& lhs,
+ CharT const* rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs.data(), lhs.size(),
+ rhs, Traits::length(rhs)) <= 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator>(
+ CharT const* lhs,
+ static_string<N, CharT, Traits> const& rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs, Traits::length(lhs),
+ rhs.data(), rhs.size()) > 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator>(
+ static_string<N, CharT, Traits> const& lhs,
+ CharT const* rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs.data(), lhs.size(),
+ rhs, Traits::length(rhs)) > 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator>=(
+ CharT const* lhs,
+ static_string<N, CharT, Traits> const& rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs, Traits::length(lhs),
+ rhs.data(), rhs.size()) >= 0;
+}
+
+template<std::size_t N, class CharT, class Traits>
+bool
+operator>=(
+ static_string<N, CharT, Traits> const& lhs,
+ CharT const* rhs)
+{
+ return detail::lexicographical_compare<CharT, Traits>(
+ lhs.data(), lhs.size(),
+ rhs, Traits::length(rhs)) >= 0;
+}
+
+//
+// swap
+//
+
+template<std::size_t N, class CharT, class Traits>
+void
+swap(
+ static_string<N, CharT, Traits>& lhs,
+ static_string<N, CharT, Traits>& rhs)
+{
+ lhs.swap(rhs);
+}
+
+template<std::size_t N, std::size_t M,
+ class CharT, class Traits>
+void
+swap(
+ static_string<N, CharT, Traits>& lhs,
+ static_string<M, CharT, Traits>& rhs)
+{
+ lhs.swap(rhs);
+}
+
+//
+// Input/Output
+//
+
+template<std::size_t N, class CharT, class Traits>
+std::basic_ostream<CharT, Traits>&
+operator<<(std::basic_ostream<CharT, Traits>& os,
+ static_string<N, CharT, Traits> const& str)
+{
+ return os << static_cast<
+ beast::basic_string_view<CharT, Traits>>(str);
+}
+
+//
+// Numeric conversions
+//
+
+/** Returns a static string representing an integer as a decimal.
+
+ @param x The signed or unsigned integer to convert.
+ This must be an integral type.
+
+ @return A @ref static_string with an implementation defined
+ maximum size large enough to hold the longest possible decimal
+ representation of any integer of the given type.
+*/
+template<class Integer>
+static_string<detail::max_digits(sizeof(Integer))>
+to_static_string(Integer x);
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/static_string.ipp>
+
+#endif
diff --git a/boost/beast/core/string.hpp b/boost/beast/core/string.hpp
new file mode 100644
index 0000000000..f262b565da
--- /dev/null
+++ b/boost/beast/core/string.hpp
@@ -0,0 +1,155 @@
+//
+// 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_STRING_HPP
+#define BOOST_BEAST_STRING_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/version.hpp>
+#ifndef BOOST_BEAST_NO_BOOST_STRING_VIEW
+# if BOOST_VERSION >= 106400
+# define BOOST_BEAST_NO_BOOST_STRING_VIEW 0
+# else
+# define BOOST_BEAST_NO_BOOST_STRING_VIEW 1
+# endif
+#endif
+
+#if BOOST_BEAST_NO_BOOST_STRING_VIEW
+#include <boost/utility/string_ref.hpp>
+#else
+#include <boost/utility/string_view.hpp>
+#endif
+
+#include <algorithm>
+
+namespace boost {
+namespace beast {
+
+#if BOOST_BEAST_NO_BOOST_STRING_VIEW
+/// The type of string view used by the library
+using string_view = boost::string_ref;
+
+/// The type of basic string view used by the library
+template<class CharT, class Traits>
+using basic_string_view =
+ boost::basic_string_ref<CharT, Traits>;
+#else
+/// The type of string view used by the library
+using string_view = boost::string_view;
+
+/// The type of basic string view used by the library
+template<class CharT, class Traits>
+using basic_string_view =
+ boost::basic_string_view<CharT, Traits>;
+#endif
+
+namespace detail {
+
+inline
+char
+ascii_tolower(char c)
+{
+ if(c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ return c;
+}
+
+template<class = void>
+bool
+iequals(
+ beast::string_view lhs,
+ beast::string_view rhs)
+{
+ auto n = lhs.size();
+ if(rhs.size() != n)
+ return false;
+ auto p1 = lhs.data();
+ auto p2 = rhs.data();
+ char a, b;
+ while(n--)
+ {
+ a = *p1++;
+ b = *p2++;
+ if(a != b)
+ goto slow;
+ }
+ return true;
+
+ while(n--)
+ {
+ slow:
+ if(ascii_tolower(a) != ascii_tolower(b))
+ return false;
+ a = *p1++;
+ b = *p2++;
+ }
+ return true;
+}
+
+} // detail
+
+/** Returns `true` if two strings are equal, using a case-insensitive comparison.
+
+ The case-comparison operation is defined only for low-ASCII characters.
+
+ @param lhs The string on the left side of the equality
+
+ @param rhs The string on the right side of the equality
+*/
+inline
+bool
+iequals(
+ beast::string_view lhs,
+ beast::string_view rhs)
+{
+ return detail::iequals(lhs, rhs);
+}
+
+/** A case-insensitive less predicate for strings.
+
+ The case-comparison operation is defined only for low-ASCII characters.
+*/
+struct iless
+{
+ bool
+ operator()(
+ string_view lhs,
+ string_view rhs) const
+ {
+ using std::begin;
+ using std::end;
+ return std::lexicographical_compare(
+ begin(lhs), end(lhs), begin(rhs), end(rhs),
+ [](char c1, char c2)
+ {
+ return detail::ascii_tolower(c1) < detail::ascii_tolower(c2);
+ }
+ );
+ }
+};
+
+/** A case-insensitive equality predicate for strings.
+
+ The case-comparison operation is defined only for low-ASCII characters.
+*/
+struct iequal
+{
+ bool
+ operator()(
+ string_view lhs,
+ string_view rhs) const
+ {
+ return iequals(lhs, rhs);
+ }
+};
+
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/core/string_param.hpp b/boost/beast/core/string_param.hpp
new file mode 100644
index 0000000000..a068cc4091
--- /dev/null
+++ b/boost/beast/core/string_param.hpp
@@ -0,0 +1,130 @@
+//
+// 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_STRING_PARAM_HPP
+#define BOOST_BEAST_STRING_PARAM_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/string.hpp>
+#include <boost/beast/core/static_string.hpp>
+#include <boost/beast/core/detail/static_ostream.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/optional.hpp>
+
+namespace boost {
+namespace beast {
+
+/** A function parameter which efficiently converts to string.
+
+ This is used as a function parameter type to allow callers
+ notational convenience: objects other than strings may be
+ passed in contexts where a string is expected. The conversion
+ to string is made using `operator<<` to a non-dynamically
+ allocated static buffer if possible, else to a `std::string`
+ on overflow.
+
+ To use it, modify your function signature to accept
+ `string_param` and then extract the string inside the
+ function:
+ @code
+ void print(string_param s)
+ {
+ std::cout << s.str();
+ }
+ @endcode
+*/
+class string_param
+{
+ string_view sv_;
+ char buf_[128];
+ boost::optional<detail::static_ostream> os_;
+
+ template<class T>
+ typename std::enable_if<
+ std::is_integral<T>::value>::type
+ print(T const&);
+
+ template<class T>
+ typename std::enable_if<
+ ! std::is_integral<T>::value &&
+ ! std::is_convertible<T, string_view>::value
+ >::type
+ print(T const&);
+
+ void
+ print(string_view);
+
+ template<class T>
+ typename std::enable_if<
+ std::is_integral<T>::value>::type
+ print_1(T const&);
+
+ template<class T>
+ typename std::enable_if<
+ ! std::is_integral<T>::value>::type
+ print_1(T const&);
+
+ void
+ print_n()
+ {
+ }
+
+ template<class T0, class... TN>
+ void
+ print_n(T0 const&, TN const&...);
+
+ template<class T0, class T1, class... TN>
+ void
+ print(T0 const&, T1 const&, TN const&...);
+
+public:
+ /// Copy constructor (disallowed)
+ string_param(string_param const&) = delete;
+
+ /// Copy assignment (disallowed)
+ string_param& operator=(string_param const&) = delete;
+
+ /** Constructor
+
+ This function constructs a string as if by concatenating
+ the result of streaming each argument in order into an
+ output stream. It is used as a notational convenience
+ at call sites which expect a parameter with the semantics
+ of a @ref string_view.
+
+ The implementation uses a small, internal static buffer
+ to avoid memory allocations especially for the case where
+ the list of arguments to be converted consists of a single
+ integral type.
+
+ @param args One or more arguments to convert
+ */
+ template<class... Args>
+ string_param(Args const&... args);
+
+ /// Returns the contained string
+ string_view
+ str() const
+ {
+ return sv_;
+ }
+
+ /// Implicit conversion to @ref string_view
+ operator string_view const() const
+ {
+ return sv_;
+ }
+};
+
+} // beast
+} // boost
+
+#include <boost/beast/core/impl/string_param.ipp>
+
+#endif
diff --git a/boost/beast/core/type_traits.hpp b/boost/beast/core/type_traits.hpp
new file mode 100644
index 0000000000..d622e0e8ec
--- /dev/null
+++ b/boost/beast/core/type_traits.hpp
@@ -0,0 +1,490 @@
+//
+// 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_TYPE_TRAITS_HPP
+#define BOOST_BEAST_TYPE_TRAITS_HPP
+
+#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>
+
+namespace boost {
+namespace beast {
+
+//------------------------------------------------------------------------------
+//
+// Handler concepts
+//
+//------------------------------------------------------------------------------
+
+/** Determine if `T` meets the requirements of @b CompletionHandler.
+
+ This trait checks whether a type meets the requirements for a completion
+ handler, and is also callable with the specified signature.
+ 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
+ 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, ...>;
+#else
+using is_completion_handler = std::integral_constant<bool,
+ std::is_copy_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(),
+ (void)0)>> : std::true_type {};
+#endif
+
+/** Returns `T::lowest_layer_type` if it exists, else `T`
+
+ This will contain a nested `type` equal to `T::lowest_layer_type`
+ if it exists, else `type` will be equal to `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 = typename get_lowest_layer<stream_type>::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, typename get_lowest_layer<T>::type>::value> {};
+ @endcode
+*/
+#if BOOST_BEAST_DOXYGEN
+template<class T>
+struct get_lowest_layer;
+#else
+template<class T, class = void>
+struct get_lowest_layer
+{
+ using type = T;
+};
+
+template<class T>
+struct get_lowest_layer<T, detail::void_t<
+ typename T::lowest_layer_type>>
+{
+ using type = typename T::lowest_layer_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>()),
+ (void)0)>> : 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>()),
+ (void)0)>> : 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&>()),
+ (void)0)>> : 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&>()),
+ (void)0)>> : 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&>()),
+ (void)0)>> : std::integral_constant<bool,
+ std::is_default_constructible<T>::value &&
+ std::is_destructible<T>::value
+ > {};
+#endif
+
+} // beast
+} // boost
+
+#endif