mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 21:34:46 +02:00
Add static_buffer (API Change):
* static_buffer is added Note this is the same name from two versions ago, when static_buffer was renamed to flat_static_buffer for consistency and to clear the name for a circular static buffer. Actions Required: * Callers who depend on static_buffer returning sequences of exactly length one should switch to flat_static_buffer.
This commit is contained in:
@@ -10,6 +10,15 @@ WebSocket
|
|||||||
* Add wstest compression option
|
* Add wstest compression option
|
||||||
* Fix buffer lifetime in websocket write
|
* Fix buffer lifetime in websocket write
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* Add static_buffer
|
||||||
|
|
||||||
|
Actions Required:
|
||||||
|
|
||||||
|
* Callers who depend on static_buffer returning sequences of
|
||||||
|
exactly length one should switch to flat_static_buffer.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Version 82:
|
Version 82:
|
||||||
|
@@ -89,6 +89,17 @@ of scenarios:
|
|||||||
by a constexpr template parameter. The storage for the sequences are
|
by a constexpr template parameter. The storage for the sequences are
|
||||||
kept in the class; the implementation does not perform heap allocations.
|
kept in the class; the implementation does not perform heap allocations.
|
||||||
]]
|
]]
|
||||||
|
[[
|
||||||
|
[link beast.ref.beast__static_buffer `static_buffer`]
|
||||||
|
[link beast.ref.beast__static_buffer_base `static_buffer_base`]
|
||||||
|
][
|
||||||
|
Provides the facilities of a circular dynamic buffer. subject to an
|
||||||
|
upper limit placed on the total size of the input and output areas
|
||||||
|
defined by a constexpr template parameter.
|
||||||
|
The implementation never moves memory during buffer operations.
|
||||||
|
The storage for the sequences are kept in the class; the implementation
|
||||||
|
does not perform heap allocations.
|
||||||
|
]]
|
||||||
]
|
]
|
||||||
|
|
||||||
Network applications frequently need to manipulate buffer sequences. To
|
Network applications frequently need to manipulate buffer sequences. To
|
||||||
|
@@ -186,13 +186,13 @@
|
|||||||
<member><link linkend="beast.ref.beast__error_condition">error_condition</link></member>
|
<member><link linkend="beast.ref.beast__error_condition">error_condition</link></member>
|
||||||
<member><link linkend="beast.ref.beast__file">file</link></member>
|
<member><link linkend="beast.ref.beast__file">file</link></member>
|
||||||
<member><link linkend="beast.ref.beast__file_mode">file_mode</link></member>
|
<member><link linkend="beast.ref.beast__file_mode">file_mode</link></member>
|
||||||
|
<member><link linkend="beast.ref.beast__file_posix">file_posix</link></member>
|
||||||
|
<member><link linkend="beast.ref.beast__file_stdio">file_stdio</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
<bridgehead renderas="sect3"> </bridgehead>
|
<bridgehead renderas="sect3"> </bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.beast__file_posix">file_posix</link></member>
|
|
||||||
<member><link linkend="beast.ref.beast__file_stdio">file_stdio</link></member>
|
|
||||||
<member><link linkend="beast.ref.beast__file_win32">file_win32</link></member>
|
<member><link linkend="beast.ref.beast__file_win32">file_win32</link></member>
|
||||||
<member><link linkend="beast.ref.beast__flat_buffer">flat_buffer</link></member>
|
<member><link linkend="beast.ref.beast__flat_buffer">flat_buffer</link></member>
|
||||||
<member><link linkend="beast.ref.beast__flat_static_buffer">flat_static_buffer</link></member>
|
<member><link linkend="beast.ref.beast__flat_static_buffer">flat_static_buffer</link></member>
|
||||||
@@ -204,6 +204,8 @@
|
|||||||
<member><link linkend="beast.ref.beast__iless">iless</link></member>
|
<member><link linkend="beast.ref.beast__iless">iless</link></member>
|
||||||
<member><link linkend="beast.ref.beast__multi_buffer">multi_buffer</link></member>
|
<member><link linkend="beast.ref.beast__multi_buffer">multi_buffer</link></member>
|
||||||
<member><link linkend="beast.ref.beast__span">span</link></member>
|
<member><link linkend="beast.ref.beast__span">span</link></member>
|
||||||
|
<member><link linkend="beast.ref.beast__static_buffer">static_buffer</link></member>
|
||||||
|
<member><link linkend="beast.ref.beast__static_buffer_base">static_buffer_base</link></member>
|
||||||
<member><link linkend="beast.ref.beast__static_string">static_string</link></member>
|
<member><link linkend="beast.ref.beast__static_string">static_string</link></member>
|
||||||
<member><link linkend="beast.ref.beast__string_param">string_param</link></member>
|
<member><link linkend="beast.ref.beast__string_param">string_param</link></member>
|
||||||
<member><link linkend="beast.ref.beast__string_view">string_view</link></member>
|
<member><link linkend="beast.ref.beast__string_view">string_view</link></member>
|
||||||
|
307
include/beast/core/impl/static_buffer.ipp
Normal file
307
include/beast/core/impl/static_buffer.ipp
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
//
|
||||||
|
// 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_IMPL_STATIC_BUFFER_IPP
|
||||||
|
#define BEAST_IMPL_STATIC_BUFFER_IPP
|
||||||
|
|
||||||
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/throw_exception.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iterator>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
template<bool isInput, class T>
|
||||||
|
class static_buffer_base::buffers_type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
class const_iterator
|
||||||
|
{
|
||||||
|
friend class buffers_type;
|
||||||
|
|
||||||
|
static_buffer_base const* b_ = nullptr;
|
||||||
|
int seg_ = 0;
|
||||||
|
|
||||||
|
const_iterator(bool at_end,
|
||||||
|
static_buffer_base const& b)
|
||||||
|
: b_(&b)
|
||||||
|
{
|
||||||
|
if(! at_end)
|
||||||
|
{
|
||||||
|
seg_ = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_end(std::integral_constant<bool, isInput>{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_end(std::true_type)
|
||||||
|
{
|
||||||
|
if(b_->in_off_ + b_->in_size_ <= b_->capacity_)
|
||||||
|
seg_ = 1;
|
||||||
|
else
|
||||||
|
seg_ = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_end(std::false_type)
|
||||||
|
{
|
||||||
|
if(((b_->in_off_ + b_->in_size_) % b_->capacity_)
|
||||||
|
+ b_->out_size_ <= b_->capacity_)
|
||||||
|
seg_ = 1;
|
||||||
|
else
|
||||||
|
seg_ = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
T
|
||||||
|
dereference(std::true_type) const
|
||||||
|
{
|
||||||
|
switch(seg_)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return {
|
||||||
|
b_->begin_ + b_->in_off_,
|
||||||
|
(std::min)(
|
||||||
|
b_->in_size_,
|
||||||
|
b_->capacity_ - b_->in_off_)};
|
||||||
|
default:
|
||||||
|
case 1:
|
||||||
|
return {
|
||||||
|
b_->begin_,
|
||||||
|
b_->in_size_ - (
|
||||||
|
b_->capacity_ - b_->in_off_)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T
|
||||||
|
dereference(std::false_type) const
|
||||||
|
{
|
||||||
|
switch(seg_)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
auto const out_off =
|
||||||
|
(b_->in_off_ + b_->in_size_)
|
||||||
|
% b_->capacity_;
|
||||||
|
return {
|
||||||
|
b_->begin_ + out_off,
|
||||||
|
(std::min)(
|
||||||
|
b_->out_size_,
|
||||||
|
b_->capacity_ - out_off)};
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
auto const out_off =
|
||||||
|
(b_->in_off_ + b_->in_size_)
|
||||||
|
% b_->capacity_;
|
||||||
|
return {
|
||||||
|
b_->begin_,
|
||||||
|
b_->out_size_ - (
|
||||||
|
b_->capacity_ - out_off)};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type const&;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return b_ == other.b_ && seg_ == other.seg_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return dereference(
|
||||||
|
std::integral_constant<bool, isInput>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++seg_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
--seg_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
buffers_type() = delete;
|
||||||
|
buffers_type(buffers_type const&) = default;
|
||||||
|
buffers_type& operator=(buffers_type const&) = delete;
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
begin() const
|
||||||
|
{
|
||||||
|
return const_iterator{false, b_};
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
end() const
|
||||||
|
{
|
||||||
|
return const_iterator{true, b_};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class static_buffer_base;
|
||||||
|
|
||||||
|
static_buffer_base const& b_;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
buffers_type(static_buffer_base const& b)
|
||||||
|
: b_(b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
static_buffer_base::
|
||||||
|
static_buffer_base(void* p, std::size_t size)
|
||||||
|
: begin_(reinterpret_cast<char*>(p))
|
||||||
|
, capacity_(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_buffer_base::
|
||||||
|
data() const ->
|
||||||
|
const_buffers_type
|
||||||
|
{
|
||||||
|
return const_buffers_type{*this};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_buffer_base::
|
||||||
|
mutable_data() ->
|
||||||
|
mutable_data_type
|
||||||
|
{
|
||||||
|
return mutable_data_type{*this};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_buffer_base::
|
||||||
|
prepare(std::size_t size) ->
|
||||||
|
mutable_buffers_type
|
||||||
|
{
|
||||||
|
if(size > capacity_ - in_size_)
|
||||||
|
BOOST_THROW_EXCEPTION(std::length_error{
|
||||||
|
"buffer overflow"});
|
||||||
|
out_size_ = size;
|
||||||
|
return mutable_buffers_type{*this};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
static_buffer_base::
|
||||||
|
commit(std::size_t size)
|
||||||
|
{
|
||||||
|
in_size_ += (std::min)(size, out_size_);
|
||||||
|
out_size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
static_buffer_base::
|
||||||
|
consume(std::size_t size)
|
||||||
|
{
|
||||||
|
size = (std::min)(size, in_size_);
|
||||||
|
in_off_ = (in_off_ + size) % capacity_;
|
||||||
|
in_size_ -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
static_buffer_base::
|
||||||
|
reset(void* p, std::size_t size)
|
||||||
|
{
|
||||||
|
begin_ = reinterpret_cast<char*>(p);
|
||||||
|
capacity_ = size;
|
||||||
|
in_off_ = 0;
|
||||||
|
in_size_ = 0;
|
||||||
|
out_size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<std::size_t N>
|
||||||
|
static_buffer<N>::
|
||||||
|
static_buffer(static_buffer const& other)
|
||||||
|
: static_buffer_base(buf_, N)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
this->commit(buffer_copy(
|
||||||
|
this->prepare(other.size()), other.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N>
|
||||||
|
auto
|
||||||
|
static_buffer<N>::
|
||||||
|
operator=(static_buffer const& other) ->
|
||||||
|
static_buffer<N>&
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
this->consume(this->size());
|
||||||
|
this->commit(buffer_copy(
|
||||||
|
this->prepare(other.size()), other.data()));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
222
include/beast/core/static_buffer.hpp
Normal file
222
include/beast/core/static_buffer.hpp
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
//
|
||||||
|
// 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_STATIC_BUFFER_HPP
|
||||||
|
#define BEAST_STATIC_BUFFER_HPP
|
||||||
|
|
||||||
|
#include <beast/config.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** A circular @b DynamicBuffer with a fixed size internal buffer.
|
||||||
|
|
||||||
|
This implements a circular dynamic buffer. Calls to @ref prepare
|
||||||
|
never require moving memory. The buffer sequences returned may
|
||||||
|
be up to length two.
|
||||||
|
Ownership of the underlying storage belongs to the derived class.
|
||||||
|
|
||||||
|
@note Variables are usually declared using the template class
|
||||||
|
@ref static_buffer; however, to reduce the number of instantiations
|
||||||
|
of template functions receiving static stream buffer arguments in a
|
||||||
|
deduced context, the signature of the receiving function should use
|
||||||
|
@ref static_buffer_base.
|
||||||
|
|
||||||
|
When used with @ref static_buffer this implements a dynamic
|
||||||
|
buffer using no memory allocations.
|
||||||
|
|
||||||
|
@see @ref static_buffer
|
||||||
|
*/
|
||||||
|
class static_buffer_base
|
||||||
|
{
|
||||||
|
char* begin_;
|
||||||
|
std::size_t in_off_ = 0;
|
||||||
|
std::size_t in_size_ = 0;
|
||||||
|
std::size_t out_size_ = 0;
|
||||||
|
std::size_t capacity_;
|
||||||
|
|
||||||
|
template<bool, class T>
|
||||||
|
class buffers_type;
|
||||||
|
|
||||||
|
static_buffer_base(static_buffer_base const& other) = delete;
|
||||||
|
static_buffer_base& operator=(static_buffer_base const&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The type used to represent the input sequence as a list of buffers.
|
||||||
|
#if BEAST_DOXYGEN
|
||||||
|
using const_buffers_type = implementation_defined;
|
||||||
|
#else
|
||||||
|
using const_buffers_type =
|
||||||
|
buffers_type<true, boost::asio::const_buffer>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// The type used to represent the mutable input sequence as a list of buffers.
|
||||||
|
#if BEAST_DOXYGEN
|
||||||
|
using mutable_data_type = implementation_defined;
|
||||||
|
#else
|
||||||
|
using mutable_data_type =
|
||||||
|
buffers_type<true, boost::asio::mutable_buffer>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// The type used to represent the output sequence as a list of buffers.
|
||||||
|
#if BEAST_DOXYGEN
|
||||||
|
using mutable_buffers_type = implementation_defined;
|
||||||
|
#else
|
||||||
|
using mutable_buffers_type =
|
||||||
|
buffers_type<false, boost::asio::mutable_buffer>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
|
This creates a dynamic buffer using the provided storage area.
|
||||||
|
|
||||||
|
@param p A pointer to valid storage of at least `n` bytes.
|
||||||
|
|
||||||
|
@param size The number of valid bytes pointed to by `p`.
|
||||||
|
*/
|
||||||
|
static_buffer_base(void* p, std::size_t size);
|
||||||
|
|
||||||
|
/// Return the size of the input sequence.
|
||||||
|
std::size_t
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return in_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the maximum sum of the input and output sequence sizes.
|
||||||
|
std::size_t
|
||||||
|
max_size() const
|
||||||
|
{
|
||||||
|
return capacity_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the maximum sum of input and output sizes that can be held without an allocation.
|
||||||
|
std::size_t
|
||||||
|
capacity() const
|
||||||
|
{
|
||||||
|
return capacity_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a list of buffers that represent the input sequence.
|
||||||
|
*/
|
||||||
|
const_buffers_type
|
||||||
|
data() const;
|
||||||
|
|
||||||
|
/** Get a list of mutable buffers that represent the input sequence.
|
||||||
|
*/
|
||||||
|
mutable_data_type
|
||||||
|
mutable_data();
|
||||||
|
|
||||||
|
/** Get a list of buffers that represent the output sequence, with the given size.
|
||||||
|
|
||||||
|
@param size The number of bytes to request.
|
||||||
|
|
||||||
|
@throws std::length_error if the size would exceed the capacity.
|
||||||
|
*/
|
||||||
|
mutable_buffers_type
|
||||||
|
prepare(std::size_t size);
|
||||||
|
|
||||||
|
/** Move bytes from the output sequence to the input sequence.
|
||||||
|
|
||||||
|
@param size The nubmer of bytes to commit. If this is greater
|
||||||
|
than the size of the output sequence, the entire output
|
||||||
|
sequence is committed.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
commit(std::size_t size);
|
||||||
|
|
||||||
|
/** Remove bytes from the input sequence.
|
||||||
|
|
||||||
|
@param size The number of bytes to consume. If this is greater
|
||||||
|
than the size of the input sequence, the entire input sequence
|
||||||
|
is consumed.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
consume(std::size_t size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
|
The buffer will be in an undefined state. It is necessary
|
||||||
|
for the derived class to call @ref reset in order to
|
||||||
|
initialize the object.
|
||||||
|
*/
|
||||||
|
static_buffer_base();
|
||||||
|
|
||||||
|
/** Reset the pointed-to buffer.
|
||||||
|
|
||||||
|
This function resets the internal state to the buffer provided.
|
||||||
|
All input and output sequences are invalidated. This function
|
||||||
|
allows the derived class to construct its members before
|
||||||
|
initializing the static buffer.
|
||||||
|
|
||||||
|
@param p A pointer to valid storage of at least `n` bytes.
|
||||||
|
|
||||||
|
@param size The number of valid bytes pointed to by `p`.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
reset(void* p, std::size_t size);
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** A circular @b DynamicBuffer with a fixed size internal buffer.
|
||||||
|
|
||||||
|
This implements a circular dynamic buffer. Calls to @ref prepare
|
||||||
|
never require moving memory. The buffer sequences returned may
|
||||||
|
be up to length two.
|
||||||
|
Ownership of the underlying storage belongs to the derived class.
|
||||||
|
|
||||||
|
@tparam N The number of bytes in the internal buffer.
|
||||||
|
|
||||||
|
@note To reduce the number of template instantiations when passing
|
||||||
|
objects of this type in a deduced context, the signature of the
|
||||||
|
receiving function should use @ref static_buffer_base instead.
|
||||||
|
|
||||||
|
@see @ref static_buffer_base
|
||||||
|
*/
|
||||||
|
template<std::size_t N>
|
||||||
|
class static_buffer : public static_buffer_base
|
||||||
|
{
|
||||||
|
char buf_[N];
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Constructor
|
||||||
|
static_buffer(static_buffer const&);
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
static_buffer()
|
||||||
|
: static_buffer_base(buf_, N)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assignment
|
||||||
|
static_buffer& operator=(static_buffer const&);
|
||||||
|
|
||||||
|
/// Returns the @ref static_buffer_base portion of this object
|
||||||
|
static_buffer_base&
|
||||||
|
base()
|
||||||
|
{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the @ref static_buffer_base portion of this object
|
||||||
|
static_buffer_base const&
|
||||||
|
base() const
|
||||||
|
{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/core/impl/static_buffer.ipp>
|
||||||
|
|
||||||
|
#endif
|
@@ -265,7 +265,7 @@ public:
|
|||||||
pointer
|
pointer
|
||||||
operator->()
|
operator->()
|
||||||
{
|
{
|
||||||
return &(*this);
|
return &(**this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const_iterator&
|
const_iterator&
|
||||||
|
@@ -39,6 +39,7 @@ add_executable (core-tests
|
|||||||
span.cpp
|
span.cpp
|
||||||
static_string.cpp
|
static_string.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
|
static_buffer.cpp
|
||||||
string_param.cpp
|
string_param.cpp
|
||||||
type_traits.cpp
|
type_traits.cpp
|
||||||
base64.cpp
|
base64.cpp
|
||||||
|
@@ -31,6 +31,7 @@ unit-test core-tests :
|
|||||||
ostream.cpp
|
ostream.cpp
|
||||||
read_size.cpp
|
read_size.cpp
|
||||||
span.cpp
|
span.cpp
|
||||||
|
static_buffer.cpp
|
||||||
static_string.cpp
|
static_string.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
string_param.cpp
|
string_param.cpp
|
||||||
|
234
test/core/static_buffer.cpp
Normal file
234
test/core/static_buffer.cpp
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
//
|
||||||
|
// 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 <beast/core/static_buffer.hpp>
|
||||||
|
|
||||||
|
#include "buffer_test.hpp"
|
||||||
|
|
||||||
|
#include <beast/core/ostream.hpp>
|
||||||
|
#include <beast/core/string.hpp>
|
||||||
|
#include <beast/unit_test/suite.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
is_dynamic_buffer<static_buffer_base>::value,
|
||||||
|
"DynamicBuffer requirements not met");
|
||||||
|
|
||||||
|
class static_buffer_test : public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
testStaticBuffer()
|
||||||
|
{
|
||||||
|
using namespace test;
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
char buf[12];
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
BEAST_EXPECT(s.size() == sizeof(buf));
|
||||||
|
for(std::size_t i = 1; i < 4; ++i) {
|
||||||
|
for(std::size_t j = 1; j < 4; ++j) {
|
||||||
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
|
for(std::size_t t = 1; t < 4; ++ t) {
|
||||||
|
for(std::size_t u = 1; u < 4; ++ u) {
|
||||||
|
std::size_t z = sizeof(buf) - (x + y);
|
||||||
|
std::size_t v = sizeof(buf) - (t + u);
|
||||||
|
{
|
||||||
|
std::memset(buf, 0, sizeof(buf));
|
||||||
|
static_buffer<sizeof(buf)> ba;
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(z);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(y);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(x);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
|
}
|
||||||
|
BEAST_EXPECT(ba.size() == x);
|
||||||
|
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(x);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(z);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(y);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
|
}
|
||||||
|
ba.commit(1);
|
||||||
|
BEAST_EXPECT(ba.size() == x + y);
|
||||||
|
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(x);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(y);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(z);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
|
}
|
||||||
|
ba.commit(2);
|
||||||
|
BEAST_EXPECT(buffer_size(ba.data()) == buffer_size(ba.mutable_data()));
|
||||||
|
BEAST_EXPECT(ba.size() == x + y + z);
|
||||||
|
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
|
||||||
|
BEAST_EXPECT(to_string(ba.data()) == s);
|
||||||
|
ba.consume(t);
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
BEAST_EXPECT(to_string(ba.data()) == s.substr(t, std::string::npos));
|
||||||
|
ba.consume(u);
|
||||||
|
BEAST_EXPECT(to_string(ba.data()) == s.substr(t + u, std::string::npos));
|
||||||
|
ba.consume(v);
|
||||||
|
BEAST_EXPECT(to_string(ba.data()) == "");
|
||||||
|
ba.consume(1);
|
||||||
|
{
|
||||||
|
auto d = ba.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ba.prepare(ba.capacity() - ba.size() + 1);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testBuffer()
|
||||||
|
{
|
||||||
|
using namespace test;
|
||||||
|
string_view const s = "Hello, world!";
|
||||||
|
|
||||||
|
// static_buffer_base
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
static_buffer_base b{buf, sizeof(buf)};
|
||||||
|
ostream(b) << s;
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == s);
|
||||||
|
b.consume(b.size());
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// static_buffer
|
||||||
|
{
|
||||||
|
static_buffer<64> b1;
|
||||||
|
BEAST_EXPECT(b1.size() == 0);
|
||||||
|
BEAST_EXPECT(b1.max_size() == 64);
|
||||||
|
BEAST_EXPECT(b1.capacity() == 64);
|
||||||
|
ostream(b1) << s;
|
||||||
|
BEAST_EXPECT(to_string(b1.data()) == s);
|
||||||
|
{
|
||||||
|
static_buffer<64> b2{b1};
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == s);
|
||||||
|
b2.consume(7);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == s.substr(7));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static_buffer<64> b2;
|
||||||
|
b2 = b1;
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == s);
|
||||||
|
b2.consume(7);
|
||||||
|
BEAST_EXPECT(to_string(b2.data()) == s.substr(7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cause memmove
|
||||||
|
{
|
||||||
|
static_buffer<10> b;
|
||||||
|
write_buffer(b, "12345");
|
||||||
|
b.consume(3);
|
||||||
|
write_buffer(b, "67890123");
|
||||||
|
BEAST_EXPECT(to_string(b.data()) == "4567890123");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
b.prepare(1);
|
||||||
|
fail("", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
catch(std::length_error const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read_size
|
||||||
|
{
|
||||||
|
static_buffer<10> b;
|
||||||
|
BEAST_EXPECT(read_size(b, 512) == 10);
|
||||||
|
b.prepare(4);
|
||||||
|
b.commit(4);
|
||||||
|
BEAST_EXPECT(read_size(b, 512) == 6);
|
||||||
|
b.consume(2);
|
||||||
|
BEAST_EXPECT(read_size(b, 512) == 8);
|
||||||
|
b.prepare(8);
|
||||||
|
b.commit(8);
|
||||||
|
BEAST_EXPECT(read_size(b, 512) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// base
|
||||||
|
{
|
||||||
|
static_buffer<10> b;
|
||||||
|
[&](static_buffer_base& base)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(base.max_size() == b.capacity());
|
||||||
|
}
|
||||||
|
(b.base());
|
||||||
|
|
||||||
|
[&](static_buffer_base const& base)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(base.max_size() == b.capacity());
|
||||||
|
}
|
||||||
|
(b.base());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testBuffer();
|
||||||
|
//testStaticBuffer();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(static_buffer,core,beast);
|
||||||
|
|
||||||
|
} // beast
|
Reference in New Issue
Block a user