mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 12:57:31 +02:00
Move basic_streambuf to streambuf.hpp (API Change):
* Also change allocator element type to char
This commit is contained in:
@ -3,6 +3,7 @@
|
|||||||
API Changes:
|
API Changes:
|
||||||
|
|
||||||
* Invoke callback on pings and pongs
|
* Invoke callback on pings and pongs
|
||||||
|
* Move basic_streambuf to streambuf.hpp
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#define BEAST_CORE_HPP
|
#define BEAST_CORE_HPP
|
||||||
|
|
||||||
#include <beast/core/async_completion.hpp>
|
#include <beast/core/async_completion.hpp>
|
||||||
#include <beast/core/basic_streambuf.hpp>
|
|
||||||
#include <beast/core/bind_handler.hpp>
|
#include <beast/core/bind_handler.hpp>
|
||||||
#include <beast/core/buffer_cat.hpp>
|
#include <beast/core/buffer_cat.hpp>
|
||||||
#include <beast/core/buffer_concepts.hpp>
|
#include <beast/core/buffer_concepts.hpp>
|
||||||
|
@ -1,333 +0,0 @@
|
|||||||
//
|
|
||||||
// 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_BASIC_STREAMBUF_HPP
|
|
||||||
#define BEAST_BASIC_STREAMBUF_HPP
|
|
||||||
|
|
||||||
#include <beast/core/detail/empty_base_optimization.hpp>
|
|
||||||
#include <boost/asio/buffer.hpp>
|
|
||||||
#include <boost/intrusive/list.hpp>
|
|
||||||
#include <iterator>
|
|
||||||
#include <limits>
|
|
||||||
#include <memory>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
/** A @b `DynamicBuffer` that uses multiple buffers internally.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
@note Meets the requirements of @b DynamicBuffer.
|
|
||||||
|
|
||||||
@tparam Allocator The allocator to use for managing memory.
|
|
||||||
*/
|
|
||||||
template<class Allocator>
|
|
||||||
class basic_streambuf
|
|
||||||
#if ! GENERATING_DOCS
|
|
||||||
: private detail::empty_base_optimization<
|
|
||||||
typename std::allocator_traits<Allocator>::
|
|
||||||
template rebind_alloc<std::uint8_t>>
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
#if GENERATING_DOCS
|
|
||||||
/// The type of allocator used.
|
|
||||||
using allocator_type = Allocator;
|
|
||||||
#else
|
|
||||||
using allocator_type = typename
|
|
||||||
std::allocator_traits<Allocator>::
|
|
||||||
template rebind_alloc<std::uint8_t>;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Storage for the list of buffers representing the input
|
|
||||||
// and output sequences. The allocation for each element
|
|
||||||
// contains `element` followed by raw storage bytes.
|
|
||||||
class element;
|
|
||||||
|
|
||||||
using alloc_traits = std::allocator_traits<allocator_type>;
|
|
||||||
using list_type = typename boost::intrusive::make_list<element,
|
|
||||||
boost::intrusive::constant_time_size<true>>::type;
|
|
||||||
using iterator = typename list_type::iterator;
|
|
||||||
using const_iterator = typename list_type::const_iterator;
|
|
||||||
|
|
||||||
using size_type = typename std::allocator_traits<Allocator>::size_type;
|
|
||||||
using const_buffer = boost::asio::const_buffer;
|
|
||||||
using mutable_buffer = boost::asio::mutable_buffer;
|
|
||||||
|
|
||||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag,
|
|
||||||
typename std::iterator_traits<iterator>::iterator_category>::value,
|
|
||||||
"BidirectionalIterator requirements not met");
|
|
||||||
|
|
||||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag,
|
|
||||||
typename std::iterator_traits<const_iterator>::iterator_category>::value,
|
|
||||||
"BidirectionalIterator requirements not met");
|
|
||||||
|
|
||||||
list_type list_; // list of allocated buffers
|
|
||||||
iterator out_; // element that contains out_pos_
|
|
||||||
size_type alloc_size_; // min amount to allocate
|
|
||||||
size_type in_size_ = 0; // size of the input sequence
|
|
||||||
size_type in_pos_ = 0; // input offset in list_.front()
|
|
||||||
size_type out_pos_ = 0; // output offset in *out_
|
|
||||||
size_type out_end_ = 0; // output end offset in list_.back()
|
|
||||||
|
|
||||||
public:
|
|
||||||
#if GENERATING_DOCS
|
|
||||||
/// 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_streambuf();
|
|
||||||
|
|
||||||
/** Move constructor.
|
|
||||||
|
|
||||||
The new object will have the input sequence of
|
|
||||||
the other stream buffer, and an empty output sequence.
|
|
||||||
|
|
||||||
@note After the move, the moved-from object will have
|
|
||||||
an empty input and output sequence, with no internal
|
|
||||||
buffers allocated.
|
|
||||||
*/
|
|
||||||
basic_streambuf(basic_streambuf&&);
|
|
||||||
|
|
||||||
/** Move constructor.
|
|
||||||
|
|
||||||
The new object will have the input sequence of
|
|
||||||
the other stream buffer, and an empty output sequence.
|
|
||||||
|
|
||||||
@note After the move, the moved-from object will have
|
|
||||||
an empty input and output sequence, with no internal
|
|
||||||
buffers allocated.
|
|
||||||
|
|
||||||
@param alloc The allocator to associate with the
|
|
||||||
stream buffer.
|
|
||||||
*/
|
|
||||||
basic_streambuf(basic_streambuf&&,
|
|
||||||
allocator_type const& alloc);
|
|
||||||
|
|
||||||
/** Move assignment.
|
|
||||||
|
|
||||||
This object will have the input sequence of
|
|
||||||
the other stream buffer, and an empty output sequence.
|
|
||||||
|
|
||||||
@note After the move, the moved-from object will have
|
|
||||||
an empty input and output sequence, with no internal
|
|
||||||
buffers allocated.
|
|
||||||
*/
|
|
||||||
basic_streambuf&
|
|
||||||
operator=(basic_streambuf&&);
|
|
||||||
|
|
||||||
/** Copy constructor.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
*/
|
|
||||||
basic_streambuf(basic_streambuf const&);
|
|
||||||
|
|
||||||
/** Copy constructor.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
|
|
||||||
@param alloc The allocator to associate with the
|
|
||||||
stream buffer.
|
|
||||||
*/
|
|
||||||
basic_streambuf(basic_streambuf const&,
|
|
||||||
allocator_type const& alloc);
|
|
||||||
|
|
||||||
/** Copy assignment.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
*/
|
|
||||||
basic_streambuf& operator=(basic_streambuf const&);
|
|
||||||
|
|
||||||
/** Copy constructor.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
*/
|
|
||||||
template<class OtherAlloc>
|
|
||||||
basic_streambuf(basic_streambuf<OtherAlloc> const&);
|
|
||||||
|
|
||||||
/** Copy constructor.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
|
|
||||||
@param alloc The allocator to associate with the
|
|
||||||
stream buffer.
|
|
||||||
*/
|
|
||||||
template<class OtherAlloc>
|
|
||||||
basic_streambuf(basic_streambuf<OtherAlloc> const&,
|
|
||||||
allocator_type const& alloc);
|
|
||||||
|
|
||||||
/** Copy assignment.
|
|
||||||
|
|
||||||
This object will have a copy of the other stream
|
|
||||||
buffer's input sequence, and an empty output sequence.
|
|
||||||
*/
|
|
||||||
template<class OtherAlloc>
|
|
||||||
basic_streambuf& operator=(basic_streambuf<OtherAlloc> const&);
|
|
||||||
|
|
||||||
/** Construct a stream buffer.
|
|
||||||
|
|
||||||
@param alloc_size The size of buffer to allocate. This is a
|
|
||||||
soft limit, calls to prepare for buffers exceeding this size
|
|
||||||
will allocate the larger size. The default allocation size
|
|
||||||
is 1KB (1024 bytes).
|
|
||||||
|
|
||||||
@param alloc The allocator to use. If this parameter is
|
|
||||||
unspecified, a default constructed allocator will be used.
|
|
||||||
*/
|
|
||||||
explicit
|
|
||||||
basic_streambuf(std::size_t alloc_size = 1024,
|
|
||||||
Allocator const& alloc = allocator_type{});
|
|
||||||
|
|
||||||
/// Returns a copy of the associated allocator.
|
|
||||||
allocator_type
|
|
||||||
get_allocator() const
|
|
||||||
{
|
|
||||||
return this->member();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the default allocation size.
|
|
||||||
|
|
||||||
This is the smallest size that the stream buffer will allocate.
|
|
||||||
The size of the allocation can influence capacity, which will
|
|
||||||
affect algorithms that use capacity to efficiently read from
|
|
||||||
streams.
|
|
||||||
*/
|
|
||||||
std::size_t
|
|
||||||
alloc_size() const
|
|
||||||
{
|
|
||||||
return alloc_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set the default allocation size.
|
|
||||||
|
|
||||||
This is the smallest size that the stream buffer will allocate.
|
|
||||||
The size of the allocation can influence capacity, which will
|
|
||||||
affect algorithms that use capacity to efficiently read from
|
|
||||||
streams.
|
|
||||||
|
|
||||||
@note This will not affect any already-existing allocations.
|
|
||||||
|
|
||||||
@param n The number of bytes.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
alloc_size(std::size_t n)
|
|
||||||
{
|
|
||||||
alloc_size_ = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the size of the input sequence.
|
|
||||||
size_type
|
|
||||||
size() const
|
|
||||||
{
|
|
||||||
return in_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the permitted maximum sum of the sizes of the input and output sequence.
|
|
||||||
size_type
|
|
||||||
max_size() const
|
|
||||||
{
|
|
||||||
return (std::numeric_limits<std::size_t>::max)();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
|
|
||||||
std::size_t
|
|
||||||
capacity() const;
|
|
||||||
|
|
||||||
/** Get a list of buffers that represents the input sequence.
|
|
||||||
|
|
||||||
@note These buffers remain valid across subsequent calls to `prepare`.
|
|
||||||
*/
|
|
||||||
const_buffers_type
|
|
||||||
data() const;
|
|
||||||
|
|
||||||
/** Get a list of buffers that represents the output sequence, with the given size.
|
|
||||||
|
|
||||||
@note Buffers representing the input sequence acquired prior to
|
|
||||||
this call remain valid.
|
|
||||||
*/
|
|
||||||
mutable_buffers_type
|
|
||||||
prepare(size_type n);
|
|
||||||
|
|
||||||
/** Move bytes from the output sequence to the input sequence.
|
|
||||||
|
|
||||||
@note Buffers representing the input sequence acquired prior to
|
|
||||||
this call remain valid.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
commit(size_type n);
|
|
||||||
|
|
||||||
/// Remove bytes from the input sequence.
|
|
||||||
void
|
|
||||||
consume(size_type n);
|
|
||||||
|
|
||||||
// Helper for boost::asio::read_until
|
|
||||||
template<class OtherAllocator>
|
|
||||||
friend
|
|
||||||
std::size_t
|
|
||||||
read_size_helper(basic_streambuf<
|
|
||||||
OtherAllocator> const& streambuf, std::size_t max_size);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void
|
|
||||||
clear();
|
|
||||||
|
|
||||||
void
|
|
||||||
move_assign(basic_streambuf& other, std::false_type);
|
|
||||||
|
|
||||||
void
|
|
||||||
move_assign(basic_streambuf& other, std::true_type);
|
|
||||||
|
|
||||||
void
|
|
||||||
copy_assign(basic_streambuf const& other, std::false_type);
|
|
||||||
|
|
||||||
void
|
|
||||||
copy_assign(basic_streambuf const& other, std::true_type);
|
|
||||||
|
|
||||||
void
|
|
||||||
delete_list();
|
|
||||||
|
|
||||||
void
|
|
||||||
debug_check() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Format output to a @ref basic_streambuf.
|
|
||||||
|
|
||||||
@param streambuf The @ref basic_streambuf to write to.
|
|
||||||
|
|
||||||
@param t The object to write.
|
|
||||||
|
|
||||||
@return A reference to the @ref basic_streambuf.
|
|
||||||
*/
|
|
||||||
template<class Allocator, class T>
|
|
||||||
basic_streambuf<Allocator>&
|
|
||||||
operator<<(basic_streambuf<Allocator>& streambuf, T const& t);
|
|
||||||
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#include <beast/core/impl/basic_streambuf.ipp>
|
|
||||||
|
|
||||||
#endif
|
|
@ -5,8 +5,8 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BEAST_IMPL_BASIC_STREAMBUF_IPP
|
#ifndef BEAST_IMPL_STREAMBUF_IPP
|
||||||
#define BEAST_IMPL_BASIC_STREAMBUF_IPP
|
#define BEAST_IMPL_STREAMBUF_IPP
|
||||||
|
|
||||||
#include <beast/core/detail/type_traits.hpp>
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
#include <beast/core/detail/write_dynabuf.hpp>
|
#include <beast/core/detail/write_dynabuf.hpp>
|
||||||
@ -624,7 +624,7 @@ basic_streambuf<Allocator>::prepare(size_type n) ->
|
|||||||
auto const len = e.size() + sizeof(e);
|
auto const len = e.size() + sizeof(e);
|
||||||
alloc_traits::destroy(this->member(), &e);
|
alloc_traits::destroy(this->member(), &e);
|
||||||
alloc_traits::deallocate(this->member(),
|
alloc_traits::deallocate(this->member(),
|
||||||
reinterpret_cast<std::uint8_t*>(&e), len);
|
reinterpret_cast<char*>(&e), len);
|
||||||
}
|
}
|
||||||
return mutable_buffers_type(*this);
|
return mutable_buffers_type(*this);
|
||||||
}
|
}
|
||||||
@ -696,7 +696,7 @@ basic_streambuf<Allocator>::consume(size_type n)
|
|||||||
auto const len = e.size() + sizeof(e);
|
auto const len = e.size() + sizeof(e);
|
||||||
alloc_traits::destroy(this->member(), &e);
|
alloc_traits::destroy(this->member(), &e);
|
||||||
alloc_traits::deallocate(this->member(),
|
alloc_traits::deallocate(this->member(),
|
||||||
reinterpret_cast<std::uint8_t*>(&e), len);
|
reinterpret_cast<char*>(&e), len);
|
||||||
debug_check();
|
debug_check();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -808,7 +808,7 @@ basic_streambuf<Allocator>::delete_list()
|
|||||||
auto const n = e.size() + sizeof(e);
|
auto const n = e.size() + sizeof(e);
|
||||||
alloc_traits::destroy(this->member(), &e);
|
alloc_traits::destroy(this->member(), &e);
|
||||||
alloc_traits::deallocate(this->member(),
|
alloc_traits::deallocate(this->member(),
|
||||||
reinterpret_cast<std::uint8_t*>(&e), n);
|
reinterpret_cast<char*>(&e), n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,10 +8,312 @@
|
|||||||
#ifndef BEAST_STREAMBUF_HPP
|
#ifndef BEAST_STREAMBUF_HPP
|
||||||
#define BEAST_STREAMBUF_HPP
|
#define BEAST_STREAMBUF_HPP
|
||||||
|
|
||||||
#include <beast/core/basic_streambuf.hpp>
|
#include <beast/core/detail/empty_base_optimization.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/intrusive/list.hpp>
|
||||||
|
#include <iterator>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
|
/** A @b `DynamicBuffer` that uses multiple buffers internally.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@note Meets the requirements of @b DynamicBuffer.
|
||||||
|
|
||||||
|
@tparam Allocator The allocator to use for managing memory.
|
||||||
|
*/
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_streambuf
|
||||||
|
#if ! GENERATING_DOCS
|
||||||
|
: private detail::empty_base_optimization<
|
||||||
|
typename std::allocator_traits<Allocator>::
|
||||||
|
template rebind_alloc<char>>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
/// The type of allocator used.
|
||||||
|
using allocator_type = Allocator;
|
||||||
|
#else
|
||||||
|
using allocator_type = typename
|
||||||
|
std::allocator_traits<Allocator>::
|
||||||
|
template rebind_alloc<char>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Storage for the list of buffers representing the input
|
||||||
|
// and output sequences. The allocation for each element
|
||||||
|
// contains `element` followed by raw storage bytes.
|
||||||
|
class element;
|
||||||
|
|
||||||
|
using alloc_traits = std::allocator_traits<allocator_type>;
|
||||||
|
using list_type = typename boost::intrusive::make_list<element,
|
||||||
|
boost::intrusive::constant_time_size<true>>::type;
|
||||||
|
using iterator = typename list_type::iterator;
|
||||||
|
using const_iterator = typename list_type::const_iterator;
|
||||||
|
|
||||||
|
using size_type = typename std::allocator_traits<Allocator>::size_type;
|
||||||
|
using const_buffer = boost::asio::const_buffer;
|
||||||
|
using mutable_buffer = boost::asio::mutable_buffer;
|
||||||
|
|
||||||
|
static_assert(std::is_base_of<std::bidirectional_iterator_tag,
|
||||||
|
typename std::iterator_traits<iterator>::iterator_category>::value,
|
||||||
|
"BidirectionalIterator requirements not met");
|
||||||
|
|
||||||
|
static_assert(std::is_base_of<std::bidirectional_iterator_tag,
|
||||||
|
typename std::iterator_traits<const_iterator>::iterator_category>::value,
|
||||||
|
"BidirectionalIterator requirements not met");
|
||||||
|
|
||||||
|
list_type list_; // list of allocated buffers
|
||||||
|
iterator out_; // element that contains out_pos_
|
||||||
|
size_type alloc_size_; // min amount to allocate
|
||||||
|
size_type in_size_ = 0; // size of the input sequence
|
||||||
|
size_type in_pos_ = 0; // input offset in list_.front()
|
||||||
|
size_type out_pos_ = 0; // output offset in *out_
|
||||||
|
size_type out_end_ = 0; // output end offset in list_.back()
|
||||||
|
|
||||||
|
public:
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
/// 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_streambuf();
|
||||||
|
|
||||||
|
/** Move constructor.
|
||||||
|
|
||||||
|
The new object will have the input sequence of
|
||||||
|
the other stream buffer, and an empty output sequence.
|
||||||
|
|
||||||
|
@note After the move, the moved-from object will have
|
||||||
|
an empty input and output sequence, with no internal
|
||||||
|
buffers allocated.
|
||||||
|
*/
|
||||||
|
basic_streambuf(basic_streambuf&&);
|
||||||
|
|
||||||
|
/** Move constructor.
|
||||||
|
|
||||||
|
The new object will have the input sequence of
|
||||||
|
the other stream buffer, and an empty output sequence.
|
||||||
|
|
||||||
|
@note After the move, the moved-from object will have
|
||||||
|
an empty input and output sequence, with no internal
|
||||||
|
buffers allocated.
|
||||||
|
|
||||||
|
@param alloc The allocator to associate with the
|
||||||
|
stream buffer.
|
||||||
|
*/
|
||||||
|
basic_streambuf(basic_streambuf&&,
|
||||||
|
allocator_type const& alloc);
|
||||||
|
|
||||||
|
/** Move assignment.
|
||||||
|
|
||||||
|
This object will have the input sequence of
|
||||||
|
the other stream buffer, and an empty output sequence.
|
||||||
|
|
||||||
|
@note After the move, the moved-from object will have
|
||||||
|
an empty input and output sequence, with no internal
|
||||||
|
buffers allocated.
|
||||||
|
*/
|
||||||
|
basic_streambuf&
|
||||||
|
operator=(basic_streambuf&&);
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
|
||||||
|
This object will have a copy of the other stream
|
||||||
|
buffer's input sequence, and an empty output sequence.
|
||||||
|
*/
|
||||||
|
basic_streambuf(basic_streambuf const&);
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
|
||||||
|
This object will have a copy of the other stream
|
||||||
|
buffer's input sequence, and an empty output sequence.
|
||||||
|
|
||||||
|
@param alloc The allocator to associate with the
|
||||||
|
stream buffer.
|
||||||
|
*/
|
||||||
|
basic_streambuf(basic_streambuf const&,
|
||||||
|
allocator_type const& alloc);
|
||||||
|
|
||||||
|
/** Copy assignment.
|
||||||
|
|
||||||
|
This object will have a copy of the other stream
|
||||||
|
buffer's input sequence, and an empty output sequence.
|
||||||
|
*/
|
||||||
|
basic_streambuf& operator=(basic_streambuf const&);
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
|
||||||
|
This object will have a copy of the other stream
|
||||||
|
buffer's input sequence, and an empty output sequence.
|
||||||
|
*/
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_streambuf(basic_streambuf<OtherAlloc> const&);
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
|
||||||
|
This object will have a copy of the other stream
|
||||||
|
buffer's input sequence, and an empty output sequence.
|
||||||
|
|
||||||
|
@param alloc The allocator to associate with the
|
||||||
|
stream buffer.
|
||||||
|
*/
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_streambuf(basic_streambuf<OtherAlloc> const&,
|
||||||
|
allocator_type const& alloc);
|
||||||
|
|
||||||
|
/** Copy assignment.
|
||||||
|
|
||||||
|
This object will have a copy of the other stream
|
||||||
|
buffer's input sequence, and an empty output sequence.
|
||||||
|
*/
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_streambuf& operator=(basic_streambuf<OtherAlloc> const&);
|
||||||
|
|
||||||
|
/** Construct a stream buffer.
|
||||||
|
|
||||||
|
@param alloc_size The size of buffer to allocate. This is a
|
||||||
|
soft limit, calls to prepare for buffers exceeding this size
|
||||||
|
will allocate the larger size. The default allocation size
|
||||||
|
is 1KB (1024 bytes).
|
||||||
|
|
||||||
|
@param alloc The allocator to use. If this parameter is
|
||||||
|
unspecified, a default constructed allocator will be used.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
basic_streambuf(std::size_t alloc_size = 1024,
|
||||||
|
Allocator const& alloc = allocator_type{});
|
||||||
|
|
||||||
|
/// Returns a copy of the associated allocator.
|
||||||
|
allocator_type
|
||||||
|
get_allocator() const
|
||||||
|
{
|
||||||
|
return this->member();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the default allocation size.
|
||||||
|
|
||||||
|
This is the smallest size that the stream buffer will allocate.
|
||||||
|
The size of the allocation can influence capacity, which will
|
||||||
|
affect algorithms that use capacity to efficiently read from
|
||||||
|
streams.
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
alloc_size() const
|
||||||
|
{
|
||||||
|
return alloc_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the default allocation size.
|
||||||
|
|
||||||
|
This is the smallest size that the stream buffer will allocate.
|
||||||
|
The size of the allocation can influence capacity, which will
|
||||||
|
affect algorithms that use capacity to efficiently read from
|
||||||
|
streams.
|
||||||
|
|
||||||
|
@note This will not affect any already-existing allocations.
|
||||||
|
|
||||||
|
@param n The number of bytes.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
alloc_size(std::size_t n)
|
||||||
|
{
|
||||||
|
alloc_size_ = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the size of the input sequence.
|
||||||
|
size_type
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return in_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the permitted maximum sum of the sizes of the input and output sequence.
|
||||||
|
size_type
|
||||||
|
max_size() const
|
||||||
|
{
|
||||||
|
return (std::numeric_limits<std::size_t>::max)();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
|
||||||
|
std::size_t
|
||||||
|
capacity() const;
|
||||||
|
|
||||||
|
/** Get a list of buffers that represents the input sequence.
|
||||||
|
|
||||||
|
@note These buffers remain valid across subsequent calls to `prepare`.
|
||||||
|
*/
|
||||||
|
const_buffers_type
|
||||||
|
data() const;
|
||||||
|
|
||||||
|
/** Get a list of buffers that represents the output sequence, with the given size.
|
||||||
|
|
||||||
|
@note Buffers representing the input sequence acquired prior to
|
||||||
|
this call remain valid.
|
||||||
|
*/
|
||||||
|
mutable_buffers_type
|
||||||
|
prepare(size_type n);
|
||||||
|
|
||||||
|
/** Move bytes from the output sequence to the input sequence.
|
||||||
|
|
||||||
|
@note Buffers representing the input sequence acquired prior to
|
||||||
|
this call remain valid.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
commit(size_type n);
|
||||||
|
|
||||||
|
/// Remove bytes from the input sequence.
|
||||||
|
void
|
||||||
|
consume(size_type n);
|
||||||
|
|
||||||
|
// Helper for boost::asio::read_until
|
||||||
|
template<class OtherAllocator>
|
||||||
|
friend
|
||||||
|
std::size_t
|
||||||
|
read_size_helper(basic_streambuf<
|
||||||
|
OtherAllocator> const& streambuf, std::size_t max_size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
clear();
|
||||||
|
|
||||||
|
void
|
||||||
|
move_assign(basic_streambuf& other, std::false_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
move_assign(basic_streambuf& other, std::true_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
copy_assign(basic_streambuf const& other, std::false_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
copy_assign(basic_streambuf const& other, std::true_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
delete_list();
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_check() const;
|
||||||
|
};
|
||||||
|
|
||||||
/** A @b `DynamicBuffer` that uses multiple buffers internally.
|
/** A @b `DynamicBuffer` that uses multiple buffers internally.
|
||||||
|
|
||||||
The implementation uses a sequence of one or more character arrays
|
The implementation uses a sequence of one or more character arrays
|
||||||
@ -23,6 +325,20 @@ namespace beast {
|
|||||||
*/
|
*/
|
||||||
using streambuf = basic_streambuf<std::allocator<char>>;
|
using streambuf = basic_streambuf<std::allocator<char>>;
|
||||||
|
|
||||||
|
/** Format output to a @ref basic_streambuf.
|
||||||
|
|
||||||
|
@param streambuf The @ref basic_streambuf to write to.
|
||||||
|
|
||||||
|
@param t The object to write.
|
||||||
|
|
||||||
|
@return A reference to the @ref basic_streambuf.
|
||||||
|
*/
|
||||||
|
template<class Allocator, class T>
|
||||||
|
basic_streambuf<Allocator>&
|
||||||
|
operator<<(basic_streambuf<Allocator>& streambuf, T const& t);
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/core/impl/streambuf.ipp>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,7 +16,6 @@ compile zlib.cpp : : ;
|
|||||||
unit-test core-tests :
|
unit-test core-tests :
|
||||||
../extras/beast/unit_test/main.cpp
|
../extras/beast/unit_test/main.cpp
|
||||||
core/async_completion.cpp
|
core/async_completion.cpp
|
||||||
core/basic_streambuf.cpp
|
|
||||||
core/bind_handler.cpp
|
core/bind_handler.cpp
|
||||||
core/buffer_cat.cpp
|
core/buffer_cat.cpp
|
||||||
core/buffer_concepts.cpp
|
core/buffer_concepts.cpp
|
||||||
|
@ -10,7 +10,6 @@ add_executable (core-tests
|
|||||||
../../extras/beast/unit_test/main.cpp
|
../../extras/beast/unit_test/main.cpp
|
||||||
buffer_test.hpp
|
buffer_test.hpp
|
||||||
async_completion.cpp
|
async_completion.cpp
|
||||||
basic_streambuf.cpp
|
|
||||||
bind_handler.cpp
|
bind_handler.cpp
|
||||||
buffer_cat.cpp
|
buffer_cat.cpp
|
||||||
buffer_concepts.cpp
|
buffer_concepts.cpp
|
||||||
|
@ -1,480 +0,0 @@
|
|||||||
//
|
|
||||||
// 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)
|
|
||||||
//
|
|
||||||
|
|
||||||
// Test that header file is self-contained.
|
|
||||||
#include <beast/core/basic_streambuf.hpp>
|
|
||||||
|
|
||||||
#include "buffer_test.hpp"
|
|
||||||
#include <beast/core/streambuf.hpp>
|
|
||||||
#include <beast/core/to_string.hpp>
|
|
||||||
#include <beast/unit_test/suite.hpp>
|
|
||||||
#include <boost/asio/buffer.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <atomic>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
struct test_allocator_info
|
|
||||||
{
|
|
||||||
std::size_t ncopy = 0;
|
|
||||||
std::size_t nmove = 0;
|
|
||||||
std::size_t nselect = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T,
|
|
||||||
bool Assign, bool Move, bool Swap, bool Select>
|
|
||||||
class test_allocator;
|
|
||||||
|
|
||||||
template<class T,
|
|
||||||
bool Assign, bool Move, bool Swap, bool Select>
|
|
||||||
struct test_allocator_base
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T,
|
|
||||||
bool Assign, bool Move, bool Swap>
|
|
||||||
struct test_allocator_base<T, Assign, Move, Swap, true>
|
|
||||||
{
|
|
||||||
static
|
|
||||||
test_allocator<T, Assign, Move, Swap, true>
|
|
||||||
select_on_container_copy_construction(
|
|
||||||
test_allocator<T, Assign, Move, Swap, true> const& a)
|
|
||||||
{
|
|
||||||
return test_allocator<T, Assign, Move, Swap, true>{};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T,
|
|
||||||
bool Assign, bool Move, bool Swap, bool Select>
|
|
||||||
class test_allocator : public test_allocator_base<
|
|
||||||
T, Assign, Move, Swap, Select>
|
|
||||||
{
|
|
||||||
std::size_t id_;
|
|
||||||
std::shared_ptr<test_allocator_info> info_;
|
|
||||||
|
|
||||||
template<class, bool, bool, bool, bool>
|
|
||||||
friend class test_allocator;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using value_type = T;
|
|
||||||
using propagate_on_container_copy_assignment =
|
|
||||||
std::integral_constant<bool, Assign>;
|
|
||||||
using propagate_on_container_move_assignment =
|
|
||||||
std::integral_constant<bool, Move>;
|
|
||||||
using propagate_on_container_swap =
|
|
||||||
std::integral_constant<bool, Swap>;
|
|
||||||
|
|
||||||
template<class U>
|
|
||||||
struct rebind
|
|
||||||
{
|
|
||||||
using other = test_allocator<
|
|
||||||
U, Assign, Move, Swap, Select>;
|
|
||||||
};
|
|
||||||
|
|
||||||
test_allocator()
|
|
||||||
: id_([]
|
|
||||||
{
|
|
||||||
static std::atomic<
|
|
||||||
std::size_t> sid(0);
|
|
||||||
return ++sid;
|
|
||||||
}())
|
|
||||||
, info_(std::make_shared<test_allocator_info>())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
test_allocator(test_allocator const& u) noexcept
|
|
||||||
: id_(u.id_)
|
|
||||||
, info_(u.info_)
|
|
||||||
{
|
|
||||||
++info_->ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U>
|
|
||||||
test_allocator(test_allocator<
|
|
||||||
U, Assign, Move, Swap, Select> const& u) noexcept
|
|
||||||
: id_(u.id_)
|
|
||||||
, info_(u.info_)
|
|
||||||
{
|
|
||||||
++info_->ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
test_allocator(test_allocator&& t)
|
|
||||||
: id_(t.id_)
|
|
||||||
, info_(t.info_)
|
|
||||||
{
|
|
||||||
++info_->nmove;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type*
|
|
||||||
allocate(std::size_t n)
|
|
||||||
{
|
|
||||||
return static_cast<value_type*>(
|
|
||||||
::operator new (n*sizeof(value_type)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
deallocate(value_type* p, std::size_t) noexcept
|
|
||||||
{
|
|
||||||
::operator delete(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
id() const
|
|
||||||
{
|
|
||||||
return id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
test_allocator_info const*
|
|
||||||
operator->() const
|
|
||||||
{
|
|
||||||
return info_.get();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class basic_streambuf_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template<class Alloc1, class Alloc2>
|
|
||||||
static
|
|
||||||
bool
|
|
||||||
eq(basic_streambuf<Alloc1> const& sb1,
|
|
||||||
basic_streambuf<Alloc2> const& sb2)
|
|
||||||
{
|
|
||||||
return to_string(sb1.data()) == to_string(sb2.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
void
|
|
||||||
expect_size(std::size_t n, ConstBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
BEAST_EXPECT(test::size_pre(buffers) == n);
|
|
||||||
BEAST_EXPECT(test::size_post(buffers) == n);
|
|
||||||
BEAST_EXPECT(test::size_rev_pre(buffers) == n);
|
|
||||||
BEAST_EXPECT(test::size_rev_post(buffers) == n);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U, class V>
|
|
||||||
static
|
|
||||||
void
|
|
||||||
self_assign(U& u, V&& v)
|
|
||||||
{
|
|
||||||
u = std::forward<V>(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testSpecialMembers()
|
|
||||||
{
|
|
||||||
using boost::asio::buffer;
|
|
||||||
using boost::asio::buffer_cast;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
std::string const s = "Hello, world";
|
|
||||||
BEAST_EXPECT(s.size() == 12);
|
|
||||||
for(std::size_t i = 1; i < 12; ++i) {
|
|
||||||
for(std::size_t x = 1; x < 4; ++x) {
|
|
||||||
for(std::size_t y = 1; y < 4; ++y) {
|
|
||||||
std::size_t z = s.size() - (x + y);
|
|
||||||
{
|
|
||||||
streambuf sb(i);
|
|
||||||
sb.commit(buffer_copy(sb.prepare(x), buffer(s.data(), x)));
|
|
||||||
sb.commit(buffer_copy(sb.prepare(y), buffer(s.data()+x, y)));
|
|
||||||
sb.commit(buffer_copy(sb.prepare(z), buffer(s.data()+x+y, z)));
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == s);
|
|
||||||
{
|
|
||||||
streambuf sb2(sb);
|
|
||||||
BEAST_EXPECT(eq(sb, sb2));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
streambuf sb2;
|
|
||||||
sb2 = sb;
|
|
||||||
BEAST_EXPECT(eq(sb, sb2));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
streambuf sb2(std::move(sb));
|
|
||||||
BEAST_EXPECT(to_string(sb2.data()) == s);
|
|
||||||
expect_size(0, sb.data());
|
|
||||||
sb = std::move(sb2);
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == s);
|
|
||||||
expect_size(0, sb2.data());
|
|
||||||
}
|
|
||||||
self_assign(sb, sb);
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == s);
|
|
||||||
self_assign(sb, std::move(sb));
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == s);
|
|
||||||
}
|
|
||||||
}}}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
streambuf sb0(0);
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
catch(std::exception const&)
|
|
||||||
{
|
|
||||||
pass();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testAllocator()
|
|
||||||
{
|
|
||||||
// VFALCO This needs work
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
test_allocator<char, false, false, false, false>;
|
|
||||||
using sb_type = basic_streambuf<alloc_type>;
|
|
||||||
sb_type sb;
|
|
||||||
BEAST_EXPECT(sb.get_allocator().id() == 1);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
test_allocator<char, false, false, false, false>;
|
|
||||||
using sb_type = basic_streambuf<alloc_type>;
|
|
||||||
sb_type sb;
|
|
||||||
BEAST_EXPECT(sb.get_allocator().id() == 2);
|
|
||||||
sb_type sb2(sb);
|
|
||||||
BEAST_EXPECT(sb2.get_allocator().id() == 2);
|
|
||||||
sb_type sb3(sb, alloc_type{});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testPrepare()
|
|
||||||
{
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
{
|
|
||||||
streambuf sb(2);
|
|
||||||
BEAST_EXPECT(buffer_size(sb.prepare(5)) == 5);
|
|
||||||
BEAST_EXPECT(buffer_size(sb.prepare(8)) == 8);
|
|
||||||
BEAST_EXPECT(buffer_size(sb.prepare(7)) == 7);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
streambuf sb(2);
|
|
||||||
sb.prepare(2);
|
|
||||||
BEAST_EXPECT(test::buffer_count(sb.prepare(5)) == 2);
|
|
||||||
BEAST_EXPECT(test::buffer_count(sb.prepare(8)) == 3);
|
|
||||||
BEAST_EXPECT(test::buffer_count(sb.prepare(4)) == 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testCommit()
|
|
||||||
{
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
streambuf sb(2);
|
|
||||||
sb.prepare(2);
|
|
||||||
sb.prepare(5);
|
|
||||||
sb.commit(1);
|
|
||||||
expect_size(1, sb.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void testConsume()
|
|
||||||
{
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
streambuf sb(1);
|
|
||||||
expect_size(5, sb.prepare(5));
|
|
||||||
sb.commit(3);
|
|
||||||
expect_size(3, sb.data());
|
|
||||||
sb.consume(1);
|
|
||||||
expect_size(2, sb.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void testMatrix()
|
|
||||||
{
|
|
||||||
using boost::asio::buffer;
|
|
||||||
using boost::asio::buffer_cast;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
std::string const s = "Hello, world";
|
|
||||||
BEAST_EXPECT(s.size() == 12);
|
|
||||||
for(std::size_t i = 1; i < 12; ++i) {
|
|
||||||
for(std::size_t x = 1; x < 4; ++x) {
|
|
||||||
for(std::size_t y = 1; y < 4; ++y) {
|
|
||||||
for(std::size_t t = 1; t < 4; ++ t) {
|
|
||||||
for(std::size_t u = 1; u < 4; ++ u) {
|
|
||||||
std::size_t z = s.size() - (x + y);
|
|
||||||
std::size_t v = s.size() - (t + u);
|
|
||||||
{
|
|
||||||
streambuf sb(i);
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(z);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == z);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(0);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == 0);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(y);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == y);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(x);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == x);
|
|
||||||
sb.commit(buffer_copy(d, buffer(s.data(), x)));
|
|
||||||
}
|
|
||||||
BEAST_EXPECT(sb.size() == x);
|
|
||||||
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(x);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == x);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(0);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == 0);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(z);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == z);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(y);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == y);
|
|
||||||
sb.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
|
||||||
}
|
|
||||||
sb.commit(1);
|
|
||||||
BEAST_EXPECT(sb.size() == x + y);
|
|
||||||
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(x);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == x);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(y);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == y);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(0);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == 0);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(z);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == z);
|
|
||||||
sb.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
|
||||||
}
|
|
||||||
sb.commit(2);
|
|
||||||
BEAST_EXPECT(sb.size() == x + y + z);
|
|
||||||
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == s);
|
|
||||||
sb.consume(t);
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(0);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == 0);
|
|
||||||
}
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == s.substr(t, std::string::npos));
|
|
||||||
sb.consume(u);
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == s.substr(t + u, std::string::npos));
|
|
||||||
sb.consume(v);
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == "");
|
|
||||||
sb.consume(1);
|
|
||||||
{
|
|
||||||
auto d = sb.prepare(0);
|
|
||||||
BEAST_EXPECT(buffer_size(d) == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}}}}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testIterators()
|
|
||||||
{
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
streambuf sb(1);
|
|
||||||
sb.prepare(1);
|
|
||||||
sb.commit(1);
|
|
||||||
sb.prepare(2);
|
|
||||||
sb.commit(2);
|
|
||||||
expect_size(3, sb.data());
|
|
||||||
sb.prepare(1);
|
|
||||||
expect_size(3, sb.prepare(3));
|
|
||||||
sb.commit(2);
|
|
||||||
BEAST_EXPECT(test::buffer_count(sb.data()) == 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testOutputStream()
|
|
||||||
{
|
|
||||||
streambuf sb;
|
|
||||||
sb << "x";
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == "x");
|
|
||||||
}
|
|
||||||
|
|
||||||
void testCapacity()
|
|
||||||
{
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
{
|
|
||||||
streambuf sb{10};
|
|
||||||
BEAST_EXPECT(sb.alloc_size() == 10);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 10) == 10);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 20) == 20);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1000) == 512);
|
|
||||||
sb.prepare(3);
|
|
||||||
sb.commit(3);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 10) == 7);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1000) == 7);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
streambuf sb(1000);
|
|
||||||
BEAST_EXPECT(sb.alloc_size() == 1000);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1000) == 1000);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 2000) == 1000);
|
|
||||||
sb.prepare(3);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1000) == 1000);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 2000) == 1000);
|
|
||||||
sb.commit(3);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1000) == 997);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 2000) == 997);
|
|
||||||
sb.consume(2);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 1000) == 997);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 2000) == 997);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
streambuf sb{2};
|
|
||||||
BEAST_EXPECT(sb.alloc_size() == 2);
|
|
||||||
BEAST_EXPECT(test::buffer_count(sb.prepare(2)) == 1);
|
|
||||||
BEAST_EXPECT(test::buffer_count(sb.prepare(3)) == 2);
|
|
||||||
BEAST_EXPECT(buffer_size(sb.prepare(5)) == 5);
|
|
||||||
BEAST_EXPECT(read_size_helper(sb, 10) == 6);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto avail =
|
|
||||||
[](streambuf const& sb)
|
|
||||||
{
|
|
||||||
return sb.capacity() - sb.size();
|
|
||||||
};
|
|
||||||
streambuf sb{100};
|
|
||||||
BEAST_EXPECT(sb.alloc_size() == 100);
|
|
||||||
BEAST_EXPECT(avail(sb) == 0);
|
|
||||||
sb.prepare(100);
|
|
||||||
BEAST_EXPECT(avail(sb) == 100);
|
|
||||||
sb.commit(100);
|
|
||||||
BEAST_EXPECT(avail(sb) == 0);
|
|
||||||
sb.consume(100);
|
|
||||||
BEAST_EXPECT(avail(sb) == 0);
|
|
||||||
sb.alloc_size(200);
|
|
||||||
BEAST_EXPECT(sb.alloc_size() == 200);
|
|
||||||
sb.prepare(1);
|
|
||||||
BEAST_EXPECT(avail(sb) == 200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() override
|
|
||||||
{
|
|
||||||
testSpecialMembers();
|
|
||||||
testAllocator();
|
|
||||||
testPrepare();
|
|
||||||
testCommit();
|
|
||||||
testConsume();
|
|
||||||
testMatrix();
|
|
||||||
testIterators();
|
|
||||||
testOutputStream();
|
|
||||||
testCapacity();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(basic_streambuf,core,beast);
|
|
||||||
|
|
||||||
} // beast
|
|
@ -8,9 +8,475 @@
|
|||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <beast/core/streambuf.hpp>
|
#include <beast/core/streambuf.hpp>
|
||||||
|
|
||||||
|
#include "buffer_test.hpp"
|
||||||
#include <beast/core/buffer_concepts.hpp>
|
#include <beast/core/buffer_concepts.hpp>
|
||||||
|
#include <beast/core/to_string.hpp>
|
||||||
|
#include <beast/unit_test/suite.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
static_assert(is_DynamicBuffer<streambuf>::value, "");
|
static_assert(is_DynamicBuffer<streambuf>::value, "");
|
||||||
|
|
||||||
|
struct test_allocator_info
|
||||||
|
{
|
||||||
|
std::size_t ncopy = 0;
|
||||||
|
std::size_t nmove = 0;
|
||||||
|
std::size_t nselect = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T,
|
||||||
|
bool Assign, bool Move, bool Swap, bool Select>
|
||||||
|
class test_allocator;
|
||||||
|
|
||||||
|
template<class T,
|
||||||
|
bool Assign, bool Move, bool Swap, bool Select>
|
||||||
|
struct test_allocator_base
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T,
|
||||||
|
bool Assign, bool Move, bool Swap>
|
||||||
|
struct test_allocator_base<T, Assign, Move, Swap, true>
|
||||||
|
{
|
||||||
|
static
|
||||||
|
test_allocator<T, Assign, Move, Swap, true>
|
||||||
|
select_on_container_copy_construction(
|
||||||
|
test_allocator<T, Assign, Move, Swap, true> const& a)
|
||||||
|
{
|
||||||
|
return test_allocator<T, Assign, Move, Swap, true>{};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T,
|
||||||
|
bool Assign, bool Move, bool Swap, bool Select>
|
||||||
|
class test_allocator : public test_allocator_base<
|
||||||
|
T, Assign, Move, Swap, Select>
|
||||||
|
{
|
||||||
|
std::size_t id_;
|
||||||
|
std::shared_ptr<test_allocator_info> info_;
|
||||||
|
|
||||||
|
template<class, bool, bool, bool, bool>
|
||||||
|
friend class test_allocator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
using propagate_on_container_copy_assignment =
|
||||||
|
std::integral_constant<bool, Assign>;
|
||||||
|
using propagate_on_container_move_assignment =
|
||||||
|
std::integral_constant<bool, Move>;
|
||||||
|
using propagate_on_container_swap =
|
||||||
|
std::integral_constant<bool, Swap>;
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
using other = test_allocator<
|
||||||
|
U, Assign, Move, Swap, Select>;
|
||||||
|
};
|
||||||
|
|
||||||
|
test_allocator()
|
||||||
|
: id_([]
|
||||||
|
{
|
||||||
|
static std::atomic<
|
||||||
|
std::size_t> sid(0);
|
||||||
|
return ++sid;
|
||||||
|
}())
|
||||||
|
, info_(std::make_shared<test_allocator_info>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
test_allocator(test_allocator const& u) noexcept
|
||||||
|
: id_(u.id_)
|
||||||
|
, info_(u.info_)
|
||||||
|
{
|
||||||
|
++info_->ncopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
test_allocator(test_allocator<
|
||||||
|
U, Assign, Move, Swap, Select> const& u) noexcept
|
||||||
|
: id_(u.id_)
|
||||||
|
, info_(u.info_)
|
||||||
|
{
|
||||||
|
++info_->ncopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_allocator(test_allocator&& t)
|
||||||
|
: id_(t.id_)
|
||||||
|
, info_(t.info_)
|
||||||
|
{
|
||||||
|
++info_->nmove;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type*
|
||||||
|
allocate(std::size_t n)
|
||||||
|
{
|
||||||
|
return static_cast<value_type*>(
|
||||||
|
::operator new (n*sizeof(value_type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
deallocate(value_type* p, std::size_t) noexcept
|
||||||
|
{
|
||||||
|
::operator delete(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_allocator_info const*
|
||||||
|
operator->() const
|
||||||
|
{
|
||||||
|
return info_.get();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class basic_streambuf_test : public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class Alloc1, class Alloc2>
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
eq(basic_streambuf<Alloc1> const& sb1,
|
||||||
|
basic_streambuf<Alloc2> const& sb2)
|
||||||
|
{
|
||||||
|
return to_string(sb1.data()) == to_string(sb2.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void
|
||||||
|
expect_size(std::size_t n, ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(test::size_pre(buffers) == n);
|
||||||
|
BEAST_EXPECT(test::size_post(buffers) == n);
|
||||||
|
BEAST_EXPECT(test::size_rev_pre(buffers) == n);
|
||||||
|
BEAST_EXPECT(test::size_rev_post(buffers) == n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U, class V>
|
||||||
|
static
|
||||||
|
void
|
||||||
|
self_assign(U& u, V&& v)
|
||||||
|
{
|
||||||
|
u = std::forward<V>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSpecialMembers()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
BEAST_EXPECT(s.size() == 12);
|
||||||
|
for(std::size_t i = 1; i < 12; ++i) {
|
||||||
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
|
std::size_t z = s.size() - (x + y);
|
||||||
|
{
|
||||||
|
streambuf sb(i);
|
||||||
|
sb.commit(buffer_copy(sb.prepare(x), buffer(s.data(), x)));
|
||||||
|
sb.commit(buffer_copy(sb.prepare(y), buffer(s.data()+x, y)));
|
||||||
|
sb.commit(buffer_copy(sb.prepare(z), buffer(s.data()+x+y, z)));
|
||||||
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
|
{
|
||||||
|
streambuf sb2(sb);
|
||||||
|
BEAST_EXPECT(eq(sb, sb2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
streambuf sb2;
|
||||||
|
sb2 = sb;
|
||||||
|
BEAST_EXPECT(eq(sb, sb2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
streambuf sb2(std::move(sb));
|
||||||
|
BEAST_EXPECT(to_string(sb2.data()) == s);
|
||||||
|
expect_size(0, sb.data());
|
||||||
|
sb = std::move(sb2);
|
||||||
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
|
expect_size(0, sb2.data());
|
||||||
|
}
|
||||||
|
self_assign(sb, sb);
|
||||||
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
|
self_assign(sb, std::move(sb));
|
||||||
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
|
}
|
||||||
|
}}}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
streambuf sb0(0);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAllocator()
|
||||||
|
{
|
||||||
|
// VFALCO This needs work
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
test_allocator<char, false, false, false, false>;
|
||||||
|
using sb_type = basic_streambuf<alloc_type>;
|
||||||
|
sb_type sb;
|
||||||
|
BEAST_EXPECT(sb.get_allocator().id() == 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
test_allocator<char, false, false, false, false>;
|
||||||
|
using sb_type = basic_streambuf<alloc_type>;
|
||||||
|
sb_type sb;
|
||||||
|
BEAST_EXPECT(sb.get_allocator().id() == 2);
|
||||||
|
sb_type sb2(sb);
|
||||||
|
BEAST_EXPECT(sb2.get_allocator().id() == 2);
|
||||||
|
sb_type sb3(sb, alloc_type{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testPrepare()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
{
|
||||||
|
streambuf sb(2);
|
||||||
|
BEAST_EXPECT(buffer_size(sb.prepare(5)) == 5);
|
||||||
|
BEAST_EXPECT(buffer_size(sb.prepare(8)) == 8);
|
||||||
|
BEAST_EXPECT(buffer_size(sb.prepare(7)) == 7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
streambuf sb(2);
|
||||||
|
sb.prepare(2);
|
||||||
|
BEAST_EXPECT(test::buffer_count(sb.prepare(5)) == 2);
|
||||||
|
BEAST_EXPECT(test::buffer_count(sb.prepare(8)) == 3);
|
||||||
|
BEAST_EXPECT(test::buffer_count(sb.prepare(4)) == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCommit()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
streambuf sb(2);
|
||||||
|
sb.prepare(2);
|
||||||
|
sb.prepare(5);
|
||||||
|
sb.commit(1);
|
||||||
|
expect_size(1, sb.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testConsume()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
streambuf sb(1);
|
||||||
|
expect_size(5, sb.prepare(5));
|
||||||
|
sb.commit(3);
|
||||||
|
expect_size(3, sb.data());
|
||||||
|
sb.consume(1);
|
||||||
|
expect_size(2, sb.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testMatrix()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
BEAST_EXPECT(s.size() == 12);
|
||||||
|
for(std::size_t i = 1; i < 12; ++i) {
|
||||||
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
|
for(std::size_t t = 1; t < 4; ++ t) {
|
||||||
|
for(std::size_t u = 1; u < 4; ++ u) {
|
||||||
|
std::size_t z = s.size() - (x + y);
|
||||||
|
std::size_t v = s.size() - (t + u);
|
||||||
|
{
|
||||||
|
streambuf sb(i);
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(z);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(y);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(x);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
|
sb.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
|
}
|
||||||
|
BEAST_EXPECT(sb.size() == x);
|
||||||
|
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(x);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(z);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(y);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
|
sb.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
|
}
|
||||||
|
sb.commit(1);
|
||||||
|
BEAST_EXPECT(sb.size() == x + y);
|
||||||
|
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(x);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(y);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(z);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
|
sb.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
|
}
|
||||||
|
sb.commit(2);
|
||||||
|
BEAST_EXPECT(sb.size() == x + y + z);
|
||||||
|
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
|
||||||
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
|
sb.consume(t);
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
BEAST_EXPECT(to_string(sb.data()) == s.substr(t, std::string::npos));
|
||||||
|
sb.consume(u);
|
||||||
|
BEAST_EXPECT(to_string(sb.data()) == s.substr(t + u, std::string::npos));
|
||||||
|
sb.consume(v);
|
||||||
|
BEAST_EXPECT(to_string(sb.data()) == "");
|
||||||
|
sb.consume(1);
|
||||||
|
{
|
||||||
|
auto d = sb.prepare(0);
|
||||||
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testIterators()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
streambuf sb(1);
|
||||||
|
sb.prepare(1);
|
||||||
|
sb.commit(1);
|
||||||
|
sb.prepare(2);
|
||||||
|
sb.commit(2);
|
||||||
|
expect_size(3, sb.data());
|
||||||
|
sb.prepare(1);
|
||||||
|
expect_size(3, sb.prepare(3));
|
||||||
|
sb.commit(2);
|
||||||
|
BEAST_EXPECT(test::buffer_count(sb.data()) == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testOutputStream()
|
||||||
|
{
|
||||||
|
streambuf sb;
|
||||||
|
sb << "x";
|
||||||
|
BEAST_EXPECT(to_string(sb.data()) == "x");
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCapacity()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
{
|
||||||
|
streambuf sb{10};
|
||||||
|
BEAST_EXPECT(sb.alloc_size() == 10);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 10) == 10);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 20) == 20);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 512);
|
||||||
|
sb.prepare(3);
|
||||||
|
sb.commit(3);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 10) == 7);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
streambuf sb(1000);
|
||||||
|
BEAST_EXPECT(sb.alloc_size() == 1000);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 1000);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 2000) == 1000);
|
||||||
|
sb.prepare(3);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 1000);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 2000) == 1000);
|
||||||
|
sb.commit(3);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 997);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 2000) == 997);
|
||||||
|
sb.consume(2);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 997);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 2000) == 997);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
streambuf sb{2};
|
||||||
|
BEAST_EXPECT(sb.alloc_size() == 2);
|
||||||
|
BEAST_EXPECT(test::buffer_count(sb.prepare(2)) == 1);
|
||||||
|
BEAST_EXPECT(test::buffer_count(sb.prepare(3)) == 2);
|
||||||
|
BEAST_EXPECT(buffer_size(sb.prepare(5)) == 5);
|
||||||
|
BEAST_EXPECT(read_size_helper(sb, 10) == 6);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto avail =
|
||||||
|
[](streambuf const& sb)
|
||||||
|
{
|
||||||
|
return sb.capacity() - sb.size();
|
||||||
|
};
|
||||||
|
streambuf sb{100};
|
||||||
|
BEAST_EXPECT(sb.alloc_size() == 100);
|
||||||
|
BEAST_EXPECT(avail(sb) == 0);
|
||||||
|
sb.prepare(100);
|
||||||
|
BEAST_EXPECT(avail(sb) == 100);
|
||||||
|
sb.commit(100);
|
||||||
|
BEAST_EXPECT(avail(sb) == 0);
|
||||||
|
sb.consume(100);
|
||||||
|
BEAST_EXPECT(avail(sb) == 0);
|
||||||
|
sb.alloc_size(200);
|
||||||
|
BEAST_EXPECT(sb.alloc_size() == 200);
|
||||||
|
sb.prepare(1);
|
||||||
|
BEAST_EXPECT(avail(sb) == 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testSpecialMembers();
|
||||||
|
testAllocator();
|
||||||
|
testPrepare();
|
||||||
|
testCommit();
|
||||||
|
testConsume();
|
||||||
|
testMatrix();
|
||||||
|
testIterators();
|
||||||
|
testOutputStream();
|
||||||
|
testCapacity();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(basic_streambuf,core,beast);
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
Reference in New Issue
Block a user