diff options
Diffstat (limited to 'boost/beast/core')
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 |