forked from boostorg/beast
Add static_buffer (API Change):
* static_buffer is added Note this is the same name from two versions ago, when static_buffer was renamed to flat_static_buffer for consistency and to clear the name for a circular static buffer. Actions Required: * Callers who depend on static_buffer returning sequences of exactly length one should switch to flat_static_buffer.
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_IMPL_STATIC_BUFFER_IPP
|
||||
#define BEAST_IMPL_STATIC_BUFFER_IPP
|
||||
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template<bool isInput, class T>
|
||||
class static_buffer_base::buffers_type
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
class const_iterator
|
||||
{
|
||||
friend class buffers_type;
|
||||
|
||||
static_buffer_base const* b_ = nullptr;
|
||||
int seg_ = 0;
|
||||
|
||||
const_iterator(bool at_end,
|
||||
static_buffer_base const& b)
|
||||
: b_(&b)
|
||||
{
|
||||
if(! at_end)
|
||||
{
|
||||
seg_ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_end(std::integral_constant<bool, isInput>{});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_end(std::true_type)
|
||||
{
|
||||
if(b_->in_off_ + b_->in_size_ <= b_->capacity_)
|
||||
seg_ = 1;
|
||||
else
|
||||
seg_ = 2;
|
||||
}
|
||||
|
||||
void
|
||||
set_end(std::false_type)
|
||||
{
|
||||
if(((b_->in_off_ + b_->in_size_) % b_->capacity_)
|
||||
+ b_->out_size_ <= b_->capacity_)
|
||||
seg_ = 1;
|
||||
else
|
||||
seg_ = 2;
|
||||
}
|
||||
|
||||
T
|
||||
dereference(std::true_type) const
|
||||
{
|
||||
switch(seg_)
|
||||
{
|
||||
case 0:
|
||||
return {
|
||||
b_->begin_ + b_->in_off_,
|
||||
(std::min)(
|
||||
b_->in_size_,
|
||||
b_->capacity_ - b_->in_off_)};
|
||||
default:
|
||||
case 1:
|
||||
return {
|
||||
b_->begin_,
|
||||
b_->in_size_ - (
|
||||
b_->capacity_ - b_->in_off_)};
|
||||
}
|
||||
}
|
||||
|
||||
T
|
||||
dereference(std::false_type) const
|
||||
{
|
||||
switch(seg_)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
auto const out_off =
|
||||
(b_->in_off_ + b_->in_size_)
|
||||
% b_->capacity_;
|
||||
return {
|
||||
b_->begin_ + out_off,
|
||||
(std::min)(
|
||||
b_->out_size_,
|
||||
b_->capacity_ - out_off)};
|
||||
}
|
||||
default:
|
||||
case 1:
|
||||
{
|
||||
auto const out_off =
|
||||
(b_->in_off_ + b_->in_size_)
|
||||
% b_->capacity_;
|
||||
return {
|
||||
b_->begin_,
|
||||
b_->out_size_ - (
|
||||
b_->capacity_ - out_off)};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type const&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category =
|
||||
std::bidirectional_iterator_tag;
|
||||
|
||||
const_iterator() = default;
|
||||
const_iterator(const_iterator const& other) = default;
|
||||
const_iterator& operator=(const_iterator const& other) = default;
|
||||
|
||||
bool
|
||||
operator==(const_iterator const& other) const
|
||||
{
|
||||
return b_ == other.b_ && seg_ == other.seg_;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
value_type
|
||||
operator*() const
|
||||
{
|
||||
return dereference(
|
||||
std::integral_constant<bool, isInput>{});
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() = delete;
|
||||
|
||||
const_iterator&
|
||||
operator++()
|
||||
{
|
||||
++seg_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
operator--()
|
||||
{
|
||||
--seg_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
operator--(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
};
|
||||
|
||||
buffers_type() = delete;
|
||||
buffers_type(buffers_type const&) = default;
|
||||
buffers_type& operator=(buffers_type const&) = delete;
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return const_iterator{false, b_};
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return const_iterator{true, b_};
|
||||
}
|
||||
|
||||
private:
|
||||
friend class static_buffer_base;
|
||||
|
||||
static_buffer_base const& b_;
|
||||
|
||||
explicit
|
||||
buffers_type(static_buffer_base const& b)
|
||||
: b_(b)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline
|
||||
static_buffer_base::
|
||||
static_buffer_base(void* p, std::size_t size)
|
||||
: begin_(reinterpret_cast<char*>(p))
|
||||
, capacity_(size)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
static_buffer_base::
|
||||
data() const ->
|
||||
const_buffers_type
|
||||
{
|
||||
return const_buffers_type{*this};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
static_buffer_base::
|
||||
mutable_data() ->
|
||||
mutable_data_type
|
||||
{
|
||||
return mutable_data_type{*this};
|
||||
}
|
||||
|
||||
inline
|
||||
auto
|
||||
static_buffer_base::
|
||||
prepare(std::size_t size) ->
|
||||
mutable_buffers_type
|
||||
{
|
||||
if(size > capacity_ - in_size_)
|
||||
BOOST_THROW_EXCEPTION(std::length_error{
|
||||
"buffer overflow"});
|
||||
out_size_ = size;
|
||||
return mutable_buffers_type{*this};
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
static_buffer_base::
|
||||
commit(std::size_t size)
|
||||
{
|
||||
in_size_ += (std::min)(size, out_size_);
|
||||
out_size_ = 0;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
static_buffer_base::
|
||||
consume(std::size_t size)
|
||||
{
|
||||
size = (std::min)(size, in_size_);
|
||||
in_off_ = (in_off_ + size) % capacity_;
|
||||
in_size_ -= size;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
static_buffer_base::
|
||||
reset(void* p, std::size_t size)
|
||||
{
|
||||
begin_ = reinterpret_cast<char*>(p);
|
||||
capacity_ = size;
|
||||
in_off_ = 0;
|
||||
in_size_ = 0;
|
||||
out_size_ = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<std::size_t N>
|
||||
static_buffer<N>::
|
||||
static_buffer(static_buffer const& other)
|
||||
: static_buffer_base(buf_, N)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
this->commit(buffer_copy(
|
||||
this->prepare(other.size()), other.data()));
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
auto
|
||||
static_buffer<N>::
|
||||
operator=(static_buffer const& other) ->
|
||||
static_buffer<N>&
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
this->consume(this->size());
|
||||
this->commit(buffer_copy(
|
||||
this->prepare(other.size()), other.data()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,222 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_STATIC_BUFFER_HPP
|
||||
#define BEAST_STATIC_BUFFER_HPP
|
||||
|
||||
#include <beast/config.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A circular @b DynamicBuffer with a fixed size internal buffer.
|
||||
|
||||
This implements a circular dynamic buffer. Calls to @ref prepare
|
||||
never require moving memory. The buffer sequences returned may
|
||||
be up to length two.
|
||||
Ownership of the underlying storage belongs to the derived class.
|
||||
|
||||
@note Variables are usually declared using the template class
|
||||
@ref static_buffer; however, to reduce the number of instantiations
|
||||
of template functions receiving static stream buffer arguments in a
|
||||
deduced context, the signature of the receiving function should use
|
||||
@ref static_buffer_base.
|
||||
|
||||
When used with @ref static_buffer this implements a dynamic
|
||||
buffer using no memory allocations.
|
||||
|
||||
@see @ref static_buffer
|
||||
*/
|
||||
class static_buffer_base
|
||||
{
|
||||
char* begin_;
|
||||
std::size_t in_off_ = 0;
|
||||
std::size_t in_size_ = 0;
|
||||
std::size_t out_size_ = 0;
|
||||
std::size_t capacity_;
|
||||
|
||||
template<bool, class T>
|
||||
class buffers_type;
|
||||
|
||||
static_buffer_base(static_buffer_base const& other) = delete;
|
||||
static_buffer_base& operator=(static_buffer_base const&) = delete;
|
||||
|
||||
public:
|
||||
/// The type used to represent the input sequence as a list of buffers.
|
||||
#if BEAST_DOXYGEN
|
||||
using const_buffers_type = implementation_defined;
|
||||
#else
|
||||
using const_buffers_type =
|
||||
buffers_type<true, boost::asio::const_buffer>;
|
||||
#endif
|
||||
|
||||
/// The type used to represent the mutable input sequence as a list of buffers.
|
||||
#if BEAST_DOXYGEN
|
||||
using mutable_data_type = implementation_defined;
|
||||
#else
|
||||
using mutable_data_type =
|
||||
buffers_type<true, boost::asio::mutable_buffer>;
|
||||
#endif
|
||||
|
||||
/// The type used to represent the output sequence as a list of buffers.
|
||||
#if BEAST_DOXYGEN
|
||||
using mutable_buffers_type = implementation_defined;
|
||||
#else
|
||||
using mutable_buffers_type =
|
||||
buffers_type<false, boost::asio::mutable_buffer>;
|
||||
#endif
|
||||
|
||||
/** Constructor
|
||||
|
||||
This creates a dynamic buffer using the provided storage area.
|
||||
|
||||
@param p A pointer to valid storage of at least `n` bytes.
|
||||
|
||||
@param size The number of valid bytes pointed to by `p`.
|
||||
*/
|
||||
static_buffer_base(void* p, std::size_t size);
|
||||
|
||||
/// Return the size of the input sequence.
|
||||
std::size_t
|
||||
size() const
|
||||
{
|
||||
return in_size_;
|
||||
}
|
||||
|
||||
/// Return the maximum sum of the input and output sequence sizes.
|
||||
std::size_t
|
||||
max_size() const
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
/// Return the maximum sum of input and output sizes that can be held without an allocation.
|
||||
std::size_t
|
||||
capacity() const
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
/** Get a list of buffers that represent the input sequence.
|
||||
*/
|
||||
const_buffers_type
|
||||
data() const;
|
||||
|
||||
/** Get a list of mutable buffers that represent the input sequence.
|
||||
*/
|
||||
mutable_data_type
|
||||
mutable_data();
|
||||
|
||||
/** Get a list of buffers that represent the output sequence, with the given size.
|
||||
|
||||
@param size The number of bytes to request.
|
||||
|
||||
@throws std::length_error if the size would exceed the capacity.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(std::size_t size);
|
||||
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
|
||||
@param size The nubmer of bytes to commit. If this is greater
|
||||
than the size of the output sequence, the entire output
|
||||
sequence is committed.
|
||||
*/
|
||||
void
|
||||
commit(std::size_t size);
|
||||
|
||||
/** Remove bytes from the input sequence.
|
||||
|
||||
@param size The number of bytes to consume. If this is greater
|
||||
than the size of the input sequence, the entire input sequence
|
||||
is consumed.
|
||||
*/
|
||||
void
|
||||
consume(std::size_t size);
|
||||
|
||||
protected:
|
||||
/** Constructor
|
||||
|
||||
The buffer will be in an undefined state. It is necessary
|
||||
for the derived class to call @ref reset in order to
|
||||
initialize the object.
|
||||
*/
|
||||
static_buffer_base();
|
||||
|
||||
/** Reset the pointed-to buffer.
|
||||
|
||||
This function resets the internal state to the buffer provided.
|
||||
All input and output sequences are invalidated. This function
|
||||
allows the derived class to construct its members before
|
||||
initializing the static buffer.
|
||||
|
||||
@param p A pointer to valid storage of at least `n` bytes.
|
||||
|
||||
@param size The number of valid bytes pointed to by `p`.
|
||||
*/
|
||||
void
|
||||
reset(void* p, std::size_t size);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A circular @b DynamicBuffer with a fixed size internal buffer.
|
||||
|
||||
This implements a circular dynamic buffer. Calls to @ref prepare
|
||||
never require moving memory. The buffer sequences returned may
|
||||
be up to length two.
|
||||
Ownership of the underlying storage belongs to the derived class.
|
||||
|
||||
@tparam N The number of bytes in the internal buffer.
|
||||
|
||||
@note To reduce the number of template instantiations when passing
|
||||
objects of this type in a deduced context, the signature of the
|
||||
receiving function should use @ref static_buffer_base instead.
|
||||
|
||||
@see @ref static_buffer_base
|
||||
*/
|
||||
template<std::size_t N>
|
||||
class static_buffer : public static_buffer_base
|
||||
{
|
||||
char buf_[N];
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
static_buffer(static_buffer const&);
|
||||
|
||||
/// Constructor
|
||||
static_buffer()
|
||||
: static_buffer_base(buf_, N)
|
||||
{
|
||||
}
|
||||
|
||||
/// Assignment
|
||||
static_buffer& operator=(static_buffer const&);
|
||||
|
||||
/// Returns the @ref static_buffer_base portion of this object
|
||||
static_buffer_base&
|
||||
base()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Returns the @ref static_buffer_base portion of this object
|
||||
static_buffer_base const&
|
||||
base() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/static_buffer.ipp>
|
||||
|
||||
#endif
|
||||
@@ -265,7 +265,7 @@ public:
|
||||
pointer
|
||||
operator->()
|
||||
{
|
||||
return &(*this);
|
||||
return &(**this);
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
|
||||
Reference in New Issue
Block a user