diff --git a/CHANGELOG.md b/CHANGELOG.md index 09021deb..3819ddcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Version 42 * Fix javadoc typo * Add formal review notes +* Make buffers_view a public interface -------------------------------------------------------------------------------- diff --git a/doc/core.qbk b/doc/core.qbk index 6b87f211..0088aaca 100644 --- a/doc/core.qbk +++ b/doc/core.qbk @@ -120,13 +120,12 @@ dynamic buffer concept using various strategies: [table Dynamic buffer implementations [[Name][Description]] [[ - [link beast.ref.multi_buffer `multi_buffer`] - [link beast.ref.basic_multi_buffer `basic_multi_buffer`] + [link beast.ref.buffers_adapter `buffers_adapter`] ][ - 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. The basic - container supports the standard allocator model. + This wrapper adapts any __MutableBufferSequence__ into a + __DynamicBuffer__ with an upper limit on the total size of the input and + output areas equal to the size of the underlying mutable buffer sequence. + The implementation does not perform heap allocations. ]] [[ [link beast.ref.flat_buffer `flat_buffer`] @@ -137,6 +136,15 @@ dynamic buffer concept using various strategies: size of the input and output areas may be set. The basic container supports the standard allocator model. ]] +[[ + [link beast.ref.multi_buffer `multi_buffer`] + [link beast.ref.basic_multi_buffer `basic_multi_buffer`] +][ + 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. The basic + container supports the standard allocator model. +]] [[ [link beast.ref.static_buffer `static_buffer`] [link beast.ref.static_buffer `static_buffer_n`] @@ -146,14 +154,6 @@ dynamic buffer concept using various strategies: by a constexpr template parameter. The storage for the sequences are kept in the class; the implementation does not perform heap allocations. ]] -[[ - [link beast.ref.buffers_adapter `buffers_adapter`] -][ - This wrapper adapts any __MutableBufferSequence__ into a - __DynamicBuffer__ with an upper limit on the total size of the input and - output areas equal to the size of the underlying mutable buffer sequence. - The implementation does not perform heap allocations. -]] ] [endsect] @@ -180,6 +180,20 @@ underlying memory, whose lifetime is retained by the caller. to a stream's `write_some` function to be combined into one, eliminating expensive system calls. ]] +[[ + [link beast.ref.buffer_prefix `buffer_prefix`] +][ + This function returns a new buffer or buffer sequence which wraps the + underlying memory of an existing buffer sequence, but with a smaller size. + This lets callers work with a prefix of a buffer sequence. +]] +[[ + [link beast.ref.buffer_cat `buffers_view`] +][ + This class represents a buffer sequence which represents the concatenation + of two or more buffer sequences. This is type of object returned by + [link beast.ref.buffer_cat `buffer_cat`]. +]] [[ [link beast.ref.consuming_buffers `consuming_buffers`] ][ @@ -188,13 +202,6 @@ underlying memory, whose lifetime is retained by the caller. may be progressively shortened. This lets callers work with sequential increments of a buffer sequence. ]] -[[ - [link beast.ref.buffer_prefix `buffer_prefix`] -][ - This function returns a new buffer or buffer sequence which wraps the - underlying memory of an existing buffer sequence, but with a smaller size. - This lets callers work with a prefix of a buffer sequence. -]] ] [endsect] @@ -236,12 +243,13 @@ the associated asynchronous initiation functions used to launch them. [table Asynchronous Helpers [[Name][Description]] [[ - [link beast.ref.handler_type `handler_type`] + [link beast.ref.async_completion `async_completion`] ][ - This template alias converts a completion token and signature to the - correct completion handler type. It is used in the implementation of - asynchronous initiation functions to meet the requirements of the - Extensible Asynchronous Model. + This class aggregates the completion handler customization point and + the asynchronous initiation function return value customization point + into a single object which exposes the appropriate output types for the + given input types, and also contains boilerplate that is necessary to + implement an initiation function using the Extensible Model. ]] [[ [link beast.ref.async_return_type `async_return_type`] @@ -252,13 +260,15 @@ the associated asynchronous initiation functions used to launch them. Extensible Asynchronous Model. ]] [[ - [link beast.ref.async_completion `async_completion`] + [link beast.ref.bind_handler `bind_handler`] ][ - This class aggregates the completion handler customization point and - the asynchronous initiation function return value customization point - into a single object which exposes the appropriate output types for the - given input types, and also contains boilerplate that is necessary to - implement an initiation function using the Extensible Model. + This function returns a new, nullary completion handler which when + invoked with no arguments invokes the original completion handler with a + list of bound arguments. The invocation is made from the same implicit + or explicit strand as that which would be used to invoke the original + handler. This is accomplished by using the correct overload of + `asio_handler_invoke` associated with the original completion handler. + ]] [[ [link beast.ref.handler_alloc `handler_alloc`] @@ -282,15 +292,12 @@ the associated asynchronous initiation functions used to launch them. optimizations transparently. ]] [[ - [link beast.ref.bind_handler `bind_handler`] + [link beast.ref.handler_type `handler_type`] ][ - This function returns a new, nullary completion handler which when - invoked with no arguments invokes the original completion handler with a - list of bound arguments. The invocation is made from the same implicit - or explicit strand as that which would be used to invoke the original - handler. This is accomplished by using the correct overload of - `asio_handler_invoke` associated with the original completion handler. - + This template alias converts a completion token and signature to the + correct completion handler type. It is used in the implementation of + asynchronous initiation functions to meet the requirements of the + Extensible Asynchronous Model. ]] ] diff --git a/doc/quickref.xml b/doc/quickref.xml index d99617dd..42765b4e 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -157,6 +157,7 @@ basic_flat_buffer basic_multi_buffer buffers_adapter + buffers_view consuming_buffers buffered_read_stream error_category diff --git a/include/beast/core/buffer_cat.hpp b/include/beast/core/buffer_cat.hpp index 0f83393f..300d8c26 100644 --- a/include/beast/core/buffer_cat.hpp +++ b/include/beast/core/buffer_cat.hpp @@ -9,17 +9,67 @@ #define BEAST_BUFFER_CAT_HPP #include -#include -#include -#include -#include -#include -#include +#include #include -#include namespace beast { +/** A buffer sequence representing a concatenation of buffer sequences. + + @see @ref buffer_cat +*/ +template +class buffers_view +{ + std::tuple 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`. + */ + using value_type = + #if BEAST_DOXYGEN + implementation_defined; + #else + typename detail::common_buffers_type::type; + #endif + + /// The type of iterator used by the concatenated sequence + class const_iterator; + + /// Move constructor + buffers_view(buffers_view&&) = default; + + /// Copy constructor + buffers_view(buffers_view const&) = default; + + /// Move assignment + buffers_view& operator=(buffers_view&&) = default; + + // Copy assignment + buffers_view& operator=(buffers_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_view(Buffers const&... buffers); + + /// Return an iterator to the beginning of the concatenated sequence. + const_iterator + begin() const; + + /// Return an iterator to the end of the concatenated sequence. + const_iterator + end() const; +}; + /** Concatenate 2 or more buffer sequences. This function returns a constant or mutable buffer sequence which, @@ -36,24 +86,28 @@ namespace beast { @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_view */ #if BEAST_DOXYGEN template -implementation_defined +buffers_view buffer_cat(BufferSequence const&... buffers) #else template -detail::buffer_cat_helper +inline +buffers_view buffer_cat(B1 const& b1, B2 const& b2, Bn const&... bn) #endif { static_assert( - detail::is_all_ConstBufferSequence::value, + detail::is_all_const_buffer_sequence::value, "BufferSequence requirements not met"); - return detail::buffer_cat_helper< - B1, B2, Bn...>{b1, b2, bn...}; + return buffers_view{b1, b2, bn...}; } } // beast +#include + #endif diff --git a/include/beast/core/detail/type_traits.hpp b/include/beast/core/detail/type_traits.hpp index d3f24919..d3467b7d 100644 --- a/include/beast/core/detail/type_traits.hpp +++ b/include/beast/core/detail/type_traits.hpp @@ -244,20 +244,6 @@ public: type3::value && type4::value>; }; -template -struct is_all_ConstBufferSequence - : std::integral_constant::type::value && - is_all_ConstBufferSequence::value> -{ -}; - -template -struct is_all_ConstBufferSequence - : is_buffer_sequence::type -{ -}; - template class is_dynamic_buffer { @@ -335,6 +321,33 @@ public: //------------------------------------------------------------------------------ +template +struct is_all_const_buffer_sequence + : std::integral_constant::type::value && + is_all_const_buffer_sequence::value> +{ +}; + +template +struct is_all_const_buffer_sequence + : is_buffer_sequence::type +{ +}; + +template +struct common_buffers_type +{ + using type = typename std::conditional< + std::is_convertible, + typename repeat_tuple::type>::value, + boost::asio::mutable_buffer, + boost::asio::const_buffer>::type; +}; + +//------------------------------------------------------------------------------ + // // stream concepts // diff --git a/include/beast/core/detail/buffer_cat.hpp b/include/beast/core/impl/buffer_cat.ipp similarity index 79% rename from include/beast/core/detail/buffer_cat.hpp rename to include/beast/core/impl/buffer_cat.ipp index d441f0e4..38c8d1c6 100644 --- a/include/beast/core/detail/buffer_cat.hpp +++ b/include/beast/core/impl/buffer_cat.ipp @@ -5,10 +5,10 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_DETAIL_BUFFER_CAT_HPP -#define BEAST_DETAIL_BUFFER_CAT_HPP +#ifndef BEAST_IMPL_BUFFER_CAT_IPP +#define BEAST_IMPL_BUFFER_CAT_IPP -#include +#include #include #include #include @@ -18,57 +18,16 @@ #include namespace beast { -namespace detail { template -struct common_buffers_type -{ - using type = typename std::conditional< - std::is_convertible, - typename repeat_tuple::type>::value, - boost::asio::mutable_buffer, - boost::asio::const_buffer>::type; -}; - -template -class buffer_cat_helper -{ - std::tuple bn_; - -public: - using value_type = typename - common_buffers_type::type; - - class const_iterator; - - buffer_cat_helper(buffer_cat_helper&&) = default; - buffer_cat_helper(buffer_cat_helper const&) = default; - buffer_cat_helper& operator=(buffer_cat_helper&&) = delete; - buffer_cat_helper& operator=(buffer_cat_helper const&) = delete; - - explicit - buffer_cat_helper(Bn const&... bn) - : bn_(bn...) - { - } - - const_iterator - begin() const; - - const_iterator - end() const; -}; - -template -class buffer_cat_helper::const_iterator +class buffers_view::const_iterator { std::size_t n_; std::tuple const* bn_; - std::array()> buf_; + char buf_[detail::max_sizeof< + typename Bn::const_iterator...>()]; - friend class buffer_cat_helper; + friend class buffers_view; template using C = std::integral_constant; @@ -83,8 +42,7 @@ class buffer_cat_helper::const_iterator { // type-pun return *reinterpret_cast< - iter_t*>(static_cast( - buf_.data())); + iter_t*>(static_cast(buf_)); } template @@ -94,12 +52,12 @@ class buffer_cat_helper::const_iterator // type-pun return *reinterpret_cast< iter_t const*>(static_cast< - void const*>(buf_.data())); + void const*>(buf_)); } public: using value_type = typename - common_buffers_type::type; + detail::common_buffers_type::type; using pointer = value_type const*; using reference = value_type; using difference_type = std::ptrdiff_t; @@ -119,7 +77,7 @@ public: bool operator!=(const_iterator const& other) const { - return !(*this == other); + return ! (*this == other); } reference @@ -169,7 +127,7 @@ private: std::get(*bn_).end()) { n_ = I; - new(buf_.data()) iter_t{ + new(buf_) iter_t{ std::get(*bn_).begin()}; return; } @@ -208,7 +166,7 @@ private: { if(n_ == I) { - new(buf_.data()) iter_t{ + new(buf_) iter_t{ std::move(other.iter())}; return; } @@ -228,7 +186,7 @@ private: { if(n_ == I) { - new(buf_.data()) iter_t{ + new(buf_) iter_t{ other.iter()}; return; } @@ -300,7 +258,7 @@ private: if(n_ == I) { --n_; - new(buf_.data()) iter_t{ + new(buf_) iter_t{ std::get(*bn_).end()}; } decrement(C{}); @@ -333,7 +291,7 @@ private: --n_; using Iter = iter_t; iter().~Iter(); - new(buf_.data()) iter_t{ + new(buf_) iter_t{ std::get(*bn_).end()}; } decrement(C{}); @@ -343,14 +301,14 @@ private: //------------------------------------------------------------------------------ template -buffer_cat_helper:: +buffers_view:: const_iterator::~const_iterator() { destroy(C<0>{}); } template -buffer_cat_helper:: +buffers_view:: const_iterator::const_iterator() : n_(sizeof...(Bn)) , bn_(nullptr) @@ -358,7 +316,7 @@ const_iterator::const_iterator() } template -buffer_cat_helper:: +buffers_view:: const_iterator::const_iterator( std::tuple const& bn, bool at_end) : bn_(&bn) @@ -370,7 +328,7 @@ const_iterator::const_iterator( } template -buffer_cat_helper:: +buffers_view:: const_iterator::const_iterator(const_iterator&& other) : n_(other.n_) , bn_(other.bn_) @@ -379,7 +337,7 @@ const_iterator::const_iterator(const_iterator&& other) } template -buffer_cat_helper:: +buffers_view:: const_iterator::const_iterator(const_iterator const& other) : n_(other.n_) , bn_(other.bn_) @@ -389,7 +347,7 @@ const_iterator::const_iterator(const_iterator const& other) template auto -buffer_cat_helper:: +buffers_view:: const_iterator::operator=(const_iterator&& other) -> const_iterator& { @@ -404,7 +362,7 @@ const_iterator::operator=(const_iterator&& other) -> template auto -buffer_cat_helper:: +buffers_view:: const_iterator::operator=(const_iterator const& other) -> const_iterator& { @@ -419,7 +377,7 @@ const_iterator& template bool -buffer_cat_helper:: +buffers_view:: const_iterator::operator==(const_iterator const& other) const { if(bn_ != other.bn_) @@ -431,7 +389,7 @@ const_iterator::operator==(const_iterator const& other) const template auto -buffer_cat_helper:: +buffers_view:: const_iterator::operator*() const -> reference { @@ -440,7 +398,7 @@ const_iterator::operator*() const -> template auto -buffer_cat_helper:: +buffers_view:: const_iterator::operator++() -> const_iterator& { @@ -450,7 +408,7 @@ const_iterator::operator++() -> template auto -buffer_cat_helper:: +buffers_view:: const_iterator::operator--() -> const_iterator& { @@ -458,10 +416,20 @@ const_iterator::operator--() -> return *this; } +//------------------------------------------------------------------------------ + +template +buffers_view:: +buffers_view(Bn const&... bn) + : bn_(bn...) +{ +} + + template inline auto -buffer_cat_helper::begin() const -> +buffers_view::begin() const -> const_iterator { return const_iterator{bn_, false}; @@ -470,13 +438,12 @@ buffer_cat_helper::begin() const -> template inline auto -buffer_cat_helper::end() const -> +buffers_view::end() const -> const_iterator { return const_iterator{bn_, true}; } -} // detail } // beast #endif diff --git a/include/beast/http/chunk_encode.hpp b/include/beast/http/chunk_encode.hpp index 082d2df1..ab7e883b 100644 --- a/include/beast/http/chunk_encode.hpp +++ b/include/beast/http/chunk_encode.hpp @@ -39,7 +39,7 @@ template #if BEAST_DOXYGEN implementation_defined #else -beast::detail::buffer_cat_helper< +beast::buffers_view< detail::chunk_encode_delim, ConstBufferSequence, boost::asio::const_buffers_1> diff --git a/test/core/buffer_cat.cpp b/test/core/buffer_cat.cpp index 688b315c..b9f2d932 100644 --- a/test/core/buffer_cat.cpp +++ b/test/core/buffer_cat.cpp @@ -215,29 +215,29 @@ public: { }; - // Check is_all_ConstBufferSequence + // Check is_all_const_buffer_sequence static_assert( - detail::is_all_ConstBufferSequence< + detail::is_all_const_buffer_sequence< const_buffers_1 >::value, ""); static_assert( - detail::is_all_ConstBufferSequence< + detail::is_all_const_buffer_sequence< const_buffers_1, const_buffers_1 >::value, ""); static_assert( - detail::is_all_ConstBufferSequence< + detail::is_all_const_buffer_sequence< mutable_buffers_1 >::value, ""); static_assert( - detail::is_all_ConstBufferSequence< + detail::is_all_const_buffer_sequence< mutable_buffers_1, mutable_buffers_1 >::value, ""); static_assert( - detail::is_all_ConstBufferSequence< + detail::is_all_const_buffer_sequence< const_buffers_1, mutable_buffers_1 >::value, ""); static_assert( - ! detail::is_all_ConstBufferSequence< + ! detail::is_all_const_buffer_sequence< const_buffers_1, mutable_buffers_1, int >::value, "");