diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2b297279..1c956445 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
Version 52:
* flat_buffer is an AllocatorAwareContainer
+* Add drain_buffer class
API Changes:
diff --git a/doc/3_3_buffers.qbk b/doc/3_3_buffers.qbk
index 09fcc5ac..288ad04e 100644
--- a/doc/3_3_buffers.qbk
+++ b/doc/3_3_buffers.qbk
@@ -47,6 +47,15 @@ To suit various needs, several implementation of dynamic buffer are available:
output areas equal to the size of the underlying mutable buffer sequence.
The implementation does not perform heap allocations.
]]
+[[
+ [link beast.ref.drain_buffer `drain_buffer`]
+][
+ A drain buffer has a small internal buffer and maximum size that
+ uses no dynamic allocation. It always has a size of zero, and
+ silently discards its input. This buffer may be passed to functions
+ which store data in a dynamic buffer when the caller wishes to
+ efficiently discard the data.
+]]
[[
[link beast.ref.flat_buffer `flat_buffer`]
[link beast.ref.basic_flat_buffer `basic_flat_buffer`]
diff --git a/doc/quickref.xml b/doc/quickref.xml
index ee080157..b64ac0de 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -165,6 +165,7 @@
buffered_read_streambuffers_adapterconsuming_buffers
+ drain_buffererror_categoryerror_codeerror_condition
diff --git a/include/beast/core/drain_buffer.hpp b/include/beast/core/drain_buffer.hpp
new file mode 100644
index 00000000..6b02fb89
--- /dev/null
+++ b/include/beast/core/drain_buffer.hpp
@@ -0,0 +1,121 @@
+//
+// Copyright (c) 2013-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)
+//
+
+#ifndef BEAST_DRAIN_BUFFER_HPP
+#define BEAST_DRAIN_BUFFER_HPP
+
+#include
+#include
+#include
+
+namespace beast {
+
+/** A @b DynamicBuffer which does not retain its input sequence.
+
+ This object implements a dynamic buffer with a fixed size
+ output area, not dynamically allocated, and whose input
+ sequence is always length zero. Bytes committed from the
+ output area to the input area are always discarded. This
+ is useful for calling interfaces that require a dynamic
+ buffer for storage, but where the caller does not want
+ to retain the data.
+*/
+class drain_buffer
+{
+ char buf_[512];
+ std::size_t n_ = 0;
+
+public:
+ /// The type used to represent the input sequence as a list of buffers.
+ using const_buffers_type = boost::asio::null_buffers;
+
+ /// The type used to represent the output sequence as a list of buffers.
+ using mutable_buffers_type = boost::asio::mutable_buffers_1;
+
+ /// Constructor
+ drain_buffer() = default;
+
+ /// Copy constructor
+ drain_buffer(drain_buffer const&)
+ {
+ }
+
+ /// Copy assignment
+ drain_buffer&
+ operator=(drain_buffer const&)
+ {
+ n_ = 0;
+ return *this;
+ }
+
+ /// Return the size of the input sequence.
+ std::size_t
+ size() const
+ {
+ return 0;
+ }
+
+ /// Return the maximum sum of the input and output sequence sizes.
+ std::size_t
+ max_size() const
+ {
+ return sizeof(buf_);
+ }
+
+ /// 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
+ {
+ return {};
+ }
+
+ /** Get a list of buffers that represent the output sequence, with the given size.
+
+ @throws std::length_error if the size would exceed the buffer limit
+ */
+ mutable_buffers_type
+ prepare(std::size_t n)
+ {
+ if(n > sizeof(buf_))
+ BOOST_THROW_EXCEPTION(std::length_error{
+ "buffer overflow"});
+ n_ = n;
+ return {buf_, n_};
+ }
+
+ /** Move bytes from the output sequence to the input sequence.
+
+ This call always discards the output sequence.
+ The size of the input sequence will remain at zero.
+ */
+ void
+ commit(std::size_t)
+ {
+ }
+
+ /** Remove bytes from the input sequence.
+
+ This call has no effect.
+ */
+ void
+ consume(std::size_t) const
+ {
+ }
+};
+} // beast
+
+#endif
diff --git a/test/Jamfile b/test/Jamfile
index 50ecfd9a..5d6bb606 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -27,6 +27,7 @@ unit-test core-tests :
core/consuming_buffers.cpp
core/doc_core_samples.cpp
core/doc_snippets.cpp
+ core/drain_buffer.cpp
core/error.cpp
core/flat_buffer.cpp
core/handler_alloc.cpp
diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt
index 95911dce..23f946b0 100644
--- a/test/core/CMakeLists.txt
+++ b/test/core/CMakeLists.txt
@@ -22,6 +22,7 @@ add_executable (core-tests
consuming_buffers.cpp
doc_core_samples.cpp
doc_snippets.cpp
+ drain_buffer.cpp
error.cpp
flat_buffer.cpp
handler_alloc.cpp
diff --git a/test/core/drain_buffer.cpp b/test/core/drain_buffer.cpp
new file mode 100644
index 00000000..5e7e35e7
--- /dev/null
+++ b/test/core/drain_buffer.cpp
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2013-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)
+//
+
+// Test that header file is self-contained.
+#include
+
+#include
+#include
+
+namespace beast {
+
+static_assert(is_dynamic_buffer::value,
+ "DynamicBuffer requirements not met");
+
+class drain_buffer_test : public beast::unit_test::suite
+{
+public:
+ void
+ run() override
+ {
+ using boost::asio::buffer_size;
+ drain_buffer b;
+ BEAST_EXPECT(buffer_size(b.prepare(0)) == 0);
+ BEAST_EXPECT(buffer_size(b.prepare(100)) == 100);
+ try
+ {
+ b.prepare(b.max_size() + 1);
+ fail("", __FILE__, __LINE__);
+ }
+ catch(std::length_error const&)
+ {
+ pass();
+ }
+ b.prepare(10);
+ BEAST_EXPECT(b.size() == 0);
+ b.commit(10);
+ BEAST_EXPECT(b.size() == 0);
+ b.consume(10);
+ BEAST_EXPECT(b.size() == 0);
+ b.consume(1000);
+ BEAST_EXPECT(b.size() == 0);
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(drain_buffer,core,beast);
+
+} // beast