mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
Dynamic buffers improvements:
fix #1305 Applies to: flat_buffer flat_static_buffer multi_buffer static_buffer Changes: * Revised all javadocs * Move construction does not invalidate in some cases * non-const data() returns a mutable buffer sequence * Add cdata() to also return constant readable bytes * Eligible member functions are declared noexcept
This commit is contained in:
@ -4,6 +4,7 @@ Version 194:
|
||||
* Add net namespace alias
|
||||
* Don't use-after-free in test
|
||||
* Tidy up ssl_stream (experimental)
|
||||
* Dynamic buffer improvements
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -20,18 +20,30 @@
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
/** A linear dynamic buffer.
|
||||
/** A dynamic buffer providing buffer sequences of length one.
|
||||
|
||||
A dynamic buffer encapsulates memory storage that may be
|
||||
automatically resized as required, where the memory is
|
||||
divided into two regions: readable bytes followed by
|
||||
writable bytes. These memory regions are internal to
|
||||
the dynamic buffer, but direct access to the elements
|
||||
is provided to permit them to be efficiently used with
|
||||
I/O operations.
|
||||
|
||||
Objects of this type meet the requirements of @b DynamicBuffer
|
||||
and offer additional invariants:
|
||||
and have the following additional properties:
|
||||
|
||||
@li Buffer sequences returned by @ref data and @ref prepare
|
||||
will always be of length one.
|
||||
@li A mutable buffer sequence representing the readable
|
||||
bytes is returned by @ref data when `this` is non-const.
|
||||
|
||||
@li A configurable maximum buffer size may be set upon
|
||||
construction. Attempts to exceed the buffer size will throw
|
||||
`std::length_error`.
|
||||
|
||||
@li Buffer sequences representing the readable and writable
|
||||
bytes, returned by @ref data and @ref prepare, will have
|
||||
length one.
|
||||
|
||||
Upon construction, a maximum size for the buffer may be
|
||||
specified. If this limit is exceeded, the `std::length_error`
|
||||
exception will be thrown.
|
||||
@ -65,7 +77,6 @@ class basic_flat_buffer
|
||||
detail::allocator_traits<base_alloc_type>;
|
||||
|
||||
static
|
||||
inline
|
||||
std::size_t
|
||||
dist(char const* first, char const* last)
|
||||
{
|
||||
@ -83,24 +94,18 @@ public:
|
||||
/// The type of allocator used.
|
||||
using allocator_type = Allocator;
|
||||
|
||||
/// The type used to represent the input sequence as a list of buffers.
|
||||
using const_buffers_type = boost::asio::const_buffer;
|
||||
|
||||
/// The type used to represent the output sequence as a list of buffers.
|
||||
using mutable_buffers_type = boost::asio::mutable_buffer;
|
||||
|
||||
/// Destructor
|
||||
~basic_flat_buffer();
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, capacity will be zero.
|
||||
Upon construction, @ref capacity will return zero.
|
||||
*/
|
||||
basic_flat_buffer();
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, capacity will be zero.
|
||||
Upon construction, @ref capacity will return zero.
|
||||
|
||||
@param limit The setting for @ref max_size.
|
||||
*/
|
||||
@ -109,7 +114,7 @@ public:
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, capacity will be zero.
|
||||
Upon construction, @ref capacity will return zero.
|
||||
|
||||
@param alloc The allocator to construct with.
|
||||
*/
|
||||
@ -118,7 +123,7 @@ public:
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, capacity will be zero.
|
||||
Upon construction, @ref capacity will return zero.
|
||||
|
||||
@param limit The setting for @ref max_size.
|
||||
|
||||
@ -127,36 +132,55 @@ public:
|
||||
basic_flat_buffer(
|
||||
std::size_t limit, Allocator const& alloc);
|
||||
|
||||
/** Constructor
|
||||
/** Move Constructor
|
||||
|
||||
After the move, `*this` will have an empty output sequence.
|
||||
Constructs the container with the contents of other
|
||||
using move semantics. After the move, other is
|
||||
guaranteed to be empty.
|
||||
|
||||
Buffer sequences previously obtained using @ref data
|
||||
or @ref prepare are not invalidated after the move.
|
||||
|
||||
@param other The object to move from. After the move,
|
||||
The object's state will be as if constructed using
|
||||
its current allocator and limit.
|
||||
the moved-from object's state will be as if default
|
||||
constructed using its current allocator and limit.
|
||||
*/
|
||||
basic_flat_buffer(basic_flat_buffer&& other);
|
||||
|
||||
/** Constructor
|
||||
/** Move Constructor
|
||||
|
||||
After the move, `*this` will have an empty output sequence.
|
||||
Using alloc as the allocator for the new container, the
|
||||
contents of other are moved. If `alloc != other.get_allocator()`,
|
||||
this results in a copy. After the move, other is
|
||||
guaranteed to be empty.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param other The object to move from. After the move,
|
||||
The object's state will be as if constructed using
|
||||
its current allocator and limit.
|
||||
the moved-from object's state will be as if default
|
||||
constructed using its current allocator and limit.
|
||||
|
||||
@param alloc The allocator to use.
|
||||
@param alloc The allocator to use for the newly
|
||||
constructed object.
|
||||
*/
|
||||
basic_flat_buffer(
|
||||
basic_flat_buffer&& other, Allocator const& alloc);
|
||||
|
||||
/** Constructor
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
allocator and contents of other, and zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
*/
|
||||
basic_flat_buffer(basic_flat_buffer const& other);
|
||||
|
||||
/** Constructor
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
specified allocator, a copy of the contents of other,
|
||||
and zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@ -165,7 +189,10 @@ public:
|
||||
basic_flat_buffer(basic_flat_buffer const& other,
|
||||
Allocator const& alloc);
|
||||
|
||||
/** Constructor
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
contents of other, and zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
*/
|
||||
@ -173,7 +200,11 @@ public:
|
||||
basic_flat_buffer(
|
||||
basic_flat_buffer<OtherAlloc> const& other);
|
||||
|
||||
/** Constructor
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
specified allocator, a copy of the contents of other,
|
||||
and zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@ -184,20 +215,28 @@ public:
|
||||
basic_flat_buffer<OtherAlloc> const& other,
|
||||
Allocator const& alloc);
|
||||
|
||||
/** Assignment
|
||||
/** Move Assignment
|
||||
|
||||
After the move, `*this` will have an empty output sequence.
|
||||
Assigns the container with the contents of other
|
||||
using move semantics. After the move, other is
|
||||
guaranteed to be empty. The previous contents of
|
||||
this container are deleted.
|
||||
|
||||
Buffer sequences previously obtained using @ref data
|
||||
or @ref prepare are not invalidated after the move.
|
||||
|
||||
@param other The object to move from. After the move,
|
||||
the object's state will be as if constructed using
|
||||
its current allocator and limit.
|
||||
the moved-from object's state will be as if default
|
||||
constructed using its current allocator and limit.
|
||||
*/
|
||||
basic_flat_buffer&
|
||||
operator=(basic_flat_buffer&& other);
|
||||
|
||||
/** Assignment
|
||||
/** Copy Assignment
|
||||
|
||||
After the copy, `*this` will have an empty output sequence.
|
||||
The assigned object will have a copy of the allocator
|
||||
and contents of other, and zero writable bytes. The
|
||||
previous contents of this container are deleted.
|
||||
|
||||
@param other The object to copy from.
|
||||
*/
|
||||
@ -206,7 +245,9 @@ public:
|
||||
|
||||
/** Copy assignment
|
||||
|
||||
After the copy, `*this` will have an empty output sequence.
|
||||
The assigned object will have a copy of the contents
|
||||
of other, and zero writable bytes. The previous contents
|
||||
of this container are deleted.
|
||||
|
||||
@param other The object to copy from.
|
||||
*/
|
||||
@ -214,123 +255,149 @@ public:
|
||||
basic_flat_buffer&
|
||||
operator=(basic_flat_buffer<OtherAlloc> const& other);
|
||||
|
||||
/// Returns a copy of the associated allocator.
|
||||
/// Returns a copy of the allocator used.
|
||||
allocator_type
|
||||
get_allocator() const
|
||||
{
|
||||
return this->get();
|
||||
}
|
||||
|
||||
/// Returns the size of the input sequence.
|
||||
std::size_t
|
||||
size() const
|
||||
{
|
||||
return dist(in_, out_);
|
||||
}
|
||||
/** Reallocate the buffer to fit the readable bytes exactly.
|
||||
|
||||
/// Return the maximum sum of the input and output sequence sizes.
|
||||
std::size_t
|
||||
max_size() const
|
||||
{
|
||||
return max_;
|
||||
}
|
||||
|
||||
/// Return the maximum sum of input and output sizes that can be held without an allocation.
|
||||
std::size_t
|
||||
capacity() const
|
||||
{
|
||||
return dist(begin_, end_);
|
||||
}
|
||||
|
||||
/// Get a list of buffers that represent the input sequence.
|
||||
const_buffers_type
|
||||
data() const
|
||||
{
|
||||
return {in_, dist(in_, out_)};
|
||||
}
|
||||
|
||||
/** Get a list of buffers that represent the output sequence, with the given size.
|
||||
|
||||
@throws std::length_error if `size() + n` exceeds `max_size()`.
|
||||
|
||||
@note All previous buffers sequences obtained from
|
||||
calls to @ref data or @ref prepare are invalidated.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(std::size_t n);
|
||||
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
|
||||
@param n The number of bytes to move. If this is larger than
|
||||
the number of bytes in the output sequences, then the entire
|
||||
output sequences is moved.
|
||||
|
||||
@note All previous buffers sequences obtained from
|
||||
calls to @ref data or @ref prepare are invalidated.
|
||||
*/
|
||||
void
|
||||
commit(std::size_t n)
|
||||
{
|
||||
out_ += (std::min)(n, dist(out_, last_));
|
||||
}
|
||||
|
||||
/** Remove bytes from the input sequence.
|
||||
|
||||
If `n` is greater than the number of bytes in the input
|
||||
sequence, all bytes in the input sequence are removed.
|
||||
|
||||
@note All previous buffers sequences obtained from
|
||||
calls to @ref data or @ref prepare are invalidated.
|
||||
*/
|
||||
void
|
||||
consume(std::size_t n);
|
||||
|
||||
/** Reallocate the buffer to fit the input sequence.
|
||||
|
||||
@note All previous buffers sequences obtained from
|
||||
calls to @ref data or @ref prepare are invalidated.
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
*/
|
||||
void
|
||||
shrink_to_fit();
|
||||
|
||||
/// Exchange two flat buffers
|
||||
/// Exchange two dynamic buffers
|
||||
template<class Alloc>
|
||||
friend
|
||||
void
|
||||
swap(
|
||||
basic_flat_buffer<Alloc>& lhs,
|
||||
basic_flat_buffer<Alloc>& rhs);
|
||||
basic_flat_buffer<Alloc>&,
|
||||
basic_flat_buffer<Alloc>&);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// The ConstBufferSequence used to represent the readable bytes.
|
||||
using const_buffers_type = boost::asio::const_buffer;
|
||||
|
||||
/// The MutableBufferSequence used to represent the readable bytes.
|
||||
using mutable_data_type = boost::asio::mutable_buffer;
|
||||
|
||||
/// The MutableBufferSequence used to represent the writable bytes.
|
||||
using mutable_buffers_type = boost::asio::mutable_buffer;
|
||||
|
||||
/// Returns the number of readable bytes.
|
||||
std::size_t
|
||||
size() const noexcept
|
||||
{
|
||||
return dist(in_, out_);
|
||||
}
|
||||
|
||||
/// Return the maximum number of bytes, both readable and writable, that can ever be held.
|
||||
std::size_t
|
||||
max_size() const noexcept
|
||||
{
|
||||
return max_;
|
||||
}
|
||||
|
||||
/// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
|
||||
std::size_t
|
||||
capacity() const noexcept
|
||||
{
|
||||
return dist(begin_, end_);
|
||||
}
|
||||
|
||||
/// Returns a constant buffer sequence representing the readable bytes
|
||||
const_buffers_type
|
||||
data() const noexcept
|
||||
{
|
||||
return {in_, dist(in_, out_)};
|
||||
}
|
||||
|
||||
/// Returns a constant buffer sequence representing the readable bytes
|
||||
const_buffers_type
|
||||
cdata() const noexcept
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
/// Returns a mutable buffer sequence representing the readable bytes
|
||||
mutable_data_type
|
||||
data() noexcept
|
||||
{
|
||||
return {in_, dist(in_, out_)};
|
||||
}
|
||||
|
||||
/** Returns a mutable buffer sequence representing writable bytes.
|
||||
|
||||
Returns a mutable buffer sequence representing the writable
|
||||
bytes containing exactly `n` bytes of storage. Memory may be
|
||||
reallocated as needed.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param n The desired number of bytes in the returned buffer
|
||||
sequence.
|
||||
|
||||
@throws std::length_error if `size() + n` exceeds `max_size()`.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(std::size_t n);
|
||||
|
||||
/** Append writable bytes to the readable bytes.
|
||||
|
||||
Appends n bytes from the start of the writable bytes to the
|
||||
end of the readable bytes. The remainder of the writable bytes
|
||||
are discarded. If n is greater than the number of writable
|
||||
bytes, all writable bytes are appended to the readable bytes.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param n The number of bytes to append. If this number
|
||||
is greater than the number of writable bytes, all
|
||||
writable bytes are appended.
|
||||
*/
|
||||
void
|
||||
commit(std::size_t n) noexcept
|
||||
{
|
||||
out_ += (std::min)(n, dist(out_, last_));
|
||||
}
|
||||
|
||||
/** Remove bytes from beginning of the readable bytes.
|
||||
|
||||
Removes n bytes from the beginning of the readable bytes.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param n The number of bytes to remove. If this number
|
||||
is greater than the number of readable bytes, all
|
||||
readable bytes are removed.
|
||||
*/
|
||||
void
|
||||
consume(std::size_t n) noexcept;
|
||||
|
||||
private:
|
||||
void
|
||||
reset();
|
||||
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
copy_from(DynamicBuffer const& other);
|
||||
|
||||
void
|
||||
move_assign(basic_flat_buffer&, std::true_type);
|
||||
|
||||
void
|
||||
move_assign(basic_flat_buffer&, std::false_type);
|
||||
|
||||
void
|
||||
copy_assign(basic_flat_buffer const&, std::true_type);
|
||||
|
||||
void
|
||||
copy_assign(basic_flat_buffer const&, std::false_type);
|
||||
|
||||
void
|
||||
swap(basic_flat_buffer&);
|
||||
|
||||
void
|
||||
swap(basic_flat_buffer&, std::true_type);
|
||||
|
||||
void
|
||||
swap(basic_flat_buffer&, std::false_type);
|
||||
void copy_from(DynamicBuffer const& other);
|
||||
void move_assign(basic_flat_buffer&, std::true_type);
|
||||
void move_assign(basic_flat_buffer&, std::false_type);
|
||||
void copy_assign(basic_flat_buffer const&, std::true_type);
|
||||
void copy_assign(basic_flat_buffer const&, std::false_type);
|
||||
void swap(basic_flat_buffer&);
|
||||
void swap(basic_flat_buffer&, std::true_type);
|
||||
void swap(basic_flat_buffer&, std::false_type);
|
||||
};
|
||||
|
||||
/// A flat buffer which uses the default allocator.
|
||||
using flat_buffer =
|
||||
basic_flat_buffer<std::allocator<char>>;
|
||||
|
||||
|
@ -19,20 +19,32 @@
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
/** A flat @b DynamicBuffer with a fixed size internal buffer.
|
||||
/** A dynamic buffer using a fixed size internal buffer.
|
||||
|
||||
Buffer sequences returned by @ref data and @ref prepare
|
||||
will always be of length one.
|
||||
Ownership of the underlying storage belongs to the derived class.
|
||||
A dynamic buffer encapsulates memory storage that may be
|
||||
automatically resized as required, where the memory is
|
||||
divided into two regions: readable bytes followed by
|
||||
writable bytes. These memory regions are internal to
|
||||
the dynamic buffer, but direct access to the elements
|
||||
is provided to permit them to be efficiently used with
|
||||
I/O operations.
|
||||
|
||||
Objects of this type meet the requirements of @b DynamicBuffer
|
||||
and have the following additional properties:
|
||||
|
||||
@li A mutable buffer sequence representing the readable
|
||||
bytes is returned by @ref data when `this` is non-const.
|
||||
|
||||
@li Buffer sequences representing the readable and writable
|
||||
bytes, returned by @ref data and @ref prepare, will have
|
||||
length one.
|
||||
|
||||
@li Ownership of the underlying storage belongs to the
|
||||
derived class.
|
||||
|
||||
@note Variables are usually declared using the template class
|
||||
@ref flat_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 flat_static_buffer_base.
|
||||
|
||||
When used with @ref flat_static_buffer this implements a dynamic
|
||||
buffer using no memory allocations.
|
||||
@ref flat_static_buffer; however, to reduce the number of template
|
||||
instantiations, objects should be passed `flat_static_buffer_base&`.
|
||||
|
||||
@see @ref flat_static_buffer
|
||||
*/
|
||||
@ -44,22 +56,12 @@ class flat_static_buffer_base
|
||||
char* last_;
|
||||
char* end_;
|
||||
|
||||
flat_static_buffer_base(flat_static_buffer_base const& other) = delete;
|
||||
flat_static_buffer_base& operator=(flat_static_buffer_base const&) = delete;
|
||||
flat_static_buffer_base(
|
||||
flat_static_buffer_base const& other) = delete;
|
||||
flat_static_buffer_base& operator=(
|
||||
flat_static_buffer_base const&) = delete;
|
||||
|
||||
public:
|
||||
/** The type used to represent the input sequence as a list of buffers.
|
||||
|
||||
This buffer sequence is guaranteed to have length 1.
|
||||
*/
|
||||
using const_buffers_type = boost::asio::const_buffer;
|
||||
|
||||
/** The type used to represent the output sequence as a list of buffers.
|
||||
|
||||
This buffer sequence is guaranteed to have length 1.
|
||||
*/
|
||||
using mutable_buffers_type = boost::asio::mutable_buffer;
|
||||
|
||||
/** Constructor
|
||||
|
||||
This creates a dynamic buffer using the provided storage area.
|
||||
@ -68,71 +70,129 @@ public:
|
||||
|
||||
@param n The number of valid bytes pointed to by `p`.
|
||||
*/
|
||||
flat_static_buffer_base(void* p, std::size_t n)
|
||||
flat_static_buffer_base(
|
||||
void* p, std::size_t n) noexcept
|
||||
{
|
||||
reset_impl(p, n);
|
||||
reset(p, n);
|
||||
}
|
||||
|
||||
/// Return the size of the input sequence.
|
||||
/// Change the number of readable and writable bytes to zero.
|
||||
inline
|
||||
void
|
||||
clear() noexcept;
|
||||
|
||||
// VFALCO Deprecate this
|
||||
/// Change the number of readable and writable bytes to zero.
|
||||
void
|
||||
reset() noexcept
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// The ConstBufferSequence used to represent the readable bytes.
|
||||
using const_buffers_type = boost::asio::const_buffer;
|
||||
|
||||
/// The MutableBufferSequence used to represent the readable bytes.
|
||||
using mutable_data_type = boost::asio::mutable_buffer;
|
||||
|
||||
/// The MutableBufferSequence used to represent the writable bytes.
|
||||
using mutable_buffers_type = boost::asio::mutable_buffer;
|
||||
|
||||
/// Returns the number of readable bytes.
|
||||
std::size_t
|
||||
size() const
|
||||
size() const noexcept
|
||||
{
|
||||
return out_ - in_;
|
||||
}
|
||||
|
||||
/// Return the maximum sum of the input and output sequence sizes.
|
||||
/// Return the maximum number of bytes, both readable and writable, that can ever be held.
|
||||
std::size_t
|
||||
max_size() const
|
||||
max_size() const noexcept
|
||||
{
|
||||
return dist(begin_, end_);
|
||||
}
|
||||
|
||||
/// Return the maximum sum of input and output sizes that can be held without an allocation.
|
||||
/// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
|
||||
std::size_t
|
||||
capacity() const
|
||||
capacity() const noexcept
|
||||
{
|
||||
return max_size();
|
||||
}
|
||||
|
||||
/** Get a list of buffers that represent the input sequence.
|
||||
|
||||
@note These buffers remain valid across subsequent calls to `prepare`.
|
||||
*/
|
||||
/// Returns a constant buffer sequence representing the readable bytes
|
||||
const_buffers_type
|
||||
data() const;
|
||||
data() const noexcept
|
||||
{
|
||||
return {in_, dist(in_, out_)};
|
||||
}
|
||||
|
||||
/// Set the input and output sequences to size 0
|
||||
void
|
||||
reset();
|
||||
/// Returns a constant buffer sequence representing the readable bytes
|
||||
const_buffers_type
|
||||
cdata() const noexcept
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
/** Get a list of buffers that represent the output sequence, with the given size.
|
||||
/// Returns a mutable buffer sequence representing the readable bytes
|
||||
mutable_data_type
|
||||
data() noexcept
|
||||
{
|
||||
return {in_, dist(in_, out_)};
|
||||
}
|
||||
|
||||
@throws std::length_error if the size would exceed the limit
|
||||
imposed by the underlying mutable buffer sequence.
|
||||
/** Returns a mutable buffer sequence representing writable bytes.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
Returns a mutable buffer sequence representing the writable
|
||||
bytes containing exactly `n` bytes of storage.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param n The desired number of bytes in the returned buffer
|
||||
sequence.
|
||||
|
||||
@throws std::length_error if `size() + n` exceeds `max_size()`.
|
||||
*/
|
||||
inline
|
||||
mutable_buffers_type
|
||||
prepare(std::size_t n);
|
||||
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
/** Append writable bytes to the readable bytes.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
Appends n bytes from the start of the writable bytes to the
|
||||
end of the readable bytes. The remainder of the writable bytes
|
||||
are discarded. If n is greater than the number of writable
|
||||
bytes, all writable bytes are appended to the readable bytes.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param n The number of bytes to append. If this number
|
||||
is greater than the number of writable bytes, all
|
||||
writable bytes are appended.
|
||||
*/
|
||||
void
|
||||
commit(std::size_t n)
|
||||
commit(std::size_t n) noexcept
|
||||
{
|
||||
out_ += (std::min<std::size_t>)(n, last_ - out_);
|
||||
}
|
||||
|
||||
/// Remove bytes from the input sequence.
|
||||
/** Remove bytes from beginning of the readable bytes.
|
||||
|
||||
Removes n bytes from the beginning of the readable bytes.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param n The number of bytes to remove. If this number
|
||||
is greater than the number of readable bytes, all
|
||||
readable bytes are removed.
|
||||
*/
|
||||
inline
|
||||
void
|
||||
consume(std::size_t n)
|
||||
{
|
||||
consume_impl(n);
|
||||
}
|
||||
consume(std::size_t n) noexcept;
|
||||
|
||||
protected:
|
||||
/** Constructor
|
||||
@ -154,33 +214,17 @@ protected:
|
||||
|
||||
@param n The number of valid bytes pointed to by `p`.
|
||||
*/
|
||||
inline
|
||||
void
|
||||
reset(void* p, std::size_t n);
|
||||
reset(void* p, std::size_t n) noexcept;
|
||||
|
||||
private:
|
||||
static
|
||||
inline
|
||||
std::size_t
|
||||
dist(char const* first, char const* last)
|
||||
{
|
||||
return static_cast<std::size_t>(last - first);
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
reset_impl();
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
reset_impl(void* p, std::size_t n);
|
||||
|
||||
template<class = void>
|
||||
mutable_buffers_type
|
||||
prepare_impl(std::size_t n);
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
consume_impl(std::size_t n);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -18,9 +18,11 @@
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
/* Memory is laid out thusly:
|
||||
/* Layout:
|
||||
|
||||
begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
|
||||
begin_ in_ out_ last_ end_
|
||||
|<------->|<---------->|<---------->|<------->|
|
||||
| readable | writable |
|
||||
*/
|
||||
|
||||
template<class Allocator>
|
||||
@ -40,7 +42,8 @@ basic_flat_buffer()
|
||||
, out_(nullptr)
|
||||
, last_(nullptr)
|
||||
, end_(nullptr)
|
||||
, max_((std::numeric_limits<std::size_t>::max)())
|
||||
, max_((std::numeric_limits<
|
||||
std::size_t>::max)())
|
||||
{
|
||||
}
|
||||
|
||||
@ -59,20 +62,24 @@ basic_flat_buffer(std::size_t limit)
|
||||
template<class Allocator>
|
||||
basic_flat_buffer<Allocator>::
|
||||
basic_flat_buffer(Allocator const& alloc)
|
||||
: boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc)
|
||||
: boost::empty_value<base_alloc_type>(
|
||||
boost::empty_init_t(), alloc)
|
||||
, begin_(nullptr)
|
||||
, in_(nullptr)
|
||||
, out_(nullptr)
|
||||
, last_(nullptr)
|
||||
, end_(nullptr)
|
||||
, max_((std::numeric_limits<std::size_t>::max)())
|
||||
, max_((std::numeric_limits<
|
||||
std::size_t>::max)())
|
||||
{
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
basic_flat_buffer<Allocator>::
|
||||
basic_flat_buffer(std::size_t limit, Allocator const& alloc)
|
||||
: boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc)
|
||||
basic_flat_buffer(
|
||||
std::size_t limit, Allocator const& alloc)
|
||||
: boost::empty_value<base_alloc_type>(
|
||||
boost::empty_init_t(), alloc)
|
||||
, begin_(nullptr)
|
||||
, in_(nullptr)
|
||||
, out_(nullptr)
|
||||
@ -85,23 +92,23 @@ basic_flat_buffer(std::size_t limit, Allocator const& alloc)
|
||||
template<class Allocator>
|
||||
basic_flat_buffer<Allocator>::
|
||||
basic_flat_buffer(basic_flat_buffer&& other)
|
||||
: boost::empty_value<base_alloc_type>(boost::empty_init_t(),
|
||||
std::move(other.get()))
|
||||
: boost::empty_value<base_alloc_type>(
|
||||
boost::empty_init_t(), std::move(other.get()))
|
||||
, begin_(boost::exchange(other.begin_, nullptr))
|
||||
, in_(boost::exchange(other.in_, nullptr))
|
||||
, out_(boost::exchange(other.out_, nullptr))
|
||||
, last_(out_)
|
||||
, last_(boost::exchange(other.last_, nullptr))
|
||||
, end_(boost::exchange(other.end_, nullptr))
|
||||
, max_(other.max_)
|
||||
{
|
||||
other.last_ = nullptr;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
basic_flat_buffer<Allocator>::
|
||||
basic_flat_buffer(basic_flat_buffer&& other,
|
||||
Allocator const& alloc)
|
||||
: boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc)
|
||||
basic_flat_buffer(
|
||||
basic_flat_buffer&& other, Allocator const& alloc)
|
||||
: boost::empty_value<base_alloc_type>(
|
||||
boost::empty_init_t(), alloc)
|
||||
{
|
||||
if(this->get() != other.get())
|
||||
{
|
||||
@ -119,7 +126,7 @@ basic_flat_buffer(basic_flat_buffer&& other,
|
||||
begin_ = other.begin_;
|
||||
in_ = other.in_;
|
||||
out_ = other.out_;
|
||||
last_ = out_;
|
||||
last_ = other.out_; // invalidate
|
||||
end_ = other.end_;
|
||||
max_ = other.max_;
|
||||
other.begin_ = nullptr;
|
||||
@ -229,6 +236,36 @@ operator=(basic_flat_buffer<OtherAlloc> const& other) ->
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
shrink_to_fit()
|
||||
{
|
||||
auto const len = size();
|
||||
if(len == capacity())
|
||||
return;
|
||||
char* p;
|
||||
if(len > 0)
|
||||
{
|
||||
BOOST_ASSERT(begin_);
|
||||
BOOST_ASSERT(in_);
|
||||
p = alloc_traits::allocate(
|
||||
this->get(), len);
|
||||
std::memcpy(p, in_, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = nullptr;
|
||||
}
|
||||
alloc_traits::deallocate(
|
||||
this->get(), begin_, this->dist(begin_, end_));
|
||||
begin_ = p;
|
||||
in_ = begin_;
|
||||
out_ = begin_ + len;
|
||||
last_ = out_;
|
||||
end_ = out_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
@ -284,7 +321,7 @@ prepare(std::size_t n) ->
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
consume(std::size_t n)
|
||||
consume(std::size_t n) noexcept
|
||||
{
|
||||
if(n >= dist(in_, out_))
|
||||
{
|
||||
@ -295,40 +332,9 @@ consume(std::size_t n)
|
||||
in_ += n;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
shrink_to_fit()
|
||||
{
|
||||
auto const len = size();
|
||||
if(len == capacity())
|
||||
return;
|
||||
char* p;
|
||||
if(len > 0)
|
||||
{
|
||||
BOOST_ASSERT(begin_);
|
||||
BOOST_ASSERT(in_);
|
||||
p = alloc_traits::allocate(
|
||||
this->get(), len);
|
||||
std::memcpy(p, in_, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = nullptr;
|
||||
}
|
||||
alloc_traits::deallocate(
|
||||
this->get(), begin_, dist(begin_, end_));
|
||||
begin_ = p;
|
||||
in_ = begin_;
|
||||
out_ = begin_ + len;
|
||||
last_ = out_;
|
||||
end_ = out_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
reset()
|
||||
@ -339,20 +345,17 @@ reset()
|
||||
|
||||
template<class Allocator>
|
||||
template<class DynamicBuffer>
|
||||
inline
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
copy_from(DynamicBuffer const& buffer)
|
||||
{
|
||||
if(buffer.size() == 0)
|
||||
return;
|
||||
using boost::asio::buffer_copy;
|
||||
commit(buffer_copy(
|
||||
commit(boost::asio::buffer_copy(
|
||||
prepare(buffer.size()), buffer.data()));
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
move_assign(basic_flat_buffer& other, std::true_type)
|
||||
@ -373,7 +376,6 @@ move_assign(basic_flat_buffer& other, std::true_type)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
move_assign(basic_flat_buffer& other, std::false_type)
|
||||
@ -391,7 +393,6 @@ move_assign(basic_flat_buffer& other, std::false_type)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
copy_assign(basic_flat_buffer const& other, std::true_type)
|
||||
@ -403,7 +404,6 @@ copy_assign(basic_flat_buffer const& other, std::true_type)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
copy_assign(basic_flat_buffer const& other, std::false_type)
|
||||
@ -414,7 +414,6 @@ copy_assign(basic_flat_buffer const& other, std::false_type)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
swap(basic_flat_buffer& other)
|
||||
@ -424,7 +423,6 @@ swap(basic_flat_buffer& other)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
swap(basic_flat_buffer& other, std::true_type)
|
||||
@ -441,7 +439,6 @@ swap(basic_flat_buffer& other, std::true_type)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_flat_buffer<Allocator>::
|
||||
swap(basic_flat_buffer& other, std::false_type)
|
||||
|
@ -21,72 +21,26 @@
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
/* Memory is laid out thusly:
|
||||
/* Layout:
|
||||
|
||||
begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
|
||||
begin_ in_ out_ last_ end_
|
||||
|<------->|<---------->|<---------->|<------->|
|
||||
| readable | writable |
|
||||
*/
|
||||
|
||||
inline
|
||||
auto
|
||||
flat_static_buffer_base::
|
||||
data() const ->
|
||||
const_buffers_type
|
||||
{
|
||||
return {in_, dist(in_, out_)};
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
flat_static_buffer_base::
|
||||
reset()
|
||||
clear() noexcept
|
||||
{
|
||||
reset_impl();
|
||||
in_ = begin_;
|
||||
out_ = begin_;
|
||||
last_ = begin_;
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
flat_static_buffer_base::
|
||||
prepare(std::size_t n) ->
|
||||
mutable_buffers_type
|
||||
{
|
||||
return prepare_impl(n);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
flat_static_buffer_base::
|
||||
reset(void* p, std::size_t n)
|
||||
{
|
||||
reset_impl(p, n);
|
||||
}
|
||||
|
||||
template<class>
|
||||
void
|
||||
flat_static_buffer_base::
|
||||
reset_impl()
|
||||
{
|
||||
in_ = begin_;
|
||||
out_ = begin_;
|
||||
last_ = begin_;
|
||||
}
|
||||
|
||||
template<class>
|
||||
void
|
||||
flat_static_buffer_base::
|
||||
reset_impl(void* p, std::size_t n)
|
||||
{
|
||||
begin_ = static_cast<char*>(p);
|
||||
in_ = begin_;
|
||||
out_ = begin_;
|
||||
last_ = begin_;
|
||||
end_ = begin_ + n;
|
||||
}
|
||||
|
||||
template<class>
|
||||
auto
|
||||
flat_static_buffer_base::
|
||||
prepare_impl(std::size_t n) ->
|
||||
mutable_buffers_type
|
||||
{
|
||||
if(n <= dist(out_, end_))
|
||||
{
|
||||
@ -105,10 +59,9 @@ prepare_impl(std::size_t n) ->
|
||||
return {out_, n};
|
||||
}
|
||||
|
||||
template<class>
|
||||
void
|
||||
flat_static_buffer_base::
|
||||
consume_impl(std::size_t n)
|
||||
consume(std::size_t n) noexcept
|
||||
{
|
||||
if(n >= size())
|
||||
{
|
||||
@ -119,6 +72,17 @@ consume_impl(std::size_t n)
|
||||
in_ += n;
|
||||
}
|
||||
|
||||
void
|
||||
flat_static_buffer_base::
|
||||
reset(void* p, std::size_t n) noexcept
|
||||
{
|
||||
begin_ = static_cast<char*>(p);
|
||||
in_ = begin_;
|
||||
out_ = begin_;
|
||||
last_ = begin_;
|
||||
end_ = begin_ + n;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<std::size_t N>
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
@ -86,6 +87,7 @@ namespace beast {
|
||||
in_pos_ out_pos_ == 0
|
||||
out_end_ == 0
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
class basic_multi_buffer<Allocator>::element
|
||||
@ -93,105 +95,99 @@ class basic_multi_buffer<Allocator>::element
|
||||
boost::intrusive::link_mode<
|
||||
boost::intrusive::normal_link>>
|
||||
{
|
||||
using size_type =
|
||||
typename detail::allocator_traits<Allocator>::size_type;
|
||||
using size_type = typename
|
||||
detail::allocator_traits<Allocator>::size_type;
|
||||
|
||||
size_type const size_;
|
||||
|
||||
public:
|
||||
element(element const&) = delete;
|
||||
element& operator=(element const&) = delete;
|
||||
|
||||
explicit
|
||||
element(size_type n)
|
||||
element(size_type n) noexcept
|
||||
: size_(n)
|
||||
{
|
||||
}
|
||||
|
||||
size_type
|
||||
size() const
|
||||
size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
char*
|
||||
data() const
|
||||
data() const noexcept
|
||||
{
|
||||
return const_cast<char*>(
|
||||
reinterpret_cast<char const*>(this + 1));
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
class basic_multi_buffer<Allocator>::const_buffers_type
|
||||
template<bool IsMutable>
|
||||
class basic_multi_buffer<Allocator>::readable_bytes
|
||||
{
|
||||
basic_multi_buffer const* b_;
|
||||
|
||||
friend class basic_multi_buffer;
|
||||
|
||||
explicit
|
||||
const_buffers_type(basic_multi_buffer const& b);
|
||||
readable_bytes(
|
||||
basic_multi_buffer const& b) noexcept
|
||||
: b_(&b)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = boost::asio::const_buffer;
|
||||
using value_type = typename std::conditional<
|
||||
IsMutable,
|
||||
boost::asio::mutable_buffer,
|
||||
boost::asio::const_buffer>::type;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
const_buffers_type() = delete;
|
||||
const_buffers_type(const_buffers_type const&) = default;
|
||||
const_buffers_type& operator=(const_buffers_type const&) = default;
|
||||
readable_bytes() = delete;
|
||||
readable_bytes& operator=(readable_bytes const&) = default;
|
||||
|
||||
const_iterator
|
||||
begin() const;
|
||||
template<
|
||||
bool OtherIsMutable,
|
||||
bool ThisIsMutable = IsMutable>
|
||||
readable_bytes(
|
||||
readable_bytes<OtherIsMutable> const& other,
|
||||
typename std::enable_if<
|
||||
! ThisIsMutable || OtherIsMutable>::type* = 0)
|
||||
: b_(other.b_)
|
||||
{
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
|
||||
friend
|
||||
std::size_t
|
||||
buffer_size(const_buffers_type const& buffers)
|
||||
buffer_size(readable_bytes const& buffers) noexcept
|
||||
{
|
||||
return buffers.b_->size();
|
||||
}
|
||||
};
|
||||
|
||||
template<class Allocator>
|
||||
class basic_multi_buffer<Allocator>::mutable_buffers_type
|
||||
{
|
||||
basic_multi_buffer const* b_;
|
||||
|
||||
friend class basic_multi_buffer;
|
||||
|
||||
explicit
|
||||
mutable_buffers_type(basic_multi_buffer const& b);
|
||||
|
||||
public:
|
||||
using value_type = mutable_buffer;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
mutable_buffers_type() = delete;
|
||||
mutable_buffers_type(mutable_buffers_type const&) = default;
|
||||
mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
|
||||
|
||||
const_iterator
|
||||
begin() const;
|
||||
|
||||
const_iterator
|
||||
end() const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
class basic_multi_buffer<Allocator>::const_buffers_type::const_iterator
|
||||
template<bool IsMutable>
|
||||
class
|
||||
basic_multi_buffer<Allocator>::
|
||||
readable_bytes<IsMutable>::
|
||||
const_iterator
|
||||
{
|
||||
basic_multi_buffer const* b_ = nullptr;
|
||||
typename list_type::const_iterator it_;
|
||||
|
||||
public:
|
||||
using value_type =
|
||||
typename const_buffers_type::value_type;
|
||||
typename readable_bytes::value_type;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
@ -204,27 +200,28 @@ public:
|
||||
const_iterator& operator=(const_iterator&& other) = default;
|
||||
const_iterator& operator=(const_iterator const& other) = default;
|
||||
|
||||
const_iterator(basic_multi_buffer const& b,
|
||||
typename list_type::const_iterator const& it)
|
||||
const_iterator(
|
||||
basic_multi_buffer const& b,
|
||||
typename list_type::const_iterator const& it) noexcept
|
||||
: b_(&b)
|
||||
, it_(it)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const_iterator const& other) const
|
||||
operator==(const_iterator const& other) const noexcept
|
||||
{
|
||||
return b_ == other.b_ && it_ == other.it_;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const_iterator const& other) const
|
||||
operator!=(const_iterator const& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
operator*() const noexcept
|
||||
{
|
||||
auto const& e = *it_;
|
||||
return value_type{e.data(),
|
||||
@ -237,14 +234,14 @@ public:
|
||||
operator->() const = delete;
|
||||
|
||||
const_iterator&
|
||||
operator++()
|
||||
operator++() noexcept
|
||||
{
|
||||
++it_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
operator++(int)
|
||||
operator++(int) noexcept
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
@ -252,14 +249,14 @@ public:
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
operator--()
|
||||
operator--() noexcept
|
||||
{
|
||||
--it_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
operator--(int)
|
||||
operator--(int) noexcept
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
@ -267,36 +264,34 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
const_buffers_type::
|
||||
const_buffers_type(
|
||||
basic_multi_buffer const& b)
|
||||
class basic_multi_buffer<Allocator>::mutable_buffers_type
|
||||
{
|
||||
basic_multi_buffer const* b_;
|
||||
|
||||
friend class basic_multi_buffer;
|
||||
|
||||
explicit
|
||||
mutable_buffers_type(
|
||||
basic_multi_buffer const& b) noexcept
|
||||
: b_(&b)
|
||||
{
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
const_buffers_type::
|
||||
begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->list_.begin()};
|
||||
}
|
||||
public:
|
||||
using value_type = mutable_buffer;
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
const_buffers_type::
|
||||
end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->out_ ==
|
||||
b_->list_.end() ? b_->list_.end() :
|
||||
std::next(b_->out_)};
|
||||
}
|
||||
class const_iterator;
|
||||
|
||||
mutable_buffers_type() = delete;
|
||||
mutable_buffers_type(mutable_buffers_type const&) = default;
|
||||
mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
|
||||
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -321,27 +316,28 @@ public:
|
||||
const_iterator& operator=(const_iterator&& other) = default;
|
||||
const_iterator& operator=(const_iterator const& other) = default;
|
||||
|
||||
const_iterator(basic_multi_buffer const& b,
|
||||
typename list_type::const_iterator const& it)
|
||||
const_iterator(
|
||||
basic_multi_buffer const& b,
|
||||
typename list_type::const_iterator const& it) noexcept
|
||||
: b_(&b)
|
||||
, it_(it)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const_iterator const& other) const
|
||||
operator==(const_iterator const& other) const noexcept
|
||||
{
|
||||
return b_ == other.b_ && it_ == other.it_;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const_iterator const& other) const
|
||||
operator!=(const_iterator const& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
operator*() const noexcept
|
||||
{
|
||||
auto const& e = *it_;
|
||||
return value_type{e.data(),
|
||||
@ -354,14 +350,14 @@ public:
|
||||
operator->() const = delete;
|
||||
|
||||
const_iterator&
|
||||
operator++()
|
||||
operator++() noexcept
|
||||
{
|
||||
++it_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
operator++(int)
|
||||
operator++(int) noexcept
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
@ -369,14 +365,14 @@ public:
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
operator--()
|
||||
operator--() noexcept
|
||||
{
|
||||
--it_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
operator--(int)
|
||||
operator--(int) noexcept
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
@ -384,20 +380,37 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
template<bool IsMutable>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
mutable_buffers_type::
|
||||
mutable_buffers_type(
|
||||
basic_multi_buffer const& b)
|
||||
: b_(&b)
|
||||
readable_bytes<IsMutable>::
|
||||
begin() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->list_.begin()};
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
template<bool IsMutable>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
readable_bytes<IsMutable>::
|
||||
end() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->out_ ==
|
||||
b_->list_.end() ? b_->list_.end() :
|
||||
std::next(b_->out_)};
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
mutable_buffers_type::
|
||||
begin() const ->
|
||||
begin() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->out_};
|
||||
@ -407,7 +420,7 @@ template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
mutable_buffers_type::
|
||||
end() const ->
|
||||
end() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*b_, b_->list_.end()};
|
||||
@ -424,22 +437,7 @@ basic_multi_buffer<Allocator>::
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer()
|
||||
: out_(list_.end())
|
||||
{
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(std::size_t limit)
|
||||
: max_(limit)
|
||||
, out_(list_.end())
|
||||
{
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(Allocator const& alloc)
|
||||
basic_multi_buffer(Allocator const& alloc) noexcept
|
||||
: boost::empty_value<
|
||||
base_alloc_type>(boost::empty_init_t(), alloc)
|
||||
, out_(list_.end())
|
||||
@ -449,7 +447,7 @@ basic_multi_buffer(Allocator const& alloc)
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(std::size_t limit,
|
||||
Allocator const& alloc)
|
||||
Allocator const& alloc) noexcept
|
||||
: boost::empty_value<
|
||||
base_alloc_type>(boost::empty_init_t(), alloc)
|
||||
, max_(limit)
|
||||
@ -459,7 +457,7 @@ basic_multi_buffer(std::size_t limit,
|
||||
|
||||
template<class Allocator>
|
||||
basic_multi_buffer<Allocator>::
|
||||
basic_multi_buffer(basic_multi_buffer&& other)
|
||||
basic_multi_buffer(basic_multi_buffer&& other) noexcept
|
||||
: boost::empty_value<
|
||||
base_alloc_type>(boost::empty_init_t(), std::move(other.get()))
|
||||
, max_(other.max_)
|
||||
@ -598,10 +596,12 @@ operator=(
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
std::size_t
|
||||
basic_multi_buffer<Allocator>::
|
||||
capacity() const
|
||||
capacity() const noexcept
|
||||
{
|
||||
auto pos = out_;
|
||||
if(pos == list_.end())
|
||||
@ -615,12 +615,21 @@ capacity() const
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
data() const ->
|
||||
data() const noexcept ->
|
||||
const_buffers_type
|
||||
{
|
||||
return const_buffers_type(*this);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
data() noexcept ->
|
||||
mutable_data_type
|
||||
{
|
||||
return mutable_data_type(*this);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_multi_buffer<Allocator>::
|
||||
@ -723,7 +732,7 @@ prepare(size_type n) ->
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
commit(size_type n)
|
||||
commit(size_type n) noexcept
|
||||
{
|
||||
if(list_.empty())
|
||||
return;
|
||||
@ -770,7 +779,7 @@ commit(size_type n)
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
consume(size_type n)
|
||||
consume(size_type n) noexcept
|
||||
{
|
||||
if(list_.empty())
|
||||
return;
|
||||
@ -836,10 +845,23 @@ consume(size_type n)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
delete_list()
|
||||
reset() noexcept
|
||||
{
|
||||
delete_list();
|
||||
list_.clear();
|
||||
out_ = list_.end();
|
||||
in_size_ = 0;
|
||||
in_pos_ = 0;
|
||||
out_pos_ = 0;
|
||||
out_end_ = 0;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
delete_list() noexcept
|
||||
{
|
||||
for(auto iter = list_.begin(); iter != list_.end();)
|
||||
{
|
||||
@ -851,24 +873,8 @@ delete_list()
|
||||
}
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
reset()
|
||||
{
|
||||
delete_list();
|
||||
list_.clear();
|
||||
out_ = list_.end();
|
||||
in_size_ = 0;
|
||||
in_pos_ = 0;
|
||||
out_pos_ = 0;
|
||||
out_end_ = 0;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
template<class DynamicBuffer>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
copy_from(DynamicBuffer const& buffer)
|
||||
@ -881,7 +887,6 @@ copy_from(DynamicBuffer const& buffer)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
move_assign(basic_multi_buffer& other, std::false_type)
|
||||
@ -898,10 +903,9 @@ move_assign(basic_multi_buffer& other, std::false_type)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
move_assign(basic_multi_buffer& other, std::true_type)
|
||||
move_assign(basic_multi_buffer& other, std::true_type) noexcept
|
||||
{
|
||||
this->get() = std::move(other.get());
|
||||
auto const at_end =
|
||||
@ -922,7 +926,6 @@ move_assign(basic_multi_buffer& other, std::true_type)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
copy_assign(
|
||||
@ -934,7 +937,6 @@ copy_assign(
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
copy_assign(
|
||||
@ -947,20 +949,18 @@ copy_assign(
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
swap(basic_multi_buffer& other)
|
||||
swap(basic_multi_buffer& other) noexcept
|
||||
{
|
||||
swap(other, typename
|
||||
alloc_traits::propagate_on_container_swap{});
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
swap(basic_multi_buffer& other, std::true_type)
|
||||
swap(basic_multi_buffer& other, std::true_type) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
auto const at_end0 =
|
||||
@ -981,10 +981,9 @@ swap(basic_multi_buffer& other, std::true_type)
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_multi_buffer<Allocator>::
|
||||
swap(basic_multi_buffer& other, std::false_type)
|
||||
swap(basic_multi_buffer& other, std::false_type) noexcept
|
||||
{
|
||||
BOOST_ASSERT(this->get() == other.get());
|
||||
using std::swap;
|
||||
@ -1008,7 +1007,7 @@ template<class Allocator>
|
||||
void
|
||||
swap(
|
||||
basic_multi_buffer<Allocator>& lhs,
|
||||
basic_multi_buffer<Allocator>& rhs)
|
||||
basic_multi_buffer<Allocator>& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace beast {
|
||||
|
||||
inline
|
||||
static_buffer_base::
|
||||
static_buffer_base(void* p, std::size_t size)
|
||||
static_buffer_base(void* p, std::size_t size) noexcept
|
||||
: begin_(static_cast<char*>(p))
|
||||
, capacity_(size)
|
||||
{
|
||||
@ -32,7 +32,7 @@ static_buffer_base(void* p, std::size_t size)
|
||||
inline
|
||||
auto
|
||||
static_buffer_base::
|
||||
data() const ->
|
||||
data() const noexcept ->
|
||||
const_buffers_type
|
||||
{
|
||||
using boost::asio::const_buffer;
|
||||
@ -53,11 +53,11 @@ data() const ->
|
||||
inline
|
||||
auto
|
||||
static_buffer_base::
|
||||
mutable_data() ->
|
||||
mutable_buffers_type
|
||||
data() noexcept ->
|
||||
mutable_data_type
|
||||
{
|
||||
using boost::asio::mutable_buffer;
|
||||
mutable_buffers_type result;
|
||||
mutable_data_type result;
|
||||
if(in_off_ + in_size_ <= capacity_)
|
||||
{
|
||||
result[0] = mutable_buffer{begin_ + in_off_, in_size_};
|
||||
@ -74,14 +74,14 @@ mutable_data() ->
|
||||
inline
|
||||
auto
|
||||
static_buffer_base::
|
||||
prepare(std::size_t size) ->
|
||||
prepare(std::size_t n) ->
|
||||
mutable_buffers_type
|
||||
{
|
||||
using boost::asio::mutable_buffer;
|
||||
if(size > capacity_ - in_size_)
|
||||
if(n > capacity_ - in_size_)
|
||||
BOOST_THROW_EXCEPTION(std::length_error{
|
||||
"buffer overflow"});
|
||||
out_size_ = size;
|
||||
out_size_ = n;
|
||||
auto const out_off = (in_off_ + in_size_) % capacity_;
|
||||
mutable_buffers_type result;
|
||||
if(out_off + out_size_ <= capacity_ )
|
||||
@ -100,27 +100,27 @@ prepare(std::size_t size) ->
|
||||
inline
|
||||
void
|
||||
static_buffer_base::
|
||||
commit(std::size_t size)
|
||||
commit(std::size_t n) noexcept
|
||||
{
|
||||
in_size_ += (std::min)(size, out_size_);
|
||||
in_size_ += (std::min)(n, out_size_);
|
||||
out_size_ = 0;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
static_buffer_base::
|
||||
consume(std::size_t size)
|
||||
consume(std::size_t n) noexcept
|
||||
{
|
||||
if(size < in_size_)
|
||||
if(n < in_size_)
|
||||
{
|
||||
in_off_ = (in_off_ + size) % capacity_;
|
||||
in_size_ -= size;
|
||||
in_off_ = (in_off_ + n) % capacity_;
|
||||
in_size_ -= n;
|
||||
}
|
||||
else
|
||||
{
|
||||
// rewind the offset, so the next call to prepare
|
||||
// can have a longer contiguous segment. this helps
|
||||
// algorithms optimized for larger buffesr.
|
||||
// algorithms optimized for larger buffers.
|
||||
in_off_ = 0;
|
||||
in_size_ = 0;
|
||||
}
|
||||
@ -129,10 +129,10 @@ consume(std::size_t size)
|
||||
inline
|
||||
void
|
||||
static_buffer_base::
|
||||
reset(void* p, std::size_t size)
|
||||
reset(void* p, std::size_t n) noexcept
|
||||
{
|
||||
begin_ = static_cast<char*>(p);
|
||||
capacity_ = size;
|
||||
capacity_ = n;
|
||||
in_off_ = 0;
|
||||
in_size_ = 0;
|
||||
out_size_ = 0;
|
||||
|
@ -23,14 +23,39 @@
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
/** A @b DynamicBuffer that uses multiple buffers internally.
|
||||
/** A dynamic buffer providing sequences of variable length.
|
||||
|
||||
The implementation uses a sequence of one or more character arrays
|
||||
of varying sizes. Additional character array objects are appended to
|
||||
the sequence to accommodate changes in the size of the character
|
||||
sequence.
|
||||
A dynamic buffer encapsulates memory storage that may be
|
||||
automatically resized as required, where the memory is
|
||||
divided into two regions: readable bytes followed by
|
||||
writable bytes. These memory regions are internal to
|
||||
the dynamic buffer, but direct access to the elements
|
||||
is provided to permit them to be efficiently used with
|
||||
I/O operations.
|
||||
|
||||
@note Meets the requirements of @b DynamicBuffer.
|
||||
The implementation uses a sequence of one or more byte
|
||||
arrays of varying sizes to represent the readable and
|
||||
writable bytes. Additional byte array objects are
|
||||
appended to the sequence to accommodate changes in the
|
||||
desired size. The behavior and implementation of this
|
||||
container is most similar to `std::deque`.
|
||||
|
||||
Objects of this type meet the requirements of @b DynamicBuffer
|
||||
and have the following additional properties:
|
||||
|
||||
@li The buffer sequence representing the readable bytes
|
||||
returned by @ref data is mutable.
|
||||
|
||||
@li Buffer sequences representing the readable and writable
|
||||
bytes, returned by @ref data and @ref prepare, may have
|
||||
length greater than one.
|
||||
|
||||
@li A configurable maximum buffer size may be set upon
|
||||
construction. Attempts to exceed the buffer size will throw
|
||||
`std::length_error`.
|
||||
|
||||
@li Sequences previously obtained using @ref data remain
|
||||
valid after calls to @ref prepare or @ref commit.
|
||||
|
||||
@tparam Allocator The allocator to use for managing memory.
|
||||
*/
|
||||
@ -51,6 +76,9 @@ class basic_multi_buffer
|
||||
// contains `element` followed by raw storage bytes.
|
||||
class element;
|
||||
|
||||
template<bool IsMutable>
|
||||
class readable_bytes;
|
||||
|
||||
using alloc_traits = detail::allocator_traits<base_alloc_type>;
|
||||
using list_type = typename boost::intrusive::make_list<element,
|
||||
boost::intrusive::constant_time_size<true>>::type;
|
||||
@ -82,82 +110,103 @@ public:
|
||||
/// The type of allocator used.
|
||||
using allocator_type = Allocator;
|
||||
|
||||
#if BOOST_BEAST_DOXYGEN
|
||||
/// The type used to represent the input sequence as a list of buffers.
|
||||
using const_buffers_type = __implementation_defined__;
|
||||
|
||||
/// The type used to represent the output sequence as a list of buffers.
|
||||
using mutable_buffers_type = __implementation_defined__;
|
||||
|
||||
#else
|
||||
class const_buffers_type;
|
||||
|
||||
class mutable_buffers_type;
|
||||
|
||||
#endif
|
||||
|
||||
/// Destructor
|
||||
~basic_multi_buffer();
|
||||
|
||||
/** Constructor
|
||||
|
||||
Upon construction, capacity will be zero.
|
||||
Upon construction, @ref capacity will return zero.
|
||||
*/
|
||||
basic_multi_buffer();
|
||||
basic_multi_buffer() noexcept(
|
||||
std::is_nothrow_default_constructible<Allocator>::value)
|
||||
:
|
||||
out_(list_.end())
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor.
|
||||
/** Constructor
|
||||
|
||||
Upon construction, @ref capacity will return zero.
|
||||
|
||||
@param limit The setting for @ref max_size.
|
||||
*/
|
||||
explicit
|
||||
basic_multi_buffer(std::size_t limit);
|
||||
basic_multi_buffer(std::size_t limit) noexcept(
|
||||
std::is_nothrow_default_constructible<Allocator>::value)
|
||||
: max_(limit)
|
||||
, out_(list_.end())
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor.
|
||||
/** Constructor
|
||||
|
||||
Upon construction, @ref capacity will return zero.
|
||||
|
||||
@param alloc The allocator to use.
|
||||
*/
|
||||
explicit
|
||||
basic_multi_buffer(Allocator const& alloc);
|
||||
basic_multi_buffer(Allocator const& alloc) noexcept;
|
||||
|
||||
/** Constructor.
|
||||
/** Constructor
|
||||
|
||||
Upon construction, @ref capacity will return zero.
|
||||
|
||||
@param limit The setting for @ref max_size.
|
||||
|
||||
@param alloc The allocator to use.
|
||||
*/
|
||||
basic_multi_buffer(
|
||||
std::size_t limit, Allocator const& alloc);
|
||||
std::size_t limit, Allocator const& alloc) noexcept;
|
||||
|
||||
/** Move constructor
|
||||
/** Move Constructor
|
||||
|
||||
After the move, `*this` will have an empty output sequence.
|
||||
Constructs the container with the contents of other
|
||||
using move semantics. After the move, other is
|
||||
guaranteed to be empty.
|
||||
|
||||
Buffer sequences previously obtained using @ref data
|
||||
or @ref prepare are not invalidated after the move.
|
||||
|
||||
@param other The object to move from. After the move,
|
||||
The object's state will be as if constructed using
|
||||
its current allocator and limit.
|
||||
the moved-from object's state will be as if default
|
||||
constructed using its current allocator and limit.
|
||||
*/
|
||||
basic_multi_buffer(basic_multi_buffer&& other);
|
||||
basic_multi_buffer(basic_multi_buffer&& other) noexcept;
|
||||
|
||||
/** Move constructor
|
||||
/** Move Constructor
|
||||
|
||||
After the move, `*this` will have an empty output sequence.
|
||||
Using alloc as the allocator for the new container, the
|
||||
contents of other are moved. If `alloc != other.get_allocator()`,
|
||||
this results in a copy. After the move, other is
|
||||
guaranteed to be empty.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param other The object to move from. After the move,
|
||||
The object's state will be as if constructed using
|
||||
its current allocator and limit.
|
||||
the moved-from object's state will be as if default
|
||||
constructed using its current allocator and limit.
|
||||
|
||||
@param alloc The allocator to use.
|
||||
@param alloc The allocator to use for the newly
|
||||
constructed object.
|
||||
*/
|
||||
basic_multi_buffer(basic_multi_buffer&& other,
|
||||
Allocator const& alloc);
|
||||
|
||||
/** Copy constructor.
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
allocator and contents of other, and zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
*/
|
||||
basic_multi_buffer(basic_multi_buffer const& other);
|
||||
|
||||
/** Copy constructor
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
specified allocator, a copy of the contents of other,
|
||||
and zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@ -166,7 +215,10 @@ public:
|
||||
basic_multi_buffer(basic_multi_buffer const& other,
|
||||
Allocator const& alloc);
|
||||
|
||||
/** Copy constructor.
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
contents of other, and zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
*/
|
||||
@ -174,7 +226,11 @@ public:
|
||||
basic_multi_buffer(basic_multi_buffer<
|
||||
OtherAlloc> const& other);
|
||||
|
||||
/** Copy constructor.
|
||||
/** Copy Constructor
|
||||
|
||||
The newly constructed object will have a copy of the
|
||||
specified allocator, a copy of the contents of other,
|
||||
and zero writable bytes.
|
||||
|
||||
@param other The object to copy from.
|
||||
|
||||
@ -184,20 +240,28 @@ public:
|
||||
basic_multi_buffer(basic_multi_buffer<
|
||||
OtherAlloc> const& other, allocator_type const& alloc);
|
||||
|
||||
/** Move assignment
|
||||
/** Move Assignment
|
||||
|
||||
After the move, `*this` will have an empty output sequence.
|
||||
Assigns the container with the contents of other
|
||||
using move semantics. After the move, other is
|
||||
guaranteed to be empty. The previous contents of
|
||||
this container are deleted.
|
||||
|
||||
Buffer sequences previously obtained using @ref data
|
||||
or @ref prepare are not invalidated after the move.
|
||||
|
||||
@param other The object to move from. After the move,
|
||||
The object's state will be as if constructed using
|
||||
its current allocator and limit.
|
||||
the moved-from object's state will be as if default
|
||||
constructed using its current allocator and limit.
|
||||
*/
|
||||
basic_multi_buffer&
|
||||
operator=(basic_multi_buffer&& other);
|
||||
|
||||
/** Copy assignment
|
||||
/** Copy Assignment
|
||||
|
||||
After the copy, `*this` will have an empty output sequence.
|
||||
The assigned object will have a copy of the allocator
|
||||
and contents of other, and zero writable bytes. The
|
||||
previous contents of this container are deleted.
|
||||
|
||||
@param other The object to copy from.
|
||||
*/
|
||||
@ -205,7 +269,9 @@ public:
|
||||
|
||||
/** Copy assignment
|
||||
|
||||
After the copy, `*this` will have an empty output sequence.
|
||||
The assigned object will have a copy of the contents
|
||||
of other, and zero writable bytes. The previous contents
|
||||
of this container are deleted.
|
||||
|
||||
@param other The object to copy from.
|
||||
*/
|
||||
@ -213,102 +279,142 @@ public:
|
||||
basic_multi_buffer& operator=(
|
||||
basic_multi_buffer<OtherAlloc> const& other);
|
||||
|
||||
/// Returns a copy of the associated allocator.
|
||||
/// Returns a copy of the allocator used.
|
||||
allocator_type
|
||||
get_allocator() const
|
||||
{
|
||||
return this->get();
|
||||
}
|
||||
|
||||
/// Returns the size of the input sequence.
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#if BOOST_BEAST_DOXYGEN
|
||||
/// The ConstBufferSequence used to represent the readable bytes.
|
||||
using const_buffers_type = __implementation_defined__;
|
||||
|
||||
/// The MutableBufferSequence used to represent the readable bytes.
|
||||
using mutable_data_type = __implementation_defined__;
|
||||
|
||||
/// The MutableBufferSequence used to represent the writable bytes.
|
||||
using mutable_buffers_type = __implementation_defined__;
|
||||
#else
|
||||
using const_buffers_type = readable_bytes<false>;
|
||||
using mutable_data_type = readable_bytes<true>;
|
||||
class mutable_buffers_type;
|
||||
#endif
|
||||
|
||||
/// Returns the number of readable bytes.
|
||||
size_type
|
||||
size() const
|
||||
size() const noexcept
|
||||
{
|
||||
return in_size_;
|
||||
}
|
||||
|
||||
/// Returns the permitted maximum sum of the sizes of the input and output sequence.
|
||||
/// Return the maximum number of bytes, both readable and writable, that can ever be held.
|
||||
size_type
|
||||
max_size() const
|
||||
max_size() const noexcept
|
||||
{
|
||||
return max_;
|
||||
}
|
||||
|
||||
/// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
|
||||
/// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
|
||||
std::size_t
|
||||
capacity() const;
|
||||
capacity() const noexcept;
|
||||
|
||||
/** Get a list of buffers that represents the input sequence.
|
||||
|
||||
@note These buffers remain valid across subsequent calls to `prepare`.
|
||||
*/
|
||||
/// Returns a constant buffer sequence representing the readable bytes
|
||||
const_buffers_type
|
||||
data() const;
|
||||
data() const noexcept;
|
||||
|
||||
/** Get a list of buffers that represents the output sequence, with the given size.
|
||||
/// Returns a constant buffer sequence representing the readable bytes
|
||||
const_buffers_type
|
||||
cdata() const noexcept
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
/** Returns a mutable buffer sequence representing the readable bytes.
|
||||
|
||||
@note The sequence may contain zero or more contiguous memory
|
||||
regions.
|
||||
*/
|
||||
mutable_data_type
|
||||
data() noexcept;
|
||||
|
||||
/** Returns a mutable buffer sequence representing writable bytes.
|
||||
|
||||
Returns a mutable buffer sequence representing the writable
|
||||
bytes containing exactly `n` bytes of storage. Memory may be
|
||||
reallocated as needed.
|
||||
|
||||
All buffer sequences previously obtained using @ref prepare are
|
||||
invalidated. Buffer sequences previously obtained using @ref data
|
||||
remain valid.
|
||||
|
||||
@param n The desired number of bytes in the returned buffer
|
||||
sequence.
|
||||
|
||||
@throws std::length_error if `size() + n` exceeds `max_size()`.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(size_type n);
|
||||
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
/** Append writable bytes to the readable bytes.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
Appends n bytes from the start of the writable bytes to the
|
||||
end of the readable bytes. The remainder of the writable bytes
|
||||
are discarded. If n is greater than the number of writable
|
||||
bytes, all writable bytes are appended to the readable bytes.
|
||||
|
||||
All buffer sequences previously obtained using @ref prepare are
|
||||
invalidated. Buffer sequences previously obtained using @ref data
|
||||
remain valid.
|
||||
|
||||
@param n The number of bytes to append. If this number
|
||||
is greater than the number of writable bytes, all
|
||||
writable bytes are appended.
|
||||
*/
|
||||
void
|
||||
commit(size_type n);
|
||||
commit(size_type n) noexcept;
|
||||
|
||||
/// Remove bytes from the input sequence.
|
||||
/** Remove bytes from beginning of the readable bytes.
|
||||
|
||||
Removes n bytes from the beginning of the readable bytes.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param n The number of bytes to remove. If this number
|
||||
is greater than the number of readable bytes, all
|
||||
readable bytes are removed.
|
||||
*/
|
||||
void
|
||||
consume(size_type n);
|
||||
consume(size_type n) noexcept;
|
||||
|
||||
/// Exchange two dynamic buffers
|
||||
template<class Alloc>
|
||||
friend
|
||||
void
|
||||
swap(
|
||||
basic_multi_buffer<Alloc>& lhs,
|
||||
basic_multi_buffer<Alloc>& rhs);
|
||||
basic_multi_buffer<Alloc>& rhs) noexcept;
|
||||
|
||||
private:
|
||||
template<class OtherAlloc>
|
||||
friend class basic_multi_buffer;
|
||||
|
||||
void
|
||||
delete_list();
|
||||
|
||||
void
|
||||
reset();
|
||||
void reset() noexcept;
|
||||
void delete_list() noexcept;
|
||||
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
copy_from(DynamicBuffer const& other);
|
||||
|
||||
void
|
||||
move_assign(basic_multi_buffer& other, std::false_type);
|
||||
|
||||
void
|
||||
move_assign(basic_multi_buffer& other, std::true_type);
|
||||
|
||||
void
|
||||
copy_assign(basic_multi_buffer const& other, std::false_type);
|
||||
|
||||
void
|
||||
copy_assign(basic_multi_buffer const& other, std::true_type);
|
||||
|
||||
void
|
||||
swap(basic_multi_buffer&);
|
||||
|
||||
void
|
||||
swap(basic_multi_buffer&, std::true_type);
|
||||
|
||||
void
|
||||
swap(basic_multi_buffer&, std::false_type);
|
||||
|
||||
void
|
||||
debug_check() const;
|
||||
void copy_from(DynamicBuffer const& other);
|
||||
void move_assign(basic_multi_buffer& other, std::false_type);
|
||||
void move_assign(basic_multi_buffer& other, std::true_type) noexcept;
|
||||
void copy_assign(basic_multi_buffer const& other, std::false_type);
|
||||
void copy_assign(basic_multi_buffer const& other, std::true_type);
|
||||
void swap(basic_multi_buffer&) noexcept;
|
||||
void swap(basic_multi_buffer&, std::true_type) noexcept;
|
||||
void swap(basic_multi_buffer&, std::false_type) noexcept;
|
||||
void debug_check() const;
|
||||
};
|
||||
|
||||
/// A typical multi buffer
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
@ -20,21 +21,34 @@
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
/** A circular @b DynamicBuffer with a fixed size internal buffer.
|
||||
/** A dynamic buffer providing a fixed, circular 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.
|
||||
A dynamic buffer encapsulates memory storage that may be
|
||||
automatically resized as required, where the memory is
|
||||
divided into two regions: readable bytes followed by
|
||||
writable bytes. These memory regions are internal to
|
||||
the dynamic buffer, but direct access to the elements
|
||||
is provided to permit them to be efficiently used with
|
||||
I/O operations.
|
||||
|
||||
Objects of this type meet the requirements of @b DynamicBuffer
|
||||
and have the following additional properties:
|
||||
|
||||
@li A mutable buffer sequence representing the readable
|
||||
bytes is returned by @ref data when `this` is non-const.
|
||||
|
||||
@li Buffer sequences representing the readable and writable
|
||||
bytes, returned by @ref data and @ref prepare, will have
|
||||
length at most one.
|
||||
|
||||
@li All operations execute in constant time.
|
||||
|
||||
@li 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.
|
||||
@ref static_buffer; however, to reduce the number of template
|
||||
instantiations, objects should be passed `static_buffer_base&`.
|
||||
|
||||
@see @ref static_buffer
|
||||
*/
|
||||
@ -46,18 +60,98 @@ class static_buffer_base
|
||||
std::size_t out_size_ = 0;
|
||||
std::size_t capacity_;
|
||||
|
||||
class const_buffer_pair;
|
||||
|
||||
class mutable_buffer_pair
|
||||
{
|
||||
boost::asio::mutable_buffer b_[2];
|
||||
|
||||
friend class const_buffer_pair;
|
||||
|
||||
public:
|
||||
using const_iterator =
|
||||
boost::asio::mutable_buffer const*;
|
||||
|
||||
// workaround for buffers_iterator bug
|
||||
using value_type =
|
||||
boost::asio::mutable_buffer;
|
||||
|
||||
mutable_buffer_pair() = default;
|
||||
mutable_buffer_pair(
|
||||
mutable_buffer_pair const&) = default;
|
||||
|
||||
boost::asio::mutable_buffer&
|
||||
operator[](int i) noexcept
|
||||
{
|
||||
BOOST_ASSERT(i >= 0 && i < 2);
|
||||
return b_[i];
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const noexcept
|
||||
{
|
||||
return &b_[0];
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const noexcept
|
||||
{
|
||||
if(b_[1].size() > 0)
|
||||
return &b_[2];
|
||||
else
|
||||
return &b_[1];
|
||||
}
|
||||
};
|
||||
|
||||
class const_buffer_pair
|
||||
{
|
||||
boost::asio::const_buffer b_[2];
|
||||
|
||||
public:
|
||||
using const_iterator =
|
||||
boost::asio::const_buffer const*;
|
||||
|
||||
// workaround for buffers_iterator bug
|
||||
using value_type =
|
||||
boost::asio::const_buffer;
|
||||
|
||||
const_buffer_pair() = default;
|
||||
const_buffer_pair(
|
||||
const_buffer_pair const&) = default;
|
||||
|
||||
const_buffer_pair(
|
||||
mutable_buffer_pair const& other)
|
||||
: b_{other.b_[0], other.b_[1]}
|
||||
{
|
||||
}
|
||||
|
||||
boost::asio::const_buffer&
|
||||
operator[](int i) noexcept
|
||||
{
|
||||
BOOST_ASSERT(i >= 0 && i < 2);
|
||||
return b_[i];
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const noexcept
|
||||
{
|
||||
return &b_[0];
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const noexcept
|
||||
{
|
||||
if(b_[1].size() > 0)
|
||||
return &b_[2];
|
||||
else
|
||||
return &b_[1];
|
||||
}
|
||||
};
|
||||
|
||||
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.
|
||||
using const_buffers_type =
|
||||
std::array<boost::asio::const_buffer, 2>;
|
||||
|
||||
/// The type used to represent the output sequence as a list of buffers.
|
||||
using mutable_buffers_type =
|
||||
std::array<boost::asio::mutable_buffer, 2>;
|
||||
|
||||
/** Constructor
|
||||
|
||||
This creates a dynamic buffer using the provided storage area.
|
||||
@ -66,65 +160,108 @@ public:
|
||||
|
||||
@param size The number of valid bytes pointed to by `p`.
|
||||
*/
|
||||
static_buffer_base(void* p, std::size_t size);
|
||||
static_buffer_base(void* p, std::size_t size) noexcept;
|
||||
|
||||
/// Return the size of the input sequence.
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#if BOOST_BEAST_DOXYGEN
|
||||
/// The ConstBufferSequence used to represent the readable bytes.
|
||||
using const_buffers_type = __implementation_defined__;
|
||||
|
||||
/// The MutableBufferSequence used to represent the readable bytes.
|
||||
using mutable_data_type = __implementation_defined__;
|
||||
|
||||
/// The MutableBufferSequence used to represent the writable bytes.
|
||||
using mutable_buffers_type = __implementation_defined__;
|
||||
#else
|
||||
using const_buffers_type = const_buffer_pair;
|
||||
using mutable_data_type = mutable_buffer_pair;
|
||||
using mutable_buffers_type = mutable_buffer_pair;
|
||||
#endif
|
||||
|
||||
/// Returns the number of readable bytes.
|
||||
std::size_t
|
||||
size() const
|
||||
size() const noexcept
|
||||
{
|
||||
return in_size_;
|
||||
}
|
||||
|
||||
/// Return the maximum sum of the input and output sequence sizes.
|
||||
/// Return the maximum number of bytes, both readable and writable, that can ever be held.
|
||||
std::size_t
|
||||
max_size() const
|
||||
max_size() const noexcept
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
/// Return the maximum sum of input and output sizes that can be held without an allocation.
|
||||
/// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
|
||||
std::size_t
|
||||
capacity() const
|
||||
capacity() const noexcept
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
/** Get a list of buffers that represent the input sequence.
|
||||
*/
|
||||
/// Returns a constant buffer sequence representing the readable bytes
|
||||
const_buffers_type
|
||||
data() const;
|
||||
data() const noexcept;
|
||||
|
||||
/** Get a mutable list of buffers that represent the input sequence.
|
||||
/// Returns a constant buffer sequence representing the readable bytes
|
||||
const_buffers_type
|
||||
cdata() const noexcept
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
/// Returns a mutable buffer sequence representing the readable bytes
|
||||
mutable_data_type
|
||||
data() noexcept;
|
||||
|
||||
/** Returns a mutable buffer sequence representing writable bytes.
|
||||
|
||||
Returns a mutable buffer sequence representing the writable
|
||||
bytes containing exactly `n` bytes of storage. Memory may be
|
||||
reallocated as needed.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param n The desired number of bytes in the returned buffer
|
||||
sequence.
|
||||
|
||||
@throws std::length_error if `size() + n` exceeds `max_size()`.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
mutable_data();
|
||||
prepare(std::size_t n);
|
||||
|
||||
/** Get a list of buffers that represent the output sequence, with the given size.
|
||||
/** Append writable bytes to the readable bytes.
|
||||
|
||||
@param size The number of bytes to request.
|
||||
Appends n bytes from the start of the writable bytes to the
|
||||
end of the readable bytes. The remainder of the writable bytes
|
||||
are discarded. If n is greater than the number of writable
|
||||
bytes, all writable bytes are appended to the readable bytes.
|
||||
|
||||
@throws std::length_error if the size would exceed the capacity.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(std::size_t size);
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
|
||||
@param size The number of bytes to commit. If this is greater
|
||||
than the size of the output sequence, the entire output
|
||||
sequence is committed.
|
||||
@param n The number of bytes to append. If this number
|
||||
is greater than the number of writable bytes, all
|
||||
writable bytes are appended.
|
||||
*/
|
||||
void
|
||||
commit(std::size_t size);
|
||||
commit(std::size_t n) noexcept;
|
||||
|
||||
/** Remove bytes from the input sequence.
|
||||
/** Remove bytes from beginning of the readable bytes.
|
||||
|
||||
@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.
|
||||
Removes n bytes from the beginning of the readable bytes.
|
||||
|
||||
All buffers sequences previously obtained using
|
||||
@ref data or @ref prepare are invalidated.
|
||||
|
||||
@param n The number of bytes to remove. If this number
|
||||
is greater than the number of readable bytes, all
|
||||
readable bytes are removed.
|
||||
*/
|
||||
void
|
||||
consume(std::size_t size);
|
||||
consume(std::size_t n) noexcept;
|
||||
|
||||
protected:
|
||||
/** Constructor
|
||||
@ -147,7 +284,7 @@ protected:
|
||||
@param size The number of valid bytes pointed to by `p`.
|
||||
*/
|
||||
void
|
||||
reset(void* p, std::size_t size);
|
||||
reset(void* p, std::size_t size) noexcept;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -236,7 +236,7 @@ operator()(
|
||||
d.ws.rd_close_ = true;
|
||||
auto const mb = buffers_prefix(
|
||||
clamp(d.ws.rd_fh_.len),
|
||||
d.ws.rd_buf_.mutable_data());
|
||||
d.ws.rd_buf_.data());
|
||||
if(d.ws.rd_fh_.len > 0 && d.ws.rd_fh_.mask)
|
||||
detail::mask_inplace(mb, d.ws.rd_key_);
|
||||
detail::read_close(d.ws.cr_, mb, d.ev);
|
||||
@ -381,7 +381,7 @@ close(close_reason const& cr, error_code& ec)
|
||||
rd_close_ = true;
|
||||
auto const mb = buffers_prefix(
|
||||
clamp(rd_fh_.len),
|
||||
rd_buf_.mutable_data());
|
||||
rd_buf_.data());
|
||||
if(rd_fh_.len > 0 && rd_fh_.mask)
|
||||
detail::mask_inplace(mb, rd_key_);
|
||||
detail::read_close(cr_, mb, result);
|
||||
|
@ -267,7 +267,7 @@ operator()(
|
||||
if(ws_.rd_fh_.len > 0 && ws_.rd_fh_.mask)
|
||||
detail::mask_inplace(buffers_prefix(
|
||||
clamp(ws_.rd_fh_.len),
|
||||
ws_.rd_buf_.mutable_data()),
|
||||
ws_.rd_buf_.data()),
|
||||
ws_.rd_key_);
|
||||
if(detail::is_control(ws_.rd_fh_.op))
|
||||
{
|
||||
@ -454,14 +454,14 @@ operator()(
|
||||
ws_.rd_buf_.commit(bytes_transferred);
|
||||
if(ws_.rd_fh_.mask)
|
||||
detail::mask_inplace(buffers_prefix(clamp(
|
||||
ws_.rd_remain_), ws_.rd_buf_.mutable_data()),
|
||||
ws_.rd_remain_), ws_.rd_buf_.data()),
|
||||
ws_.rd_key_);
|
||||
}
|
||||
if(ws_.rd_buf_.size() > 0)
|
||||
{
|
||||
// Copy from the read buffer.
|
||||
// The mask was already applied.
|
||||
bytes_transferred = buffer_copy(cb_,
|
||||
bytes_transferred = boost::asio::buffer_copy(cb_,
|
||||
ws_.rd_buf_.data(), clamp(ws_.rd_remain_));
|
||||
auto const mb = buffers_prefix(
|
||||
bytes_transferred, cb_);
|
||||
@ -542,7 +542,7 @@ operator()(
|
||||
if(ws_.rd_fh_.mask)
|
||||
detail::mask_inplace(
|
||||
buffers_prefix(clamp(ws_.rd_remain_),
|
||||
ws_.rd_buf_.mutable_data()), ws_.rd_key_);
|
||||
ws_.rd_buf_.data()), ws_.rd_key_);
|
||||
did_read_ = true;
|
||||
}
|
||||
zlib::z_params zs;
|
||||
@ -1058,7 +1058,7 @@ loop:
|
||||
// of the buffer holding payload data.
|
||||
if(rd_fh_.len > 0 && rd_fh_.mask)
|
||||
detail::mask_inplace(buffers_prefix(
|
||||
clamp(rd_fh_.len), rd_buf_.mutable_data()),
|
||||
clamp(rd_fh_.len), rd_buf_.data()),
|
||||
rd_key_);
|
||||
if(detail::is_control(rd_fh_.op))
|
||||
{
|
||||
@ -1160,15 +1160,15 @@ loop:
|
||||
if(rd_fh_.mask)
|
||||
detail::mask_inplace(
|
||||
buffers_prefix(clamp(rd_remain_),
|
||||
rd_buf_.mutable_data()), rd_key_);
|
||||
rd_buf_.data()), rd_key_);
|
||||
}
|
||||
if(rd_buf_.size() > 0)
|
||||
{
|
||||
// Copy from the read buffer.
|
||||
// The mask was already applied.
|
||||
auto const bytes_transferred =
|
||||
buffer_copy(buffers, rd_buf_.data(),
|
||||
clamp(rd_remain_));
|
||||
boost::asio::buffer_copy(buffers,
|
||||
rd_buf_.data(), clamp(rd_remain_));
|
||||
auto const mb = buffers_prefix(
|
||||
bytes_transferred, buffers);
|
||||
rd_remain_ -= bytes_transferred;
|
||||
@ -1267,7 +1267,7 @@ loop:
|
||||
if(rd_fh_.mask)
|
||||
detail::mask_inplace(
|
||||
buffers_prefix(clamp(rd_remain_),
|
||||
rd_buf_.mutable_data()), rd_key_);
|
||||
rd_buf_.data()), rd_key_);
|
||||
auto const in = buffers_prefix(
|
||||
clamp(rd_remain_), buffers_front(
|
||||
rd_buf_.data()));
|
||||
|
@ -17,17 +17,63 @@
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/beast/test/test_allocator.hpp>
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/asio/buffers_iterator.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_dynamic_buffer<flat_buffer>::value);
|
||||
|
||||
class flat_buffer_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_dynamic_buffer<
|
||||
flat_buffer>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
flat_buffer::const_buffers_type>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
flat_buffer::mutable_data_type>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
flat_buffer::mutable_buffers_type>::value);
|
||||
BOOST_STATIC_ASSERT(std::is_convertible<
|
||||
flat_buffer::mutable_data_type,
|
||||
flat_buffer::const_buffers_type>::value);
|
||||
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
testMutableData()
|
||||
{
|
||||
DynamicBuffer b;
|
||||
DynamicBuffer const& cb = b;
|
||||
ostream(b) << "Hello";
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
decltype(cb.data())>::value &&
|
||||
! boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(cb.data())>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
decltype(cb.cdata())>::value &&
|
||||
! boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(cb.cdata())>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(b.data())>::value);
|
||||
std::for_each(
|
||||
boost::asio::buffers_iterator<decltype(b.data())>::begin(b.data()),
|
||||
boost::asio::buffers_iterator<decltype(b.data())>::end(b.data()),
|
||||
[](char& c)
|
||||
{
|
||||
c = static_cast<char>(std::toupper(c));
|
||||
});
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "HELLO");
|
||||
BEAST_EXPECT(buffers_to_string(b.cdata()) == "HELLO");
|
||||
}
|
||||
|
||||
void
|
||||
testBuffer()
|
||||
{
|
||||
@ -338,7 +384,6 @@ public:
|
||||
BEAST_EXPECT(b.capacity() >= 125);
|
||||
b.shrink_to_fit();
|
||||
BEAST_EXPECT(b.capacity() == b.size());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,6 +391,7 @@ public:
|
||||
run() override
|
||||
{
|
||||
testBuffer();
|
||||
testMutableData<flat_buffer>();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -15,17 +15,64 @@
|
||||
#include <boost/beast/core/ostream.hpp>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/asio/buffers_iterator.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_dynamic_buffer<flat_static_buffer_base>::value);
|
||||
|
||||
class flat_static_buffer_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_dynamic_buffer<
|
||||
flat_static_buffer_base>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
flat_static_buffer_base::const_buffers_type>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
flat_static_buffer_base::mutable_data_type>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
flat_static_buffer_base::mutable_buffers_type>::value);
|
||||
BOOST_STATIC_ASSERT(std::is_convertible<
|
||||
flat_static_buffer_base::mutable_data_type,
|
||||
flat_static_buffer_base::const_buffers_type>::value);
|
||||
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
testMutableData()
|
||||
{
|
||||
DynamicBuffer b;
|
||||
DynamicBuffer const& cb = b;
|
||||
ostream(b) << "Hello";
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
decltype(cb.data())>::value &&
|
||||
! boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(cb.data())>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
decltype(cb.cdata())>::value &&
|
||||
! boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(cb.cdata())>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(b.data())>::value);
|
||||
std::for_each(
|
||||
boost::asio::buffers_iterator<decltype(b.data())>::begin(b.data()),
|
||||
boost::asio::buffers_iterator<decltype(b.data())>::end(b.data()),
|
||||
[](char& c)
|
||||
{
|
||||
c = static_cast<char>(std::toupper(c));
|
||||
});
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "HELLO");
|
||||
BEAST_EXPECT(buffers_to_string(b.cdata()) == "HELLO");
|
||||
}
|
||||
|
||||
void
|
||||
testStaticBuffer()
|
||||
{
|
||||
@ -226,6 +273,7 @@ public:
|
||||
{
|
||||
testBuffer();
|
||||
testStaticBuffer();
|
||||
testMutableData<flat_static_buffer<32>>();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -18,20 +18,35 @@
|
||||
#include <boost/beast/test/test_allocator.hpp>
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/buffers_iterator.hpp>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_dynamic_buffer<multi_buffer>::value);
|
||||
|
||||
class multi_buffer_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_dynamic_buffer<
|
||||
multi_buffer>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
multi_buffer::const_buffers_type>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
multi_buffer::mutable_data_type>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
multi_buffer::mutable_buffers_type>::value);
|
||||
BOOST_STATIC_ASSERT(std::is_convertible<
|
||||
multi_buffer::mutable_data_type,
|
||||
multi_buffer::const_buffers_type>::value);
|
||||
|
||||
template<class Alloc1, class Alloc2>
|
||||
static
|
||||
bool
|
||||
@ -60,6 +75,38 @@ public:
|
||||
u = std::forward<V>(v);
|
||||
}
|
||||
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
testMutableData()
|
||||
{
|
||||
DynamicBuffer b;
|
||||
DynamicBuffer const& cb = b;
|
||||
ostream(b) << "Hello";
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
decltype(cb.data())>::value &&
|
||||
! boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(cb.data())>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
decltype(cb.cdata())>::value &&
|
||||
! boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(cb.cdata())>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(b.data())>::value);
|
||||
|
||||
std::for_each(
|
||||
boost::asio::buffers_iterator<decltype(b.data())>::begin(b.data()),
|
||||
boost::asio::buffers_iterator<decltype(b.data())>::end(b.data()),
|
||||
[](char& c)
|
||||
{
|
||||
c = static_cast<char>(std::toupper(c));
|
||||
});
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "HELLO");
|
||||
BEAST_EXPECT(buffers_to_string(b.cdata()) == "HELLO");
|
||||
}
|
||||
|
||||
void
|
||||
testMatrix1()
|
||||
{
|
||||
@ -588,6 +635,7 @@ public:
|
||||
testMatrix2();
|
||||
testIterators();
|
||||
testMembers();
|
||||
testMutableData<multi_buffer>();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include <boost/beast/core/ostream.hpp>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/asio/buffers_iterator.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
|
||||
namespace boost {
|
||||
@ -26,6 +29,53 @@ BOOST_STATIC_ASSERT(
|
||||
class static_buffer_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_dynamic_buffer<
|
||||
static_buffer_base>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
static_buffer_base::const_buffers_type>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
static_buffer_base::mutable_data_type>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
static_buffer_base::mutable_buffers_type>::value);
|
||||
BOOST_STATIC_ASSERT(std::is_convertible<
|
||||
static_buffer_base::mutable_data_type,
|
||||
static_buffer_base::const_buffers_type>::value);
|
||||
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
testMutableData()
|
||||
{
|
||||
DynamicBuffer b;
|
||||
DynamicBuffer const& cb = b;
|
||||
ostream(b) << "Hello";
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
decltype(cb.data())>::value &&
|
||||
! boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(cb.data())>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_const_buffer_sequence<
|
||||
decltype(cb.cdata())>::value &&
|
||||
! boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(cb.cdata())>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
boost::asio::is_mutable_buffer_sequence<
|
||||
decltype(b.data())>::value);
|
||||
std::for_each(
|
||||
boost::asio::buffers_iterator<decltype(b.data())>::begin(b.data()),
|
||||
boost::asio::buffers_iterator<decltype(b.data())>::end(b.data()),
|
||||
[](char& c)
|
||||
{
|
||||
c = static_cast<char>(std::toupper(c));
|
||||
});
|
||||
BEAST_EXPECT(buffers_to_string(b.data()) == "HELLO");
|
||||
BEAST_EXPECT(buffers_to_string(b.cdata()) == "HELLO");
|
||||
}
|
||||
|
||||
void
|
||||
testStaticBuffer()
|
||||
{
|
||||
@ -225,7 +275,8 @@ public:
|
||||
void run() override
|
||||
{
|
||||
testBuffer();
|
||||
//testStaticBuffer();
|
||||
testStaticBuffer();
|
||||
testMutableData<static_buffer<32>>();
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user