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()),