diff --git a/CHANGELOG.md b/CHANGELOG.md index fec2ad4c..ff65ee35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Version 190: * Add missing includes to convenience headers * Unit test framework is experimental +* Add buffers_range -------------------------------------------------------------------------------- diff --git a/doc/qbk/03_core/3_buffers.qbk b/doc/qbk/03_core/3_buffers.qbk index 38010ea5..10bab37f 100644 --- a/doc/qbk/03_core/3_buffers.qbk +++ b/doc/qbk/03_core/3_buffers.qbk @@ -55,6 +55,16 @@ transferred. an existing buffer sequence. This is the type of buffer returned by [link beast.ref.boost__beast__buffers_prefix.overload3 `buffers_prefix`]. ]] +[[ + [link beast.ref.boost__beast__buffers_range `buffers_range`] +][ + This function returns an iterable range representing the passed + buffer sequence. The values obtained when iterating the range + will always be a constant buffer, unless the underlying buffer + sequence is mutable, in which case the value obtained when iterating + will be a mutable buffer. It is intended as a notational convenience + when writing a ['range-for] statement over a buffer sequence. +]] [[ [link beast.ref.boost__beast__buffers_suffix `buffers_suffix`] ][ diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml index 13354b97..e051551e 100644 --- a/doc/qbk/quickref.xml +++ b/doc/qbk/quickref.xml @@ -217,6 +217,7 @@ buffers_cat buffers_front buffers_prefix + buffers_range buffers_to_string generic_category iequals diff --git a/doc/source.dox b/doc/source.dox index b12527ac..f783767c 100644 --- a/doc/source.dox +++ b/doc/source.dox @@ -38,7 +38,7 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES -DISTRIBUTE_GROUP_DOC = NO +DISTRIBUTE_GROUP_DOC = YES GROUP_NESTED_COMPOUNDS = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO diff --git a/include/boost/beast/core.hpp b/include/boost/beast/core.hpp index 620d42ad..6e189def 100644 --- a/include/boost/beast/core.hpp +++ b/include/boost/beast/core.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/beast/core/buffers_range.hpp b/include/boost/beast/core/buffers_range.hpp new file mode 100644 index 00000000..a0d4a661 --- /dev/null +++ b/include/boost/beast/core/buffers_range.hpp @@ -0,0 +1,90 @@ +// +// 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_RANGE_HPP +#define BOOST_BEAST_BUFFERS_RANGE_HPP + +#include +#include +#include +#include + +namespace boost { +namespace beast { + +/** Return a range representing a const or mutable buffer sequence. + + This function returns an iterable range representing the + passed buffer sequence. The values obtained when iterating + the range will always be `const_buffer`, unless the underlying + buffer sequence is a @em MutableBufferSequence, in which case + the value obtained when iterating will be a `mutable_buffer`. + + @par Example + + The following function returns the total number of bytes in + the specified buffer sequence: + + @code + template + std::size_t buffer_sequence_size(ConstBufferSequence const& buffers) + { + std::size_t size = 0; + for(auto const buffer : buffers_range(std::ref(buffers))) + size += buffer.size(); + return size; + } + @endcode + + @param buffers The buffer sequence to adapt into a range. The + range returned from this function will contain a copy of the + passed buffer sequence. If `buffers` is a `std::reference_wrapper`, + the range returned from this function will contain a reference to the + passed buffer sequence. In this case, the caller is responsible + for ensuring that the lifetime of the buffer sequence is valid for + the lifetime of the returned range. + + @return An object of unspecified type, meeting the requirements of + @em ConstBufferSequence, or @em MutableBufferSequence if `buffers` + is a mutable buffer sequence. +*/ +/** @{ */ +template +#if BOOST_BEAST_DOXYGEN +__implementation_defined__ +#else +detail::buffers_range_adaptor +#endif +buffers_range(ConstBufferSequence const& buffers) +{ + static_assert( + boost::asio::is_const_buffer_sequence::value, + "ConstBufferSequence requirements not met"); + return detail::buffers_range_adaptor(buffers); +} + +template +#if BOOST_BEAST_DOXYGEN +__implementation_defined__ +#else +detail::buffers_range_adaptor +#endif +buffers_range(std::reference_wrapper buffers) +{ + static_assert( + boost::asio::is_const_buffer_sequence::value, + "ConstBufferSequence requirements not met"); + return detail::buffers_range_adaptor(buffers.get()); +} +/** @} */ + +} // beast +} // boost + +#endif diff --git a/include/boost/beast/core/buffers_to_string.hpp b/include/boost/beast/core/buffers_to_string.hpp index 1c70768e..8bd659ce 100644 --- a/include/boost/beast/core/buffers_to_string.hpp +++ b/include/boost/beast/core/buffers_to_string.hpp @@ -11,7 +11,7 @@ #define BOOST_BEAST_BUFFERS_TO_STRING_HPP #include -#include +#include #include #include @@ -41,16 +41,17 @@ namespace beast { @endcode */ template -inline std::string buffers_to_string(ConstBufferSequence const& buffers) { + static_assert( + boost::asio::is_const_buffer_sequence::value, + "ConstBufferSequence requirements not met"); std::string result; result.reserve(boost::asio::buffer_size(buffers)); - for(boost::asio::const_buffer buffer : - detail::buffers_range(buffers)) - result.append(static_cast< - char const*>(buffer.data()), buffer.size()); + for(auto const buffer : buffers_range(std::ref(buffers))) + result.append(static_cast( + buffer.data()), buffer.size()); return result; } diff --git a/include/boost/beast/core/detail/buffers_range.hpp b/include/boost/beast/core/detail/buffers_range.hpp new file mode 100644 index 00000000..56b1c712 --- /dev/null +++ b/include/boost/beast/core/detail/buffers_range.hpp @@ -0,0 +1,141 @@ +// +// 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_RANGE_HPP +#define BOOST_BEAST_DETAIL_BUFFERS_RANGE_HPP + +#include +#include +#include +#include + +namespace boost { +namespace beast { +namespace detail { + +template +class buffers_range_adaptor +{ + BufferSequence b_; + +public: +#if BOOST_BEAST_DOXYGEN + using value_type = __see_below__; +#else + using value_type = typename std::conditional< + boost::is_convertible< + typename std::iterator_traits< + typename detail::buffer_sequence_iterator< + BufferSequence>::type>::value_type, + boost::asio::mutable_buffer>::value, + boost::asio::mutable_buffer, + boost::asio::const_buffer>::type; +#endif + + class const_iterator + { + friend class buffers_range_adaptor; + + using iter_type = typename + buffer_sequence_iterator::type; + + iter_type it_; + + const_iterator(iter_type const& it) + : it_(it) + { + } + + public: + using value_type = typename + buffers_range_adaptor::value_type; + using pointer = value_type const*; + using reference = value_type; + using difference_type = std::ptrdiff_t; + using iterator_category = + std::bidirectional_iterator_tag; + + bool + operator==(const_iterator const& other) const + { + return it_ == other.it_; + } + + bool + operator!=(const_iterator const& other) const + { + return ! (*this == other); + } + + reference + operator*() const + { + return *it_; + } + + pointer + operator->() const = delete; + + const_iterator& + operator++() + { + ++it_; + return *this; + } + + const_iterator + operator++(int) + { + auto temp = *this; + ++(*this); + return temp; + } + + // deprecated + const_iterator& + operator--() + { + --it_; + return *this; + } + + // deprecated + const_iterator + operator--(int) + { + auto temp = *this; + --(*this); + return temp; + } + }; + + explicit + buffers_range_adaptor(BufferSequence 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_); + } +}; + +} // detail +} // beast +} // boost + +#endif diff --git a/include/boost/beast/core/detail/ostream.hpp b/include/boost/beast/core/detail/ostream.hpp index 6b921367..19619834 100644 --- a/include/boost/beast/core/detail/ostream.hpp +++ b/include/boost/beast/core/detail/ostream.hpp @@ -48,7 +48,7 @@ std::ostream& operator<<(std::ostream& os, buffers_helper const& v) { - for(auto b : buffers_range(v.b_)) + for(auto b : buffers_range(std::ref(v.b_))) os.write(static_cast(b.data()), b.size()); return os; } diff --git a/include/boost/beast/core/detail/type_traits.hpp b/include/boost/beast/core/detail/type_traits.hpp index 3d379846..c389df5c 100644 --- a/include/boost/beast/core/detail/type_traits.hpp +++ b/include/boost/beast/core/detail/type_traits.hpp @@ -336,124 +336,6 @@ struct StreamHandler using ReadHandler = StreamHandler; using WriteHandler = StreamHandler; -template -class buffers_range_adaptor -{ - Buffers const& b_; - -public: - using value_type = typename std::conditional< - boost::is_convertible< - typename std::iterator_traits< - typename buffer_sequence_iterator< - Buffers>::type>::value_type, - boost::asio::mutable_buffer>::value, - boost::asio::mutable_buffer, - boost::asio::const_buffer>::type; - - class const_iterator - { - friend class buffers_range_adaptor; - - using iter_type = typename - buffer_sequence_iterator::type; - - iter_type it_; - - const_iterator(iter_type const& it) - : it_(it) - { - } - - public: - using value_type = typename - buffers_range_adaptor::value_type; - using pointer = value_type const*; - using reference = value_type; - using difference_type = std::ptrdiff_t; - using iterator_category = - std::bidirectional_iterator_tag; - - bool - operator==(const_iterator const& other) const - { - return it_ == other.it_; - } - - bool - operator!=(const_iterator const& other) const - { - return ! (*this == other); - } - - reference - operator*() const - { - return *it_; - } - - pointer - operator->() const = delete; - - const_iterator& - operator++() - { - ++it_; - return *this; - } - - const_iterator - operator++(int) - { - auto temp = *this; - ++(*this); - return temp; - } - - // deprecated - const_iterator& - operator--() - { - --it_; - return *this; - } - - // deprecated - const_iterator - operator--(int) - { - auto temp = *this; - --(*this); - return temp; - } - }; - - explicit - buffers_range_adaptor(Buffers const& b) - : b_(b) - { - } - - const_iterator - begin() const noexcept - { - return boost::asio::buffer_sequence_begin(b_); - } - - const_iterator - end() const noexcept - { - return boost::asio::buffer_sequence_end(b_); - } -}; - -template -buffers_range_adaptor -buffers_range(Buffers const& buffers) -{ - return buffers_range_adaptor{buffers}; -} - /* If this static assert goes off, it means that the completion handler you provided to an asynchronous initiating function did not have the right signature. Check the parameter types for your diff --git a/include/boost/beast/http/impl/file_body_win32.ipp b/include/boost/beast/http/impl/file_body_win32.ipp index 6357cf49..346d39af 100644 --- a/include/boost/beast/http/impl/file_body_win32.ipp +++ b/include/boost/beast/http/impl/file_body_win32.ipp @@ -13,6 +13,7 @@ #if BOOST_BEAST_USE_WIN32_FILE #include +#include #include #include #include @@ -191,7 +192,7 @@ struct basic_file_body error_code& ec) { std::size_t nwritten = 0; - for(auto buffer : beast::detail::buffers_range(buffers)) + for(auto buffer : beast::buffers_range(std::ref(buffers))) { nwritten += body_.file_.write( buffer.data(), buffer.size(), ec); diff --git a/include/boost/beast/http/impl/write.ipp b/include/boost/beast/http/impl/write.ipp index bbada070..5e657b19 100644 --- a/include/boost/beast/http/impl/write.ipp +++ b/include/boost/beast/http/impl/write.ipp @@ -12,8 +12,9 @@ #include #include -#include +#include #include +#include #include #include #include @@ -935,7 +936,7 @@ public: if(os_.fail()) return; std::size_t bytes_transferred = 0; - for(auto b : buffers_range(buffers)) + for(auto b : beast::buffers_range(std::ref(buffers))) { os_.write(static_cast( b.data()), b.size()); diff --git a/include/boost/beast/http/string_body.hpp b/include/boost/beast/http/string_body.hpp index 2b4e1b43..27320375 100644 --- a/include/boost/beast/http/string_body.hpp +++ b/include/boost/beast/http/string_body.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -131,7 +132,7 @@ public: } ec.assign(0, ec.category()); CharT* dest = &body_[size]; - for(auto b : beast::detail::buffers_range(buffers)) + for(auto b : beast::buffers_range(std::ref(buffers))) { Traits::copy(dest, static_cast< CharT const*>(b.data()), b.size()); diff --git a/include/boost/beast/websocket/detail/mask.hpp b/include/boost/beast/websocket/detail/mask.hpp index 9f43a578..3b30f9e3 100644 --- a/include/boost/beast/websocket/detail/mask.hpp +++ b/include/boost/beast/websocket/detail/mask.hpp @@ -11,7 +11,7 @@ #define BOOST_BEAST_WEBSOCKET_DETAIL_MASK_HPP #include -#include +#include #include #include #include @@ -76,7 +76,7 @@ void mask_inplace(MutableBuffers const& bs, KeyType& key) { for(boost::asio::mutable_buffer b : - beast::detail::buffers_range(bs)) + beast::buffers_range(std::ref(bs))) mask_inplace(b, key); } diff --git a/include/boost/beast/websocket/detail/utf8_checker.hpp b/include/boost/beast/websocket/detail/utf8_checker.hpp index ea6e61a9..32a0a30f 100644 --- a/include/boost/beast/websocket/detail/utf8_checker.hpp +++ b/include/boost/beast/websocket/detail/utf8_checker.hpp @@ -10,7 +10,7 @@ #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_UTF8_CHECKER_HPP #define BOOST_BEAST_WEBSOCKET_DETAIL_UTF8_CHECKER_HPP -#include +#include #include #include #include @@ -88,7 +88,7 @@ write(ConstBufferSequence const& bs) { static_assert(boost::asio::is_const_buffer_sequence::value, "ConstBufferSequence requirements not met"); - for(auto b : beast::detail::buffers_range(bs)) + for(auto b : beast::buffers_range(std::ref(bs))) if(! write(static_cast< std::uint8_t const*>(b.data()), b.size())) diff --git a/include/boost/beast/websocket/impl/write.ipp b/include/boost/beast/websocket/impl/write.ipp index 08b9943d..d5c097f1 100644 --- a/include/boost/beast/websocket/impl/write.ipp +++ b/include/boost/beast/websocket/impl/write.ipp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,7 @@ deflate( zs.next_in = nullptr; zs.avail_out = out.size(); zs.next_out = out.data(); - for(auto in : beast::detail::buffers_range(cb)) + for(auto in : beast::buffers_range(std::ref(cb))) { zs.avail_in = in.size(); if(zs.avail_in == 0) diff --git a/test/beast/core/CMakeLists.txt b/test/beast/core/CMakeLists.txt index ce14546b..95f0171c 100644 --- a/test/beast/core/CMakeLists.txt +++ b/test/beast/core/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable (tests-beast-core buffers_adapter.cpp buffers_cat.cpp buffers_prefix.cpp + buffers_range.cpp buffers_suffix.cpp buffers_to_string.cpp error.cpp diff --git a/test/beast/core/Jamfile b/test/beast/core/Jamfile index 52c3401d..16d88133 100644 --- a/test/beast/core/Jamfile +++ b/test/beast/core/Jamfile @@ -14,6 +14,7 @@ local SOURCES = buffers_adapter.cpp buffers_cat.cpp buffers_prefix.cpp + buffers_range.cpp buffers_suffix.cpp buffers_to_string.cpp error.cpp diff --git a/test/beast/core/buffers_range.cpp b/test/beast/core/buffers_range.cpp new file mode 100644 index 00000000..4c895506 --- /dev/null +++ b/test/beast/core/buffers_range.cpp @@ -0,0 +1,11 @@ +// +// 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 +// + +// Test that header file is self-contained. +#include diff --git a/test/bench/buffers/bench_buffers.cpp b/test/bench/buffers/bench_buffers.cpp index 11a18f37..85692f4e 100644 --- a/test/bench/buffers/bench_buffers.cpp +++ b/test/bench/buffers/bench_buffers.cpp @@ -7,6 +7,7 @@ // Official repository: https://github.com/boostorg/beast // +#include #include #include #include @@ -67,7 +68,7 @@ public: fill(MutableBufferSequence const& buffers) { std::size_t n = 0; - for(auto b : beast::detail::buffers_range(buffers)) + for(auto b : beast::buffers_range(std::ref(buffers))) { std::fill( static_cast(b.data()), diff --git a/test/bench/parser/nodejs_parser.hpp b/test/bench/parser/nodejs_parser.hpp index 82dcd6a1..a62c340e 100644 --- a/test/bench/parser/nodejs_parser.hpp +++ b/test/bench/parser/nodejs_parser.hpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -268,7 +269,7 @@ nodejs_basic_parser::write( ConstBufferSequence>::value, "ConstBufferSequence requirements not met"); std::size_t bytes_used = 0; - for(auto buffer : beast::detail::buffers_range(buffers)) + for(auto buffer : beast::buffers_range(std::ref(buffers))) { auto const n = write( static_cast(buffer.data()),