mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
Beast.Asio:
New classes:
class async_completion:
Helper class for implementing asynchronous initiation functions.
See n3964:
Library Foundations for Asynchronous Operations, Revision 1
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3964.pdf
class basic_streambuf:
Meets the requirements of Streambuf.
class buffered_readstream:
Buffers a ReadStream with a ConstBufferSequence.
class consuming_buffers:
Adapts a BufferSequence which wraps the underlying buffer
sequence and presents fewer bytes, with the retained bytes
occurring at the end of the sequence.
class handler_alloc:
A C++ Allocator the uses asio handler allocation hooks.
class static_streambuf:
An implementation of the Streambuf concept that uses a
fixed size buffer with size determined at compile-time.
class streambuf_readstream:
Buffers a ReadStream with a Streambuf.
New functions:
append_buffers()
Returns a new BufferSequence which efficiently concatenates
two or more buffer sequences together.
prepare_buffers()
Shortens a buffer sequence. The bytes excluded are at the
end of the underlying buffer sequence.
boost::asio::read_until()
A copy of boost::asio::read_until overloads, modified to work
with a beast::asio::basic_streambuf.
Debugging:
buffers_to_string()
Convert a ConstBufferSequence to a human readable string
suitable for diagnostics.
type_check.h:
Metafunctions for checking asio concepts:
AsyncReadStream, AsyncWriteStream
SyncReadStream, SyncWriteStream
ConstBufferSequence, MutableBufferSequence
Streambuf
Handler
Changes:
* All symbols moved up a namespace level.
* streambuf provides all move and copy special members,
behavior of moved from objects is well-defined.
Fixes:
* Fix basic_streambuf iterator category.
This commit is contained in:
68
Jamroot
Normal file
68
Jamroot
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#
|
||||||
|
# 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)
|
||||||
|
#
|
||||||
|
|
||||||
|
import os ;
|
||||||
|
import feature ;
|
||||||
|
import boost ;
|
||||||
|
|
||||||
|
boost.use-project ;
|
||||||
|
|
||||||
|
if [ os.name ] = SOLARIS
|
||||||
|
{
|
||||||
|
lib socket ;
|
||||||
|
lib nsl ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = NT
|
||||||
|
{
|
||||||
|
lib ws2_32 ;
|
||||||
|
lib mswsock ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = HPUX
|
||||||
|
{
|
||||||
|
lib ipv6 ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = QNXNTO
|
||||||
|
{
|
||||||
|
lib socket ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = HAIKU
|
||||||
|
{
|
||||||
|
lib network ;
|
||||||
|
}
|
||||||
|
|
||||||
|
build-project test/asio ;
|
||||||
|
|
||||||
|
project beast
|
||||||
|
: requirements
|
||||||
|
<include>.
|
||||||
|
#<use>/boost//headers
|
||||||
|
<library>/boost/system//boost_system
|
||||||
|
<define>BOOST_ALL_NO_LIB=1
|
||||||
|
<threading>multi
|
||||||
|
<link>static
|
||||||
|
<runtime-link>static
|
||||||
|
<os>LINUX:<define>_XOPEN_SOURCE=600
|
||||||
|
<os>LINUX:<define>_GNU_SOURCE=1
|
||||||
|
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
||||||
|
<os>SOLARIS:<define>__EXTENSIONS__
|
||||||
|
<os>SOLARIS:<library>socket
|
||||||
|
<os>SOLARIS:<library>nsl
|
||||||
|
<os>NT:<define>_WIN32_WINNT=0x0501
|
||||||
|
<os>NT,<toolset>cw:<library>ws2_32
|
||||||
|
<os>NT,<toolset>cw:<library>mswsock
|
||||||
|
<os>NT,<toolset>gcc:<library>ws2_32
|
||||||
|
<os>NT,<toolset>gcc:<library>mswsock
|
||||||
|
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
|
||||||
|
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
|
||||||
|
<os>HPUX:<library>ipv6
|
||||||
|
<os>QNXNTO:<library>socket
|
||||||
|
<os>HAIKU:<library>network
|
||||||
|
: usage-requirements
|
||||||
|
<include>.
|
||||||
|
:
|
||||||
|
build-dir bin
|
||||||
|
;
|
||||||
@@ -17,29 +17,22 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef BEAST_ASIO_ERROR_H_INCLUDED
|
#ifndef BEAST_ASIO_H_INCLUDED
|
||||||
#define BEAST_ASIO_ERROR_H_INCLUDED
|
#define BEAST_ASIO_H_INCLUDED
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <beast/asio/append_buffers.h>
|
||||||
#include <boost/asio/ssl/error.hpp>
|
#include <beast/asio/async_completion.h>
|
||||||
|
#include <beast/asio/basic_streambuf.h>
|
||||||
namespace beast {
|
#include <beast/asio/bind_handler.h>
|
||||||
namespace asio {
|
#include <beast/asio/buffers_adapter.h>
|
||||||
|
#include <beast/asio/buffers_debug.h>
|
||||||
/** Returns `true` if the error code is a SSL "short read." */
|
#include <beast/asio/consuming_buffers.h>
|
||||||
inline
|
#include <beast/asio/handler_alloc.h>
|
||||||
bool
|
#include <beast/asio/placeholders.h>
|
||||||
is_short_read (boost::system::error_code const& ec)
|
#include <beast/asio/prepare_buffers.h>
|
||||||
{
|
#include <beast/asio/static_streambuf.h>
|
||||||
return (ec.category() == boost::asio::error::get_ssl_category())
|
#include <beast/asio/streambuf.h>
|
||||||
&& (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ);
|
#include <beast/asio/streambuf_readstream.h>
|
||||||
}
|
#include <beast/asio/type_check.h>
|
||||||
|
|
||||||
/** Returns a human readable message if the error code is SSL related. */
|
|
||||||
std::string
|
|
||||||
asio_message(boost::system::error_code const& ec);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
517
beast/asio/append_buffers.h
Normal file
517
beast/asio/append_buffers.h
Normal file
@@ -0,0 +1,517 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_APPEND_BUFFERS_H_INLUDED
|
||||||
|
#define BEAST_ASIO_APPEND_BUFFERS_H_INLUDED
|
||||||
|
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iterator>
|
||||||
|
#include <new>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
class append_buffers_helper
|
||||||
|
{
|
||||||
|
std::tuple<Bs...> bs_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = ValueType;
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
append_buffers_helper(append_buffers_helper&&) = default;
|
||||||
|
append_buffers_helper(append_buffers_helper const&) = default;
|
||||||
|
append_buffers_helper& operator=(append_buffers_helper&&) = default;
|
||||||
|
append_buffers_helper& operator=(append_buffers_helper const&) = default;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
append_buffers_helper(Bs const&... bs)
|
||||||
|
: bs_(bs...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
begin() const;
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
end() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
std::size_t constexpr
|
||||||
|
max_sizeof()
|
||||||
|
{
|
||||||
|
return sizeof(U);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U0, class U1, class... Us>
|
||||||
|
std::size_t constexpr
|
||||||
|
max_sizeof()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
max_sizeof<U0>() > max_sizeof<U1, Us...>() ?
|
||||||
|
max_sizeof<U0>() : max_sizeof<U1, Us...>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
class append_buffers_helper<
|
||||||
|
ValueType, Bs...>::const_iterator
|
||||||
|
{
|
||||||
|
std::size_t n_;
|
||||||
|
std::tuple<Bs...> const* bs_;
|
||||||
|
std::array<std::uint8_t,
|
||||||
|
max_sizeof<typename Bs::const_iterator...>()> buf_;
|
||||||
|
|
||||||
|
friend class append_buffers_helper<ValueType, Bs...>;
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
using C = std::integral_constant<std::size_t, I>;
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
using iter_t = typename std::tuple_element_t<
|
||||||
|
I, std::tuple<Bs...>>::const_iterator;
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
iter_t<I>&
|
||||||
|
iter()
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<
|
||||||
|
iter_t<I>*>(buf_.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
iter_t<I> const&
|
||||||
|
iter() const
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<
|
||||||
|
iter_t<I> const*>(buf_.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = ValueType;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
~const_iterator();
|
||||||
|
const_iterator();
|
||||||
|
const_iterator(const_iterator&& other);
|
||||||
|
const_iterator(const_iterator const& other);
|
||||||
|
const_iterator& operator=(const_iterator&& other);
|
||||||
|
const_iterator& operator=(const_iterator const& other);
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const;
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++();
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--();
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const_iterator(
|
||||||
|
std::tuple<Bs...> const& bs, bool at_end);
|
||||||
|
|
||||||
|
void
|
||||||
|
construct(C<sizeof...(Bs)>)
|
||||||
|
{
|
||||||
|
auto constexpr I = sizeof...(Bs);
|
||||||
|
n_ = I;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
void
|
||||||
|
construct(C<I>)
|
||||||
|
{
|
||||||
|
if(std::get<I>(*bs_).begin() !=
|
||||||
|
std::get<I>(*bs_).end())
|
||||||
|
{
|
||||||
|
n_ = I;
|
||||||
|
new(buf_.data()) iter_t<I>{
|
||||||
|
std::get<I>(*bs_).begin()};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
construct(C<I+1>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
destroy(C<sizeof...(Bs)>)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
void
|
||||||
|
destroy(C<I>)
|
||||||
|
{
|
||||||
|
if(n_ == I)
|
||||||
|
{
|
||||||
|
using Iter = iter_t<I>;
|
||||||
|
iter<I>().~Iter();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
destroy(C<I+1>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
move(C<sizeof...(Bs)>, const_iterator&&)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
void
|
||||||
|
move(C<I>, const_iterator&& other)
|
||||||
|
{
|
||||||
|
if(n_ == I)
|
||||||
|
{
|
||||||
|
new(buf_.data()) iter_t<I>{
|
||||||
|
std::move(other.iter<I>())};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
move(C<I+1>{}, std::move(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copy(C<sizeof...(Bs)>, const_iterator const&)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
void
|
||||||
|
copy(C<I>, const_iterator const& other)
|
||||||
|
{
|
||||||
|
if(n_ == I)
|
||||||
|
{
|
||||||
|
new(buf_.data()) iter_t<I>{
|
||||||
|
other.iter<I>()};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
copy(C<I+1>{}, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
equal(C<sizeof...(Bs)>,
|
||||||
|
const_iterator const&) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
bool
|
||||||
|
equal(C<I>, const_iterator const& other) const
|
||||||
|
{
|
||||||
|
if(n_ == I)
|
||||||
|
return iter<I>() == other.iter<I>();
|
||||||
|
return equal(C<I+1>{}, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
|
reference
|
||||||
|
dereference(C<sizeof...(Bs)>) const
|
||||||
|
{
|
||||||
|
throw std::logic_error("invalid iterator");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
reference
|
||||||
|
dereference(C<I>) const
|
||||||
|
{
|
||||||
|
if(n_ == I)
|
||||||
|
return *iter<I>();
|
||||||
|
return dereference(C<I+1>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
|
void
|
||||||
|
increment(C<sizeof...(Bs)>)
|
||||||
|
{
|
||||||
|
throw std::logic_error("invalid iterator");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
void
|
||||||
|
increment(C<I>)
|
||||||
|
{
|
||||||
|
if(n_ == I)
|
||||||
|
{
|
||||||
|
if(++iter<I>() !=
|
||||||
|
std::get<I>(*bs_).end())
|
||||||
|
return;
|
||||||
|
using Iter = iter_t<I>;
|
||||||
|
iter<I>().~Iter();
|
||||||
|
return construct(C<I+1>{});
|
||||||
|
}
|
||||||
|
increment(C<I+1>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
decrement(C<sizeof...(Bs)>)
|
||||||
|
{
|
||||||
|
auto constexpr I = sizeof...(Bs);
|
||||||
|
if(n_ == I)
|
||||||
|
{
|
||||||
|
--n_;
|
||||||
|
new(buf_.data()) iter_t<I-1>{
|
||||||
|
std::get<I-1>(*bs_).end()};
|
||||||
|
}
|
||||||
|
decrement(C<I-1>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
decrement(C<0>)
|
||||||
|
{
|
||||||
|
auto constexpr I = 0;
|
||||||
|
if(iter<I>() != std::get<I>(*bs_).begin())
|
||||||
|
{
|
||||||
|
--iter<I>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw std::logic_error("invalid iterator");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I>
|
||||||
|
void
|
||||||
|
decrement(C<I>)
|
||||||
|
{
|
||||||
|
if(n_ == I)
|
||||||
|
{
|
||||||
|
if(iter<I>() != std::get<I>(*bs_).begin())
|
||||||
|
{
|
||||||
|
--iter<I>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
--n_;
|
||||||
|
using Iter = iter_t<I>;
|
||||||
|
iter<I>().~Iter();
|
||||||
|
new(buf_.data()) iter_t<I-1>{
|
||||||
|
std::get<I-1>(*bs_).end()};
|
||||||
|
}
|
||||||
|
decrement(C<I-1>{});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::~const_iterator()
|
||||||
|
{
|
||||||
|
destroy(C<0>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::const_iterator()
|
||||||
|
: n_(sizeof...(Bs))
|
||||||
|
, bs_(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::const_iterator(
|
||||||
|
std::tuple<Bs...> const& bs, bool at_end)
|
||||||
|
: bs_(&bs)
|
||||||
|
{
|
||||||
|
if(at_end)
|
||||||
|
n_ = sizeof...(Bs);
|
||||||
|
else
|
||||||
|
construct(C<0>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::const_iterator(const_iterator&& other)
|
||||||
|
: n_(other.n_)
|
||||||
|
, bs_(other.bs_)
|
||||||
|
{
|
||||||
|
move(C<0>{}, std::move(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::const_iterator(const_iterator const& other)
|
||||||
|
: n_(other.n_)
|
||||||
|
, bs_(other.bs_)
|
||||||
|
{
|
||||||
|
copy(C<0>{}, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
auto
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::operator=(const_iterator&& other) ->
|
||||||
|
const_iterator&
|
||||||
|
{
|
||||||
|
if(&other == this)
|
||||||
|
return *this;
|
||||||
|
destroy(C<0>{});
|
||||||
|
n_ = other.n_;
|
||||||
|
bs_ = other.bs_;
|
||||||
|
move(C<0>{}, std::move(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
auto
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::operator=(const_iterator const& other) ->
|
||||||
|
const_iterator&
|
||||||
|
{
|
||||||
|
if(&other == this)
|
||||||
|
return *this;
|
||||||
|
destroy(C<0>{});
|
||||||
|
n_ = other.n_;
|
||||||
|
bs_ = other.bs_;
|
||||||
|
copy(C<0>{}, other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
bool
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
if(bs_ != other.bs_)
|
||||||
|
return false;
|
||||||
|
if(n_ != other.n_)
|
||||||
|
return false;
|
||||||
|
return equal(C<0>{}, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
auto
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::operator*() const ->
|
||||||
|
reference
|
||||||
|
{
|
||||||
|
return dereference(C<0>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
auto
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::operator++() ->
|
||||||
|
const_iterator&
|
||||||
|
{
|
||||||
|
increment(C<0>{});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
auto
|
||||||
|
append_buffers_helper<ValueType, Bs...>::
|
||||||
|
const_iterator::operator--() ->
|
||||||
|
const_iterator&
|
||||||
|
{
|
||||||
|
decrement(C<sizeof...(Bs)>{});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
auto
|
||||||
|
append_buffers_helper<ValueType, Bs...>::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator(bs_, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ValueType, class... Bs>
|
||||||
|
auto
|
||||||
|
append_buffers_helper<ValueType, Bs...>::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator(bs_, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Concatenate 2 or more buffer sequences to form a `ConstBufferSequence`.
|
||||||
|
|
||||||
|
This function returns a `ConstBufferSequence` that when iterated,
|
||||||
|
efficiently concatenates the input buffer sequences. Copies of the
|
||||||
|
arguments passed will be made; however, the returned object does
|
||||||
|
not take ownership of the underlying memory. The application is still
|
||||||
|
responsible for managing the lifetime of the referenced memory.
|
||||||
|
|
||||||
|
@param buffers The list of buffer sequences to concatenate.
|
||||||
|
|
||||||
|
@return A new `ConstBufferSequence` that represents the concatenation
|
||||||
|
of the input buffer sequences.
|
||||||
|
*/
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
template<class... BufferSequence>
|
||||||
|
implementation_defined
|
||||||
|
append_buffers(BufferSequence const&... buffers)
|
||||||
|
#else
|
||||||
|
template<class B1, class B2, class... Bn>
|
||||||
|
auto
|
||||||
|
append_buffers(B1 const& b1, B2 const& b2, Bn const&... bn)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return detail::append_buffers_helper<
|
||||||
|
boost::asio::const_buffer,
|
||||||
|
B1, B2, Bn...>(b1, b2, bn...);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
96
beast/asio/async_completion.h
Normal file
96
beast/asio/async_completion.h
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_ASYNC_COMPLETION_H_INLUDED
|
||||||
|
#define BEAST_ASIO_ASYNC_COMPLETION_H_INLUDED
|
||||||
|
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
|
#include <boost/asio/async_result.hpp>
|
||||||
|
#include <boost/asio/handler_type.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** Completion helper for implementing the extensible asynchronous model.
|
||||||
|
|
||||||
|
This class template is used to transform caller-provided
|
||||||
|
completion tokens in calls to asynchronous initiation
|
||||||
|
functions. The transformation allows customization of
|
||||||
|
the return type of the initiating function, and the type
|
||||||
|
of the final handler.
|
||||||
|
|
||||||
|
@tparam CompletionToken A CompletionHandler, or a user defined type
|
||||||
|
with specializations for customizing the return type (for example,
|
||||||
|
`boost::asio::use_future` or `boost::asio::yield_context`).
|
||||||
|
|
||||||
|
@tparam Signature The callable signature of the final completion handler.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
@code
|
||||||
|
template<class CompletionToken>
|
||||||
|
auto
|
||||||
|
async_initfn(..., CompletionToken&& token)
|
||||||
|
{
|
||||||
|
async_completion<CompletionToken,
|
||||||
|
void(error_code, std::size_t)> completion(token);
|
||||||
|
...
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
See <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf">
|
||||||
|
Library Foundations For Asynchronous Operations</a>
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <class CompletionToken, class Signature>
|
||||||
|
struct async_completion
|
||||||
|
{
|
||||||
|
/** The type of the final handler.
|
||||||
|
|
||||||
|
Objects of this type will be callable with the
|
||||||
|
specified signature.
|
||||||
|
*/
|
||||||
|
using handler_type =
|
||||||
|
typename boost::asio::handler_type<
|
||||||
|
CompletionToken, Signature>::type;
|
||||||
|
|
||||||
|
/** Construct the completion helper.
|
||||||
|
|
||||||
|
@param token The completion token. Copies will be made as
|
||||||
|
required. If `CompletionToken` is movable, it may also be moved.
|
||||||
|
*/
|
||||||
|
async_completion(std::remove_reference_t<CompletionToken>& token)
|
||||||
|
: handler(std::forward<CompletionToken>(token))
|
||||||
|
, result(handler)
|
||||||
|
{
|
||||||
|
static_assert(is_Handler<handler_type, Signature>::value,
|
||||||
|
"Handler requirements not met");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The final completion handler, callable with the specified signature. */
|
||||||
|
handler_type handler;
|
||||||
|
|
||||||
|
/** The return value of the asynchronous initiation function. */
|
||||||
|
boost::asio::async_result<handler_type> result;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
350
beast/asio/basic_streambuf.h
Normal file
350
beast/asio/basic_streambuf.h
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_BASIC_STREAMBUF_H_INCLUDED
|
||||||
|
#define BEAST_ASIO_BASIC_STREAMBUF_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/empty_base_optimization.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/intrusive/list.hpp>
|
||||||
|
#include <iterator>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** A `Streambuf` 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.
|
||||||
|
|
||||||
|
@tparam Allocator The allocator to use for managing memory.
|
||||||
|
*/
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_streambuf
|
||||||
|
#if ! GENERATING_DOCS
|
||||||
|
: private empty_base_optimization<
|
||||||
|
typename std::allocator_traits<Allocator>::
|
||||||
|
template rebind_alloc<std::uint8_t>>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using allocator_type = typename
|
||||||
|
std::allocator_traits<Allocator>::
|
||||||
|
template rebind_alloc<std::uint8_t>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
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:
|
||||||
|
class const_buffers_type;
|
||||||
|
|
||||||
|
class mutable_buffers_type;
|
||||||
|
|
||||||
|
/// Destructor.
|
||||||
|
~basic_streambuf();
|
||||||
|
|
||||||
|
/** Move constructor.
|
||||||
|
|
||||||
|
The output sequence of this object will be empty.
|
||||||
|
|
||||||
|
After the move, the moved-from object will have an
|
||||||
|
empty input and output sequence, with no internal
|
||||||
|
buffers allocated.
|
||||||
|
|
||||||
|
@param other The stream buffer to move from.
|
||||||
|
*/
|
||||||
|
basic_streambuf(basic_streambuf&& other);
|
||||||
|
|
||||||
|
/** Move constructor.
|
||||||
|
|
||||||
|
The output sequence of this object will be empty.
|
||||||
|
|
||||||
|
After the move, the moved-from object will have an
|
||||||
|
empty input and output sequence, with no internal
|
||||||
|
buffers allocated.
|
||||||
|
|
||||||
|
@param other The stream buffer to move from.
|
||||||
|
|
||||||
|
@param alloc The allocator to associate with the
|
||||||
|
stream buffer.
|
||||||
|
*/
|
||||||
|
basic_streambuf(basic_streambuf&& other,
|
||||||
|
allocator_type const& alloc);
|
||||||
|
|
||||||
|
/** Move assignment.
|
||||||
|
|
||||||
|
The output sequence of this object will be empty.
|
||||||
|
|
||||||
|
After the move, the moved-from object will have an
|
||||||
|
empty input and output sequence, with no internal
|
||||||
|
buffers allocated.
|
||||||
|
|
||||||
|
@param other The stream buffer to move from.
|
||||||
|
*/
|
||||||
|
basic_streambuf&
|
||||||
|
operator=(basic_streambuf&& other);
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
basic_streambuf(basic_streambuf const& other);
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
|
||||||
|
The output sequence of this object will be empty.
|
||||||
|
|
||||||
|
@param other The stream buffer to copy.
|
||||||
|
|
||||||
|
@param alloc The allocator to associate with the
|
||||||
|
stream buffer.
|
||||||
|
*/
|
||||||
|
basic_streambuf(basic_streambuf const& other,
|
||||||
|
allocator_type const& alloc);
|
||||||
|
|
||||||
|
/** Copy assignment.
|
||||||
|
|
||||||
|
The output sequence of this object will be empty.
|
||||||
|
|
||||||
|
@param other The stream buffer to copy.
|
||||||
|
*/
|
||||||
|
basic_streambuf& operator=(basic_streambuf const& other);
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
|
||||||
|
The output sequence of this object will be empty.
|
||||||
|
|
||||||
|
@param other The stream buffer to copy.
|
||||||
|
*/
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_streambuf(basic_streambuf<OtherAlloc> const& other);
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
|
||||||
|
The output sequence of this object will be empty.
|
||||||
|
|
||||||
|
@param other The stream buffer to copy.
|
||||||
|
|
||||||
|
@param alloc The allocator to associate with the
|
||||||
|
stream buffer.
|
||||||
|
*/
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_streambuf(basic_streambuf<OtherAlloc> const& other,
|
||||||
|
allocator_type const& alloc);
|
||||||
|
|
||||||
|
/** Copy assignment.
|
||||||
|
|
||||||
|
The output sequence of this object will be empty.
|
||||||
|
|
||||||
|
@param other The stream buffer to copy.
|
||||||
|
*/
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_streambuf& operator=(basic_streambuf<OtherAlloc> const& other);
|
||||||
|
|
||||||
|
/** 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.
|
||||||
|
|
||||||
|
@param alloc The allocator to use.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
basic_streambuf(std::size_t alloc_size = 1024,
|
||||||
|
Allocator const& alloc = allocator_type{});
|
||||||
|
|
||||||
|
/// Get the associated allocator
|
||||||
|
allocator_type
|
||||||
|
get_allocator() const
|
||||||
|
{
|
||||||
|
return this->member();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the maximum size of the basic_streambuf.
|
||||||
|
size_type
|
||||||
|
max_size() const
|
||||||
|
{
|
||||||
|
return std::numeric_limits<std::size_t>::max();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the size of the input sequence.
|
||||||
|
size_type
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return in_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a list of buffers that represents the output sequence, with the given size.
|
||||||
|
mutable_buffers_type
|
||||||
|
prepare(size_type n);
|
||||||
|
|
||||||
|
/// Move bytes from the output sequence to the input sequence.
|
||||||
|
void
|
||||||
|
commit(size_type n);
|
||||||
|
|
||||||
|
/// Get a list of buffers that represents the input sequence.
|
||||||
|
const_buffers_type
|
||||||
|
data() const;
|
||||||
|
|
||||||
|
/// Remove bytes from the input sequence.
|
||||||
|
void
|
||||||
|
consume(size_type n);
|
||||||
|
|
||||||
|
/// Clear everything.
|
||||||
|
void
|
||||||
|
clear();
|
||||||
|
|
||||||
|
// Helper for read_until
|
||||||
|
template<class OtherAllocator>
|
||||||
|
friend
|
||||||
|
std::size_t
|
||||||
|
read_size_helper(basic_streambuf<
|
||||||
|
OtherAllocator> const& streambuf, std::size_t max_size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
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();
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
prepare_size() const;
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_check() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The type used to represent the input sequence as a list of buffers.
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_streambuf<Allocator>::const_buffers_type
|
||||||
|
{
|
||||||
|
basic_streambuf const* sb_ = nullptr;
|
||||||
|
|
||||||
|
friend class basic_streambuf;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
const_buffers_type(basic_streambuf const& sb);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = boost::asio::const_buffer;
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
const_buffers_type() = default;
|
||||||
|
const_buffers_type(const_buffers_type const&) = default;
|
||||||
|
const_buffers_type& operator=(const_buffers_type const&) = default;
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
begin() const;
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
end() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The type used to represent the output sequence as a list of buffers.
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_streambuf<Allocator>::mutable_buffers_type
|
||||||
|
{
|
||||||
|
basic_streambuf const* sb_;
|
||||||
|
|
||||||
|
friend class basic_streambuf;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
mutable_buffers_type(basic_streambuf const& sb);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = mutable_buffer;
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
mutable_buffers_type() = default;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Format output to a stream buffer.
|
||||||
|
|
||||||
|
@param streambuf The streambuf to write to.
|
||||||
|
|
||||||
|
@param t The object to write.
|
||||||
|
|
||||||
|
@return The stream buffer.
|
||||||
|
*/
|
||||||
|
template<class Alloc, class T>
|
||||||
|
basic_streambuf<Alloc>&
|
||||||
|
operator<<(basic_streambuf<Alloc>& buf, T const& t);
|
||||||
|
|
||||||
|
/** Convert the entire basic_streambuf to a string.
|
||||||
|
|
||||||
|
@param streambuf The streambuf to convert.
|
||||||
|
|
||||||
|
@return A string representing the contents of the input sequence.
|
||||||
|
*/
|
||||||
|
template<class Allocator>
|
||||||
|
std::string
|
||||||
|
to_string(basic_streambuf<Allocator> const& streambuf);
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/asio/impl/basic_streambuf.ipp>
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -23,142 +23,151 @@
|
|||||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||||
#include <boost/asio/detail/handler_cont_helpers.hpp>
|
#include <boost/asio/detail/handler_cont_helpers.hpp>
|
||||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace asio {
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
/** Nullary handler that calls Handler with bound arguments.
|
/** Nullary handler that calls Handler with bound arguments.
|
||||||
The rebound handler provides the same io_service execution
|
|
||||||
|
The bound handler provides the same io_service execution
|
||||||
guarantees as the original handler.
|
guarantees as the original handler.
|
||||||
*/
|
*/
|
||||||
template <class DeducedHandler, class... Args>
|
template<class Handler, class... Args>
|
||||||
class bound_handler
|
class bound_handler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
using args_type = std::tuple <std::decay_t <Args>...>;
|
using args_type = std::tuple<std::decay_t<Args>...>;
|
||||||
|
|
||||||
std::decay_t <DeducedHandler> m_handler;
|
Handler h_;
|
||||||
args_type m_args;
|
args_type args_;
|
||||||
|
|
||||||
template <class Handler, class Tuple, std::size_t... S>
|
template<class Tuple, std::size_t... S>
|
||||||
static void invoke (Handler& h, Tuple& args,
|
static void invoke(Handler& h, Tuple& args,
|
||||||
std::index_sequence <S...>)
|
std::index_sequence <S...>)
|
||||||
{
|
{
|
||||||
h (std::get <S> (args)...);
|
h(std::get<S>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using result_type = void;
|
using result_type = void;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
explicit
|
explicit
|
||||||
bound_handler (DeducedHandler&& handler, Args&&... args)
|
bound_handler(DeducedHandler&& handler, Args&&... args)
|
||||||
: m_handler (std::forward <DeducedHandler> (handler))
|
: h_(std::forward<DeducedHandler>(handler))
|
||||||
, m_args (std::forward <Args> (args)...)
|
, args_(std::forward<Args>(args)...)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
operator() ()
|
operator()()
|
||||||
{
|
{
|
||||||
invoke (m_handler, m_args,
|
invoke(h_, args_,
|
||||||
std::index_sequence_for <Args...> ());
|
std::index_sequence_for<Args...> ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
operator() () const
|
operator()() const
|
||||||
{
|
{
|
||||||
invoke (m_handler, m_args,
|
invoke(h_, args_,
|
||||||
std::index_sequence_for <Args...> ());
|
std::index_sequence_for<Args...> ());
|
||||||
}
|
|
||||||
|
|
||||||
template <class Function>
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
asio_handler_invoke (Function& f, bound_handler* h)
|
|
||||||
{
|
|
||||||
boost_asio_handler_invoke_helpers::
|
|
||||||
invoke (f, h->m_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Function>
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
asio_handler_invoke (Function const& f, bound_handler* h)
|
|
||||||
{
|
|
||||||
boost_asio_handler_invoke_helpers::
|
|
||||||
invoke (f, h->m_handler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
void*
|
void*
|
||||||
asio_handler_allocate (std::size_t size, bound_handler* h)
|
asio_handler_allocate(
|
||||||
|
std::size_t size, bound_handler* h)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_alloc_helpers::
|
return boost_asio_handler_alloc_helpers::
|
||||||
allocate (size, h->m_handler);
|
allocate(size, h->h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
void
|
void
|
||||||
asio_handler_deallocate (void* p, std::size_t size, bound_handler* h)
|
asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, bound_handler* h)
|
||||||
{
|
{
|
||||||
boost_asio_handler_alloc_helpers::
|
boost_asio_handler_alloc_helpers::
|
||||||
deallocate (p, size, h->m_handler);
|
deallocate(p, size, h->h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
bool
|
bool
|
||||||
asio_handler_is_continuation (bound_handler* h)
|
asio_handler_is_continuation(bound_handler* h)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_cont_helpers::
|
return boost_asio_handler_cont_helpers::
|
||||||
is_continuation (h->m_handler);
|
is_continuation (h->h_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F>
|
||||||
|
friend
|
||||||
|
void
|
||||||
|
asio_handler_invoke(F&& f, bound_handler* h)
|
||||||
|
{
|
||||||
|
boost_asio_handler_invoke_helpers::
|
||||||
|
invoke(f, h->h_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // detail
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
/** Binds parameters to a handler to produce a nullary functor.
|
/** Bind parameters to a completion handler, creating a wrapped handler.
|
||||||
The returned handler provides the same io_service execution guarantees
|
|
||||||
as the original handler. This is designed to use as a replacement for
|
This function creates a new handler which invoked with no parameters
|
||||||
io_service::wrap, to ensure that the handler will not be invoked
|
calls the original handler with the list of bound arguments. The passed
|
||||||
immediately by the calling function.
|
handler and arguments are forwarded into the returned handler, which
|
||||||
|
provides the same `io_service` execution guarantees as the original
|
||||||
|
handler.
|
||||||
|
|
||||||
|
Unlike `io_service::wrap`, the returned handler can be used in a
|
||||||
|
subsequent call to `io_service::post` instead of `io_service::dispatch`,
|
||||||
|
to ensure that the handler will not be invoked immediately by the
|
||||||
|
calling function.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@code
|
||||||
|
template<class AsyncReadStream, ReadHandler>
|
||||||
|
void
|
||||||
|
do_cancel(AsyncReadStream& stream, ReadHandler&& handler)
|
||||||
|
{
|
||||||
|
stream.get_io_service().post(
|
||||||
|
bind_handler(std::forward<ReadHandler>(handler),
|
||||||
|
boost::asio::error::operation_aborted, 0));
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@param handler The handler to wrap.
|
||||||
|
|
||||||
|
@param args A list of arguments to bind to the handler. The
|
||||||
|
arguments are forwarded into the returned
|
||||||
|
|
||||||
*/
|
*/
|
||||||
template <class DeducedHandler, class... Args>
|
template<class CompletionHandler, class... Args>
|
||||||
detail::bound_handler <DeducedHandler, Args...>
|
#if GENERATING_DOCS
|
||||||
bind_handler (DeducedHandler&& handler, Args&&... args)
|
implementation_defined
|
||||||
|
#else
|
||||||
|
detail::bound_handler<std::decay_t<CompletionHandler>, Args...>
|
||||||
|
#endif
|
||||||
|
bind_handler(CompletionHandler&& handler, Args&&... args)
|
||||||
{
|
{
|
||||||
return detail::bound_handler <DeducedHandler, Args...> (
|
return detail::bound_handler<std::decay_t<
|
||||||
std::forward <DeducedHandler> (handler),
|
CompletionHandler>, Args...>(std::forward<
|
||||||
std::forward <Args> (args)...);
|
CompletionHandler>(handler),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // beast
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
template<class Handler, class... Args>
|
||||||
template <class Handler, class... Args>
|
void bind(beast::detail::bound_handler<
|
||||||
void bind (beast::asio::detail::bound_handler <
|
|
||||||
Handler, Args...>, ...) = delete;
|
Handler, Args...>, ...) = delete;
|
||||||
|
} // std
|
||||||
#if 0
|
|
||||||
template <class Handler, class... Args>
|
|
||||||
struct is_bind_expression <
|
|
||||||
beast::asio::detail::bound_handler <Handler, Args...>
|
|
||||||
> : std::true_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
648
beast/asio/buffers_adapter.h
Normal file
648
beast/asio/buffers_adapter.h
Normal file
@@ -0,0 +1,648 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_BUFFERS_ADAPTER_H_INLUDED
|
||||||
|
#define BEAST_ASIO_BUFFERS_ADAPTER_H_INLUDED
|
||||||
|
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iterator>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** Adapts a `MutableBufferSequence` into a `Streambuf`.
|
||||||
|
|
||||||
|
This class wraps a `MutableBufferSequence` to meet the requirements
|
||||||
|
of `Streambuf`. Upon construction the input and output sequences are
|
||||||
|
empty. A copy of the mutable buffer sequence object is stored; however,
|
||||||
|
ownership of the underlying memory is not transferred. The caller is
|
||||||
|
responsible for making sure that referenced memory remains valid
|
||||||
|
for the duration of any operations.
|
||||||
|
|
||||||
|
The size of the mutable buffer sequence determines the maximum
|
||||||
|
number of bytes which may be prepared and committed.
|
||||||
|
|
||||||
|
@tparam Buffers The type of mutable buffer sequence to wrap.
|
||||||
|
*/
|
||||||
|
template<class Buffers>
|
||||||
|
class buffers_adapter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using buffers_type = std::decay_t<Buffers>;
|
||||||
|
using iter_type = typename buffers_type::const_iterator;
|
||||||
|
|
||||||
|
static auto constexpr is_mutable =
|
||||||
|
std::is_constructible<boost::asio::mutable_buffer,
|
||||||
|
typename std::iterator_traits<iter_type>::value_type>::value;
|
||||||
|
|
||||||
|
Buffers bs_;
|
||||||
|
iter_type begin_;
|
||||||
|
iter_type out_;
|
||||||
|
iter_type end_;
|
||||||
|
std::size_t max_size_;
|
||||||
|
std::size_t in_pos_ = 0; // offset in *begin_
|
||||||
|
std::size_t in_size_ = 0; // size of input sequence
|
||||||
|
std::size_t out_pos_ = 0; // offset in *out_
|
||||||
|
std::size_t out_end_ = 0; // output end offset
|
||||||
|
|
||||||
|
template<class Deduced>
|
||||||
|
buffers_adapter(Deduced&& other,
|
||||||
|
std::size_t nbegin, std::size_t nout,
|
||||||
|
std::size_t nend)
|
||||||
|
: bs_(std::forward<Deduced>(other).bs_)
|
||||||
|
, begin_(std::next(bs_.begin(), nbegin))
|
||||||
|
, out_(std::next(bs_.begin(), nout))
|
||||||
|
, end_(std::next(bs_.begin(), nend))
|
||||||
|
, max_size_(other.max_size_)
|
||||||
|
, in_pos_(other.in_pos_)
|
||||||
|
, in_size_(other.in_size_)
|
||||||
|
, out_pos_(other.out_pos_)
|
||||||
|
, out_end_(other.out_end_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
class const_buffers_type;
|
||||||
|
class mutable_buffers_type;
|
||||||
|
|
||||||
|
// Move constructor.
|
||||||
|
buffers_adapter(buffers_adapter&& other);
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
buffers_adapter(buffers_adapter const& other);
|
||||||
|
|
||||||
|
// Move assignment.
|
||||||
|
buffers_adapter& operator=(buffers_adapter&& other);
|
||||||
|
|
||||||
|
// Copy assignment.
|
||||||
|
buffers_adapter& operator=(buffers_adapter const&);
|
||||||
|
|
||||||
|
/** Construct a buffers adapter.
|
||||||
|
|
||||||
|
@param buffers The mutable buffer sequence to wrap. A copy of
|
||||||
|
the object will be made, but ownership of the memory is not
|
||||||
|
transferred.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
buffers_adapter(Buffers const& buffers);
|
||||||
|
|
||||||
|
/// Returns the largest size output sequence possible.
|
||||||
|
std::size_t
|
||||||
|
max_size() const
|
||||||
|
{
|
||||||
|
return max_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the size of the input sequence.
|
||||||
|
std::size_t
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return in_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a list of buffers that represents the output sequence, with the given size.
|
||||||
|
|
||||||
|
@throws std::length_error if the size would exceed the limit
|
||||||
|
imposed by the underlying mutable buffer sequence.
|
||||||
|
*/
|
||||||
|
mutable_buffers_type
|
||||||
|
prepare(std::size_t n);
|
||||||
|
|
||||||
|
/// Move bytes from the output sequence to the input sequence.
|
||||||
|
void
|
||||||
|
commit(std::size_t n);
|
||||||
|
|
||||||
|
/// Get a list of buffers that represents the input sequence.
|
||||||
|
const_buffers_type
|
||||||
|
data() const;
|
||||||
|
|
||||||
|
/// Remove bytes from the input sequence.
|
||||||
|
void
|
||||||
|
consume(std::size_t n);
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// The type used to represent the input sequence as a list of buffers.
|
||||||
|
template<class Buffers>
|
||||||
|
class buffers_adapter<Buffers>::const_buffers_type
|
||||||
|
{
|
||||||
|
buffers_adapter const* ba_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = boost::asio::const_buffer;
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
const_buffers_type() = default;
|
||||||
|
const_buffers_type(
|
||||||
|
const_buffers_type const&) = default;
|
||||||
|
const_buffers_type& operator=(
|
||||||
|
const_buffers_type const&) = default;
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
begin() const;
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
end() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class buffers_adapter;
|
||||||
|
|
||||||
|
const_buffers_type(buffers_adapter const& ba)
|
||||||
|
: ba_(&ba)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
class buffers_adapter<Buffers>::const_buffers_type::const_iterator
|
||||||
|
{
|
||||||
|
iter_type it_;
|
||||||
|
buffers_adapter const* ba_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = boost::asio::const_buffer;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return ba_ == other.ba_ &&
|
||||||
|
it_ == other.it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
return value_type{buffer_cast<void const*>(*it_),
|
||||||
|
(ba_->out_ == ba_->bs_.end() ||
|
||||||
|
it_ != ba_->out_) ? buffer_size(*it_) : ba_->out_pos_} +
|
||||||
|
(it_ == ba_->begin_ ? ba_->in_pos_ : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
--it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class const_buffers_type;
|
||||||
|
|
||||||
|
const_iterator(buffers_adapter const& ba,
|
||||||
|
iter_type iter)
|
||||||
|
: it_(iter)
|
||||||
|
, ba_(&ba)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
buffers_adapter<Buffers>::const_buffers_type::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*ba_, ba_->begin_};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
buffers_adapter<Buffers>::const_buffers_type::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*ba_, ba_->out_ ==
|
||||||
|
ba_->end_ ? ba_->end_ : std::next(ba_->out_)};
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// The type used to represent the output sequence as a list of buffers.
|
||||||
|
template<class Buffers>
|
||||||
|
class buffers_adapter<Buffers>::mutable_buffers_type
|
||||||
|
{
|
||||||
|
buffers_adapter const* ba_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = boost::asio::mutable_buffer;
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
mutable_buffers_type() = default;
|
||||||
|
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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class buffers_adapter;
|
||||||
|
|
||||||
|
mutable_buffers_type(
|
||||||
|
buffers_adapter const& ba)
|
||||||
|
: ba_(&ba)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
class buffers_adapter<Buffers>::mutable_buffers_type::const_iterator
|
||||||
|
{
|
||||||
|
iter_type it_;
|
||||||
|
buffers_adapter const* ba_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = boost::asio::mutable_buffer;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return ba_ == other.ba_ &&
|
||||||
|
it_ == other.it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
return value_type{buffer_cast<void*>(*it_),
|
||||||
|
it_ == std::prev(ba_->end_) ?
|
||||||
|
ba_->out_end_ : buffer_size(*it_)} +
|
||||||
|
(it_ == ba_->out_ ? ba_->out_pos_ : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
--it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class mutable_buffers_type;
|
||||||
|
|
||||||
|
const_iterator(buffers_adapter const& ba,
|
||||||
|
iter_type iter)
|
||||||
|
: it_(iter)
|
||||||
|
, ba_(&ba)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
buffers_adapter<Buffers>::mutable_buffers_type::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*ba_, ba_->out_};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
buffers_adapter<Buffers>::mutable_buffers_type::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*ba_, ba_->end_};
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
buffers_adapter<Buffers>::buffers_adapter(
|
||||||
|
buffers_adapter&& other)
|
||||||
|
: buffers_adapter(std::move(other),
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.begin_),
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.out_),
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.end_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
buffers_adapter<Buffers>::buffers_adapter(
|
||||||
|
buffers_adapter const& other)
|
||||||
|
: buffers_adapter(other,
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.begin_),
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.out_),
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.end_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
auto
|
||||||
|
buffers_adapter<Buffers>::operator=(
|
||||||
|
buffers_adapter&& other) -> buffers_adapter&
|
||||||
|
{
|
||||||
|
auto const nbegin = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.begin_);
|
||||||
|
auto const nout = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.out_);
|
||||||
|
auto const nend = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.end_);
|
||||||
|
bs_ = std::move(other.bs_);
|
||||||
|
begin_ = std::next(bs_.begin(), nbegin);
|
||||||
|
out_ = std::next(bs_.begin(), nout);
|
||||||
|
end_ = std::next(bs_.begin(), nend);
|
||||||
|
max_size_ = other.max_size_;
|
||||||
|
in_pos_ = other.in_pos_;
|
||||||
|
in_size_ = other.in_size_;
|
||||||
|
out_pos_ = other.out_pos_;
|
||||||
|
out_end_ = other.out_end_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
auto
|
||||||
|
buffers_adapter<Buffers>::operator=(
|
||||||
|
buffers_adapter const& other) -> buffers_adapter&
|
||||||
|
{
|
||||||
|
auto const nbegin = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.begin_);
|
||||||
|
auto const nout = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.out_);
|
||||||
|
auto const nend = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.end_);
|
||||||
|
bs_ = other.bs_;
|
||||||
|
begin_ = std::next(bs_.begin(), nbegin);
|
||||||
|
out_ = std::next(bs_.begin(), nout);
|
||||||
|
end_ = std::next(bs_.begin(), nend);
|
||||||
|
max_size_ = other.max_size_;
|
||||||
|
in_pos_ = other.in_pos_;
|
||||||
|
in_size_ = other.in_size_;
|
||||||
|
out_pos_ = other.out_pos_;
|
||||||
|
out_end_ = other.out_end_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
buffers_adapter<Buffers>::buffers_adapter(
|
||||||
|
Buffers const& bs)
|
||||||
|
: bs_(bs)
|
||||||
|
, begin_(bs_.begin())
|
||||||
|
, out_(bs_.begin())
|
||||||
|
, end_(bs_.begin())
|
||||||
|
, max_size_(boost::asio::buffer_size(bs_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
auto
|
||||||
|
buffers_adapter<Buffers>::prepare(std::size_t n) ->
|
||||||
|
mutable_buffers_type
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
static_assert(is_mutable,
|
||||||
|
"Operation not valid for ConstBufferSequence");
|
||||||
|
end_ = out_;
|
||||||
|
if(end_ != bs_.end())
|
||||||
|
{
|
||||||
|
auto size = buffer_size(*end_) - out_pos_;
|
||||||
|
if(n > size)
|
||||||
|
{
|
||||||
|
n -= size;
|
||||||
|
while(++end_ != bs_.end())
|
||||||
|
{
|
||||||
|
size = buffer_size(*end_);
|
||||||
|
if(n < size)
|
||||||
|
{
|
||||||
|
out_end_ = n;
|
||||||
|
n = 0;
|
||||||
|
++end_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n -= size;
|
||||||
|
out_end_ = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++end_;
|
||||||
|
out_end_ = out_pos_ + n;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(n > 0)
|
||||||
|
throw std::length_error(
|
||||||
|
"no space in buffers_adapter");
|
||||||
|
return mutable_buffers_type{*this};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
void
|
||||||
|
buffers_adapter<Buffers>::commit(std::size_t n)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
static_assert(is_mutable,
|
||||||
|
"Operation not valid for ConstBufferSequence");
|
||||||
|
if(out_ == end_)
|
||||||
|
return;
|
||||||
|
auto const last = std::prev(end_);
|
||||||
|
while(out_ != last)
|
||||||
|
{
|
||||||
|
auto const avail =
|
||||||
|
buffer_size(*out_) - out_pos_;
|
||||||
|
if(n < avail)
|
||||||
|
{
|
||||||
|
out_pos_ += n;
|
||||||
|
in_size_ += n;
|
||||||
|
max_size_ -= n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++out_;
|
||||||
|
n -= avail;
|
||||||
|
out_pos_ = 0;
|
||||||
|
in_size_ += avail;
|
||||||
|
max_size_ -= avail;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = std::min(n, out_end_ - out_pos_);
|
||||||
|
out_pos_ += n;
|
||||||
|
in_size_ += n;
|
||||||
|
max_size_ -= n;
|
||||||
|
if(out_pos_ == buffer_size(*out_))
|
||||||
|
{
|
||||||
|
++out_;
|
||||||
|
out_pos_ = 0;
|
||||||
|
out_end_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
buffers_adapter<Buffers>::data() const ->
|
||||||
|
const_buffers_type
|
||||||
|
{
|
||||||
|
return const_buffers_type{*this};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
void
|
||||||
|
buffers_adapter<Buffers>::consume(std::size_t n)
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if(begin_ != out_)
|
||||||
|
{
|
||||||
|
auto const avail =
|
||||||
|
buffer_size(*begin_) - in_pos_;
|
||||||
|
if(n < avail)
|
||||||
|
{
|
||||||
|
in_size_ -= n;
|
||||||
|
in_pos_ += n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n -= avail;
|
||||||
|
in_size_ -= avail;
|
||||||
|
in_pos_ = 0;
|
||||||
|
++begin_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const avail = out_pos_ - in_pos_;
|
||||||
|
if(n < avail)
|
||||||
|
{
|
||||||
|
in_size_ -= n;
|
||||||
|
in_pos_ += n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
in_size_ -= avail;
|
||||||
|
if(out_pos_ != out_end_||
|
||||||
|
out_ != std::prev(bs_.end()))
|
||||||
|
{
|
||||||
|
in_pos_ = out_pos_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use the whole buffer now.
|
||||||
|
in_pos_ = 0;
|
||||||
|
out_pos_ = 0;
|
||||||
|
out_end_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
52
beast/asio/buffers_debug.h
Normal file
52
beast/asio/buffers_debug.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_BUFFERS_DEBUG_H_INLUDED
|
||||||
|
#define BEAST_ASIO_BUFFERS_DEBUG_H_INLUDED
|
||||||
|
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace debug {
|
||||||
|
|
||||||
|
template<class Buffers>
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
buffers_to_string(Buffers const& bs)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string s;
|
||||||
|
s.reserve(buffer_size(bs));
|
||||||
|
for(auto const& b : bs)
|
||||||
|
s.append(buffer_cast<char const*>(b),
|
||||||
|
buffer_size(b));
|
||||||
|
for(auto i = s.size(); i-- > 0;)
|
||||||
|
if(s[i] == '\r')
|
||||||
|
s.replace(i, 1, "\\r");
|
||||||
|
else if(s[i] == '\n')
|
||||||
|
s.replace(i, 1, "\\n\n");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // debug
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
309
beast/asio/consuming_buffers.h
Normal file
309
beast/asio/consuming_buffers.h
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_CONSUMING_BUFFERS_H_INLUDED
|
||||||
|
#define BEAST_ASIO_CONSUMING_BUFFERS_H_INLUDED
|
||||||
|
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** Adapter to trim the front of a `BufferSequence`.
|
||||||
|
|
||||||
|
This adapter wraps a buffer sequence to create a new sequence
|
||||||
|
which may be incrementally consumed. Bytes consumed are removed
|
||||||
|
from the front of the buffer. The underlying memory is not changed,
|
||||||
|
instead the adapter efficiently iterates through a subset of
|
||||||
|
the buffers wrapped.
|
||||||
|
|
||||||
|
The wrapped buffer is not modified, a copy is made instead.
|
||||||
|
Ownership of the underlying memory is not transferred, the application
|
||||||
|
is still responsible for managing its lifetime.
|
||||||
|
|
||||||
|
@tparam Buffers The buffer sequence to wrap.
|
||||||
|
|
||||||
|
@ptaram ValueType The type of buffer of the final buffer sequence. This
|
||||||
|
can be different from the buffer type of the wrapped sequence. For
|
||||||
|
example, a `MutableBufferSequence` can be transformed into a
|
||||||
|
consumable `ConstBufferSequence`. Violations of buffer const safety
|
||||||
|
are not permitted, and will result in a compile error.
|
||||||
|
*/
|
||||||
|
template<class Buffers,
|
||||||
|
class ValueType = typename Buffers::value_type>
|
||||||
|
class consuming_buffers
|
||||||
|
{
|
||||||
|
using iter_type =
|
||||||
|
typename Buffers::const_iterator;
|
||||||
|
|
||||||
|
static_assert(std::is_constructible<ValueType,
|
||||||
|
typename std::iterator_traits<iter_type>::value_type>::value,
|
||||||
|
"ValueType requirements not met");
|
||||||
|
|
||||||
|
Buffers bs_;
|
||||||
|
iter_type begin_;
|
||||||
|
std::size_t skip_ = 0;
|
||||||
|
|
||||||
|
template<class Deduced>
|
||||||
|
consuming_buffers(Deduced&& other, std::size_t nbegin)
|
||||||
|
: bs_(std::forward<Deduced>(other).bs_)
|
||||||
|
, begin_(std::next(bs_.begin(), nbegin))
|
||||||
|
, skip_(other.skip_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The type for each element in the list of buffers.
|
||||||
|
using value_type = ValueType;
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
/// Move constructor.
|
||||||
|
consuming_buffers(consuming_buffers&&);
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
consuming_buffers(consuming_buffers const&);
|
||||||
|
|
||||||
|
/// Move assignment.
|
||||||
|
consuming_buffers& operator=(consuming_buffers&&);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
consuming_buffers& operator=(consuming_buffers const&);
|
||||||
|
|
||||||
|
/** Construct to represent a buffer sequence.
|
||||||
|
|
||||||
|
A copy of the buffer sequence is made. Ownership of the
|
||||||
|
underlying memory is not transferred or copied.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
consuming_buffers(Buffers const& buffers);
|
||||||
|
|
||||||
|
/// Get a bidirectional iterator to the first element.
|
||||||
|
const_iterator
|
||||||
|
begin() const;
|
||||||
|
|
||||||
|
/// Get a bidirectional iterator for one past the last element.
|
||||||
|
const_iterator
|
||||||
|
end() const;
|
||||||
|
|
||||||
|
/** Remove bytes from the beginning of the sequence.
|
||||||
|
|
||||||
|
@param n The number of bytes to remove. If this is
|
||||||
|
larger than the number of bytes remaining, all the
|
||||||
|
bytes remaining are removed.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
consume(std::size_t n);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A bidirectional iterator type that may be used to read elements.
|
||||||
|
template<class Buffers, class ValueType>
|
||||||
|
class consuming_buffers<Buffers, ValueType>::const_iterator
|
||||||
|
{
|
||||||
|
friend class consuming_buffers<Buffers, ValueType>;
|
||||||
|
|
||||||
|
using iter_type =
|
||||||
|
typename Buffers::const_iterator;
|
||||||
|
|
||||||
|
iter_type it_;
|
||||||
|
consuming_buffers const* b_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type =
|
||||||
|
typename std::iterator_traits<iter_type>::value_type;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return b_ == other.b_ && it_ == other.it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
if(it_ == b_->begin_)
|
||||||
|
return *it_ + b_->skip_;
|
||||||
|
return *it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
--it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const_iterator(consuming_buffers const& b,
|
||||||
|
iter_type it)
|
||||||
|
: it_(it)
|
||||||
|
, b_(&b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Buffers, class ValueType>
|
||||||
|
consuming_buffers<Buffers, ValueType>::
|
||||||
|
consuming_buffers(consuming_buffers&& other)
|
||||||
|
: consuming_buffers(std::move(other),
|
||||||
|
std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.begin_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers, class ValueType>
|
||||||
|
consuming_buffers<Buffers, ValueType>::
|
||||||
|
consuming_buffers(consuming_buffers const& other)
|
||||||
|
: consuming_buffers(other,
|
||||||
|
std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.begin_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers, class ValueType>
|
||||||
|
auto
|
||||||
|
consuming_buffers<Buffers, ValueType>::
|
||||||
|
operator=(consuming_buffers&& other) ->
|
||||||
|
consuming_buffers&
|
||||||
|
{
|
||||||
|
auto const nbegin = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.begin_);
|
||||||
|
bs_ = std::move(other.bs_);
|
||||||
|
begin_ = std::next(bs_.begin(), nbegin);
|
||||||
|
skip_ = other.skip_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers, class ValueType>
|
||||||
|
auto
|
||||||
|
consuming_buffers<Buffers, ValueType>::
|
||||||
|
operator=(consuming_buffers const& other) ->
|
||||||
|
consuming_buffers&
|
||||||
|
{
|
||||||
|
auto const nbegin = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.begin_);
|
||||||
|
bs_ = other.bs_;
|
||||||
|
begin_ = std::next(bs_.begin(), nbegin);
|
||||||
|
skip_ = other.skip_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers, class ValueType>
|
||||||
|
consuming_buffers<Buffers, ValueType>::
|
||||||
|
consuming_buffers(Buffers const& bs)
|
||||||
|
: bs_(bs)
|
||||||
|
, begin_(bs_.begin())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers, class ValueType>
|
||||||
|
auto
|
||||||
|
consuming_buffers<Buffers, ValueType>::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*this, begin_};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers, class ValueType>
|
||||||
|
auto
|
||||||
|
consuming_buffers<Buffers, ValueType>::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*this, bs_.end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Buffers, class ValueType>
|
||||||
|
void
|
||||||
|
consuming_buffers<Buffers, ValueType>::consume(std::size_t n)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
for(;n > 0 && begin_ != bs_.end(); ++begin_)
|
||||||
|
{
|
||||||
|
auto const len =
|
||||||
|
buffer_size(*begin_) - skip_;
|
||||||
|
if(n < len)
|
||||||
|
{
|
||||||
|
skip_ += n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n -= len;
|
||||||
|
skip_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a consumed buffer
|
||||||
|
template<class Buffers>
|
||||||
|
consuming_buffers<Buffers, typename Buffers::value_type>
|
||||||
|
consumed_buffers(Buffers const& bs, std::size_t n)
|
||||||
|
{
|
||||||
|
consuming_buffers<Buffers> cb(bs);
|
||||||
|
cb.consume(n);
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
150
beast/asio/handler_alloc.h
Normal file
150
beast/asio/handler_alloc.h
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_HANDLER_ALLOC_H_INCLUDED
|
||||||
|
#define BEAST_ASIO_HANDLER_ALLOC_H_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
// Guidance from
|
||||||
|
// http://howardhinnant.github.io/allocator_boilerplate.html
|
||||||
|
|
||||||
|
/** An allocator that uses handler customizations.
|
||||||
|
|
||||||
|
This allocator uses the handler customizations `asio_handler_allocate`
|
||||||
|
and `asio_handler_deallocate` to manage memory.
|
||||||
|
|
||||||
|
@tparam T The type of object
|
||||||
|
|
||||||
|
@tparam Handler The type of handler.
|
||||||
|
*/
|
||||||
|
template <class T, class Handler>
|
||||||
|
class handler_alloc
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// We want a partial template specialization as a friend
|
||||||
|
// but that isn't allowed so we friend all versions. This
|
||||||
|
// should produce a compile error if Handler is not
|
||||||
|
// constructible from H.
|
||||||
|
//
|
||||||
|
template <class U, class H>
|
||||||
|
friend class handler_alloc;
|
||||||
|
|
||||||
|
Handler h_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
using is_always_equal = std::true_type;
|
||||||
|
|
||||||
|
handler_alloc() = delete;
|
||||||
|
handler_alloc(handler_alloc&&) = default;
|
||||||
|
handler_alloc(handler_alloc const&) = default;
|
||||||
|
handler_alloc& operator=(handler_alloc&&) = default;
|
||||||
|
handler_alloc& operator=(handler_alloc const&) = default;
|
||||||
|
|
||||||
|
/** Construct the allocator.
|
||||||
|
|
||||||
|
The handler is moved or copied into the allocator.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
handler_alloc(Handler&& h)
|
||||||
|
: h_(std::move(h))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Construct the allocator.
|
||||||
|
|
||||||
|
A copy of the handler is made.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
handler_alloc(Handler const& h)
|
||||||
|
: h_(h)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
handler_alloc(
|
||||||
|
handler_alloc<U, Handler>&& other)
|
||||||
|
: h_(std::move(other.h_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
handler_alloc(
|
||||||
|
handler_alloc<U, Handler> const& other)
|
||||||
|
: h_(other.h_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type*
|
||||||
|
allocate(std::ptrdiff_t n)
|
||||||
|
{
|
||||||
|
auto const size = n * sizeof(T);
|
||||||
|
return static_cast<value_type*>(
|
||||||
|
boost_asio_handler_alloc_helpers::allocate(
|
||||||
|
size, h_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
deallocate(value_type* p, std::ptrdiff_t n)
|
||||||
|
{
|
||||||
|
auto const size = n * sizeof(T);
|
||||||
|
boost_asio_handler_alloc_helpers::deallocate(
|
||||||
|
p, size, h_);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// Work-around for MSVC not using allocator_traits
|
||||||
|
// in the implementation of shared_ptr
|
||||||
|
//
|
||||||
|
void
|
||||||
|
destroy(T* t)
|
||||||
|
{
|
||||||
|
t->~T();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
friend
|
||||||
|
bool
|
||||||
|
operator==(handler_alloc const& lhs,
|
||||||
|
handler_alloc<U, Handler> const& rhs)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
friend
|
||||||
|
bool
|
||||||
|
operator!=(handler_alloc const& lhs,
|
||||||
|
handler_alloc<U, Handler> const& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
847
beast/asio/impl/basic_streambuf.ipp
Normal file
847
beast/asio/impl/basic_streambuf.ipp
Normal file
@@ -0,0 +1,847 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_BASIC_STREAMBUF_IPP_INCLUDED
|
||||||
|
#define BEAST_ASIO_BASIC_STREAMBUF_IPP_INCLUDED
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <exception>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/* These diagrams illustrate the layout and state variables.
|
||||||
|
|
||||||
|
Input and output contained entirely in one element:
|
||||||
|
|
||||||
|
0 out_
|
||||||
|
|<-------------+------------------------------------------->|
|
||||||
|
in_pos_ out_pos_ out_end_
|
||||||
|
|
||||||
|
|
||||||
|
Output contained in first and second elements:
|
||||||
|
|
||||||
|
out_
|
||||||
|
|<------+----------+------->| |<----------+-------------->|
|
||||||
|
in_pos_ out_pos_ out_end_
|
||||||
|
|
||||||
|
|
||||||
|
Output contained in the second element:
|
||||||
|
|
||||||
|
out_
|
||||||
|
|<------------+------------>| |<----+-------------------->|
|
||||||
|
in_pos_ out_pos_ out_end_
|
||||||
|
|
||||||
|
|
||||||
|
Output contained in second and third elements:
|
||||||
|
|
||||||
|
out_
|
||||||
|
|<-----+-------->| |<-------+------>| |<--------------->|
|
||||||
|
in_pos_ out_pos_ out_end_
|
||||||
|
|
||||||
|
|
||||||
|
Input sequence is empty:
|
||||||
|
|
||||||
|
out_
|
||||||
|
|<------+------------------>| |<-----------+------------->|
|
||||||
|
out_pos_ out_end_
|
||||||
|
in_pos_
|
||||||
|
|
||||||
|
|
||||||
|
Output sequence is empty:
|
||||||
|
|
||||||
|
out_
|
||||||
|
|<------+------------------>| |<------+------------------>|
|
||||||
|
in_pos_ out_pos_
|
||||||
|
out_end_
|
||||||
|
|
||||||
|
|
||||||
|
The end of output can point to the end of an element.
|
||||||
|
But out_pos_ should never point to the end:
|
||||||
|
|
||||||
|
out_
|
||||||
|
|<------+------------------>| |<------+------------------>|
|
||||||
|
in_pos_ out_pos_ out_end_
|
||||||
|
|
||||||
|
|
||||||
|
When the input sequence entirely fills the last element and
|
||||||
|
the output sequence is empty, out_ will point to the end of
|
||||||
|
the list of buffers, and out_pos_ and out_end_ will be 0:
|
||||||
|
|
||||||
|
|
||||||
|
|<------+------------------>| out_ == list_.end()
|
||||||
|
in_pos_ out_pos_ == 0
|
||||||
|
out_end_ == 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_streambuf<Allocator>::element
|
||||||
|
: public boost::intrusive::list_base_hook<
|
||||||
|
boost::intrusive::link_mode<
|
||||||
|
boost::intrusive::normal_link>>
|
||||||
|
{
|
||||||
|
using size_type = typename std::allocator_traits<Allocator>::size_type;
|
||||||
|
|
||||||
|
size_type const size_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
element(element const&) = delete;
|
||||||
|
element& operator=(element const&) = delete;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
element(size_type n)
|
||||||
|
: size_(n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
data() const
|
||||||
|
{
|
||||||
|
return const_cast<char*>(
|
||||||
|
reinterpret_cast<char const*>(this+1));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_streambuf<Allocator>::const_buffers_type::const_iterator
|
||||||
|
{
|
||||||
|
basic_streambuf const* sb_ = nullptr;
|
||||||
|
typename list_type::const_iterator it_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type =
|
||||||
|
typename const_buffers_type::value_type;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
const_iterator(basic_streambuf const& sb,
|
||||||
|
typename list_type::const_iterator const& it)
|
||||||
|
: sb_(&sb)
|
||||||
|
, it_(it)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return sb_ == other.sb_ && it_ == other.it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
auto const& e = *it_;
|
||||||
|
return value_type{e.data(),
|
||||||
|
(sb_->out_ == sb_->list_.end() ||
|
||||||
|
&e != &*sb_->out_) ? e.size() : sb_->out_pos_} +
|
||||||
|
(&e == &*sb_->list_.begin() ? sb_->in_pos_ : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
--it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_streambuf<Allocator>::const_buffers_type::const_buffers_type(
|
||||||
|
basic_streambuf const& sb)
|
||||||
|
: sb_(&sb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_streambuf<Allocator>::const_buffers_type::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*sb_, sb_->list_.begin()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_streambuf<Allocator>::const_buffers_type::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*sb_, sb_->out_ ==
|
||||||
|
sb_->list_.end() ? sb_->list_.end() :
|
||||||
|
std::next(sb_->out_)};
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_streambuf<Allocator>::mutable_buffers_type::const_iterator
|
||||||
|
{
|
||||||
|
basic_streambuf const* sb_ = nullptr;
|
||||||
|
typename list_type::const_iterator it_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type =
|
||||||
|
typename mutable_buffers_type::value_type;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
const_iterator(basic_streambuf const& sb,
|
||||||
|
typename list_type::const_iterator const& it)
|
||||||
|
: sb_(&sb)
|
||||||
|
, it_(it)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return sb_ == other.sb_ && it_ == other.it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
auto const& e = *it_;
|
||||||
|
return value_type{e.data(),
|
||||||
|
&e == &*std::prev(sb_->list_.end()) ?
|
||||||
|
sb_->out_end_ : e.size()} +
|
||||||
|
(&e == &*sb_->out_ ? sb_->out_pos_ : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
--it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_streambuf<Allocator>::mutable_buffers_type::mutable_buffers_type(
|
||||||
|
basic_streambuf const& sb)
|
||||||
|
: sb_(&sb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_streambuf<Allocator>::mutable_buffers_type::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*sb_, sb_->out_};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_streambuf<Allocator>::mutable_buffers_type::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*sb_, sb_->list_.end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_streambuf<Allocator>::~basic_streambuf()
|
||||||
|
{
|
||||||
|
delete_list();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_streambuf<Allocator>::
|
||||||
|
basic_streambuf(basic_streambuf&& other)
|
||||||
|
: empty_base_optimization<allocator_type>(
|
||||||
|
std::move(other.member()))
|
||||||
|
, alloc_size_(other.alloc_size_)
|
||||||
|
, in_size_(other.in_size_)
|
||||||
|
, in_pos_(other.in_pos_)
|
||||||
|
, out_pos_(other.out_pos_)
|
||||||
|
, out_end_(other.out_end_)
|
||||||
|
{
|
||||||
|
auto const at_end =
|
||||||
|
other.out_ == other.list_.end();
|
||||||
|
list_ = std::move(other.list_);
|
||||||
|
out_ = at_end ? list_.end() : other.out_;
|
||||||
|
other.in_size_ = 0;
|
||||||
|
other.out_ = other.list_.end();
|
||||||
|
other.in_pos_ = 0;
|
||||||
|
other.out_pos_ = 0;
|
||||||
|
other.out_end_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_streambuf<Allocator>::
|
||||||
|
basic_streambuf(basic_streambuf&& other,
|
||||||
|
allocator_type const& alloc)
|
||||||
|
: basic_streambuf(other.alloc_size_, alloc)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
if(this->member() != other.member())
|
||||||
|
commit(buffer_copy(prepare(other.size()), other.data()));
|
||||||
|
else
|
||||||
|
move_assign(other, std::true_type{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_streambuf<Allocator>::operator=(
|
||||||
|
basic_streambuf&& other) -> basic_streambuf&
|
||||||
|
{
|
||||||
|
if(this == &other)
|
||||||
|
return *this;
|
||||||
|
// VFALCO If any memory allocated we could use it first?
|
||||||
|
clear();
|
||||||
|
alloc_size_ = other.alloc_size_;
|
||||||
|
move_assign(other, std::integral_constant<bool,
|
||||||
|
alloc_traits::propagate_on_container_move_assignment::value>{});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_streambuf<Allocator>::
|
||||||
|
basic_streambuf(basic_streambuf const& other)
|
||||||
|
: basic_streambuf(other.alloc_size_,
|
||||||
|
alloc_traits::select_on_container_copy_construction(other.member()))
|
||||||
|
{
|
||||||
|
commit(boost::asio::buffer_copy(prepare(other.size()), other.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_streambuf<Allocator>::
|
||||||
|
basic_streambuf(basic_streambuf const& other,
|
||||||
|
allocator_type const& alloc)
|
||||||
|
: basic_streambuf(other.alloc_size_, alloc)
|
||||||
|
{
|
||||||
|
commit(boost::asio::buffer_copy(prepare(other.size()), other.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_streambuf<Allocator>::operator=(
|
||||||
|
basic_streambuf const& other) ->
|
||||||
|
basic_streambuf&
|
||||||
|
{
|
||||||
|
if(this == &other)
|
||||||
|
return *this;
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
clear();
|
||||||
|
copy_assign(other, std::integral_constant<bool,
|
||||||
|
alloc_traits::propagate_on_container_copy_assignment::value>{});
|
||||||
|
commit(buffer_copy(prepare(other.size()), other.data()));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_streambuf<Allocator>::basic_streambuf(
|
||||||
|
basic_streambuf<OtherAlloc> const& other)
|
||||||
|
: basic_streambuf(other.alloc_size_)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
commit(buffer_copy(prepare(other.size()), other.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_streambuf<Allocator>::basic_streambuf(
|
||||||
|
basic_streambuf<OtherAlloc> const& other,
|
||||||
|
allocator_type const& alloc)
|
||||||
|
: basic_streambuf(other.alloc_size_, alloc)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
commit(buffer_copy(prepare(other.size()), other.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
template<class OtherAlloc>
|
||||||
|
auto
|
||||||
|
basic_streambuf<Allocator>::operator=(
|
||||||
|
basic_streambuf<OtherAlloc> const& other) ->
|
||||||
|
basic_streambuf&
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
clear();
|
||||||
|
commit(buffer_copy(prepare(other.size()), other.data()));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_streambuf<Allocator>::basic_streambuf(
|
||||||
|
std::size_t alloc_size, Allocator const& alloc)
|
||||||
|
: empty_base_optimization<allocator_type>(alloc)
|
||||||
|
, out_(list_.end())
|
||||||
|
, alloc_size_(alloc_size)
|
||||||
|
{
|
||||||
|
if(alloc_size <= 0)
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"basic_streambuf: invalid alloc_size");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_streambuf<Allocator>::prepare(size_type n) ->
|
||||||
|
mutable_buffers_type
|
||||||
|
{
|
||||||
|
iterator pos = out_;
|
||||||
|
if(pos != list_.end())
|
||||||
|
{
|
||||||
|
auto const avail = pos->size() - out_pos_;
|
||||||
|
if(n > avail)
|
||||||
|
{
|
||||||
|
n -= avail;
|
||||||
|
out_end_ = pos->size();
|
||||||
|
while(++pos != list_.end())
|
||||||
|
{
|
||||||
|
if(n < pos->size())
|
||||||
|
{
|
||||||
|
out_end_ = n;
|
||||||
|
n = 0;
|
||||||
|
++pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n -= pos->size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
out_end_ = out_pos_ + n;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n > 0)
|
||||||
|
{
|
||||||
|
assert(pos == list_.end());
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
auto const size = std::max(alloc_size_, n);
|
||||||
|
auto& e = *reinterpret_cast<element*>(
|
||||||
|
alloc_traits::allocate(this->member(),
|
||||||
|
size + sizeof(element)));
|
||||||
|
alloc_traits::construct(this->member(), &e, size);
|
||||||
|
list_.push_back(e);
|
||||||
|
if(out_ == list_.end())
|
||||||
|
{
|
||||||
|
out_ = list_.iterator_to(e);
|
||||||
|
debug_check();
|
||||||
|
}
|
||||||
|
if(n <= size)
|
||||||
|
{
|
||||||
|
out_end_ = n;
|
||||||
|
debug_check();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n -= size;
|
||||||
|
debug_check();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(pos != list_.end())
|
||||||
|
{
|
||||||
|
auto& e = *pos++;
|
||||||
|
list_.erase(list_.iterator_to(e));
|
||||||
|
auto const len = e.size() + sizeof(e);
|
||||||
|
alloc_traits::destroy(this->member(), &e);
|
||||||
|
alloc_traits::deallocate(this->member(),
|
||||||
|
reinterpret_cast<std::uint8_t*>(&e), len);
|
||||||
|
}
|
||||||
|
debug_check();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mutable_buffers_type(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_streambuf<Allocator>::commit(size_type n)
|
||||||
|
{
|
||||||
|
if(list_.empty())
|
||||||
|
return;
|
||||||
|
if(out_ == list_.end())
|
||||||
|
return;
|
||||||
|
auto const last = std::prev(list_.end());
|
||||||
|
while(out_ != last)
|
||||||
|
{
|
||||||
|
auto const avail =
|
||||||
|
out_->size() - out_pos_;
|
||||||
|
if(n < avail)
|
||||||
|
{
|
||||||
|
out_pos_ += n;
|
||||||
|
in_size_ += n;
|
||||||
|
debug_check();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++out_;
|
||||||
|
n -= avail;
|
||||||
|
out_pos_ = 0;
|
||||||
|
in_size_ += avail;
|
||||||
|
debug_check();
|
||||||
|
}
|
||||||
|
|
||||||
|
n = std::min(n, out_end_ - out_pos_);
|
||||||
|
out_pos_ += n;
|
||||||
|
in_size_ += n;
|
||||||
|
if(out_pos_ == out_->size())
|
||||||
|
{
|
||||||
|
++out_;
|
||||||
|
out_pos_ = 0;
|
||||||
|
out_end_ = 0;
|
||||||
|
}
|
||||||
|
debug_check();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
auto
|
||||||
|
basic_streambuf<Allocator>::data() const ->
|
||||||
|
const_buffers_type
|
||||||
|
{
|
||||||
|
return const_buffers_type(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_streambuf<Allocator>::consume(size_type n)
|
||||||
|
{
|
||||||
|
if(list_.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto pos = list_.begin();
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if(pos != out_)
|
||||||
|
{
|
||||||
|
auto const avail = pos->size() - in_pos_;
|
||||||
|
if(n < avail)
|
||||||
|
{
|
||||||
|
in_size_ -= n;
|
||||||
|
in_pos_ += n;
|
||||||
|
debug_check();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n -= avail;
|
||||||
|
in_size_ -= avail;
|
||||||
|
in_pos_ = 0;
|
||||||
|
debug_check();
|
||||||
|
|
||||||
|
element& e = *pos++;
|
||||||
|
list_.erase(list_.iterator_to(e));
|
||||||
|
auto const len = e.size() + sizeof(e);
|
||||||
|
alloc_traits::destroy(this->member(), &e);
|
||||||
|
alloc_traits::deallocate(this->member(),
|
||||||
|
reinterpret_cast<std::uint8_t*>(&e), len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const avail = out_pos_ - in_pos_;
|
||||||
|
if(n < avail)
|
||||||
|
{
|
||||||
|
in_size_ -= n;
|
||||||
|
in_pos_ += n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
in_size_ -= avail;
|
||||||
|
if(out_pos_ != out_end_||
|
||||||
|
out_ != list_.iterator_to(list_.back()))
|
||||||
|
{
|
||||||
|
in_pos_ = out_pos_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use the whole buffer now.
|
||||||
|
// Alternatively we could deallocate it.
|
||||||
|
in_pos_ = 0;
|
||||||
|
out_pos_ = 0;
|
||||||
|
out_end_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_check();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_streambuf<Allocator>::clear()
|
||||||
|
{
|
||||||
|
delete_list();
|
||||||
|
list_.clear();
|
||||||
|
out_ = list_.begin();
|
||||||
|
in_size_ = 0;
|
||||||
|
in_pos_ = 0;
|
||||||
|
out_pos_ = 0;
|
||||||
|
out_end_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_streambuf<Allocator>::
|
||||||
|
move_assign(basic_streambuf& other, std::false_type)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
if(this->member() != other.member())
|
||||||
|
{
|
||||||
|
commit(buffer_copy(prepare(other.size()), other.data()));
|
||||||
|
other.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
move_assign(other, std::true_type{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_streambuf<Allocator>::
|
||||||
|
move_assign(basic_streambuf& other, std::true_type)
|
||||||
|
{
|
||||||
|
this->member() = std::move(other.member());
|
||||||
|
auto const at_end =
|
||||||
|
other.out_ == other.list_.end();
|
||||||
|
list_ = std::move(other.list_);
|
||||||
|
out_ = at_end ? list_.end() : other.out_;
|
||||||
|
|
||||||
|
in_size_ = other.in_size_;
|
||||||
|
in_pos_ = other.in_pos_;
|
||||||
|
out_pos_ = other.out_pos_;
|
||||||
|
out_end_ = other.out_end_;
|
||||||
|
|
||||||
|
other.in_size_ = 0;
|
||||||
|
other.out_ = other.list_.end();
|
||||||
|
other.in_pos_ = 0;
|
||||||
|
other.out_pos_ = 0;
|
||||||
|
other.out_end_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_streambuf<Allocator>::
|
||||||
|
copy_assign(basic_streambuf const& other, std::false_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_streambuf<Allocator>::
|
||||||
|
copy_assign(basic_streambuf const& other, std::true_type)
|
||||||
|
{
|
||||||
|
this->member() = other.member();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_streambuf<Allocator>::delete_list()
|
||||||
|
{
|
||||||
|
for(auto iter = list_.begin(); iter != list_.end();)
|
||||||
|
{
|
||||||
|
auto& e = *iter++;
|
||||||
|
auto const n = e.size() + sizeof(e);
|
||||||
|
alloc_traits::destroy(this->member(), &e);
|
||||||
|
alloc_traits::deallocate(this->member(),
|
||||||
|
reinterpret_cast<std::uint8_t*>(&e), n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of bytes which can be
|
||||||
|
// prepared without causing a memory allocation.
|
||||||
|
template<class Allocator>
|
||||||
|
std::size_t
|
||||||
|
basic_streambuf<Allocator>::prepare_size() const
|
||||||
|
{
|
||||||
|
auto pos = out_;
|
||||||
|
if(pos == list_.end())
|
||||||
|
return 0;
|
||||||
|
auto n = pos->size() - out_pos_;
|
||||||
|
while(++pos != list_.end())
|
||||||
|
n += pos->size();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
void
|
||||||
|
basic_streambuf<Allocator>::debug_check() const
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if(list_.empty())
|
||||||
|
{
|
||||||
|
assert(in_pos_ == 0);
|
||||||
|
assert(in_size_ == 0);
|
||||||
|
assert(out_pos_ == 0);
|
||||||
|
assert(out_end_ == 0);
|
||||||
|
assert(out_ == list_.end());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& front = list_.front();
|
||||||
|
|
||||||
|
assert(in_pos_ < front.size());
|
||||||
|
|
||||||
|
if(out_ == list_.end())
|
||||||
|
{
|
||||||
|
assert(out_pos_ == 0);
|
||||||
|
assert(out_end_ == 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const& out = *out_;
|
||||||
|
auto const& back = list_.back();
|
||||||
|
|
||||||
|
assert(out_end_ <= back.size());
|
||||||
|
assert(out_pos_ < out.size());
|
||||||
|
assert(&out != &front || out_pos_ >= in_pos_);
|
||||||
|
assert(&out != &front || out_pos_ - in_pos_ == in_size_);
|
||||||
|
assert(&out != &back || out_pos_ <= out_end_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Alloc, class T>
|
||||||
|
basic_streambuf<Alloc>&
|
||||||
|
operator<<(basic_streambuf<Alloc>& buf, T const& t)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << t;
|
||||||
|
auto const& s = ss.str();
|
||||||
|
buf.commit(buffer_copy(buf.prepare(s.size()),
|
||||||
|
boost::asio::buffer(s)));
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
std::size_t
|
||||||
|
read_size_helper(basic_streambuf<
|
||||||
|
Allocator> const& streambuf, std::size_t max_size)
|
||||||
|
{
|
||||||
|
return std::min<std::size_t>(max_size,
|
||||||
|
std::max<std::size_t>(512, streambuf.prepare_size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
std::string
|
||||||
|
to_string(basic_streambuf<Allocator> const& streambuf)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
std::string s;
|
||||||
|
s.resize(streambuf.size());
|
||||||
|
buffer_copy(
|
||||||
|
buffer(&s[0], s.size()), streambuf.data());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
265
beast/asio/impl/streambuf_readstream.ipp
Normal file
265
beast/asio/impl/streambuf_readstream.ipp
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_STREAMBUF_READSTREAM_IPP_INLUDED
|
||||||
|
#define BEAST_ASIO_STREAMBUF_READSTREAM_IPP_INLUDED
|
||||||
|
|
||||||
|
#include <beast/asio/async_completion.h>
|
||||||
|
#include <beast/asio/bind_handler.h>
|
||||||
|
#include <beast/asio/handler_alloc.h>
|
||||||
|
#include <beast/asio/type_check.h>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
template<class Stream, class Streambuf>
|
||||||
|
template<class MutableBufferSequence, class Handler>
|
||||||
|
class streambuf_readstream<
|
||||||
|
Stream, Streambuf>::read_some_op
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
handler_alloc<char, Handler>;
|
||||||
|
|
||||||
|
struct data
|
||||||
|
{
|
||||||
|
streambuf_readstream& brs;
|
||||||
|
MutableBufferSequence bs;
|
||||||
|
Handler h;
|
||||||
|
int state = 0;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
data(DeducedHandler&& h_,
|
||||||
|
streambuf_readstream& brs_,
|
||||||
|
MutableBufferSequence const& bs_)
|
||||||
|
: brs(brs_)
|
||||||
|
, bs(bs_)
|
||||||
|
, h(std::forward<DeducedHandler>(h_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<data> d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
read_some_op(read_some_op&&) = default;
|
||||||
|
read_some_op(read_some_op const&) = default;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
read_some_op(DeducedHandler&& h, Args&&... args)
|
||||||
|
: d_(std::allocate_shared<data>(alloc_type{h},
|
||||||
|
std::forward<DeducedHandler>(h),
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
(*this)(error_code{}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code const& ec,
|
||||||
|
std::size_t bytes_transferred);
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_allocate(
|
||||||
|
std::size_t size, read_some_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
allocate(size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, read_some_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
deallocate(p, size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
auto asio_handler_is_continuation(read_some_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_cont_helpers::
|
||||||
|
is_continuation(op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
friend
|
||||||
|
auto asio_handler_invoke(Function&& f, read_some_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_invoke_helpers::
|
||||||
|
invoke(f, op->d_->h);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Stream, class Streambuf>
|
||||||
|
template<class MutableBufferSequence, class Handler>
|
||||||
|
void
|
||||||
|
streambuf_readstream<Stream, Streambuf>::
|
||||||
|
read_some_op<MutableBufferSequence, Handler>::operator()(
|
||||||
|
error_code const& ec, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
while(! ec && d.state != 99)
|
||||||
|
{
|
||||||
|
switch(d.state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if(d.brs.sb_.size() == 0)
|
||||||
|
{
|
||||||
|
d.state =
|
||||||
|
d.brs.size_ > 0 ? 2 : 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d.state = 4;
|
||||||
|
d.brs.get_io_service().post(
|
||||||
|
bind_handler(std::move(*this), ec, 0));
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// read (unbuffered)
|
||||||
|
d.state = 99;
|
||||||
|
d.brs.next_layer_.async_read_some(
|
||||||
|
d.bs, std::move(*this));
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// read
|
||||||
|
d.state = 3;
|
||||||
|
d.brs.next_layer_.async_read_some(
|
||||||
|
d.brs.sb_.prepare(d.brs.size_),
|
||||||
|
std::move(*this));
|
||||||
|
return;
|
||||||
|
|
||||||
|
// got data
|
||||||
|
case 3:
|
||||||
|
d.state = 4;
|
||||||
|
d.brs.sb_.commit(bytes_transferred);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// copy
|
||||||
|
case 4:
|
||||||
|
bytes_transferred =
|
||||||
|
boost::asio::buffer_copy(
|
||||||
|
d.bs, d.brs.sb_.data());
|
||||||
|
d.brs.sb_.consume(bytes_transferred);
|
||||||
|
// call handler
|
||||||
|
d.state = 99;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.h(ec, bytes_transferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Stream, class Streambuf>
|
||||||
|
template<class... Args>
|
||||||
|
streambuf_readstream<Stream, Streambuf>::
|
||||||
|
streambuf_readstream(Args&&... args)
|
||||||
|
: next_layer_(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
static_assert(is_Stream<next_layer_type>::value,
|
||||||
|
"Stream requirements not met");
|
||||||
|
static_assert(is_Streambuf<Streambuf>::value,
|
||||||
|
"Streambuf requirements not met");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Stream, class Streambuf>
|
||||||
|
template<class ConstBufferSequence, class WriteHandler>
|
||||||
|
auto
|
||||||
|
streambuf_readstream<Stream, Streambuf>::
|
||||||
|
async_write_some(ConstBufferSequence const& buffers,
|
||||||
|
WriteHandler&& handler)
|
||||||
|
{
|
||||||
|
static_assert(is_ConstBufferSequence<
|
||||||
|
ConstBufferSequence>::value,
|
||||||
|
"ConstBufferSequence requirements not met");
|
||||||
|
static_assert(is_Handler<WriteHandler,
|
||||||
|
void(error_code, std::size_t)>::value,
|
||||||
|
"WriteHandler requirements not met");
|
||||||
|
return next_layer_.async_write_some(buffers,
|
||||||
|
std::forward<WriteHandler>(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Stream, class Streambuf>
|
||||||
|
template<class MutableBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
streambuf_readstream<Stream, Streambuf>::
|
||||||
|
read_some(
|
||||||
|
MutableBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
static_assert(is_MutableBufferSequence<
|
||||||
|
MutableBufferSequence>::value,
|
||||||
|
"MutableBufferSequence requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
auto n = read_some(buffers, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Stream, class Streambuf>
|
||||||
|
template<class MutableBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
streambuf_readstream<Stream, Streambuf>::
|
||||||
|
read_some(MutableBufferSequence const& buffers,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
static_assert(is_MutableBufferSequence<
|
||||||
|
MutableBufferSequence>::value,
|
||||||
|
"MutableBufferSequence requirements not met");
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
if(buffer_size(buffers) == 0)
|
||||||
|
return 0;
|
||||||
|
if(size_ == 0)
|
||||||
|
return next_layer_.read_some(buffers, ec);
|
||||||
|
if(sb_.size() == 0)
|
||||||
|
{
|
||||||
|
sb_.commit(next_layer_.read_some(
|
||||||
|
sb_.prepare(size_), ec));
|
||||||
|
if(ec)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto bytes_transferred =
|
||||||
|
buffer_copy(buffers, sb_.data());
|
||||||
|
sb_.consume(bytes_transferred);
|
||||||
|
return bytes_transferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Stream, class Streambuf>
|
||||||
|
template<class MutableBufferSequence, class ReadHandler>
|
||||||
|
auto
|
||||||
|
streambuf_readstream<Stream, Streambuf>::
|
||||||
|
async_read_some(
|
||||||
|
MutableBufferSequence const& buffers,
|
||||||
|
ReadHandler&& handler)
|
||||||
|
{
|
||||||
|
static_assert(is_MutableBufferSequence<
|
||||||
|
MutableBufferSequence>::value,
|
||||||
|
"MutableBufferSequence requirements not met");
|
||||||
|
beast::async_completion<
|
||||||
|
ReadHandler, void(error_code, std::size_t)
|
||||||
|
> completion(handler);
|
||||||
|
read_some_op<MutableBufferSequence,
|
||||||
|
decltype(completion.handler)>{
|
||||||
|
completion.handler, *this, buffers};
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,15 +20,14 @@
|
|||||||
#ifndef BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
|
#ifndef BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
|
||||||
#define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
|
#define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/asio/deadline_timer.hpp>
|
||||||
|
#include <boost/asio/io_service.hpp>
|
||||||
|
#include <boost/config.hpp>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <boost/asio/deadline_timer.hpp>
|
|
||||||
#include <boost/asio/io_service.hpp>
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
/** Measures handler latency on an io_service queue. */
|
/** Measures handler latency on an io_service queue. */
|
||||||
|
|||||||
345
beast/asio/prepare_buffers.h
Normal file
345
beast/asio/prepare_buffers.h
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_PREPARE_BUFFERS_H_INLUDED
|
||||||
|
#define BEAST_ASIO_PREPARE_BUFFERS_H_INLUDED
|
||||||
|
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iterator>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** Get a trimmed const buffer.
|
||||||
|
|
||||||
|
The new buffer starts at the beginning of the passed
|
||||||
|
buffer. Ownership of the underlying memory is not
|
||||||
|
transferred.
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
boost::asio::const_buffer
|
||||||
|
prepare_buffer(std::size_t n,
|
||||||
|
boost::asio::const_buffer buffer)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
return { buffer_cast<void const*>(buffer),
|
||||||
|
std::min(n, buffer_size(buffer)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a trimmed mutable buffer.
|
||||||
|
|
||||||
|
The new buffer starts at the beginning of the passed
|
||||||
|
buffer. Ownership of the underlying memory is not
|
||||||
|
transferred.
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
boost::asio::mutable_buffer
|
||||||
|
prepare_buffer(std::size_t n,
|
||||||
|
boost::asio::mutable_buffer buffer)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
return { buffer_cast<void*>(buffer),
|
||||||
|
std::min(n, buffer_size(buffer)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Wrapper to produce a trimmed buffer sequence.
|
||||||
|
|
||||||
|
This wraps a buffer sequence to efficiently present a shorter
|
||||||
|
subset of the original list of buffers starting with the first
|
||||||
|
byte of the original sequence.
|
||||||
|
|
||||||
|
@tparam BufferSequence The buffer sequence to wrap.
|
||||||
|
*/
|
||||||
|
template<class BufferSequence>
|
||||||
|
class prepared_buffers
|
||||||
|
{
|
||||||
|
using iter_type =
|
||||||
|
typename BufferSequence::const_iterator;
|
||||||
|
|
||||||
|
BufferSequence bs_;
|
||||||
|
iter_type back_;
|
||||||
|
iter_type end_;
|
||||||
|
std::size_t size_;
|
||||||
|
|
||||||
|
template<class Deduced>
|
||||||
|
prepared_buffers(Deduced&& other,
|
||||||
|
std::size_t nback, std::size_t nend)
|
||||||
|
: bs_(std::forward<Deduced>(other).bs_)
|
||||||
|
, back_(std::next(bs_.begin(), nback))
|
||||||
|
, end_(std::next(bs_.begin(), nend))
|
||||||
|
, size_(other.size_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The type for each element in the list of buffers.
|
||||||
|
using value_type =
|
||||||
|
typename std::iterator_traits<iter_type>::value_type;
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
/// Move constructor.
|
||||||
|
prepared_buffers(prepared_buffers&&);
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
prepared_buffers(prepared_buffers const&);
|
||||||
|
|
||||||
|
/// Move assignment.
|
||||||
|
prepared_buffers& operator=(prepared_buffers&&);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
prepared_buffers& operator=(prepared_buffers const&);
|
||||||
|
|
||||||
|
/** Construct a wrapped buffer sequence.
|
||||||
|
|
||||||
|
@param n The maximum number of bytes in the wrapped sequence.
|
||||||
|
If this is larger than the size of buffers, the wrapped
|
||||||
|
sequence will represent the entire input sequence.
|
||||||
|
|
||||||
|
@param buffers The buffer sequence to wrap. A copy of the sequence
|
||||||
|
will be made, but ownership of the underlying memory is not transferred.
|
||||||
|
*/
|
||||||
|
prepared_buffers(std::size_t n, BufferSequence const& buffers);
|
||||||
|
|
||||||
|
/// Get a bidirectional iterator to the first element.
|
||||||
|
const_iterator
|
||||||
|
begin() const;
|
||||||
|
|
||||||
|
/// Get a bidirectional iterator for one past the last element.
|
||||||
|
const_iterator
|
||||||
|
end() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
setup(std::size_t n)
|
||||||
|
{
|
||||||
|
for(end_ = bs_.begin(); end_ != bs_.end(); ++end_)
|
||||||
|
{
|
||||||
|
auto const len =
|
||||||
|
boost::asio::buffer_size(*end_);
|
||||||
|
if(n <= len)
|
||||||
|
{
|
||||||
|
size_ = n;
|
||||||
|
back_ = end_++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
n -= len;
|
||||||
|
}
|
||||||
|
size_ = 0;
|
||||||
|
back_ = end_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A bidirectional iterator type that may be used to read elements.
|
||||||
|
template<class BufferSequence>
|
||||||
|
class prepared_buffers<BufferSequence>::const_iterator
|
||||||
|
{
|
||||||
|
friend class prepared_buffers<BufferSequence>;
|
||||||
|
|
||||||
|
using iter_type =
|
||||||
|
typename BufferSequence::const_iterator;
|
||||||
|
|
||||||
|
prepared_buffers const* b_;
|
||||||
|
typename BufferSequence::const_iterator it_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type =
|
||||||
|
typename std::iterator_traits<iter_type>::value_type;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return b_ == other.b_ && it_ == other.it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
if(it_ == b_->back_)
|
||||||
|
return prepare_buffer(b_->size_, *it_);
|
||||||
|
return *it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
--it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const_iterator(prepared_buffers const& b,
|
||||||
|
bool at_end)
|
||||||
|
: b_(&b)
|
||||||
|
, it_(at_end ? b.end_ : b.bs_.begin())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
prepared_buffers<BufferSequence>::
|
||||||
|
prepared_buffers(prepared_buffers&& other)
|
||||||
|
: prepared_buffers(std::move(other),
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.back_),
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.end_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
prepared_buffers<BufferSequence>::
|
||||||
|
prepared_buffers(prepared_buffers const& other)
|
||||||
|
: prepared_buffers(other,
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.back_),
|
||||||
|
std::distance<iter_type>(other.bs_.begin(), other.end_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
auto
|
||||||
|
prepared_buffers<BufferSequence>::
|
||||||
|
operator=(prepared_buffers&& other) ->
|
||||||
|
prepared_buffers&
|
||||||
|
{
|
||||||
|
auto const nback = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.back_);
|
||||||
|
auto const nend = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.end_);
|
||||||
|
bs_ = std::move(other.bs_);
|
||||||
|
back_ = std::next(bs_.begin(), nback);
|
||||||
|
end_ = std::next(bs_.begin(), nend);
|
||||||
|
size_ = other.size_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
auto
|
||||||
|
prepared_buffers<BufferSequence>::
|
||||||
|
operator=(prepared_buffers const& other) ->
|
||||||
|
prepared_buffers&
|
||||||
|
{
|
||||||
|
auto const nback = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.back_);
|
||||||
|
auto const nend = std::distance<iter_type>(
|
||||||
|
other.bs_.begin(), other.end_);
|
||||||
|
bs_ = other.bs_;
|
||||||
|
back_ = std::next(bs_.begin(), nback);
|
||||||
|
end_ = std::next(bs_.begin(), nend);
|
||||||
|
size_ = other.size_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
prepared_buffers<BufferSequence>::
|
||||||
|
prepared_buffers(std::size_t n, BufferSequence const& bs)
|
||||||
|
: bs_(bs)
|
||||||
|
{
|
||||||
|
setup(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
auto
|
||||||
|
prepared_buffers<BufferSequence>::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*this, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
auto
|
||||||
|
prepared_buffers<BufferSequence>::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{*this, true};
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Return a trimmed, wrapped buffer sequence.
|
||||||
|
|
||||||
|
This function returns a new buffer sequence which wraps the provided
|
||||||
|
buffer sequence and efficiently presents a shorter subset of the
|
||||||
|
original list of buffers starting with the first byte of the original
|
||||||
|
sequence.
|
||||||
|
|
||||||
|
@param n The maximum number of bytes in the wrapped sequence. If this
|
||||||
|
is larger than the size of buffers, the wrapped sequence will represent
|
||||||
|
the entire input sequence.
|
||||||
|
|
||||||
|
@param buffers The buffer sequence to wrap. A copy of the sequence
|
||||||
|
will be made, but ownership of the underlying memory is not transferred.
|
||||||
|
*/
|
||||||
|
template<class BufferSequence>
|
||||||
|
inline
|
||||||
|
prepared_buffers<BufferSequence>
|
||||||
|
prepare_buffers(std::size_t n, BufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
return prepared_buffers<BufferSequence>(n, buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -17,20 +17,12 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
// LIBS: boost_system
|
|
||||||
|
|
||||||
#if BEAST_INCLUDE_BEASTCONFIG
|
|
||||||
#include <BeastConfig.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <beast/unit_test/suite.h>
|
#include <beast/unit_test/suite.h>
|
||||||
|
|
||||||
#include <beast/asio/bind_handler.h>
|
#include <beast/asio/bind_handler.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace asio {
|
namespace test {
|
||||||
|
|
||||||
class bind_handler_test : public unit_test::suite
|
class bind_handler_test : public unit_test::suite
|
||||||
{
|
{
|
||||||
@@ -51,5 +43,6 @@ public:
|
|||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(bind_handler,asio,beast);
|
BEAST_DEFINE_TESTSUITE(bind_handler,asio,beast);
|
||||||
|
|
||||||
}
|
} // test
|
||||||
}
|
} // beast
|
||||||
|
|
||||||
362
beast/asio/src/test/beast_asio_buffers_test.cpp
Normal file
362
beast/asio/src/test/beast_asio_buffers_test.cpp
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <beast/asio/append_buffers.h>
|
||||||
|
#include <beast/asio/buffers_adapter.h>
|
||||||
|
#include <beast/asio/prepare_buffers.h>
|
||||||
|
#include <beast/asio/consuming_buffers.h>
|
||||||
|
#include <beast/asio/streambuf.h>
|
||||||
|
#include <beast/asio/static_streambuf.h>
|
||||||
|
#include <beast/asio/streambuf_readstream.h>
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <array>
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
class buffers_test : public unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
to_string(ConstBufferSequence const& bs)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string s;
|
||||||
|
s.reserve(buffer_size(bs));
|
||||||
|
for(auto const& b : bs)
|
||||||
|
s.append(buffer_cast<char const*>(b),
|
||||||
|
buffer_size(b));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testStreambuf()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
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);
|
||||||
|
decltype(sb)::mutable_buffers_type d;
|
||||||
|
d = sb.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = sb.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = sb.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
sb.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
|
expect(sb.size() == x);
|
||||||
|
expect(buffer_size(sb.data()) == sb.size());
|
||||||
|
d = sb.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = sb.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = sb.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
sb.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
|
sb.commit(1);
|
||||||
|
expect(sb.size() == x + y);
|
||||||
|
expect(buffer_size(sb.data()) == sb.size());
|
||||||
|
d = sb.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = sb.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = sb.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
sb.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
|
sb.commit(2);
|
||||||
|
expect(sb.size() == x + y + z);
|
||||||
|
expect(buffer_size(sb.data()) == sb.size());
|
||||||
|
expect(to_string(sb.data()) == s);
|
||||||
|
sb.consume(t);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
expect(to_string(sb.data()) == s.substr(t, std::string::npos));
|
||||||
|
sb.consume(u);
|
||||||
|
expect(to_string(sb.data()) == s.substr(t + u, std::string::npos));
|
||||||
|
sb.consume(v);
|
||||||
|
expect(to_string(sb.data()) == "");
|
||||||
|
sb.consume(1);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
}}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testBuffersAdapter()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
using boost::asio::mutable_buffer;
|
||||||
|
char buf[12];
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
expect(s.size() == sizeof(buf));
|
||||||
|
for(std::size_t i = 1; i < 4; ++i) {
|
||||||
|
for(std::size_t j = 1; j < 4; ++j) {
|
||||||
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
|
for(std::size_t t = 1; t < 4; ++ t) {
|
||||||
|
for(std::size_t u = 1; u < 4; ++ u) {
|
||||||
|
std::size_t k = sizeof(buf) - (i + j);
|
||||||
|
std::size_t z = sizeof(buf) - (x + y);
|
||||||
|
std::size_t v = sizeof(buf) - (t + u);
|
||||||
|
{
|
||||||
|
std::memset(buf, 0, sizeof(buf));
|
||||||
|
std::array<mutable_buffer, 3> bs{{
|
||||||
|
mutable_buffer{&buf[0], i},
|
||||||
|
mutable_buffer{&buf[i], j},
|
||||||
|
mutable_buffer{&buf[i+j], k}}};
|
||||||
|
buffers_adapter<decltype(bs)> ba(std::move(bs));
|
||||||
|
expect(ba.max_size() == sizeof(buf));
|
||||||
|
decltype(ba)::mutable_buffers_type d;
|
||||||
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
|
expect(ba.size() == x);
|
||||||
|
expect(ba.max_size() == sizeof(buf) - x);
|
||||||
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
|
ba.commit(1);
|
||||||
|
expect(ba.size() == x + y);
|
||||||
|
expect(ba.max_size() == sizeof(buf) - (x + y));
|
||||||
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
|
ba.commit(2);
|
||||||
|
expect(ba.size() == x + y + z);
|
||||||
|
expect(ba.max_size() == 0);
|
||||||
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
|
expect(to_string(ba.data()) == s);
|
||||||
|
ba.consume(t);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
expect(to_string(ba.data()) == s.substr(t, std::string::npos));
|
||||||
|
ba.consume(u);
|
||||||
|
expect(to_string(ba.data()) == s.substr(t + u, std::string::npos));
|
||||||
|
ba.consume(v);
|
||||||
|
expect(to_string(ba.data()) == "");
|
||||||
|
ba.consume(1);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ba.prepare(1);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testConsuming()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
char buf[12];
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
expect(s.size() == sizeof(buf));
|
||||||
|
buffer_copy(buffer(buf), buffer(s));
|
||||||
|
expect(to_string(buffer(buf)) == s);
|
||||||
|
for(std::size_t i = 1; i < 4; ++i) {
|
||||||
|
for(std::size_t j = 1; j < 4; ++j) {
|
||||||
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
|
std::size_t k = sizeof(buf) - (i + j);
|
||||||
|
std::size_t z = sizeof(buf) - (x + y);
|
||||||
|
{
|
||||||
|
std::array<const_buffer, 3> bs{{
|
||||||
|
const_buffer{&buf[0], i},
|
||||||
|
const_buffer{&buf[i], j},
|
||||||
|
const_buffer{&buf[i+j], k}}};
|
||||||
|
consuming_buffers<decltype(bs)> cb(bs);
|
||||||
|
expect(to_string(cb) == s);
|
||||||
|
cb.consume(0);
|
||||||
|
expect(to_string(cb) == s);
|
||||||
|
cb.consume(x);
|
||||||
|
expect(to_string(cb) == s.substr(x));
|
||||||
|
cb.consume(y);
|
||||||
|
expect(to_string(cb) == s.substr(x+y));
|
||||||
|
cb.consume(z);
|
||||||
|
expect(to_string(cb) == "");
|
||||||
|
cb.consume(1);
|
||||||
|
expect(to_string(cb) == "");
|
||||||
|
}
|
||||||
|
}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testStaticBuffers()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
char buf[12];
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
expect(s.size() == sizeof(buf));
|
||||||
|
for(std::size_t i = 1; i < 4; ++i) {
|
||||||
|
for(std::size_t j = 1; j < 4; ++j) {
|
||||||
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
|
for(std::size_t t = 1; t < 4; ++ t) {
|
||||||
|
for(std::size_t u = 1; u < 4; ++ u) {
|
||||||
|
std::size_t z = sizeof(buf) - (x + y);
|
||||||
|
std::size_t v = sizeof(buf) - (t + u);
|
||||||
|
{
|
||||||
|
std::memset(buf, 0, sizeof(buf));
|
||||||
|
static_streambuf_n<sizeof(buf)> ba;
|
||||||
|
decltype(ba)::mutable_buffers_type d;
|
||||||
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
|
expect(ba.size() == x);
|
||||||
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
|
ba.commit(1);
|
||||||
|
expect(ba.size() == x + y);
|
||||||
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
|
ba.commit(2);
|
||||||
|
expect(ba.size() == x + y + z);
|
||||||
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
|
expect(to_string(ba.data()) == s);
|
||||||
|
ba.consume(t);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
expect(to_string(ba.data()) == s.substr(t, std::string::npos));
|
||||||
|
ba.consume(u);
|
||||||
|
expect(to_string(ba.data()) == s.substr(t + u, std::string::npos));
|
||||||
|
ba.consume(v);
|
||||||
|
expect(to_string(ba.data()) == "");
|
||||||
|
ba.consume(1);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ba.prepare(1);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAppendBuffers()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
char buf[10];
|
||||||
|
std::list<const_buffer> b1;
|
||||||
|
std::vector<const_buffer> b2{
|
||||||
|
const_buffer{buf+0, 1},
|
||||||
|
const_buffer{buf+1, 2}};
|
||||||
|
std::list<const_buffer> b3;
|
||||||
|
std::array<const_buffer, 3> b4{{
|
||||||
|
const_buffer{buf+3, 1},
|
||||||
|
const_buffer{buf+4, 2},
|
||||||
|
const_buffer{buf+6, 3}}};
|
||||||
|
std::list<const_buffer> b5{
|
||||||
|
const_buffer{buf+9, 1}};
|
||||||
|
std::list<const_buffer> b6;
|
||||||
|
auto bs = append_buffers(
|
||||||
|
b1, b2, b3, b4, b5, b6);
|
||||||
|
expect(buffer_size(bs) == 10);
|
||||||
|
std::vector<const_buffer> v;
|
||||||
|
for(auto iter = std::make_reverse_iterator(bs.end());
|
||||||
|
iter != std::make_reverse_iterator(bs.begin()); ++iter)
|
||||||
|
v.emplace_back(*iter);
|
||||||
|
expect(buffer_size(bs) == 10);
|
||||||
|
decltype(bs) bs2(bs);
|
||||||
|
auto bs3(std::move(bs));
|
||||||
|
bs = bs2;
|
||||||
|
bs3 = std::move(bs2);
|
||||||
|
{
|
||||||
|
streambuf sb1, sb2;
|
||||||
|
expect(buffer_size(append_buffers(
|
||||||
|
sb1.prepare(5), sb2.prepare(7))) == 12);
|
||||||
|
sb1.commit(5);
|
||||||
|
sb2.commit(7);
|
||||||
|
expect(buffer_size(append_buffers(
|
||||||
|
sb1.data(), sb2.data())) == 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testClipBuffers()
|
||||||
|
{
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
expect(s.size() == 12);
|
||||||
|
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);
|
||||||
|
{
|
||||||
|
std::array<const_buffer, 3> bs{{
|
||||||
|
const_buffer{&s[0], x},
|
||||||
|
const_buffer{&s[x], y},
|
||||||
|
const_buffer{&s[x+y], z}}};
|
||||||
|
for(std::size_t i = 0; i <= s.size() + 1; ++i)
|
||||||
|
expect(to_string(prepare_buffers(i, bs)) ==
|
||||||
|
s.substr(0, i));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testStreambuf();
|
||||||
|
testBuffersAdapter();
|
||||||
|
testConsuming();
|
||||||
|
testStaticBuffers();
|
||||||
|
|
||||||
|
testAppendBuffers();
|
||||||
|
testClipBuffers();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(buffers,asio,beast);
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // beast
|
||||||
@@ -17,22 +17,22 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <beast/asio/error.h>
|
#include <beast/asio/ssl_error.h>
|
||||||
#include <beast/unit_test/suite.h>
|
#include <beast/unit_test/suite.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace asio {
|
|
||||||
|
|
||||||
class error_test : public unit_test::suite
|
class error_test : public unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void run ()
|
void run()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
boost::system::error_code ec = boost::system::error_code (335544539,
|
boost::system::error_code ec =
|
||||||
|
boost::system::error_code (335544539,
|
||||||
boost::asio::error::get_ssl_category ());
|
boost::asio::error::get_ssl_category ());
|
||||||
std::string const s = beast::asio::asio_message (ec);
|
std::string const s = beast::error_message_with_ssl(ec);
|
||||||
expect(s == " (20,0,219) error:140000DB:SSL routines:SSL routines:short read");
|
expect(s == " (20,0,219) error:140000DB:SSL routines:SSL routines:short read");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,5 +40,4 @@ public:
|
|||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(error,asio,beast);
|
BEAST_DEFINE_TESTSUITE(error,asio,beast);
|
||||||
|
|
||||||
}
|
} // beast
|
||||||
}
|
|
||||||
@@ -17,43 +17,56 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <beast/asio/error.h>
|
#ifndef BEAST_ASIO_SSL_ERROR_H_INCLUDED
|
||||||
|
#define BEAST_ASIO_SSL_ERROR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
//#include <boost/asio/error.hpp> // Causes error with WinSock.h
|
||||||
|
#include <boost/asio/ssl/error.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace asio {
|
|
||||||
|
|
||||||
// This buffer must be at least 120 bytes, most examples use 256.
|
|
||||||
// https://www.openssl.org/docs/crypto/ERR_error_string.html
|
|
||||||
static std::uint32_t const errorBufferSize (256);
|
|
||||||
|
|
||||||
|
/** Returns a human readable message if the error code is SSL related. */
|
||||||
|
template<class = void>
|
||||||
std::string
|
std::string
|
||||||
asio_message (boost::system::error_code const& ec)
|
error_message_with_ssl(boost::system::error_code const& ec)
|
||||||
{
|
{
|
||||||
std::string error;
|
std::string error;
|
||||||
|
|
||||||
if (ec.category () == boost::asio::error::get_ssl_category ())
|
if (ec.category() == boost::asio::error::get_ssl_category())
|
||||||
{
|
{
|
||||||
error = " ("
|
error = " ("
|
||||||
+ boost::lexical_cast<std::string> (ERR_GET_LIB (ec.value ()))
|
+ boost::lexical_cast<std::string>(ERR_GET_LIB (ec.value ()))
|
||||||
+ ","
|
+ ","
|
||||||
+ boost::lexical_cast<std::string> (ERR_GET_FUNC (ec.value ()))
|
+ boost::lexical_cast<std::string>(ERR_GET_FUNC (ec.value ()))
|
||||||
+ ","
|
+ ","
|
||||||
+ boost::lexical_cast<std::string> (ERR_GET_REASON (ec.value ()))
|
+ boost::lexical_cast<std::string>(ERR_GET_REASON (ec.value ()))
|
||||||
+ ") ";
|
+ ") ";
|
||||||
|
|
||||||
//
|
// This buffer must be at least 120 bytes, most examples use 256.
|
||||||
char buf[errorBufferSize];
|
// https://www.openssl.org/docs/crypto/ERR_error_string.html
|
||||||
::ERR_error_string_n (ec.value (), buf, errorBufferSize);
|
char buf[256];
|
||||||
|
::ERR_error_string_n(ec.value (), buf, sizeof(buf));
|
||||||
error += buf;
|
error += buf;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error = ec.message ();
|
error = ec.message();
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns `true` if the error code is a SSL "short read." */
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
is_short_read(boost::system::error_code const& ec)
|
||||||
|
{
|
||||||
|
return (ec.category() == boost::asio::error::get_ssl_category())
|
||||||
|
&& (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
471
beast/asio/static_streambuf.h
Normal file
471
beast/asio/static_streambuf.h
Normal file
@@ -0,0 +1,471 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_STATIC_STREAMBUF_H_INLUDED
|
||||||
|
#define BEAST_ASIO_STATIC_STREAMBUF_H_INLUDED
|
||||||
|
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/utility/base_from_member.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iterator>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** A `Streambuf` with a fixed size internal buffer.
|
||||||
|
|
||||||
|
Ownership of the underlying storage belongs to the derived class.
|
||||||
|
|
||||||
|
@note Variables are usually declared using the template class
|
||||||
|
`static_streambuf_n`; 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
|
||||||
|
`static_streambuf`.
|
||||||
|
*/
|
||||||
|
class static_streambuf
|
||||||
|
{
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
private:
|
||||||
|
#else
|
||||||
|
protected:
|
||||||
|
#endif
|
||||||
|
std::uint8_t* in_;
|
||||||
|
std::uint8_t* out_;
|
||||||
|
std::uint8_t* last_;
|
||||||
|
std::uint8_t* end_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class const_buffers_type;
|
||||||
|
class mutable_buffers_type;
|
||||||
|
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
private:
|
||||||
|
#endif
|
||||||
|
static_streambuf(
|
||||||
|
static_streambuf const& other) noexcept = delete;
|
||||||
|
static_streambuf& operator=(
|
||||||
|
static_streambuf const&) noexcept = delete;
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
public:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Returns the largest size output sequence possible.
|
||||||
|
std::size_t
|
||||||
|
max_size() const
|
||||||
|
{
|
||||||
|
return end_ - in_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the size of the input sequence.
|
||||||
|
std::size_t
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return out_ - in_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a list of buffers that represents the output sequence, with the given size.
|
||||||
|
|
||||||
|
@throws std::length_error if the size would exceed the limit
|
||||||
|
imposed by the underlying mutable buffer sequence.
|
||||||
|
*/
|
||||||
|
mutable_buffers_type
|
||||||
|
prepare(std::size_t n);
|
||||||
|
|
||||||
|
/// Move bytes from the output sequence to the input sequence.
|
||||||
|
void
|
||||||
|
commit(std::size_t n)
|
||||||
|
{
|
||||||
|
out_ += std::min<std::size_t>(n, last_ - out_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a list of buffers that represents the input sequence.
|
||||||
|
const_buffers_type
|
||||||
|
data() const;
|
||||||
|
|
||||||
|
/// Remove bytes from the input sequence.
|
||||||
|
void
|
||||||
|
consume(std::size_t n)
|
||||||
|
{
|
||||||
|
in_ += std::min<std::size_t>(n, out_ - in_);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
private:
|
||||||
|
#else
|
||||||
|
protected:
|
||||||
|
#endif
|
||||||
|
static_streambuf(std::uint8_t* p, std::size_t n)
|
||||||
|
{
|
||||||
|
reset(p, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
reset(std::uint8_t* p, std::size_t n)
|
||||||
|
{
|
||||||
|
in_ = p;
|
||||||
|
out_ = p;
|
||||||
|
last_ = p;
|
||||||
|
end_ = p + n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// The type used to represent the input sequence as a list of buffers.
|
||||||
|
class static_streambuf::const_buffers_type
|
||||||
|
{
|
||||||
|
std::size_t n_;
|
||||||
|
std::uint8_t const* p_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = boost::asio::const_buffer;
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
const_buffers_type() = default;
|
||||||
|
const_buffers_type(
|
||||||
|
const_buffers_type const&) = default;
|
||||||
|
const_buffers_type& operator=(
|
||||||
|
const_buffers_type const&) = default;
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
begin() const;
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
end() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class static_streambuf;
|
||||||
|
|
||||||
|
const_buffers_type(
|
||||||
|
std::uint8_t const* p, std::size_t n)
|
||||||
|
: n_(n)
|
||||||
|
, p_(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class static_streambuf::const_buffers_type::const_iterator
|
||||||
|
{
|
||||||
|
std::size_t n_;
|
||||||
|
std::uint8_t const* p_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = boost::asio::const_buffer;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return p_ == other.p_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return value_type{p_, n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
p_ += n_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
p_ -= n_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class const_buffers_type;
|
||||||
|
|
||||||
|
const_iterator(
|
||||||
|
std::uint8_t const* p, std::size_t n)
|
||||||
|
: n_(n)
|
||||||
|
, p_(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_streambuf::const_buffers_type::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{p_, n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_streambuf::const_buffers_type::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{p_ + n_, n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// The type used to represent the output sequence as a list of buffers.
|
||||||
|
class static_streambuf::mutable_buffers_type
|
||||||
|
{
|
||||||
|
std::size_t n_;
|
||||||
|
std::uint8_t* p_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = boost::asio::mutable_buffer;
|
||||||
|
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
mutable_buffers_type() = default;
|
||||||
|
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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class static_streambuf;
|
||||||
|
|
||||||
|
mutable_buffers_type(
|
||||||
|
std::uint8_t* p, std::size_t n)
|
||||||
|
: n_(n)
|
||||||
|
, p_(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class static_streambuf::mutable_buffers_type::const_iterator
|
||||||
|
{
|
||||||
|
std::size_t n_;
|
||||||
|
std::uint8_t* p_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = boost::asio::mutable_buffer;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return p_ == other.p_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return value_type{p_, n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const = delete;
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
p_ += n_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
p_ -= n_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class mutable_buffers_type;
|
||||||
|
|
||||||
|
const_iterator(std::uint8_t* p, std::size_t n)
|
||||||
|
: n_(n)
|
||||||
|
, p_(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_streambuf::mutable_buffers_type::begin() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{p_, n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_streambuf::mutable_buffers_type::end() const ->
|
||||||
|
const_iterator
|
||||||
|
{
|
||||||
|
return const_iterator{p_ + n_, n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_streambuf::prepare(std::size_t n) ->
|
||||||
|
mutable_buffers_type
|
||||||
|
{
|
||||||
|
if(n > static_cast<std::size_t>(end_ - out_))
|
||||||
|
throw std::length_error("no space in streambuf");
|
||||||
|
last_ = out_ + n;
|
||||||
|
return mutable_buffers_type{out_, n};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_streambuf::data() const ->
|
||||||
|
const_buffers_type
|
||||||
|
{
|
||||||
|
return const_buffers_type{in_,
|
||||||
|
static_cast<std::size_t>(out_ - in_)};
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** A `Streambuf` with a fixed size internal buffer.
|
||||||
|
|
||||||
|
@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 `static_streambuf` instead.
|
||||||
|
*/
|
||||||
|
template<std::size_t N>
|
||||||
|
class static_streambuf_n
|
||||||
|
: private boost::base_from_member<
|
||||||
|
std::array<std::uint8_t, N>>
|
||||||
|
, public static_streambuf
|
||||||
|
{
|
||||||
|
using member_type = boost::base_from_member<
|
||||||
|
std::array<std::uint8_t, N>>;
|
||||||
|
public:
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
private:
|
||||||
|
#endif
|
||||||
|
static_streambuf_n(
|
||||||
|
static_streambuf_n const&) = delete;
|
||||||
|
static_streambuf_n& operator=(
|
||||||
|
static_streambuf_n const&) = delete;
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
public:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Construct a static stream buffer.
|
||||||
|
static_streambuf_n()
|
||||||
|
: static_streambuf(
|
||||||
|
member_type::member.data(),
|
||||||
|
member_type::member.size())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reset the stream buffer.
|
||||||
|
|
||||||
|
Postconditions:
|
||||||
|
The input sequence and output sequence are empty,
|
||||||
|
`max_size()` returns `N`.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
reset()
|
||||||
|
{
|
||||||
|
static_streambuf::reset(
|
||||||
|
member_type::member.data(),
|
||||||
|
member_type::member.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,661 +20,12 @@
|
|||||||
#ifndef BEAST_ASIO_STREAMBUF_H_INCLUDED
|
#ifndef BEAST_ASIO_STREAMBUF_H_INCLUDED
|
||||||
#define BEAST_ASIO_STREAMBUF_H_INCLUDED
|
#define BEAST_ASIO_STREAMBUF_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/empty_base_optimization.h>
|
#include <beast/asio/basic_streambuf.h>
|
||||||
#include <boost/asio/buffer.hpp>
|
|
||||||
#include <boost/intrusive/list.hpp>
|
|
||||||
#include <boost/iterator/transform_iterator.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
#include <memory>
|
|
||||||
#include <exception>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace asio {
|
|
||||||
|
|
||||||
/** Implements asio::streambuf interface using multiple buffers. */
|
|
||||||
template <class Allocator>
|
|
||||||
class basic_streambuf
|
|
||||||
: private empty_base_optimization<Allocator>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using size_type = typename std::allocator_traits<Allocator>::size_type;
|
|
||||||
using const_buffer = boost::asio::const_buffer;
|
|
||||||
using mutable_buffer = boost::asio::mutable_buffer;
|
|
||||||
|
|
||||||
private:
|
|
||||||
class element;
|
|
||||||
|
|
||||||
using alloc_traits = std::allocator_traits<Allocator>;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* These diagrams illustrate the layout and state variables.
|
|
||||||
|
|
||||||
Input and output contained entirely in one element:
|
|
||||||
|
|
||||||
0 out_
|
|
||||||
|<-------------+------------------------------------------->|
|
|
||||||
in_pos_ out_pos_ out_end_
|
|
||||||
|
|
||||||
|
|
||||||
Output contained in first and second elements:
|
|
||||||
|
|
||||||
out_
|
|
||||||
|<------+----------+------->| |<----------+-------------->|
|
|
||||||
in_pos_ out_pos_ out_end_
|
|
||||||
|
|
||||||
|
|
||||||
Output contained in the second element:
|
|
||||||
|
|
||||||
out_
|
|
||||||
|<------------+------------>| |<----+-------------------->|
|
|
||||||
in_pos_ out_pos_ out_end_
|
|
||||||
|
|
||||||
|
|
||||||
Output contained in second and third elements:
|
|
||||||
|
|
||||||
out_
|
|
||||||
|<-----+-------->| |<-------+------>| |<--------------->|
|
|
||||||
in_pos_ out_pos_ out_end_
|
|
||||||
|
|
||||||
|
|
||||||
Input sequence is empty:
|
|
||||||
|
|
||||||
out_
|
|
||||||
|<------+------------------>| |<-----------+------------->|
|
|
||||||
out_pos_ out_end_
|
|
||||||
in_pos_
|
|
||||||
|
|
||||||
|
|
||||||
Output sequence is empty:
|
|
||||||
|
|
||||||
out_
|
|
||||||
|<------+------------------>| |<------+------------------>|
|
|
||||||
in_pos_ out_pos_
|
|
||||||
out_end_
|
|
||||||
|
|
||||||
|
|
||||||
The end of output can point to the end of an element.
|
|
||||||
But out_pos_ should never point to the end:
|
|
||||||
|
|
||||||
out_
|
|
||||||
|<------+------------------>| |<------+------------------>|
|
|
||||||
in_pos_ out_pos_ out_end_
|
|
||||||
|
|
||||||
|
|
||||||
When the input sequence entirely fills the last element and
|
|
||||||
the output sequence is empty, out_ will point to the end of
|
|
||||||
the list of buffers, and out_pos_ and out_end_ will be 0:
|
|
||||||
|
|
||||||
|
|
||||||
|<------+------------------>| out_ == list_.end()
|
|
||||||
in_pos_ out_pos_ == 0
|
|
||||||
out_end_ == 0
|
|
||||||
*/
|
|
||||||
|
|
||||||
list_type list_;
|
|
||||||
size_type block_size_;
|
|
||||||
size_type block_size_next_;
|
|
||||||
size_type in_size_ = 0; // size of the input sequence
|
|
||||||
iterator out_; // element that contains out_pos_
|
|
||||||
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:
|
|
||||||
class const_buffers_type;
|
|
||||||
class mutable_buffers_type;
|
|
||||||
|
|
||||||
basic_streambuf (basic_streambuf const& other) = delete;
|
|
||||||
basic_streambuf& operator= (basic_streambuf const& other) = delete;
|
|
||||||
basic_streambuf& operator= (basic_streambuf&& other) = delete;
|
|
||||||
|
|
||||||
~basic_streambuf();
|
|
||||||
|
|
||||||
explicit
|
|
||||||
basic_streambuf(std::size_t block_size = 16*1024,
|
|
||||||
Allocator const& alloc = Allocator{});
|
|
||||||
|
|
||||||
basic_streambuf (basic_streambuf&& other);
|
|
||||||
|
|
||||||
/** Get the maximum size of the basic_streambuf. */
|
|
||||||
size_type
|
|
||||||
max_size() const
|
|
||||||
{
|
|
||||||
return std::numeric_limits<std::size_t>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the size of the input sequence. */
|
|
||||||
size_type
|
|
||||||
size() const
|
|
||||||
{
|
|
||||||
return in_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a list of buffers that represents the output sequence, with the given size. */
|
|
||||||
mutable_buffers_type
|
|
||||||
prepare (size_type n);
|
|
||||||
|
|
||||||
/** Move bytes from the output sequence to the input sequence. */
|
|
||||||
void
|
|
||||||
commit (size_type n);
|
|
||||||
|
|
||||||
/** Get a list of buffers that represents the input sequence. */
|
|
||||||
const_buffers_type
|
|
||||||
data() const;
|
|
||||||
|
|
||||||
/** Remove bytes from the input sequence. */
|
|
||||||
void
|
|
||||||
consume (size_type n);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void
|
|
||||||
debug_check() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
class basic_streambuf<Allocator>::element
|
|
||||||
: public boost::intrusive::list_base_hook <
|
|
||||||
boost::intrusive::link_mode <boost::intrusive::normal_link>>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
size_type const size_; // size of the allocation minus sizeof(element)
|
|
||||||
|
|
||||||
public:
|
|
||||||
element (element const&) = delete;
|
|
||||||
element& operator= (element const&) = delete;
|
|
||||||
|
|
||||||
explicit
|
|
||||||
element (size_type block_size)
|
|
||||||
: size_(block_size)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
size_type
|
|
||||||
size() const
|
|
||||||
{
|
|
||||||
return size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type
|
|
||||||
alloc_size() const
|
|
||||||
{
|
|
||||||
return size_ + sizeof(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
data() const
|
|
||||||
{
|
|
||||||
return const_cast<char*>(
|
|
||||||
reinterpret_cast<char const*>(this+1));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
class basic_streambuf<Allocator>::const_buffers_type
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using value_type = const_buffer;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct transform
|
|
||||||
{
|
|
||||||
using argument_type = element;
|
|
||||||
using result_type = value_type;
|
|
||||||
|
|
||||||
basic_streambuf const* streambuf_ = nullptr;
|
|
||||||
|
|
||||||
transform() = default;
|
|
||||||
|
|
||||||
explicit
|
|
||||||
transform (basic_streambuf const& streambuf)
|
|
||||||
: streambuf_ (&streambuf)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type const
|
|
||||||
operator() (element const& e) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
basic_streambuf const* streambuf_ = nullptr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using const_iterator = boost::transform_iterator<
|
|
||||||
transform, typename list_type::const_iterator,
|
|
||||||
value_type, value_type>;
|
|
||||||
|
|
||||||
const_buffers_type() = default;
|
|
||||||
const_buffers_type (const_buffers_type const&) = default;
|
|
||||||
const_buffers_type& operator= (const_buffers_type const&) = default;
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
begin() const
|
|
||||||
{
|
|
||||||
return const_iterator (streambuf_->list_.begin(),
|
|
||||||
transform(*streambuf_));
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
end() const
|
|
||||||
{
|
|
||||||
return const_iterator (streambuf_->out_ ==
|
|
||||||
streambuf_->list_.end() ? streambuf_->list_.end() :
|
|
||||||
std::next(streambuf_->out_), transform(*streambuf_));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class basic_streambuf;
|
|
||||||
|
|
||||||
explicit
|
|
||||||
const_buffers_type (basic_streambuf const& streambuf);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
basic_streambuf<Allocator>::const_buffers_type::const_buffers_type (
|
|
||||||
basic_streambuf const& streambuf)
|
|
||||||
: streambuf_ (&streambuf)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
auto
|
|
||||||
basic_streambuf<Allocator>::const_buffers_type::
|
|
||||||
transform::operator() (element const& e) const ->
|
|
||||||
value_type const
|
|
||||||
{
|
|
||||||
return value_type (e.data(),
|
|
||||||
(streambuf_->out_ == streambuf_->list_.end() ||
|
|
||||||
&e != &*streambuf_->out_) ? e.size() : streambuf_->out_pos_) +
|
|
||||||
(&e == &*streambuf_->list_.begin() ?
|
|
||||||
streambuf_->in_pos_ : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
class basic_streambuf<Allocator>::mutable_buffers_type
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using value_type = mutable_buffer;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct transform
|
|
||||||
{
|
|
||||||
using argument_type = element;
|
|
||||||
using result_type = value_type;
|
|
||||||
|
|
||||||
basic_streambuf const* streambuf_ = nullptr;
|
|
||||||
|
|
||||||
transform() = default;
|
|
||||||
|
|
||||||
explicit
|
|
||||||
transform (basic_streambuf const& streambuf)
|
|
||||||
: streambuf_ (&streambuf)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type const
|
|
||||||
operator() (element const& e) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
basic_streambuf const* streambuf_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using const_iterator = boost::transform_iterator<
|
|
||||||
transform, typename list_type::const_iterator,
|
|
||||||
value_type, value_type>;
|
|
||||||
|
|
||||||
mutable_buffers_type() = default;
|
|
||||||
mutable_buffers_type (mutable_buffers_type const&) = default;
|
|
||||||
mutable_buffers_type& operator= (mutable_buffers_type const&) = default;
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
begin() const
|
|
||||||
{
|
|
||||||
return const_iterator (streambuf_->out_,
|
|
||||||
transform(*streambuf_));
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
end() const
|
|
||||||
{
|
|
||||||
return const_iterator (streambuf_->list_.end(),
|
|
||||||
transform(*streambuf_));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class basic_streambuf;
|
|
||||||
mutable_buffers_type (basic_streambuf const& streambuf);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
basic_streambuf<Allocator>::mutable_buffers_type::mutable_buffers_type (
|
|
||||||
basic_streambuf const& streambuf)
|
|
||||||
: streambuf_ (&streambuf)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
auto
|
|
||||||
basic_streambuf<Allocator>::mutable_buffers_type::
|
|
||||||
transform::operator() (element const& e) const ->
|
|
||||||
value_type const
|
|
||||||
{
|
|
||||||
return value_type (e.data(), &e == &*std::prev(streambuf_->list_.end()) ?
|
|
||||||
streambuf_->out_end_ : e.size()) + (&e == &*streambuf_->out_ ?
|
|
||||||
streambuf_->out_pos_ : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
basic_streambuf<Allocator>::~basic_streambuf()
|
|
||||||
{
|
|
||||||
for(auto iter = list_.begin(); iter != list_.end();)
|
|
||||||
{
|
|
||||||
auto& e = *iter++;
|
|
||||||
size_type const n = e.alloc_size();
|
|
||||||
alloc_traits::destroy(this->member(), &e);
|
|
||||||
alloc_traits::deallocate(this->member(),
|
|
||||||
reinterpret_cast<char*>(&e), n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
basic_streambuf<Allocator>::basic_streambuf(std::size_t block_size,
|
|
||||||
Allocator const& alloc)
|
|
||||||
: empty_base_optimization<Allocator>(alloc)
|
|
||||||
, block_size_ (block_size)
|
|
||||||
, block_size_next_ (block_size)
|
|
||||||
, out_ (list_.end())
|
|
||||||
{
|
|
||||||
if (! (block_size > 0))
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"basic_streambuf: invalid block_size");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
basic_streambuf<Allocator>::basic_streambuf (basic_streambuf&& other)
|
|
||||||
: empty_base_optimization<Allocator>(other.member())
|
|
||||||
, list_ (std::move(other.list_))
|
|
||||||
, block_size_ (other.block_size_)
|
|
||||||
, block_size_next_ (other.block_size_next_)
|
|
||||||
, in_size_ (other.in_size_)
|
|
||||||
, out_ (other.out_)
|
|
||||||
, in_pos_ (other.in_pos_)
|
|
||||||
, out_pos_ (other.out_pos_)
|
|
||||||
, out_end_ (other.out_end_)
|
|
||||||
{
|
|
||||||
other.in_size_ = 0;
|
|
||||||
other.out_ = other.list_.end();
|
|
||||||
other.in_pos_ = 0;
|
|
||||||
other.out_pos_ = 0;
|
|
||||||
other.out_end_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
auto
|
|
||||||
basic_streambuf<Allocator>::prepare (size_type n) ->
|
|
||||||
mutable_buffers_type
|
|
||||||
{
|
|
||||||
iterator pos = out_;
|
|
||||||
if (pos != list_.end())
|
|
||||||
{
|
|
||||||
auto const avail = pos->size() - out_pos_;
|
|
||||||
if (n > avail)
|
|
||||||
{
|
|
||||||
n -= avail;
|
|
||||||
while (++pos != list_.end())
|
|
||||||
{
|
|
||||||
if (n < pos->size())
|
|
||||||
{
|
|
||||||
out_end_ = n;
|
|
||||||
n = 0;
|
|
||||||
++pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out_end_ = pos->size();
|
|
||||||
n -= pos->size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++pos;
|
|
||||||
out_end_ = out_pos_ + n;
|
|
||||||
n = 0;
|
|
||||||
}
|
|
||||||
debug_check();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n > 0)
|
|
||||||
{
|
|
||||||
assert(pos == list_.end());
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
auto const avail = block_size_next_;
|
|
||||||
auto& e = *reinterpret_cast<element*>(alloc_traits::allocate(
|
|
||||||
this->member(), avail + sizeof(element)));
|
|
||||||
alloc_traits::construct(this->member(), &e, avail);
|
|
||||||
list_.push_back(e);
|
|
||||||
if (out_ == list_.end())
|
|
||||||
{
|
|
||||||
out_ = list_.iterator_to(e);
|
|
||||||
debug_check();
|
|
||||||
}
|
|
||||||
if (n <= avail)
|
|
||||||
{
|
|
||||||
out_end_ = n;
|
|
||||||
debug_check();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
n -= avail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (pos != list_.end())
|
|
||||||
{
|
|
||||||
auto& e = *pos++;
|
|
||||||
list_.erase(list_.iterator_to(e));
|
|
||||||
auto const len = e.alloc_size();
|
|
||||||
alloc_traits::destroy(this->member(), &e);
|
|
||||||
alloc_traits::deallocate(this->member(),
|
|
||||||
reinterpret_cast<char*>(&e), len);
|
|
||||||
}
|
|
||||||
debug_check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return mutable_buffers_type (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
void
|
|
||||||
basic_streambuf<Allocator>::commit (size_type n)
|
|
||||||
{
|
|
||||||
if (list_.empty())
|
|
||||||
return;
|
|
||||||
if (out_ == list_.end())
|
|
||||||
return;
|
|
||||||
auto const last = std::prev(list_.end());
|
|
||||||
while (out_ != last)
|
|
||||||
{
|
|
||||||
auto const avail =
|
|
||||||
out_->size() - out_pos_;
|
|
||||||
if (n < avail)
|
|
||||||
{
|
|
||||||
out_pos_ += n;
|
|
||||||
in_size_ += n;
|
|
||||||
debug_check();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
++out_;
|
|
||||||
n -= avail;
|
|
||||||
out_pos_ = 0;
|
|
||||||
in_size_ += avail;
|
|
||||||
debug_check();
|
|
||||||
}
|
|
||||||
|
|
||||||
n = std::min (n, out_end_ - out_pos_);
|
|
||||||
out_pos_ += n;
|
|
||||||
in_size_ += n;
|
|
||||||
if (out_pos_ == out_->size())
|
|
||||||
{
|
|
||||||
++out_;
|
|
||||||
out_pos_ = 0;
|
|
||||||
out_end_ = 0;
|
|
||||||
}
|
|
||||||
debug_check();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
auto
|
|
||||||
basic_streambuf<Allocator>::data() const ->
|
|
||||||
const_buffers_type
|
|
||||||
{
|
|
||||||
return const_buffers_type(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
void
|
|
||||||
basic_streambuf<Allocator>::consume (size_type n)
|
|
||||||
{
|
|
||||||
if (list_.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto pos = list_.begin();
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
if (pos != out_)
|
|
||||||
{
|
|
||||||
auto const avail = pos->size() - in_pos_;
|
|
||||||
if (n < avail)
|
|
||||||
{
|
|
||||||
in_size_ -= n;
|
|
||||||
in_pos_ += n;
|
|
||||||
debug_check();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
n -= avail;
|
|
||||||
in_size_ -= avail;
|
|
||||||
in_pos_ = 0;
|
|
||||||
debug_check();
|
|
||||||
|
|
||||||
element& e = *pos++;
|
|
||||||
list_.erase(list_.iterator_to(e));
|
|
||||||
size_type const len = e.alloc_size();
|
|
||||||
alloc_traits::destroy(this->member(), &e);
|
|
||||||
alloc_traits::deallocate(this->member(),
|
|
||||||
reinterpret_cast<char*>(&e), len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto const avail = out_pos_ - in_pos_;
|
|
||||||
if (n < avail)
|
|
||||||
{
|
|
||||||
in_size_ -= n;
|
|
||||||
in_pos_ += n;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
in_size_ -= avail;
|
|
||||||
if (out_pos_ != out_end_||
|
|
||||||
out_ != list_.iterator_to(list_.back()))
|
|
||||||
{
|
|
||||||
in_pos_ = out_pos_;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Use the whole buffer now.
|
|
||||||
// Alternatively we could deallocate it.
|
|
||||||
in_pos_ = 0;
|
|
||||||
out_pos_ = 0;
|
|
||||||
out_end_ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug_check();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Allocator>
|
|
||||||
void
|
|
||||||
basic_streambuf<Allocator>::debug_check() const
|
|
||||||
{
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (list_.empty())
|
|
||||||
{
|
|
||||||
assert(in_pos_ == 0);
|
|
||||||
assert(in_size_ == 0);
|
|
||||||
assert(out_pos_ == 0);
|
|
||||||
assert(out_end_ == 0);
|
|
||||||
assert(out_ == list_.end());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const& front = list_.front();
|
|
||||||
|
|
||||||
assert(in_pos_ < front.size());
|
|
||||||
|
|
||||||
if (out_ == list_.end())
|
|
||||||
{
|
|
||||||
assert(out_pos_ == 0);
|
|
||||||
assert(out_end_ == 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto const& out = *out_;
|
|
||||||
auto const& back = list_.back();
|
|
||||||
|
|
||||||
assert(out_end_ <= back.size());
|
|
||||||
assert(out_pos_ < out.size());
|
|
||||||
assert(&out != &front || out_pos_ >= in_pos_);
|
|
||||||
assert(&out != &front || out_pos_ - in_pos_ == in_size_);
|
|
||||||
assert(&out != &back || out_pos_ <= out_end_);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Alloc, class T>
|
|
||||||
basic_streambuf<Alloc>&
|
|
||||||
operator<< (basic_streambuf<Alloc>& buf, T const& t)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << t;
|
|
||||||
auto const& s = ss.str();
|
|
||||||
buf.commit(boost::asio::buffer_copy(
|
|
||||||
buf.prepare(s.size()), boost::asio::buffer(s)));
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
using streambuf = basic_streambuf<std::allocator<char>>;
|
using streambuf = basic_streambuf<std::allocator<char>>;
|
||||||
|
|
||||||
/** Convert the entire basic_streambuf to a string.
|
} // beast
|
||||||
@note It is more efficient to deal directly in the streambuf instead.
|
|
||||||
*/
|
|
||||||
template <class Allocator>
|
|
||||||
std::string
|
|
||||||
to_string (basic_streambuf<Allocator> const& buf)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
s.resize(buf.size());
|
|
||||||
boost::asio::buffer_copy(boost::asio::buffer(
|
|
||||||
&s[0], s.size()), buf.data());
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
259
beast/asio/streambuf_readstream.h
Normal file
259
beast/asio/streambuf_readstream.h
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_STREAMBUF_READSTREAM_H_INLUDED
|
||||||
|
#define BEAST_ASIO_STREAMBUF_READSTREAM_H_INLUDED
|
||||||
|
|
||||||
|
#include <beast/asio/streambuf.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/asio/io_service.hpp>
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** A `Stream` with attached `Streambuf` to buffer reads.
|
||||||
|
|
||||||
|
This wraps a `Stream` implementation so that calls to write are
|
||||||
|
passed through to the underlying stream, while calls to read will
|
||||||
|
first consume the input sequence stored in a `Streambuf` which
|
||||||
|
is part of the object.
|
||||||
|
|
||||||
|
The use-case for this class is different than that of the
|
||||||
|
`boost::asio::buffered_readstream`. It is designed to facilitate
|
||||||
|
the use of `boost::asio::read_until`, and to allow buffers
|
||||||
|
acquired during detection of handshakes to be made transparently
|
||||||
|
available to callers. A hypothetical implementation of the
|
||||||
|
buffered version of `boost::asio::ssl::stream::async_handshake`
|
||||||
|
could make use of this wrapper.
|
||||||
|
|
||||||
|
Uses:
|
||||||
|
|
||||||
|
* Transparently leave untouched input acquired in calls
|
||||||
|
to `boost::asio::read_until` behind for subsequent callers.
|
||||||
|
|
||||||
|
* "Preload" a stream with handshake input data acquired
|
||||||
|
from other sources.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@code
|
||||||
|
// Process the next HTTP headers on the stream,
|
||||||
|
// leaving excess bytes behind for the next call.
|
||||||
|
//
|
||||||
|
template<class Streambuf>
|
||||||
|
void process_http_message(
|
||||||
|
streambuf_readstream<Streambuf>& stream)
|
||||||
|
{
|
||||||
|
// Read up to and including the end of the HTTP
|
||||||
|
// headers, leaving the sequence in the stream's
|
||||||
|
// buffer. read_until may read past the end of the
|
||||||
|
// headers; the return value will include only the
|
||||||
|
// part up to the end of the delimiter.
|
||||||
|
//
|
||||||
|
std::size_t bytes_transferred =
|
||||||
|
boost::asio::read_until(
|
||||||
|
stream.next_layer(), stream.buffer(), "\r\n\r\n");
|
||||||
|
|
||||||
|
// Use prepare_buffers() to limit the input
|
||||||
|
// sequence to only the data up to and including
|
||||||
|
// the trailing "\r\n\r\n".
|
||||||
|
//
|
||||||
|
auto header_buffers = prepare_buffers(
|
||||||
|
bytes_transferred, stream.buffer().data());
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
// Discard the portion of the input corresponding
|
||||||
|
// to the HTTP headers.
|
||||||
|
//
|
||||||
|
stream.buffer().consume(bytes_transferred);
|
||||||
|
|
||||||
|
// Everything we read from the stream
|
||||||
|
// is part of the content-body.
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@tparam Stream The type of stream to wrap.
|
||||||
|
|
||||||
|
@tparam Streambuf The type of stream buffer to use.
|
||||||
|
*/
|
||||||
|
template<class Stream,
|
||||||
|
class Streambuf = streambuf>
|
||||||
|
class streambuf_readstream
|
||||||
|
{
|
||||||
|
using error_code = boost::system::error_code;
|
||||||
|
|
||||||
|
template<class Buffers, class Handler>
|
||||||
|
class read_some_op;
|
||||||
|
|
||||||
|
Streambuf sb_;
|
||||||
|
std::size_t size_ = 0;
|
||||||
|
Stream next_layer_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The type of the internal buffer
|
||||||
|
using streambuf_type = Streambuf;
|
||||||
|
|
||||||
|
/// The type of the next layer.
|
||||||
|
using next_layer_type =
|
||||||
|
std::remove_reference_t<Stream>;
|
||||||
|
|
||||||
|
/// The type of the lowest layer.
|
||||||
|
using lowest_layer_type =
|
||||||
|
typename next_layer_type::lowest_layer_type;
|
||||||
|
|
||||||
|
/// Move constructor.
|
||||||
|
streambuf_readstream(streambuf_readstream&&) = default;
|
||||||
|
|
||||||
|
/** Construct the wrapping stream.
|
||||||
|
|
||||||
|
@param args Parameters forwarded to the `Stream` constructor.
|
||||||
|
*/
|
||||||
|
template<class... Args>
|
||||||
|
explicit
|
||||||
|
streambuf_readstream(Args&&... args);
|
||||||
|
|
||||||
|
/// Get a reference to the next layer.
|
||||||
|
next_layer_type&
|
||||||
|
next_layer()
|
||||||
|
{
|
||||||
|
return next_layer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the lowest layer.
|
||||||
|
lowest_layer_type&
|
||||||
|
lowest_layer()
|
||||||
|
{
|
||||||
|
return next_layer_.lowest_layer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a const reference to the lowest layer.
|
||||||
|
lowest_layer_type const&
|
||||||
|
lowest_layer() const
|
||||||
|
{
|
||||||
|
return next_layer_.lowest_layer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the io_service associated with the object.
|
||||||
|
boost::asio::io_service&
|
||||||
|
get_io_service()
|
||||||
|
{
|
||||||
|
return next_layer_.get_io_service();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Access the internal buffer.
|
||||||
|
|
||||||
|
The internal buffer is returned. It is possible for the
|
||||||
|
caller to break invariants with this function. For example,
|
||||||
|
by causing the internal buffer size to increase beyond
|
||||||
|
the caller defined maximum.
|
||||||
|
*/
|
||||||
|
Streambuf&
|
||||||
|
buffer()
|
||||||
|
{
|
||||||
|
return sb_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Access the internal buffer.
|
||||||
|
|
||||||
|
The internal buffer is returned. It is possible for the
|
||||||
|
caller to break invariants with this function. For example,
|
||||||
|
by causing the internal buffer size to increase beyond
|
||||||
|
the caller defined maximum.
|
||||||
|
*/
|
||||||
|
Streambuf const&
|
||||||
|
buffer() const
|
||||||
|
{
|
||||||
|
return sb_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the maximum buffer size.
|
||||||
|
|
||||||
|
This changes the maximum size of the internal buffer used
|
||||||
|
to hold read data. No bytes are discarded by this call. If
|
||||||
|
the buffer size is set to zero, no more data will be buffered.
|
||||||
|
|
||||||
|
Thread safety:
|
||||||
|
The caller is responsible for making sure the call is
|
||||||
|
made from the same implicit or explicit strand.
|
||||||
|
|
||||||
|
@param size The number of bytes in the read buffer.
|
||||||
|
|
||||||
|
@note This is a soft limit. If the new maximum size is smaller
|
||||||
|
than the amount of data in the buffer, no bytes are discarded.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
reserve(std::size_t size)
|
||||||
|
{
|
||||||
|
size_ = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the given data to the stream. Returns the number of bytes written.
|
||||||
|
/// Throws an exception on failure.
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_some(ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
return next_layer_.write_some(buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the given data to the stream. Returns the number of bytes written,
|
||||||
|
/// or 0 if an error occurred.
|
||||||
|
template <class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_some(ConstBufferSequence const& buffers,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
return next_layer_.write_some(buffers, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start an asynchronous write. The data being written must be valid for the
|
||||||
|
/// lifetime of the asynchronous operation.
|
||||||
|
template<class ConstBufferSequence, class WriteHandler>
|
||||||
|
auto
|
||||||
|
async_write_some(ConstBufferSequence const& buffers,
|
||||||
|
WriteHandler&& handler);
|
||||||
|
|
||||||
|
/// Read some data from the stream. Returns the number of bytes read.
|
||||||
|
/// Throws an exception on failure.
|
||||||
|
template<class MutableBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
read_some(MutableBufferSequence const& buffers);
|
||||||
|
|
||||||
|
/// Read some data from the stream. Returns the number of bytes read
|
||||||
|
/// or 0 if an error occurred.
|
||||||
|
template<class MutableBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
read_some(MutableBufferSequence const& buffers,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
|
/// Start an asynchronous read. The buffer into which the data will be read
|
||||||
|
/// must be valid for the lifetime of the asynchronous operation.
|
||||||
|
template<class MutableBufferSequence, class ReadHandler>
|
||||||
|
auto
|
||||||
|
async_read_some(MutableBufferSequence const& buffers,
|
||||||
|
ReadHandler&& handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/asio/impl/streambuf_readstream.ipp>
|
||||||
|
|
||||||
|
#endif
|
||||||
109
beast/asio/temp_buffer.h
Normal file
109
beast/asio/temp_buffer.h
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_TEMP_BUFFER_H_INCLUDED
|
||||||
|
#define BEAST_ASIO_TEMP_BUFFER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
template<class Handler>
|
||||||
|
class temp_buffer
|
||||||
|
{
|
||||||
|
Handler& h_;
|
||||||
|
std::size_t n_ = 0;
|
||||||
|
std::uint8_t* p_ = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit
|
||||||
|
temp_buffer(Handler& h)
|
||||||
|
: h_(h)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~temp_buffer()
|
||||||
|
{
|
||||||
|
if(p_)
|
||||||
|
dealloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator
|
||||||
|
boost::asio::const_buffer() const
|
||||||
|
{
|
||||||
|
return boost::asio::const_buffer{p_, n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
operator
|
||||||
|
boost::asio::mutable_buffer() const
|
||||||
|
{
|
||||||
|
return boost::asio::mutable_buffer{p_, n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint8_t*
|
||||||
|
data() const
|
||||||
|
{
|
||||||
|
return p_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
size()
|
||||||
|
{
|
||||||
|
return n_;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::asio::mutable_buffers_1
|
||||||
|
buffers() const
|
||||||
|
{
|
||||||
|
return boost::asio::mutable_buffers_1{
|
||||||
|
p_, n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
alloc(std::size_t size)
|
||||||
|
{
|
||||||
|
if(n_ != size)
|
||||||
|
{
|
||||||
|
if(p_)
|
||||||
|
dealloc();
|
||||||
|
n_ = size;
|
||||||
|
if(n_ > 0)
|
||||||
|
p_ = reinterpret_cast<std::uint8_t*>(
|
||||||
|
boost_asio_handler_alloc_helpers::
|
||||||
|
allocate(n_, h_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dealloc()
|
||||||
|
{
|
||||||
|
boost_asio_handler_alloc_helpers::
|
||||||
|
deallocate(p_, n_, h_);
|
||||||
|
p_ = nullptr;
|
||||||
|
n_ = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
329
beast/asio/type_check.h
Normal file
329
beast/asio/type_check.h
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ASIO_TYPE_CHECK_H_INCLUDED
|
||||||
|
#define BEAST_ASIO_TYPE_CHECK_H_INCLUDED
|
||||||
|
|
||||||
|
#include <beast/is_call_possible.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/asio/error.hpp>
|
||||||
|
#include <boost/asio/io_service.hpp>
|
||||||
|
#include <iterator>
|
||||||
|
#include <beast/cxx17/type_traits.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Types that meet the requirements,
|
||||||
|
// for use with std::declval only.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
namespace detail {
|
||||||
|
#else
|
||||||
|
namespace concept {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<class BufferType>
|
||||||
|
struct BufferSequence
|
||||||
|
{
|
||||||
|
using value_type = BufferType;
|
||||||
|
using const_iterator = BufferType const*;
|
||||||
|
~BufferSequence();
|
||||||
|
BufferSequence(BufferSequence const&) = default;
|
||||||
|
const_iterator
|
||||||
|
begin() const noexcept;
|
||||||
|
const_iterator
|
||||||
|
end() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ConstBufferSequence =
|
||||||
|
BufferSequence<boost::asio::const_buffer>;
|
||||||
|
|
||||||
|
using MutableBufferSequence =
|
||||||
|
BufferSequence<boost::asio::mutable_buffer>;
|
||||||
|
|
||||||
|
struct StreamHandler
|
||||||
|
{
|
||||||
|
StreamHandler(StreamHandler const&) = default;
|
||||||
|
void
|
||||||
|
operator()(boost::system::error_code ec,
|
||||||
|
std::size_t);
|
||||||
|
};
|
||||||
|
|
||||||
|
using ReadHandler = StreamHandler;
|
||||||
|
using WriteHandler = StreamHandler;
|
||||||
|
|
||||||
|
} // concept
|
||||||
|
|
||||||
|
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html
|
||||||
|
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html
|
||||||
|
//
|
||||||
|
/// Determine if `T` meets the requirements of `BufferSequence`.
|
||||||
|
template<class T, class BufferType>
|
||||||
|
class is_BufferSequence
|
||||||
|
{
|
||||||
|
template<class U, class R = std::is_convertible<
|
||||||
|
typename U::value_type, BufferType> >
|
||||||
|
static R check1(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check1(...);
|
||||||
|
using type1 = decltype(check1<T>(0));
|
||||||
|
|
||||||
|
template<class U, class R = std::is_base_of<
|
||||||
|
#if 0
|
||||||
|
std::bidirectional_iterator_tag,
|
||||||
|
typename std::iterator_traits<
|
||||||
|
typename U::const_iterator>::iterator_category>>
|
||||||
|
#else
|
||||||
|
// workaround:
|
||||||
|
// boost::asio::detail::consuming_buffers::const_iterator
|
||||||
|
// is not bidirectional
|
||||||
|
std::forward_iterator_tag,
|
||||||
|
typename std::iterator_traits<
|
||||||
|
typename U::const_iterator>::iterator_category>>
|
||||||
|
#endif
|
||||||
|
static R check2(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check2(...);
|
||||||
|
using type2 = decltype(check2<T>(0));
|
||||||
|
|
||||||
|
template<class U, class R = typename
|
||||||
|
std::is_convertible<decltype(
|
||||||
|
std::declval<U>().begin()),
|
||||||
|
typename U::const_iterator>::type>
|
||||||
|
static R check3(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check3(...);
|
||||||
|
using type3 = decltype(check3<T>(0));
|
||||||
|
|
||||||
|
template<class U, class R = typename std::is_convertible<decltype(
|
||||||
|
std::declval<U>().end()),
|
||||||
|
typename U::const_iterator>::type>
|
||||||
|
static R check4(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check4(...);
|
||||||
|
using type4 = decltype(check4<T>(0));
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// `true` if `T` meets the requirements.
|
||||||
|
static bool const value =
|
||||||
|
std::is_copy_constructible<T>::value &&
|
||||||
|
std::is_destructible<T>::value &&
|
||||||
|
type1::value && type2::value &&
|
||||||
|
type3::value && type4::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if ! GENERATING_DOCS
|
||||||
|
|
||||||
|
/// Determine if `T` meets the requirements of `ConstBufferSequence`.
|
||||||
|
template<class T>
|
||||||
|
using is_ConstBufferSequence =
|
||||||
|
is_BufferSequence<T, boost::asio::const_buffer>;
|
||||||
|
static_assert(is_ConstBufferSequence<concept::ConstBufferSequence>::value, "");
|
||||||
|
static_assert(! is_ConstBufferSequence<int>::value, "");
|
||||||
|
|
||||||
|
/// Determine if `T` meets the requirements of `MutableBufferSequence`.
|
||||||
|
template<class C>
|
||||||
|
using is_MutableBufferSequence =
|
||||||
|
is_BufferSequence<C, boost::asio::mutable_buffer>;
|
||||||
|
static_assert(is_MutableBufferSequence<concept::MutableBufferSequence>::value, "");
|
||||||
|
static_assert(! is_MutableBufferSequence<int>::value, "");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Determine if `T` has the `get_io_service` member.
|
||||||
|
template<class T>
|
||||||
|
class has_get_io_service
|
||||||
|
{
|
||||||
|
template<class U, class R = typename std::is_same<
|
||||||
|
decltype(std::declval<U>().get_io_service()),
|
||||||
|
boost::asio::io_service&>>
|
||||||
|
static R check(int);
|
||||||
|
template <class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<T>(0));
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// `true` if `T` meets the requirements.
|
||||||
|
static bool const value = type::value;
|
||||||
|
};
|
||||||
|
static_assert(! has_get_io_service<int>::value, "");
|
||||||
|
|
||||||
|
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html
|
||||||
|
//
|
||||||
|
/// Determine if `T` meets the requirements of `AsyncReadStream`.
|
||||||
|
template<class T>
|
||||||
|
class is_AsyncReadStream
|
||||||
|
{
|
||||||
|
template<class U, class R = decltype(
|
||||||
|
std::declval<U>().async_read_some(
|
||||||
|
std::declval<concept::MutableBufferSequence>(),
|
||||||
|
std::declval<concept::ReadHandler>()),
|
||||||
|
std::true_type{})>
|
||||||
|
static R check(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<T>(0));
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// `true` if `T` meets the requirements.
|
||||||
|
static bool const value =
|
||||||
|
has_get_io_service<T>::value && type::value;
|
||||||
|
};
|
||||||
|
static_assert(! is_AsyncReadStream<int>::value, "");
|
||||||
|
|
||||||
|
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html
|
||||||
|
//
|
||||||
|
/// Determine if `T` meets the requirements of `AsyncWriteStream`.
|
||||||
|
template<class T>
|
||||||
|
class is_AsyncWriteStream
|
||||||
|
{
|
||||||
|
template<class U, class R = decltype(
|
||||||
|
std::declval<U>().async_write_some(
|
||||||
|
std::declval<concept::ConstBufferSequence>(),
|
||||||
|
std::declval<concept::WriteHandler>()),
|
||||||
|
std::true_type{})>
|
||||||
|
static R check(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<T>(0));
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// `true` if `T` meets the requirements.
|
||||||
|
static bool const value =
|
||||||
|
has_get_io_service<T>::value && type::value;
|
||||||
|
};
|
||||||
|
static_assert(! is_AsyncWriteStream<int>::value, "");
|
||||||
|
|
||||||
|
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html
|
||||||
|
//
|
||||||
|
/// Determine if `T` meets the requirements of `SyncReadStream`.
|
||||||
|
template<class T>
|
||||||
|
class is_SyncReadStream
|
||||||
|
{
|
||||||
|
using error_code =
|
||||||
|
boost::system::error_code;
|
||||||
|
|
||||||
|
template<class U, class R = std::is_same<decltype(
|
||||||
|
std::declval<U>().read_some(
|
||||||
|
std::declval<concept::MutableBufferSequence>())),
|
||||||
|
std::size_t>>
|
||||||
|
static R check1(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check1(...);
|
||||||
|
using type1 = decltype(check1<T>(0));
|
||||||
|
|
||||||
|
template<class U, class R = std::is_same<decltype(
|
||||||
|
std::declval<U>().read_some(
|
||||||
|
std::declval<concept::MutableBufferSequence>(),
|
||||||
|
std::declval<error_code&>())), std::size_t>>
|
||||||
|
static R check2(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check2(...);
|
||||||
|
using type2 = decltype(check2<T>(0));
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// `true` if `T` meets the requirements.
|
||||||
|
static bool const value =
|
||||||
|
type1::value && type2::value;
|
||||||
|
};
|
||||||
|
static_assert(! is_SyncReadStream<int>::value, "");
|
||||||
|
|
||||||
|
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html
|
||||||
|
//
|
||||||
|
/// Determine if `T` meets the requirements of `SyncWriterStream`.
|
||||||
|
template<class T>
|
||||||
|
class is_SyncWriteStream
|
||||||
|
{
|
||||||
|
using error_code =
|
||||||
|
boost::system::error_code;
|
||||||
|
|
||||||
|
template<class U, class R = std::is_same<decltype(
|
||||||
|
std::declval<U>().write_some(
|
||||||
|
std::declval<concept::ConstBufferSequence>())),
|
||||||
|
std::size_t>>
|
||||||
|
static R check1(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check1(...);
|
||||||
|
using type1 = decltype(check1<T>(0));
|
||||||
|
|
||||||
|
template<class U, class R = std::is_same<decltype(
|
||||||
|
std::declval<U>().write_some(
|
||||||
|
std::declval<concept::ConstBufferSequence>(),
|
||||||
|
std::declval<error_code&>())), std::size_t>>
|
||||||
|
static R check2(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check2(...);
|
||||||
|
using type2 = decltype(check2<T>(0));
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// `true` if `T` meets the requirements.
|
||||||
|
static bool const value =
|
||||||
|
type1::value && type2::value;
|
||||||
|
};
|
||||||
|
static_assert(! is_SyncWriteStream<int>::value, "");
|
||||||
|
|
||||||
|
/// Determine if `T` meets the requirements of `Stream`.
|
||||||
|
template<class T>
|
||||||
|
struct is_Stream
|
||||||
|
{
|
||||||
|
/// `true` if `T` meets the requirements.
|
||||||
|
static bool const value =
|
||||||
|
is_AsyncReadStream<T>::value &&
|
||||||
|
is_AsyncWriteStream<T>::value &&
|
||||||
|
is_SyncReadStream<T>::value &&
|
||||||
|
is_SyncWriteStream<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Determine if `T` meets the requirements of `Streambuf`.
|
||||||
|
template<class T, class = void>
|
||||||
|
struct is_Streambuf : std::false_type {};
|
||||||
|
template <class T>
|
||||||
|
struct is_Streambuf<T, std::void_t<
|
||||||
|
// VFALCO TODO Add check for const_buffers_type, mutable_buffers_type, max_size(?)
|
||||||
|
std::integral_constant<bool,
|
||||||
|
is_MutableBufferSequence<decltype(
|
||||||
|
std::declval<T>().prepare(1))>::value>,
|
||||||
|
std::integral_constant<bool,
|
||||||
|
is_ConstBufferSequence<decltype(
|
||||||
|
std::declval<T>().data())>::value>,
|
||||||
|
decltype(std::declval<T>().commit(1), std::true_type{}),
|
||||||
|
decltype(std::declval<T>().consume(1), std::true_type{}),
|
||||||
|
std::is_same<decltype(
|
||||||
|
std::declval<T>().size()), std::size_t>
|
||||||
|
>>:std::true_type{};
|
||||||
|
|
||||||
|
#if ! GENERATING_DOCS
|
||||||
|
|
||||||
|
/// Determine if `T` meets the requirements of `CompletionHandler`.
|
||||||
|
template<class T, class Signature>
|
||||||
|
using is_Handler = std::integral_constant<bool,
|
||||||
|
std::is_copy_constructible<std::decay_t<T>>::value &&
|
||||||
|
is_call_possible<T, Signature>::value>;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
class chunk_encode_test : public unit_test::suite
|
class chunk_encode_test : public unit_test::suite
|
||||||
{
|
{
|
||||||
@@ -98,7 +99,7 @@ public:
|
|||||||
check (std::string const& in, std::string const& answer,
|
check (std::string const& in, std::string const& answer,
|
||||||
bool final_chunk = true)
|
bool final_chunk = true)
|
||||||
{
|
{
|
||||||
asio::streambuf sb(3);
|
streambuf sb(3);
|
||||||
sb << in;
|
sb << in;
|
||||||
auto const out = streambuf_to_string (sb, final_chunk);
|
auto const out = streambuf_to_string (sb, final_chunk);
|
||||||
if (! expect (out == answer))
|
if (! expect (out == answer))
|
||||||
@@ -108,7 +109,7 @@ public:
|
|||||||
|
|
||||||
void testStreambuf()
|
void testStreambuf()
|
||||||
{
|
{
|
||||||
asio::streambuf sb(3);
|
streambuf sb(3);
|
||||||
std::string const s =
|
std::string const s =
|
||||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||||
@@ -147,5 +148,7 @@ public:
|
|||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(chunk_encode,http,beast);
|
BEAST_DEFINE_TESTSUITE(chunk_encode,http,beast);
|
||||||
|
|
||||||
}
|
} // test
|
||||||
}
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#if BEAST_INCLUDE_BEASTCONFIG
|
#include <beast/asio/src/test/beast_asio_bind_handler_test.cpp>
|
||||||
#include <BeastConfig.h>
|
#include <beast/asio/src/test/beast_asio_buffers_test.cpp>
|
||||||
#endif
|
#include <beast/asio/src/test/beast_asio_error_test.cpp>
|
||||||
|
|
||||||
#include <beast/asio/impl/error.cpp>
|
|
||||||
#include <beast/asio/tests/bind_handler.test.cpp>
|
|
||||||
#include <beast/asio/tests/streambuf.test.cpp>
|
|
||||||
#include <beast/asio/tests/error_test.cpp>
|
|
||||||
|
|
||||||
29
test/asio/Jamfile
Normal file
29
test/asio/Jamfile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#
|
||||||
|
# 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)
|
||||||
|
#
|
||||||
|
|
||||||
|
import os ;
|
||||||
|
|
||||||
|
path-constant main : ../../beast/unit_test/src/main.cpp ;
|
||||||
|
|
||||||
|
unit-test all :
|
||||||
|
append_buffers.cpp
|
||||||
|
asio.cpp
|
||||||
|
async_completion.cpp
|
||||||
|
basic_streambuf.cpp
|
||||||
|
bind_handler.cpp
|
||||||
|
buffers_adapter.cpp
|
||||||
|
buffers_debug.cpp
|
||||||
|
consuming_buffers.cpp
|
||||||
|
handler_alloc.cpp
|
||||||
|
placeholders.cpp
|
||||||
|
prepare_buffers.cpp
|
||||||
|
static_streambuf.cpp
|
||||||
|
streambuf.cpp
|
||||||
|
streambuf_readstream.cpp
|
||||||
|
type_check.cpp
|
||||||
|
$(main)
|
||||||
|
;
|
||||||
76
test/asio/append_buffers.cpp
Normal file
76
test/asio/append_buffers.cpp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/append_buffers.h>
|
||||||
|
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/asio/streambuf.hpp>
|
||||||
|
#include <iterator>
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace asio {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
class append_buffers_test : public unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void testAppendBuffers()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
char buf[10];
|
||||||
|
std::list<const_buffer> b1;
|
||||||
|
std::vector<const_buffer> b2{
|
||||||
|
const_buffer{buf+0, 1},
|
||||||
|
const_buffer{buf+1, 2}};
|
||||||
|
std::list<const_buffer> b3;
|
||||||
|
std::array<const_buffer, 3> b4{{
|
||||||
|
const_buffer{buf+3, 1},
|
||||||
|
const_buffer{buf+4, 2},
|
||||||
|
const_buffer{buf+6, 3}}};
|
||||||
|
std::list<const_buffer> b5{
|
||||||
|
const_buffer{buf+9, 1}};
|
||||||
|
std::list<const_buffer> b6;
|
||||||
|
auto bs = append_buffers(
|
||||||
|
b1, b2, b3, b4, b5, b6);
|
||||||
|
expect(buffer_size(bs) == 10);
|
||||||
|
std::vector<const_buffer> v;
|
||||||
|
for(auto iter = std::make_reverse_iterator(bs.end());
|
||||||
|
iter != std::make_reverse_iterator(bs.begin()); ++iter)
|
||||||
|
v.emplace_back(*iter);
|
||||||
|
expect(buffer_size(bs) == 10);
|
||||||
|
decltype(bs) bs2(bs);
|
||||||
|
auto bs3(std::move(bs));
|
||||||
|
bs = bs2;
|
||||||
|
bs3 = std::move(bs2);
|
||||||
|
{
|
||||||
|
boost::asio::streambuf sb1, sb2;
|
||||||
|
expect(buffer_size(append_buffers(
|
||||||
|
sb1.prepare(5), sb2.prepare(7))) == 12);
|
||||||
|
sb1.commit(5);
|
||||||
|
sb2.commit(7);
|
||||||
|
expect(buffer_size(append_buffers(
|
||||||
|
sb1.data(), sb2.data())) == 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testAppendBuffers();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(append_buffers,asio,beast);
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // asio
|
||||||
|
} // beast
|
||||||
9
test/asio/asio.cpp
Normal file
9
test/asio/asio.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// 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/asio.h>
|
||||||
9
test/asio/async_completion.cpp
Normal file
9
test/asio/async_completion.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/async_completion.h>
|
||||||
9
test/asio/basic_streambuf.cpp
Normal file
9
test/asio/basic_streambuf.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/basic_streambuf.h>
|
||||||
11
test/asio/bind_handler.cpp
Normal file
11
test/asio/bind_handler.cpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/bind_handler.h>
|
||||||
|
|
||||||
|
#include <beast/asio/src/test/beast_asio_bind_handler_test.cpp>
|
||||||
124
test/asio/buffers_adapter.cpp
Normal file
124
test/asio/buffers_adapter.cpp
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/buffers_adapter.h>
|
||||||
|
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/asio/streambuf.hpp>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace asio {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
class buffers_adapter_test : public unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
to_string(ConstBufferSequence const& bs)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string s;
|
||||||
|
s.reserve(buffer_size(bs));
|
||||||
|
for(auto const& b : bs)
|
||||||
|
s.append(buffer_cast<char const*>(b),
|
||||||
|
buffer_size(b));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testBuffersAdapter()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
using boost::asio::mutable_buffer;
|
||||||
|
char buf[12];
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
expect(s.size() == sizeof(buf));
|
||||||
|
for(std::size_t i = 1; i < 4; ++i) {
|
||||||
|
for(std::size_t j = 1; j < 4; ++j) {
|
||||||
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
|
for(std::size_t t = 1; t < 4; ++ t) {
|
||||||
|
for(std::size_t u = 1; u < 4; ++ u) {
|
||||||
|
std::size_t k = sizeof(buf) - (i + j);
|
||||||
|
std::size_t z = sizeof(buf) - (x + y);
|
||||||
|
std::size_t v = sizeof(buf) - (t + u);
|
||||||
|
{
|
||||||
|
std::memset(buf, 0, sizeof(buf));
|
||||||
|
std::array<mutable_buffer, 3> bs{{
|
||||||
|
mutable_buffer{&buf[0], i},
|
||||||
|
mutable_buffer{&buf[i], j},
|
||||||
|
mutable_buffer{&buf[i+j], k}}};
|
||||||
|
buffers_adapter<decltype(bs)> ba(std::move(bs));
|
||||||
|
expect(ba.max_size() == sizeof(buf));
|
||||||
|
decltype(ba)::mutable_buffers_type d;
|
||||||
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
|
expect(ba.size() == x);
|
||||||
|
expect(ba.max_size() == sizeof(buf) - x);
|
||||||
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
|
ba.commit(1);
|
||||||
|
expect(ba.size() == x + y);
|
||||||
|
expect(ba.max_size() == sizeof(buf) - (x + y));
|
||||||
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
|
d = ba.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = ba.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
|
ba.commit(2);
|
||||||
|
expect(ba.size() == x + y + z);
|
||||||
|
expect(ba.max_size() == 0);
|
||||||
|
expect(buffer_size(ba.data()) == ba.size());
|
||||||
|
expect(to_string(ba.data()) == s);
|
||||||
|
ba.consume(t);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
expect(to_string(ba.data()) == s.substr(t, std::string::npos));
|
||||||
|
ba.consume(u);
|
||||||
|
expect(to_string(ba.data()) == s.substr(t + u, std::string::npos));
|
||||||
|
ba.consume(v);
|
||||||
|
expect(to_string(ba.data()) == "");
|
||||||
|
ba.consume(1);
|
||||||
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ba.prepare(1);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}}}}}
|
||||||
|
}
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testBuffersAdapter();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(buffers_adapter,asio,beast);
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // asio
|
||||||
|
} // beast
|
||||||
9
test/asio/buffers_debug.cpp
Normal file
9
test/asio/buffers_debug.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/buffers_debug.h>
|
||||||
97
test/asio/consuming_buffers.cpp
Normal file
97
test/asio/consuming_buffers.cpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/consuming_buffers.h>
|
||||||
|
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace asio {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
class consuming_buffers_test : public unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
to_string(ConstBufferSequence const& bs)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string s;
|
||||||
|
s.reserve(buffer_size(bs));
|
||||||
|
for(auto const& b : bs)
|
||||||
|
s.append(buffer_cast<char const*>(b),
|
||||||
|
buffer_size(b));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testBuffers()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
char buf[12];
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
expect(s.size() == sizeof(buf));
|
||||||
|
buffer_copy(buffer(buf), buffer(s));
|
||||||
|
expect(to_string(buffer(buf)) == s);
|
||||||
|
for(std::size_t i = 1; i < 4; ++i) {
|
||||||
|
for(std::size_t j = 1; j < 4; ++j) {
|
||||||
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
|
std::size_t k = sizeof(buf) - (i + j);
|
||||||
|
std::size_t z = sizeof(buf) - (x + y);
|
||||||
|
{
|
||||||
|
std::array<const_buffer, 3> bs{{
|
||||||
|
const_buffer{&buf[0], i},
|
||||||
|
const_buffer{&buf[i], j},
|
||||||
|
const_buffer{&buf[i+j], k}}};
|
||||||
|
consuming_buffers<decltype(bs)> cb(bs);
|
||||||
|
expect(to_string(cb) == s);
|
||||||
|
cb.consume(0);
|
||||||
|
expect(to_string(cb) == s);
|
||||||
|
cb.consume(x);
|
||||||
|
expect(to_string(cb) == s.substr(x));
|
||||||
|
cb.consume(y);
|
||||||
|
expect(to_string(cb) == s.substr(x+y));
|
||||||
|
cb.consume(z);
|
||||||
|
expect(to_string(cb) == "");
|
||||||
|
cb.consume(1);
|
||||||
|
expect(to_string(cb) == "");
|
||||||
|
}
|
||||||
|
}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testNullBuffers()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
using boost::asio::null_buffers;
|
||||||
|
consuming_buffers<null_buffers> cb(
|
||||||
|
null_buffers{});
|
||||||
|
expect(buffer_size(cb) == 0);
|
||||||
|
consuming_buffers<null_buffers> cb2(
|
||||||
|
null_buffers{});
|
||||||
|
expect(buffer_copy(cb2, cb) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testBuffers();
|
||||||
|
testNullBuffers();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(consuming_buffers,asio,beast);
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // asio
|
||||||
|
} // beast
|
||||||
9
test/asio/handler_alloc.cpp
Normal file
9
test/asio/handler_alloc.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/handler_alloc.h>
|
||||||
9
test/asio/placeholders.cpp
Normal file
9
test/asio/placeholders.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/placeholders.h>
|
||||||
103
test/asio/prepare_buffers.cpp
Normal file
103
test/asio/prepare_buffers.cpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/prepare_buffers.h>
|
||||||
|
|
||||||
|
#include <beast/asio/consuming_buffers.h>
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace asio {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
class prepare_buffers_test : public unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
to_string(ConstBufferSequence const& bs)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string s;
|
||||||
|
s.reserve(buffer_size(bs));
|
||||||
|
for(auto const& b : bs)
|
||||||
|
s.append(buffer_cast<char const*>(b),
|
||||||
|
buffer_size(b));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testBuffers()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
expect(s.size() == 12);
|
||||||
|
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);
|
||||||
|
{
|
||||||
|
std::array<const_buffer, 3> bs{{
|
||||||
|
const_buffer{&s[0], x},
|
||||||
|
const_buffer{&s[x], y},
|
||||||
|
const_buffer{&s[x+y], z}}};
|
||||||
|
for(std::size_t i = 0; i <= s.size() + 1; ++i)
|
||||||
|
{
|
||||||
|
auto pb = prepare_buffers(i, bs);
|
||||||
|
expect(to_string(pb) == s.substr(0, i));
|
||||||
|
auto pb2 = pb;
|
||||||
|
expect(to_string(pb2) == to_string(pb));
|
||||||
|
pb = prepare_buffers(0, bs);
|
||||||
|
pb2 = pb;
|
||||||
|
expect(buffer_size(pb2) == 0);
|
||||||
|
pb2 = prepare_buffers(i, bs);
|
||||||
|
expect(to_string(pb2) == s.substr(0, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testNullBuffers()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_copy;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
using boost::asio::null_buffers;
|
||||||
|
auto pb0 = prepare_buffers(0, null_buffers{});
|
||||||
|
expect(buffer_size(pb0) == 0);
|
||||||
|
auto pb1 = prepare_buffers(1, null_buffers{});
|
||||||
|
expect(buffer_size(pb1) == 0);
|
||||||
|
expect(buffer_copy(pb0, pb1) == 0);
|
||||||
|
|
||||||
|
using pb_type = decltype(pb0);
|
||||||
|
consuming_buffers<pb_type> cb(pb0);
|
||||||
|
expect(buffer_size(cb) == 0);
|
||||||
|
expect(buffer_copy(cb, pb1) == 0);
|
||||||
|
cb.consume(1);
|
||||||
|
expect(buffer_size(cb) == 0);
|
||||||
|
expect(buffer_copy(cb, pb1) == 0);
|
||||||
|
|
||||||
|
auto pbc = prepare_buffers(2, cb);
|
||||||
|
expect(buffer_size(pbc) == 0);
|
||||||
|
expect(buffer_copy(pbc, cb) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testBuffers();
|
||||||
|
testNullBuffers();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(prepare_buffers,asio,beast);
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // asio
|
||||||
|
} // beast
|
||||||
@@ -1,29 +1,22 @@
|
|||||||
//------------------------------------------------------------------------------
|
//
|
||||||
/*
|
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
//
|
||||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
|
||||||
|
//
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
// Test that header file is self-contained.
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
#include <beast/asio/static_streambuf.h>
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <beast/asio/streambuf.h>
|
|
||||||
#include <beast/unit_test/suite.h>
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace asio {
|
namespace asio {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
class streambuf_test : public unit_test::suite
|
class static_streambuf_test : public unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
@@ -31,7 +24,8 @@ public:
|
|||||||
std::string
|
std::string
|
||||||
to_string(ConstBufferSequence const& bs)
|
to_string(ConstBufferSequence const& bs)
|
||||||
{
|
{
|
||||||
using namespace boost::asio;
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
std::string s;
|
std::string s;
|
||||||
s.reserve(buffer_size(bs));
|
s.reserve(buffer_size(bs));
|
||||||
for(auto const& b : bs)
|
for(auto const& b : bs)
|
||||||
@@ -40,13 +34,16 @@ public:
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void testStreambuf()
|
void testStaticStreambuf()
|
||||||
{
|
{
|
||||||
using namespace boost::asio;
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
char buf[12];
|
char buf[12];
|
||||||
std::string const s = "Hello, world";
|
std::string const s = "Hello, world";
|
||||||
expect(s.size() == sizeof(buf));
|
expect(s.size() == sizeof(buf));
|
||||||
for(std::size_t i = 1; i < 12; ++i) {
|
for(std::size_t i = 1; i < 4; ++i) {
|
||||||
|
for(std::size_t j = 1; j < 4; ++j) {
|
||||||
for(std::size_t x = 1; x < 4; ++x) {
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
for(std::size_t y = 1; y < 4; ++y) {
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
for(std::size_t t = 1; t < 4; ++ t) {
|
for(std::size_t t = 1; t < 4; ++ t) {
|
||||||
@@ -55,7 +52,7 @@ public:
|
|||||||
std::size_t v = sizeof(buf) - (t + u);
|
std::size_t v = sizeof(buf) - (t + u);
|
||||||
{
|
{
|
||||||
std::memset(buf, 0, sizeof(buf));
|
std::memset(buf, 0, sizeof(buf));
|
||||||
streambuf ba(i);
|
static_streambuf_n<sizeof(buf)> ba;
|
||||||
decltype(ba)::mutable_buffers_type d;
|
decltype(ba)::mutable_buffers_type d;
|
||||||
d = ba.prepare(z); expect(buffer_size(d) == z);
|
d = ba.prepare(z); expect(buffer_size(d) == z);
|
||||||
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
@@ -90,17 +87,27 @@ public:
|
|||||||
expect(to_string(ba.data()) == "");
|
expect(to_string(ba.data()) == "");
|
||||||
ba.consume(1);
|
ba.consume(1);
|
||||||
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
d = ba.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ba.prepare(1);
|
||||||
|
fail();
|
||||||
}
|
}
|
||||||
}}}}}
|
catch(...)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}}}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void run()
|
void run() override
|
||||||
{
|
{
|
||||||
testStreambuf();
|
testStaticStreambuf();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(streambuf,asio,beast);
|
BEAST_DEFINE_TESTSUITE(static_streambuf,asio,beast);
|
||||||
|
|
||||||
}
|
} // test
|
||||||
}
|
} // asio
|
||||||
|
} // beast
|
||||||
296
test/asio/streambuf.cpp
Normal file
296
test/asio/streambuf.cpp
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/streambuf.h>
|
||||||
|
|
||||||
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace asio {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
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 streambuf_test : public unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
to_string(ConstBufferSequence const& bs)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string s;
|
||||||
|
s.reserve(buffer_size(bs));
|
||||||
|
for(auto const& b : bs)
|
||||||
|
s.append(buffer_cast<char const*>(b),
|
||||||
|
buffer_size(b));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testStreambuf()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
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);
|
||||||
|
decltype(sb)::mutable_buffers_type d;
|
||||||
|
d = sb.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = sb.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = sb.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
sb.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
|
expect(sb.size() == x);
|
||||||
|
expect(buffer_size(sb.data()) == sb.size());
|
||||||
|
d = sb.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = sb.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
d = sb.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
sb.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
|
sb.commit(1);
|
||||||
|
expect(sb.size() == x + y);
|
||||||
|
expect(buffer_size(sb.data()) == sb.size());
|
||||||
|
d = sb.prepare(x); expect(buffer_size(d) == x);
|
||||||
|
d = sb.prepare(y); expect(buffer_size(d) == y);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
d = sb.prepare(z); expect(buffer_size(d) == z);
|
||||||
|
sb.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
|
sb.commit(2);
|
||||||
|
expect(sb.size() == x + y + z);
|
||||||
|
expect(buffer_size(sb.data()) == sb.size());
|
||||||
|
expect(to_string(sb.data()) == s);
|
||||||
|
sb.consume(t);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
expect(to_string(sb.data()) == s.substr(t, std::string::npos));
|
||||||
|
sb.consume(u);
|
||||||
|
expect(to_string(sb.data()) == s.substr(t + u, std::string::npos));
|
||||||
|
sb.consume(v);
|
||||||
|
expect(to_string(sb.data()) == "");
|
||||||
|
sb.consume(1);
|
||||||
|
d = sb.prepare(0); expect(buffer_size(d) == 0);
|
||||||
|
}
|
||||||
|
}}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSpecial()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
std::string const s = "Hello, world";
|
||||||
|
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)));
|
||||||
|
expect(to_string(sb.data()) == s);
|
||||||
|
{
|
||||||
|
streambuf sb2(sb);
|
||||||
|
expect(eq(sb, sb2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
streambuf sb2;
|
||||||
|
sb2 = sb;
|
||||||
|
expect(eq(sb, sb2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
streambuf sb2(std::move(sb));
|
||||||
|
expect(to_string(sb2.data()) == s);
|
||||||
|
expect(buffer_size(sb.data()) == 0);
|
||||||
|
sb = std::move(sb2);
|
||||||
|
expect(to_string(sb.data()) == s);
|
||||||
|
expect(buffer_size(sb2.data()) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAllocator()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
test_allocator<char, false, false, false, false>;
|
||||||
|
using sb_type = basic_streambuf<alloc_type>;
|
||||||
|
sb_type sb;
|
||||||
|
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;
|
||||||
|
expect(sb.get_allocator().id() == 2);
|
||||||
|
sb_type sb2(sb);
|
||||||
|
expect(sb2.get_allocator().id() == 2);
|
||||||
|
sb_type sb3(sb, alloc_type{});
|
||||||
|
//expect(sb3.get_allocator().id() == 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
test_allocator<char, false, false, false, false>;
|
||||||
|
using sb_type = basic_streambuf<alloc_type>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testStreambuf();
|
||||||
|
testSpecial();
|
||||||
|
testAllocator();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(streambuf,asio,beast);
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // asio
|
||||||
|
} // beast
|
||||||
9
test/asio/streambuf_readstream.cpp
Normal file
9
test/asio/streambuf_readstream.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/streambuf_readstream.h>
|
||||||
9
test/asio/temp_buffer.cpp
Normal file
9
test/asio/temp_buffer.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/temp_buffer.h>
|
||||||
9
test/asio/type_check.cpp
Normal file
9
test/asio/type_check.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//
|
||||||
|
// 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/asio/type_check.h>
|
||||||
Reference in New Issue
Block a user