diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f45c14f..ccec073e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@ Version 209:
* async_echo supports move-only handlers
* test::stream maintains a handler work guard
* Qualify buffer_copy, don't qualify buffer_size
+* Add dynamic_buffer_ref
--------------------------------------------------------------------------------
diff --git a/doc/qbk/03_core/4_buffers.qbk b/doc/qbk/03_core/4_buffers.qbk
index aa954b8e..7d8a0637 100644
--- a/doc/qbk/03_core/4_buffers.qbk
+++ b/doc/qbk/03_core/4_buffers.qbk
@@ -125,6 +125,15 @@ set of additional implementations of the dynamic buffer concept:
The basic container is an
[@https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer [*AllocatorAwareContainer]].
]]
+[[
+ [link beast.ref.boost__beast__dynamic_buffer_ref `dynamic_buffer_ref`]
+ [link beast.ref.boost__beast__dynamic_buffer_ref_wrapper `dynamic_buffer_ref_wrapper`]
+][
+ This function returns a wrapper containing a reference to the passed
+ dynamic buffer, permitting a Beast dynamic buffer type (which acts
+ like a true container type) to be used with Networking algorithms
+ which want to take ownership of the dynamic buffer in their interface.
+]]
[[
[link beast.ref.boost__beast__flat_static_buffer `flat_static_buffer`]
[link beast.ref.boost__beast__flat_static_buffer_base `flat_static_buffer_base`]
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index b68d4016..6b4a759c 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -186,6 +186,7 @@
buffers_cat_view
buffers_prefix_view
buffers_suffix
+ dynamic_buffer_ref_wrapper
file
file_mode
file_posix
@@ -236,6 +237,7 @@
buffers_range_ref
buffers_to_string
close_socket
+ dynamic_buffer_ref
generic_category
get_lowest_layer
iequals
diff --git a/include/boost/beast/_experimental/core/detail/dynamic_buffer_ref.hpp b/include/boost/beast/_experimental/core/detail/dynamic_buffer_ref.hpp
deleted file mode 100644
index 12efae65..00000000
--- a/include/boost/beast/_experimental/core/detail/dynamic_buffer_ref.hpp
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-// Copyright (c) 2018 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_DYNAMIC_BUFFER_REF_HPP
-#define BOOST_BEAST_CORE_DETAIL_DYNAMIC_BUFFER_REF_HPP
-
-#include
-#include
-#include
-
-namespace boost {
-namespace beast {
-namespace detail {
-
-template
-class dynamic_buffer_ref
-{
- DynamicBuffer& b_;
-
-public:
- using const_buffers_type = typename
- DynamicBuffer::const_buffers_type;
-
- using mutable_buffers_type = typename
- DynamicBuffer::mutable_buffers_type;
-
- dynamic_buffer_ref(
- dynamic_buffer_ref&&) = default;
-
- explicit
- dynamic_buffer_ref(
- DynamicBuffer& b) noexcept
- : b_(b)
- {
- }
-
- std::size_t
- size() const noexcept
- {
- return b_.size();
- }
-
- std::size_t
- max_size() const noexcept
- {
- return b_.max_size();
- }
-
- std::size_t
- capacity() const noexcept
- {
- return b_.capacity();
- }
-
- const_buffers_type
- data() const noexcept
- {
- return b_.data();
- }
-
- mutable_buffers_type
- prepare(std::size_t n)
- {
- return b_.prepare(n);
- }
-
- void
- commit(std::size_t n)
- {
- b_.commit(n);
- }
-
- void
- consume(std::size_t n)
- {
- b_.consume(n);
- }
-};
-
-template
-typename std::enable_if<
- net::is_dynamic_buffer::value,
- dynamic_buffer_ref>::type
-ref(DynamicBuffer& b)
-{
- return dynamic_buffer_ref(b);
-}
-
-} // detail
-} // beast
-} // boost
-
-#endif
diff --git a/include/boost/beast/_experimental/http/impl/icy_stream.hpp b/include/boost/beast/_experimental/http/impl/icy_stream.hpp
index b3f640a3..e390a9ac 100644
--- a/include/boost/beast/_experimental/http/impl/icy_stream.hpp
+++ b/include/boost/beast/_experimental/http/impl/icy_stream.hpp
@@ -10,7 +10,7 @@
#ifndef BOOST_BEAST_CORE_IMPL_ICY_STREAM_HPP
#define BOOST_BEAST_CORE_IMPL_ICY_STREAM_HPP
-#include
+#include
#include
#include
#include
@@ -164,7 +164,7 @@ public:
std::size_t bytes_transferred)
{
using iterator = net::buffers_iterator<
- typename beast::detail::dynamic_buffer_ref<
+ typename beast::dynamic_buffer_ref_wrapper<
buffers_adaptor>::const_buffers_type>;
BOOST_ASIO_CORO_REENTER(*this)
{
@@ -250,7 +250,7 @@ public:
BOOST_ASIO_CORO_YIELD
net::async_read_until(
d_.s.next_layer(),
- beast::detail::ref(d_.b),
+ beast::dynamic_buffer_ref(d_.b),
detail::match_icy(d_.match),
std::move(*this));
if(ec)
@@ -329,7 +329,7 @@ read_some(MutableBufferSequence const& buffers, error_code& ec)
MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
using iterator = net::buffers_iterator<
- typename beast::detail::dynamic_buffer_ref<
+ typename beast::dynamic_buffer_ref_wrapper<
buffers_adaptor>::const_buffers_type>;
buffers_adaptor b(buffers);
if(b.max_size() == 0)
@@ -403,7 +403,7 @@ read_some(MutableBufferSequence const& buffers, error_code& ec)
bool match = false;
auto n = net::read_until(
stream_,
- beast::detail::ref(b),
+ beast::dynamic_buffer_ref(b),
detail::match_icy(match),
ec);
if(ec)
diff --git a/include/boost/beast/core.hpp b/include/boost/beast/core.hpp
index fca13c09..b337317b 100644
--- a/include/boost/beast/core.hpp
+++ b/include/boost/beast/core.hpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/boost/beast/core/dynamic_buffer_ref.hpp b/include/boost/beast/core/dynamic_buffer_ref.hpp
new file mode 100644
index 00000000..5c17f4c9
--- /dev/null
+++ b/include/boost/beast/core/dynamic_buffer_ref.hpp
@@ -0,0 +1,140 @@
+//
+// Copyright (c) 2018 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_DYNAMIC_BUFFER_REF_HPP
+#define BOOST_BEAST_CORE_DYNAMIC_BUFFER_REF_HPP
+
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace beast {
+
+/** A lightweight reference to a dynamic buffer.
+
+ Objects of this type meet the requirements of DynamicBuffer.
+ This is the wrapper returned by the function @ref dynamic_buffer_ref.
+
+ @see dynamic_buffer_ref
+*/
+template
+class dynamic_buffer_ref_wrapper
+#if ! BOOST_BEAST_DOXYGEN
+{
+ static_assert(net::is_dynamic_buffer::value,
+ "DynamicBuffer requirements not met");
+
+ DynamicBuffer& b_;
+
+public:
+ using const_buffers_type = typename
+ DynamicBuffer::const_buffers_type;
+
+ using mutable_buffers_type = typename
+ DynamicBuffer::mutable_buffers_type;
+
+ dynamic_buffer_ref_wrapper(
+ dynamic_buffer_ref_wrapper&&) = default;
+
+ explicit
+ dynamic_buffer_ref_wrapper(
+ DynamicBuffer& b) noexcept
+ : b_(b)
+ {
+ }
+
+ std::size_t
+ size() const noexcept
+ {
+ return b_.size();
+ }
+
+ std::size_t
+ max_size() const noexcept
+ {
+ return b_.max_size();
+ }
+
+ std::size_t
+ capacity() const noexcept
+ {
+ return b_.capacity();
+ }
+
+ const_buffers_type
+ data() const noexcept
+ {
+ return b_.data();
+ }
+
+ mutable_buffers_type
+ prepare(std::size_t n)
+ {
+ return b_.prepare(n);
+ }
+
+ void
+ commit(std::size_t n)
+ {
+ b_.commit(n);
+ }
+
+ void
+ consume(std::size_t n)
+ {
+ b_.consume(n);
+ }
+}
+#endif
+;
+
+/** Return a non-owning reference to a dynamic buffer.
+
+ This function returns a wrapper which holds a reference to the
+ passed dynamic buffer. The wrapper meets the requirements of
+ DynamicBuffer, allowing its use in Networking algorithms
+ which want to take ownership of the dynamic buffer. Since Beast
+ dynamic buffers are true storage types, they cannot be used directly
+ with functions that take ownership of the dynamic buffer.
+
+ @par Example
+ This function reads a line of text from a stream into a
+ @ref flat_buffer, using the net function `async_read_until`. The
+ @code
+ template
+ std::size_t read_line (SyncReadStream& stream, flat_buffer& buffer)
+ {
+ return net::read_until(stream, dynamic_buffer_ref(buffer), "\r\n");
+ }
+ @endcode
+
+ @param buffer The dynamic buffer to wrap. Ownership of the buffer is
+ not transferred, the caller is still responsible for managing the
+ lifetime of the original object.
+
+ @return A wrapper meeting the requirements of DynamicBuffer
+ which references the original dynamic buffer.
+
+ @see dynamic_buffer_ref_wrapper
+*/
+template
+dynamic_buffer_ref_wrapper
+dynamic_buffer_ref(DynamicBuffer& buffer) noexcept
+{
+ static_assert(net::is_dynamic_buffer::value,
+ "DynamicBuffer requirements not met");
+ return dynamic_buffer_ref_wrapper(buffer);
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/test/beast/core/CMakeLists.txt b/test/beast/core/CMakeLists.txt
index 7b285631..72ee830f 100644
--- a/test/beast/core/CMakeLists.txt
+++ b/test/beast/core/CMakeLists.txt
@@ -41,6 +41,7 @@ add_executable (tests-beast-core
buffers_suffix.cpp
buffers_to_string.cpp
close_socket.cpp
+ dynamic_buffer_ref.cpp
error.cpp
file.cpp
file_posix.cpp
diff --git a/test/beast/core/Jamfile b/test/beast/core/Jamfile
index 51aa2a9b..ebbb8d53 100644
--- a/test/beast/core/Jamfile
+++ b/test/beast/core/Jamfile
@@ -29,6 +29,7 @@ local SOURCES =
buffers_suffix.cpp
buffers_to_string.cpp
close_socket.cpp
+ dynamic_buffer_ref.cpp
error.cpp
file.cpp
file_posix.cpp
diff --git a/test/beast/core/dynamic_buffer_ref.cpp b/test/beast/core/dynamic_buffer_ref.cpp
new file mode 100644
index 00000000..a0b6785d
--- /dev/null
+++ b/test/beast/core/dynamic_buffer_ref.cpp
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2018 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
+
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace beast {
+
+namespace {
+
+template
+std::size_t read_line (SyncReadStream& stream, flat_buffer& buffer)
+{
+ return net::read_until(stream, dynamic_buffer_ref(buffer), "\r\n");
+}
+
+} // (anon)
+
+class dynamic_buffer_ref_test : public beast::unit_test::suite
+{
+public:
+ void
+ testJavadocs()
+ {
+ BEAST_EXPECT(static_cast<
+ std::size_t(*)(test::stream&, flat_buffer&)>(
+ &read_line));
+ }
+
+ void run() override
+ {
+ testJavadocs();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(beast,core,dynamic_buffer_ref);
+
+} // beast
+} // boost