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_stream buffers_adapter consuming_buffers + drain_buffer error_category error_code error_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