forked from boostorg/beast
346 lines
8.4 KiB
C++
346 lines
8.4 KiB
C++
//
|
|
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
|
|
#ifndef BEAST_FLAT_BUFFER_HPP
|
|
#define BEAST_FLAT_BUFFER_HPP
|
|
|
|
#include <beast/config.hpp>
|
|
#include <beast/core/detail/empty_base_optimization.hpp>
|
|
#include <boost/asio/buffer.hpp>
|
|
#include <limits>
|
|
#include <memory>
|
|
|
|
namespace beast {
|
|
|
|
/** A linear dynamic buffer.
|
|
|
|
Objects of this type meet the requirements of @b DynamicBuffer
|
|
and offer additional invariants:
|
|
|
|
@li Buffer sequences returned by @ref data and @ref prepare
|
|
will always be of length one.
|
|
|
|
@li A configurable maximum buffer size may be set upon
|
|
construction. Attempts to exceed the buffer size will throw
|
|
`std::length_error`.
|
|
|
|
Upon construction, a maximum size for the buffer may be
|
|
specified. If this limit is exceeded, the `std::length_error`
|
|
exception will be thrown.
|
|
|
|
@note This class is designed for use with algorithms that
|
|
take dynamic buffers as parameters, and are optimized
|
|
for the case where the input sequence or output sequence
|
|
is stored in a single contiguous buffer.
|
|
*/
|
|
template<class Allocator>
|
|
class basic_flat_buffer
|
|
#if ! BEAST_DOXYGEN
|
|
: private detail::empty_base_optimization<
|
|
typename std::allocator_traits<Allocator>::
|
|
template rebind_alloc<char>>
|
|
#endif
|
|
{
|
|
public:
|
|
#if BEAST_DOXYGEN
|
|
/// The type of allocator used.
|
|
using allocator_type = Allocator;
|
|
#else
|
|
using allocator_type = typename
|
|
std::allocator_traits<Allocator>::
|
|
template rebind_alloc<char>;
|
|
#endif
|
|
|
|
private:
|
|
enum
|
|
{
|
|
min_size = 512
|
|
};
|
|
|
|
template<class OtherAlloc>
|
|
friend class basic_flat_buffer;
|
|
|
|
using alloc_traits =
|
|
std::allocator_traits<allocator_type>;
|
|
|
|
static
|
|
inline
|
|
std::size_t
|
|
dist(char const* first, char const* last)
|
|
{
|
|
return static_cast<std::size_t>(last - first);
|
|
}
|
|
|
|
char* begin_;
|
|
char* in_;
|
|
char* out_;
|
|
char* last_;
|
|
char* end_;
|
|
std::size_t max_;
|
|
|
|
public:
|
|
/// The type used to represent the input sequence as a list of buffers.
|
|
using const_buffers_type = boost::asio::const_buffers_1;
|
|
|
|
/// The type used to represent the output sequence as a list of buffers.
|
|
using mutable_buffers_type = boost::asio::mutable_buffers_1;
|
|
|
|
/// Destructor
|
|
~basic_flat_buffer();
|
|
|
|
/** Constructor
|
|
|
|
Upon construction, capacity will be zero.
|
|
*/
|
|
basic_flat_buffer();
|
|
|
|
/** Constructor
|
|
|
|
Upon construction, capacity will be zero.
|
|
|
|
@param limit The setting for @ref max_size.
|
|
*/
|
|
explicit
|
|
basic_flat_buffer(std::size_t limit);
|
|
|
|
/** Constructor
|
|
|
|
Upon construction, capacity will be zero.
|
|
|
|
@param alloc The allocator to construct with.
|
|
*/
|
|
explicit
|
|
basic_flat_buffer(Allocator const& alloc);
|
|
|
|
/** Constructor
|
|
|
|
Upon construction, capacity will be zero.
|
|
|
|
@param limit The setting for @ref max_size.
|
|
|
|
@param alloc The allocator to use.
|
|
*/
|
|
basic_flat_buffer(
|
|
std::size_t limit, Allocator const& alloc);
|
|
|
|
/** Move constructor
|
|
|
|
After the move, `*this` will have an empty output sequence.
|
|
|
|
@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.
|
|
*/
|
|
basic_flat_buffer(basic_flat_buffer&& other);
|
|
|
|
/** Move constructor
|
|
|
|
After the move, `*this` will have an empty output sequence.
|
|
|
|
@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.
|
|
|
|
@param alloc The allocator to use.
|
|
*/
|
|
basic_flat_buffer(
|
|
basic_flat_buffer&& other, Allocator const& alloc);
|
|
|
|
/** Copy constructor
|
|
|
|
@param other The object to copy from.
|
|
*/
|
|
basic_flat_buffer(basic_flat_buffer const& other);
|
|
|
|
/** Copy constructor
|
|
|
|
@param other The object to copy from.
|
|
|
|
@param alloc The allocator to use.
|
|
*/
|
|
basic_flat_buffer(basic_flat_buffer const& other,
|
|
Allocator const& alloc);
|
|
|
|
/** Copy constructor
|
|
|
|
@param other The object to copy from.
|
|
*/
|
|
template<class OtherAlloc>
|
|
basic_flat_buffer(
|
|
basic_flat_buffer<OtherAlloc> const& other);
|
|
|
|
/** Copy constructor
|
|
|
|
@param other The object to copy from.
|
|
|
|
@param alloc The allocator to use.
|
|
*/
|
|
template<class OtherAlloc>
|
|
basic_flat_buffer(
|
|
basic_flat_buffer<OtherAlloc> const& other,
|
|
Allocator const& alloc);
|
|
|
|
/** Move assignment
|
|
|
|
After the move, `*this` will have an empty output sequence.
|
|
|
|
@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.
|
|
*/
|
|
basic_flat_buffer&
|
|
operator=(basic_flat_buffer&& other);
|
|
|
|
/** Copy assignment
|
|
|
|
After the copy, `*this` will have an empty output sequence.
|
|
|
|
@param other The object to copy from.
|
|
*/
|
|
basic_flat_buffer&
|
|
operator=(basic_flat_buffer const& other);
|
|
|
|
/// Returns a copy of the associated allocator.
|
|
allocator_type
|
|
get_allocator() const
|
|
{
|
|
return this->member();
|
|
}
|
|
|
|
/// Returns the size of the input sequence.
|
|
std::size_t
|
|
size() const
|
|
{
|
|
return dist(in_, out_);
|
|
}
|
|
|
|
/// 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);
|
|
|
|
/** Reserve space in the stream.
|
|
|
|
This reallocates the buffer if necessary.
|
|
|
|
@note All previous buffers sequences obtained from
|
|
calls to @ref data or @ref prepare are invalidated.
|
|
|
|
@param n The number of bytes to reserve. Upon success,
|
|
the capacity will be at least `n`.
|
|
|
|
@throws std::length_error if `n` exceeds `max_size()`.
|
|
*/
|
|
void
|
|
reserve(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.
|
|
*/
|
|
void
|
|
shrink_to_fit();
|
|
|
|
template<class Alloc>
|
|
friend
|
|
void
|
|
swap(
|
|
basic_flat_buffer<Alloc>& lhs,
|
|
basic_flat_buffer<Alloc>& rhs);
|
|
|
|
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);
|
|
};
|
|
|
|
using flat_buffer =
|
|
basic_flat_buffer<std::allocator<char>>;
|
|
|
|
} // beast
|
|
|
|
#include <beast/core/impl/flat_buffer.ipp>
|
|
|
|
#endif
|