mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Tidy up core sources:
The core headers are moved to their own directory (but remain in the same namespace).
This commit is contained in:
87
include/beast/core/async_completion.hpp
Normal file
87
include/beast/core/async_completion.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_ASYNC_COMPLETION_HPP
|
||||
#define BEAST_ASYNC_COMPLETION_HPP
|
||||
|
||||
#include <beast/core/handler_concepts.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/handler_type.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Helper for customizing the return type of asynchronous initiation functions.
|
||||
|
||||
This class template is used to transform caller-provided completion
|
||||
handlers in calls to asynchronous initiation functions. The transformation
|
||||
allows customization of the return type of the initiating function, and the
|
||||
function signature of the final handler.
|
||||
|
||||
@tparam CompletionHandler A completion handler, 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.
|
||||
|
||||
Example:
|
||||
@code
|
||||
...
|
||||
template<class CompletionHandler>
|
||||
typename async_completion<CompletionHandler,
|
||||
void(boost::system::error_code)>::result_type
|
||||
async_initfn(..., CompletionHandler&& handler)
|
||||
{
|
||||
async_completion<CompletionHandler,
|
||||
void(boost::system::error_code)> completion(handler);
|
||||
...
|
||||
return completion.result.get();
|
||||
}
|
||||
@endcode
|
||||
|
||||
@note See <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf">
|
||||
Library Foundations For Asynchronous Operations</a>
|
||||
*/
|
||||
template <class CompletionHandler, class Signature>
|
||||
struct async_completion
|
||||
{
|
||||
/** The type of the final handler called by the asynchronous initiation function.
|
||||
|
||||
Objects of this type will be callable with the specified signature.
|
||||
*/
|
||||
using handler_type =
|
||||
typename boost::asio::handler_type<
|
||||
CompletionHandler, Signature>::type;
|
||||
|
||||
/// The type of the value returned by the asynchronous initiation function.
|
||||
using result_type = typename
|
||||
boost::asio::async_result<handler_type>::type;
|
||||
|
||||
/** Construct the helper.
|
||||
|
||||
@param token The completion handler. Copies will be made as
|
||||
required. If `CompletionHandler` is movable, it may also be moved.
|
||||
*/
|
||||
async_completion(typename std::remove_reference<CompletionHandler>::type& token)
|
||||
: handler(std::forward<CompletionHandler>(token))
|
||||
, result(handler)
|
||||
{
|
||||
static_assert(is_CompletionHandler<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
|
||||
303
include/beast/core/basic_streambuf.hpp
Normal file
303
include/beast/core/basic_streambuf.hpp
Normal file
@@ -0,0 +1,303 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_BASIC_STREAMBUF_HPP
|
||||
#define BEAST_BASIC_STREAMBUF_HPP
|
||||
|
||||
#include <beast/core/detail/empty_base_optimization.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A @b `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.
|
||||
|
||||
@note Meets the requirements of @b Streambuf.
|
||||
|
||||
@tparam Allocator The allocator to use for managing memory.
|
||||
*/
|
||||
template<class Allocator>
|
||||
class basic_streambuf
|
||||
#if ! GENERATING_DOCS
|
||||
: private detail::empty_base_optimization<
|
||||
typename std::allocator_traits<Allocator>::
|
||||
template rebind_alloc<std::uint8_t>>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
#if GENERATING_DOCS
|
||||
/// The type of allocator used.
|
||||
using allocator_type = Allocator;
|
||||
#else
|
||||
using allocator_type = typename
|
||||
std::allocator_traits<Allocator>::
|
||||
template rebind_alloc<std::uint8_t>;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Storage for the list of buffers representing the input
|
||||
// and output sequences. The allocation for each element
|
||||
// contains `element` followed by raw storage bytes.
|
||||
class element;
|
||||
|
||||
using alloc_traits = std::allocator_traits<allocator_type>;
|
||||
using list_type = typename boost::intrusive::make_list<element,
|
||||
boost::intrusive::constant_time_size<true>>::type;
|
||||
using iterator = typename list_type::iterator;
|
||||
using const_iterator = typename list_type::const_iterator;
|
||||
|
||||
using size_type = typename std::allocator_traits<Allocator>::size_type;
|
||||
using const_buffer = boost::asio::const_buffer;
|
||||
using mutable_buffer = boost::asio::mutable_buffer;
|
||||
|
||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<iterator>::iterator_category>::value,
|
||||
"BidirectionalIterator requirements not met");
|
||||
|
||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<const_iterator>::iterator_category>::value,
|
||||
"BidirectionalIterator requirements not met");
|
||||
|
||||
list_type list_; // list of allocated buffers
|
||||
iterator out_; // element that contains out_pos_
|
||||
size_type alloc_size_; // min amount to allocate
|
||||
size_type in_size_ = 0; // size of the input sequence
|
||||
size_type in_pos_ = 0; // input offset in list_.front()
|
||||
size_type out_pos_ = 0; // output offset in *out_
|
||||
size_type out_end_ = 0; // output end offset in list_.back()
|
||||
|
||||
public:
|
||||
#if GENERATING_DOCS
|
||||
/// The type used to represent the input sequence as a list of buffers.
|
||||
using const_buffers_type = implementation_defined;
|
||||
|
||||
/// The type used to represent the output sequence as a list of buffers.
|
||||
using mutable_buffers_type = implementation_defined;
|
||||
|
||||
#else
|
||||
class const_buffers_type;
|
||||
|
||||
class mutable_buffers_type;
|
||||
|
||||
#endif
|
||||
|
||||
/// Destructor.
|
||||
~basic_streambuf();
|
||||
|
||||
/** Move constructor.
|
||||
|
||||
The new object will have the input sequence of
|
||||
the other stream buffer, and an empty output sequence.
|
||||
|
||||
@note After the move, the moved-from object will have
|
||||
an empty input and output sequence, with no internal
|
||||
buffers allocated.
|
||||
*/
|
||||
basic_streambuf(basic_streambuf&&);
|
||||
|
||||
/** Move constructor.
|
||||
|
||||
The new object will have the input sequence of
|
||||
the other stream buffer, and an empty output sequence.
|
||||
|
||||
@note After the move, the moved-from object will have
|
||||
an empty input and output sequence, with no internal
|
||||
buffers allocated.
|
||||
|
||||
@param alloc The allocator to associate with the
|
||||
stream buffer.
|
||||
*/
|
||||
basic_streambuf(basic_streambuf&&,
|
||||
allocator_type const& alloc);
|
||||
|
||||
/** Move assignment.
|
||||
|
||||
This object will have the input sequence of
|
||||
the other stream buffer, and an empty output sequence.
|
||||
|
||||
@note After the move, the moved-from object will have
|
||||
an empty input and output sequence, with no internal
|
||||
buffers allocated.
|
||||
*/
|
||||
basic_streambuf&
|
||||
operator=(basic_streambuf&&);
|
||||
|
||||
/** Copy constructor.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
*/
|
||||
basic_streambuf(basic_streambuf const&);
|
||||
|
||||
/** Copy constructor.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
|
||||
@param alloc The allocator to associate with the
|
||||
stream buffer.
|
||||
*/
|
||||
basic_streambuf(basic_streambuf const&,
|
||||
allocator_type const& alloc);
|
||||
|
||||
/** Copy assignment.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
*/
|
||||
basic_streambuf& operator=(basic_streambuf const&);
|
||||
|
||||
/** Copy constructor.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
*/
|
||||
template<class OtherAlloc>
|
||||
basic_streambuf(basic_streambuf<OtherAlloc> const&);
|
||||
|
||||
/** Copy constructor.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
|
||||
@param alloc The allocator to associate with the
|
||||
stream buffer.
|
||||
*/
|
||||
template<class OtherAlloc>
|
||||
basic_streambuf(basic_streambuf<OtherAlloc> const&,
|
||||
allocator_type const& alloc);
|
||||
|
||||
/** Copy assignment.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
*/
|
||||
template<class OtherAlloc>
|
||||
basic_streambuf& operator=(basic_streambuf<OtherAlloc> const&);
|
||||
|
||||
/** Construct a stream buffer.
|
||||
|
||||
@param alloc_size The size of buffer to allocate. This is a
|
||||
soft limit, calls to prepare for buffers exceeding this size
|
||||
will allocate the larger size. The default allocation size
|
||||
is 1KB (1024 bytes).
|
||||
|
||||
@param alloc The allocator to use. If this parameter is
|
||||
unspecified, a default constructed allocator will be used.
|
||||
*/
|
||||
explicit
|
||||
basic_streambuf(std::size_t alloc_size = 1024,
|
||||
Allocator const& alloc = allocator_type{});
|
||||
|
||||
/// 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.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(size_type n);
|
||||
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
void
|
||||
commit(size_type n);
|
||||
|
||||
/** Get a list of buffers that represents the input sequence.
|
||||
|
||||
@note These buffers remain valid across subsequent calls to `prepare`.
|
||||
*/
|
||||
const_buffers_type
|
||||
data() const;
|
||||
|
||||
/// 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;
|
||||
};
|
||||
|
||||
/** 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 Allocator, class T>
|
||||
basic_streambuf<Allocator>&
|
||||
operator<<(basic_streambuf<Allocator>& streambuf, T const& t);
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/basic_streambuf.ipp>
|
||||
|
||||
#endif
|
||||
68
include/beast/core/bind_handler.hpp
Normal file
68
include/beast/core/bind_handler.hpp
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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_BIND_HANDLER_HPP
|
||||
#define BEAST_BIND_HANDLER_HPP
|
||||
|
||||
#include <beast/core/handler_concepts.hpp>
|
||||
#include <beast/core/detail/bind_handler.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Bind parameters to a completion handler, creating a wrapped handler.
|
||||
|
||||
This function creates a new handler which, when invoked with no
|
||||
parameters, calls the original handler with the list of bound arguments.
|
||||
The passed 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, class 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 object.
|
||||
*/
|
||||
template<class CompletionHandler, class... Args>
|
||||
#if GENERATING_DOCS
|
||||
implementation_defined
|
||||
#else
|
||||
detail::bound_handler<
|
||||
typename std::decay<CompletionHandler>::type, Args...>
|
||||
#endif
|
||||
bind_handler(CompletionHandler&& handler, Args&&... args)
|
||||
{
|
||||
static_assert(is_CompletionHandler<
|
||||
CompletionHandler, void(Args...)>::value,
|
||||
"CompletionHandler requirements not met");
|
||||
return detail::bound_handler<typename std::decay<
|
||||
CompletionHandler>::type, Args...>(std::forward<
|
||||
CompletionHandler>(handler),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
53
include/beast/core/buffer_cat.hpp
Normal file
53
include/beast/core/buffer_cat.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_BUFFER_CAT_HPP
|
||||
#define BEAST_BUFFER_CAT_HPP
|
||||
|
||||
#include <beast/core/detail/buffer_cat.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Concatenate 2 or more buffer sequences to form a `ConstBufferSequence`.
|
||||
|
||||
This function returns a @b `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 @b `ConstBufferSequence` that represents the
|
||||
concatenation of the input buffer sequences.
|
||||
*/
|
||||
#if GENERATING_DOCS
|
||||
template<class... BufferSequence>
|
||||
implementation_defined
|
||||
buffer_cat(BufferSequence const&... buffers)
|
||||
#else
|
||||
template<class B1, class B2, class... Bn>
|
||||
detail::buffer_cat_helper<
|
||||
boost::asio::const_buffer, B1, B2, Bn...>
|
||||
buffer_cat(B1 const& b1, B2 const& b2, Bn const&... bn)
|
||||
#endif
|
||||
{
|
||||
return detail::buffer_cat_helper<
|
||||
boost::asio::const_buffer,
|
||||
B1, B2, Bn...>(b1, b2, bn...);
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
61
include/beast/core/buffer_concepts.hpp
Normal file
61
include/beast/core/buffer_concepts.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_BUFFER_CONCEPTS_HPP
|
||||
#define BEAST_BUFFER_CONCEPTS_HPP
|
||||
|
||||
#include <beast/core/detail/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `BufferSequence`.
|
||||
template<class T, class BufferType>
|
||||
#if GENERATING_DOCS
|
||||
struct is_BufferSequence : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_BufferSequence : detail::is_BufferSequence<T, BufferType>::type
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `ConstBufferSequence`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_ConstBufferSequence : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_ConstBufferSequence :
|
||||
is_BufferSequence<T, boost::asio::const_buffer>
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `MutableBufferSequence`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_MutableBufferSequence : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_MutableBufferSequence :
|
||||
is_BufferSequence<T, boost::asio::mutable_buffer>
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `Streambuf`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_Streambuf : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_Streambuf : detail::is_Streambuf<T>::type
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
150
include/beast/core/buffers_adapter.hpp
Normal file
150
include/beast/core/buffers_adapter.hpp
Normal file
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_BUFFERS_ADAPTER_HPP
|
||||
#define BEAST_BUFFERS_ADAPTER_HPP
|
||||
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Adapts a @b `MutableBufferSequence` into a @b `Streambuf`.
|
||||
|
||||
This class wraps a @b `MutableBufferSequence` to meet the requirements
|
||||
of @b `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 MutableBufferSequence The type of mutable buffer sequence to wrap.
|
||||
*/
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter
|
||||
{
|
||||
static_assert(is_MutableBufferSequence<MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
|
||||
using iter_type = typename MutableBufferSequence::const_iterator;
|
||||
|
||||
MutableBufferSequence 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:
|
||||
#if GENERATING_DOCS
|
||||
/// The type used to represent the input sequence as a list of buffers.
|
||||
using const_buffers_type = implementation_defined;
|
||||
|
||||
/// The type used to represent the output sequence as a list of buffers.
|
||||
using mutable_buffers_type = implementation_defined;
|
||||
|
||||
#else
|
||||
class const_buffers_type;
|
||||
|
||||
class mutable_buffers_type;
|
||||
|
||||
#endif
|
||||
|
||||
/// 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(MutableBufferSequence 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.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(std::size_t n);
|
||||
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
void
|
||||
commit(std::size_t n);
|
||||
|
||||
/** Get a list of buffers that represents the input sequence.
|
||||
|
||||
@note These buffers remain valid across subsequent calls to `prepare`.
|
||||
*/
|
||||
const_buffers_type
|
||||
data() const;
|
||||
|
||||
/// Remove bytes from the input sequence.
|
||||
void
|
||||
consume(std::size_t n);
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/buffers_adapter.ipp>
|
||||
|
||||
#endif
|
||||
140
include/beast/core/consuming_buffers.hpp
Normal file
140
include/beast/core/consuming_buffers.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_CONSUMING_BUFFERS_HPP
|
||||
#define BEAST_CONSUMING_BUFFERS_HPP
|
||||
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#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 BufferSequence The buffer sequence to wrap.
|
||||
|
||||
@tparam 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 BufferSequence,
|
||||
class ValueType = typename BufferSequence::value_type>
|
||||
class consuming_buffers
|
||||
{
|
||||
using iter_type =
|
||||
typename BufferSequence::const_iterator;
|
||||
|
||||
static_assert(is_BufferSequence<BufferSequence, ValueType>::value,
|
||||
"BufferSequence requirements not met");
|
||||
|
||||
static_assert(std::is_constructible<ValueType,
|
||||
typename std::iterator_traits<iter_type>::value_type>::value,
|
||||
"ValueType requirements not met");
|
||||
|
||||
BufferSequence 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;
|
||||
|
||||
#if GENERATING_DOCS
|
||||
/// A bidirectional iterator type that may be used to read elements.
|
||||
using const_iterator = implementation_defined;
|
||||
|
||||
#else
|
||||
class const_iterator;
|
||||
|
||||
#endif
|
||||
|
||||
/// 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(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;
|
||||
|
||||
/** 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);
|
||||
};
|
||||
|
||||
/** Returns a new, consumed buffer sequence.
|
||||
|
||||
This function returns a new buffer sequence which when iterated,
|
||||
efficiently represents the portion of the original buffer sequence
|
||||
with `n` bytes removed from the beginning.
|
||||
|
||||
Copies will be made of the buffer sequence passed, but ownership
|
||||
of the underlying memory is not transferred.
|
||||
|
||||
@param buffers The buffer sequence to consume.
|
||||
|
||||
@param n The number of bytes to remove from the front. If this is
|
||||
larger than the size of the buffer sequence, an empty buffer sequence
|
||||
is returned.
|
||||
*/
|
||||
template<class BufferSequence>
|
||||
consuming_buffers<BufferSequence, typename BufferSequence::value_type>
|
||||
consumed_buffers(BufferSequence const& buffers, std::size_t n);
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/consuming_buffers.ipp>
|
||||
|
||||
#endif
|
||||
178
include/beast/core/detail/base64.hpp
Normal file
178
include/beast/core/detail/base64.hpp
Normal file
@@ -0,0 +1,178 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_BASE64_HPP
|
||||
#define BEAST_DETAIL_BASE64_HPP
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
/*
|
||||
Portions from http://www.adp-gmbh.ch/cpp/common/base64.html
|
||||
Copyright notice:
|
||||
|
||||
base64.cpp and base64.h
|
||||
|
||||
Copyright (C) 2004-2008 Ren<65> Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Ren<65> Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
template <class = void>
|
||||
std::string const&
|
||||
base64_alphabet()
|
||||
{
|
||||
static std::string const alphabet =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
return alphabet;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_base64(unsigned char c)
|
||||
{
|
||||
return (std::isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
std::string
|
||||
base64_encode (std::uint8_t const* data,
|
||||
std::size_t in_len)
|
||||
{
|
||||
unsigned char c3[3], c4[4];
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
std::string ret;
|
||||
ret.reserve (3 + in_len * 8 / 6);
|
||||
|
||||
char const* alphabet (base64_alphabet().data());
|
||||
|
||||
while(in_len--)
|
||||
{
|
||||
c3[i++] = *(data++);
|
||||
if(i == 3)
|
||||
{
|
||||
c4[0] = (c3[0] & 0xfc) >> 2;
|
||||
c4[1] = ((c3[0] & 0x03) << 4) + ((c3[1] & 0xf0) >> 4);
|
||||
c4[2] = ((c3[1] & 0x0f) << 2) + ((c3[2] & 0xc0) >> 6);
|
||||
c4[3] = c3[2] & 0x3f;
|
||||
for(i = 0; (i < 4); i++)
|
||||
ret += alphabet[c4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
c3[j] = '\0';
|
||||
|
||||
c4[0] = (c3[0] & 0xfc) >> 2;
|
||||
c4[1] = ((c3[0] & 0x03) << 4) + ((c3[1] & 0xf0) >> 4);
|
||||
c4[2] = ((c3[1] & 0x0f) << 2) + ((c3[2] & 0xc0) >> 6);
|
||||
c4[3] = c3[2] & 0x3f;
|
||||
|
||||
for(j = 0; (j < i + 1); j++)
|
||||
ret += alphabet[c4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
std::string
|
||||
base64_encode (std::string const& s)
|
||||
{
|
||||
return base64_encode (reinterpret_cast <
|
||||
std::uint8_t const*> (s.data()), s.size());
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
std::string
|
||||
base64_decode(std::string const& data)
|
||||
{
|
||||
int in_len = data.size();
|
||||
unsigned char c3[3], c4[4];
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
|
||||
std::string ret;
|
||||
ret.reserve (in_len * 6 / 8); // ???
|
||||
|
||||
while(in_len-- && (data[in_] != '=') &&
|
||||
is_base64(data[in_]))
|
||||
{
|
||||
c4[i++] = data[in_]; in_++;
|
||||
if(i == 4) {
|
||||
for(i = 0; i < 4; i++)
|
||||
c4[i] = static_cast<unsigned char>(
|
||||
base64_alphabet().find(c4[i]));
|
||||
|
||||
c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
|
||||
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
|
||||
c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
|
||||
|
||||
for(i = 0; (i < 3); i++)
|
||||
ret += c3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(i)
|
||||
{
|
||||
for(j = i; j < 4; j++)
|
||||
c4[j] = 0;
|
||||
|
||||
for(j = 0; j < 4; j++)
|
||||
c4[j] = static_cast<unsigned char>(
|
||||
base64_alphabet().find(c4[j]));
|
||||
|
||||
c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
|
||||
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
|
||||
c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
|
||||
|
||||
for(j = 0; (j < i - 1); j++)
|
||||
ret += c3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
113
include/beast/core/detail/bind_handler.hpp
Normal file
113
include/beast/core/detail/bind_handler.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_BIND_DETAIL_HANDLER_HPP
|
||||
#define BEAST_BIND_DETAIL_HANDLER_HPP
|
||||
|
||||
#include <beast/core/detail/integer_sequence.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_cont_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
/* Nullary handler that calls Handler with bound arguments.
|
||||
|
||||
The bound handler provides the same io_service execution
|
||||
guarantees as the original handler.
|
||||
*/
|
||||
template<class Handler, class... Args>
|
||||
class bound_handler
|
||||
{
|
||||
private:
|
||||
using args_type = std::tuple<
|
||||
typename std::decay<Args>::type...>;
|
||||
|
||||
Handler h_;
|
||||
args_type args_;
|
||||
|
||||
template<class Tuple, std::size_t... S>
|
||||
static void invoke(Handler& h, Tuple& args,
|
||||
index_sequence<S...>)
|
||||
{
|
||||
h(std::get<S>(args)...);
|
||||
}
|
||||
|
||||
public:
|
||||
using result_type = void;
|
||||
|
||||
template<class DeducedHandler>
|
||||
explicit
|
||||
bound_handler(DeducedHandler&& handler, Args&&... args)
|
||||
: h_(std::forward<DeducedHandler>(handler))
|
||||
, args_(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
invoke(h_, args_,
|
||||
index_sequence_for<Args...> ());
|
||||
}
|
||||
|
||||
void
|
||||
operator()() const
|
||||
{
|
||||
invoke(h_, args_,
|
||||
index_sequence_for<Args...> ());
|
||||
}
|
||||
|
||||
friend
|
||||
void*
|
||||
asio_handler_allocate(
|
||||
std::size_t size, bound_handler* h)
|
||||
{
|
||||
return boost_asio_handler_alloc_helpers::
|
||||
allocate(size, h->h_);
|
||||
}
|
||||
|
||||
friend
|
||||
void
|
||||
asio_handler_deallocate(
|
||||
void* p, std::size_t size, bound_handler* h)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::
|
||||
deallocate(p, size, h->h_);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(bound_handler* h)
|
||||
{
|
||||
return boost_asio_handler_cont_helpers::
|
||||
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
|
||||
} // beast
|
||||
|
||||
#include <functional>
|
||||
namespace std {
|
||||
template<class Handler, class... Args>
|
||||
void bind(beast::detail::bound_handler<
|
||||
Handler, Args...>, ...) = delete;
|
||||
} // std
|
||||
|
||||
#endif
|
||||
473
include/beast/core/detail/buffer_cat.hpp
Normal file
473
include/beast/core/detail/buffer_cat.hpp
Normal file
@@ -0,0 +1,473 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_BUFFER_CAT_HPP
|
||||
#define BEAST_DETAIL_BUFFER_CAT_HPP
|
||||
|
||||
#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 buffer_cat_helper
|
||||
{
|
||||
std::tuple<Bs...> bs_;
|
||||
|
||||
public:
|
||||
using value_type = ValueType;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
buffer_cat_helper(buffer_cat_helper&&) = default;
|
||||
buffer_cat_helper(buffer_cat_helper const&) = default;
|
||||
buffer_cat_helper& operator=(buffer_cat_helper&&) = default;
|
||||
buffer_cat_helper& operator=(buffer_cat_helper const&) = default;
|
||||
|
||||
explicit
|
||||
buffer_cat_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 buffer_cat_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 buffer_cat_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<
|
||||
I, std::tuple<Bs...>>::type::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>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::~const_iterator()
|
||||
{
|
||||
destroy(C<0>{});
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::const_iterator()
|
||||
: n_(sizeof...(Bs))
|
||||
, bs_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_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>
|
||||
buffer_cat_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>
|
||||
buffer_cat_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
|
||||
buffer_cat_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
|
||||
buffer_cat_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
|
||||
buffer_cat_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
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator*() const ->
|
||||
reference
|
||||
{
|
||||
return dereference(C<0>{});
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator++() ->
|
||||
const_iterator&
|
||||
{
|
||||
increment(C<0>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator--() ->
|
||||
const_iterator&
|
||||
{
|
||||
decrement(C<sizeof...(Bs)>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator(bs_, false);
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator(bs_, true);
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
140
include/beast/core/detail/buffer_concepts.hpp
Normal file
140
include/beast/core/detail/buffer_concepts.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_BUFFER_CONCEPTS_HPP
|
||||
#define BEAST_DETAIL_BUFFER_CONCEPTS_HPP
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
// Types that meet the requirements,
|
||||
// for use with std::declval only.
|
||||
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>;
|
||||
|
||||
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:
|
||||
using type = std::integral_constant<bool,
|
||||
std::is_copy_constructible<T>::value &&
|
||||
std::is_destructible<T>::value &&
|
||||
type1::value && type2::value &&
|
||||
type3::value && type4::value>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class is_Streambuf
|
||||
{
|
||||
template<class U, class R = std::integral_constant<
|
||||
bool, is_BufferSequence<decltype(
|
||||
std::declval<U>().prepare(1)),
|
||||
boost::asio::mutable_buffer>::type::value>>
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R = std::integral_constant<
|
||||
bool, is_BufferSequence<decltype(
|
||||
std::declval<U>().data()),
|
||||
boost::asio::const_buffer>::type::value>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().commit(1), std::true_type{})>
|
||||
static R check3(int);
|
||||
template<class>
|
||||
static std::false_type check3(...);
|
||||
using type3 = decltype(check3<T>(0));
|
||||
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().consume(1), std::true_type{})>
|
||||
static R check4(int);
|
||||
template<class>
|
||||
static std::false_type check4(...);
|
||||
using type4 = decltype(check4<T>(0));
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().size()), std::size_t>>
|
||||
static R check5(int);
|
||||
template<class>
|
||||
static std::false_type check5(...);
|
||||
using type5 = decltype(check5<T>(0));
|
||||
|
||||
public:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value && type2::value &&
|
||||
type3::value && type4::value &&
|
||||
type5::value>;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
86
include/beast/core/detail/ci_char_traits.hpp
Normal file
86
include/beast/core/detail/ci_char_traits.hpp
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_CI_CHAR_TRAITS_HPP
|
||||
#define BEAST_DETAIL_CI_CHAR_TRAITS_HPP
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <cctype>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
/** Case-insensitive function object for performing less than comparisons. */
|
||||
struct ci_less
|
||||
{
|
||||
static bool const is_transparent = true;
|
||||
|
||||
bool
|
||||
operator()(boost::string_ref const& lhs,
|
||||
boost::string_ref const& rhs) const noexcept
|
||||
{
|
||||
using std::begin;
|
||||
using std::end;
|
||||
return std::lexicographical_compare(
|
||||
begin(lhs), end(lhs), begin(rhs), end(rhs),
|
||||
[](char lhs, char rhs)
|
||||
{
|
||||
return std::tolower(lhs) < std::tolower(rhs);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
inline
|
||||
bool
|
||||
ci_equal(std::pair<const char*, std::size_t> lhs,
|
||||
std::pair<const char*, std::size_t> rhs)
|
||||
{
|
||||
if(lhs.second != rhs.second)
|
||||
return false;
|
||||
return std::equal (lhs.first, lhs.first + lhs.second,
|
||||
rhs.first,
|
||||
[] (char lhs, char rhs)
|
||||
{
|
||||
return std::tolower(lhs) == std::tolower(rhs);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
inline
|
||||
std::pair<const char*, std::size_t>
|
||||
view(const char (&s)[N])
|
||||
{
|
||||
return {s, N-1};
|
||||
}
|
||||
|
||||
inline
|
||||
std::pair<const char*, std::size_t>
|
||||
view(std::string const& s)
|
||||
{
|
||||
return {s.data(), s.size()};
|
||||
}
|
||||
|
||||
/** Returns `true` if strings are case-insensitive equal. */
|
||||
template <class String1, class String2>
|
||||
inline
|
||||
bool
|
||||
ci_equal(String1 const& lhs, String2 const& rhs)
|
||||
{
|
||||
return ci_equal(view(lhs), view(rhs));
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
94
include/beast/core/detail/empty_base_optimization.hpp
Normal file
94
include/beast/core/detail/empty_base_optimization.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_EMPTY_BASE_OPTIMIZATION_HPP
|
||||
#define BEAST_DETAIL_EMPTY_BASE_OPTIMIZATION_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct empty_base_optimization_decide
|
||||
: std::integral_constant <bool,
|
||||
std::is_empty <T>::value
|
||||
#ifdef __clang__
|
||||
&& !__is_final(T)
|
||||
#endif
|
||||
>
|
||||
{
|
||||
};
|
||||
|
||||
template <
|
||||
class T,
|
||||
int UniqueID = 0,
|
||||
bool ShouldDeriveFrom =
|
||||
empty_base_optimization_decide<T>::value
|
||||
>
|
||||
class empty_base_optimization : private T
|
||||
{
|
||||
public:
|
||||
empty_base_optimization() = default;
|
||||
|
||||
empty_base_optimization(T const& t)
|
||||
: T (t)
|
||||
{}
|
||||
|
||||
empty_base_optimization(T&& t)
|
||||
: T (std::move (t))
|
||||
{}
|
||||
|
||||
T& member() noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
T const& member() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
class T,
|
||||
int UniqueID
|
||||
>
|
||||
class empty_base_optimization <T, UniqueID, false>
|
||||
{
|
||||
public:
|
||||
empty_base_optimization() = default;
|
||||
|
||||
empty_base_optimization(T const& t)
|
||||
: m_t (t)
|
||||
{}
|
||||
|
||||
empty_base_optimization(T&& t)
|
||||
: m_t (std::move (t))
|
||||
{}
|
||||
|
||||
T& member() noexcept
|
||||
{
|
||||
return m_t;
|
||||
}
|
||||
|
||||
T const& member() const noexcept
|
||||
{
|
||||
return m_t;
|
||||
}
|
||||
|
||||
private:
|
||||
T m_t;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
53
include/beast/core/detail/get_lowest_layer.hpp
Normal file
53
include/beast/core/detail/get_lowest_layer.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_GET_LOWEST_LAYER_HPP
|
||||
#define BEAST_DETAIL_GET_LOWEST_LAYER_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
class has_lowest_layer
|
||||
{
|
||||
template<class U, class R =
|
||||
typename U::lowest_layer_type>
|
||||
static std::true_type check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
using type = decltype(check<T>(0));
|
||||
public:
|
||||
static bool constexpr value = type::value;
|
||||
};
|
||||
|
||||
template<class T, bool B>
|
||||
struct maybe_get_lowest_layer
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct maybe_get_lowest_layer<T, true>
|
||||
{
|
||||
using type = typename T::lowest_layer_type;
|
||||
};
|
||||
|
||||
// If T has a nested type lowest_layer_type,
|
||||
// returns that, else returns T.
|
||||
template<class T>
|
||||
struct get_lowest_layer
|
||||
{
|
||||
using type = typename maybe_get_lowest_layer<T,
|
||||
has_lowest_layer<T>::value>::type;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
145
include/beast/core/detail/integer_sequence.hpp
Normal file
145
include/beast/core/detail/integer_sequence.hpp
Normal file
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_INTEGER_SEQUENCE_H_INCLUDED
|
||||
#define BEAST_DETAIL_INTEGER_SEQUENCE_H_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<class T, T... Ints>
|
||||
struct integer_sequence
|
||||
{
|
||||
using value_type = T;
|
||||
static_assert (std::is_integral<T>::value,
|
||||
"std::integer_sequence can only be instantiated with an integral type" );
|
||||
|
||||
static std::size_t constexpr static_size = sizeof...(Ints);
|
||||
|
||||
static std::size_t constexpr size()
|
||||
{
|
||||
return sizeof...(Ints);
|
||||
}
|
||||
};
|
||||
|
||||
template<std::size_t... Ints>
|
||||
using index_sequence = integer_sequence<std::size_t, Ints...>;
|
||||
|
||||
// This workaround is needed for broken sizeof...
|
||||
template<class... Args>
|
||||
struct sizeof_workaround
|
||||
{
|
||||
static std::size_t constexpr size = sizeof... (Args);
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// This implementation compiles on MSVC and clang but not gcc
|
||||
|
||||
template<class T, unsigned long long N, class Seq>
|
||||
struct make_integer_sequence_unchecked;
|
||||
|
||||
template<class T, unsigned long long N, unsigned long long ...Indices>
|
||||
struct make_integer_sequence_unchecked<
|
||||
T, N, integer_sequence<T, Indices...>>
|
||||
{
|
||||
using type = typename make_integer_sequence_unchecked<
|
||||
T, N-1, integer_sequence<T, N-1, Indices...>>::type;
|
||||
};
|
||||
|
||||
template<class T, unsigned long long ...Indices>
|
||||
struct make_integer_sequence_unchecked<
|
||||
T, 0, integer_sequence<T, Indices...>>
|
||||
{
|
||||
using type = integer_sequence<T, Indices...>;
|
||||
};
|
||||
|
||||
template<class T, T N>
|
||||
struct make_integer_sequence_checked
|
||||
{
|
||||
static_assert (std::is_integral<T>::value,
|
||||
"T must be an integral type");
|
||||
|
||||
static_assert (N >= 0,
|
||||
"N must be non-negative");
|
||||
|
||||
using type = typename make_integer_sequence_unchecked<
|
||||
T, N, integer_sequence<T>>::type;
|
||||
};
|
||||
|
||||
template<class T, T N>
|
||||
using make_integer_sequence =
|
||||
typename make_integer_sequence_checked<T, N>::type;
|
||||
|
||||
template<std::size_t N>
|
||||
using make_index_sequence = make_integer_sequence<std::size_t, N>;
|
||||
|
||||
template<class... Args>
|
||||
using index_sequence_for =
|
||||
make_index_sequence<sizeof_workaround<Args...>::size>;
|
||||
|
||||
#else
|
||||
|
||||
// This implementation compiles on gcc but not MSVC
|
||||
|
||||
template<std::size_t... Ints>
|
||||
struct index_tuple
|
||||
{
|
||||
using next = index_tuple<Ints..., sizeof... (Ints)>;
|
||||
|
||||
};
|
||||
|
||||
template<std::size_t N>
|
||||
struct build_index_tuple
|
||||
{
|
||||
using type = typename build_index_tuple<N-1>::type::next;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct build_index_tuple<0>
|
||||
{
|
||||
using type = index_tuple<>;
|
||||
};
|
||||
|
||||
template<class T, T N,
|
||||
class Seq = typename build_index_tuple<N>::type
|
||||
>
|
||||
struct integer_sequence_helper;
|
||||
|
||||
template<class T, T N, std::size_t... Ints>
|
||||
struct integer_sequence_helper<T, N, index_tuple<Ints...>>
|
||||
{
|
||||
static_assert (std::is_integral<T>::value,
|
||||
"T must be an integral type");
|
||||
|
||||
static_assert (N >= 0,
|
||||
"N must be non-negative");
|
||||
|
||||
using type = integer_sequence<T, static_cast<T> (Ints)...>;
|
||||
};
|
||||
|
||||
template<class T, T N>
|
||||
using make_integer_sequence =
|
||||
typename integer_sequence_helper<T, N>::type;
|
||||
|
||||
template<std::size_t N>
|
||||
using make_index_sequence = make_integer_sequence<std::size_t, N>;
|
||||
|
||||
template<class... Args>
|
||||
using index_sequence_for =
|
||||
make_index_sequence<sizeof_workaround<Args...>::size>;
|
||||
|
||||
#endif
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
90
include/beast/core/detail/is_call_possible.hpp
Normal file
90
include/beast/core/detail/is_call_possible.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_IS_CALL_POSSIBLE_HPP
|
||||
#define BEAST_DETAIL_IS_CALL_POSSIBLE_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template <class R, class C, class ...A>
|
||||
auto
|
||||
is_call_possible_test(C&& c, int, A&& ...a)
|
||||
-> decltype(std::is_convertible<
|
||||
decltype(c(a...)), R>::value ||
|
||||
std::is_same<R, void>::value,
|
||||
std::true_type());
|
||||
|
||||
template <class R, class C, class ...A>
|
||||
std::false_type
|
||||
is_call_possible_test(C&& c, long, A&& ...a);
|
||||
|
||||
/** Metafunction returns `true` if F callable as R(A...)
|
||||
Example:
|
||||
is_call_possible<T, void(std::string)>
|
||||
*/
|
||||
/** @{ */
|
||||
template <class C, class F>
|
||||
struct is_call_possible
|
||||
: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class C, class R, class ...A>
|
||||
struct is_call_possible<C, R(A...)>
|
||||
: decltype(is_call_possible_test<R>(
|
||||
std::declval<C>(), 1, std::declval<A>()...))
|
||||
{
|
||||
};
|
||||
/** @} */
|
||||
|
||||
namespace test {
|
||||
|
||||
struct is_call_possible_udt1
|
||||
{
|
||||
void operator()(int) const;
|
||||
};
|
||||
|
||||
struct is_call_possible_udt2
|
||||
{
|
||||
int operator()(int) const;
|
||||
};
|
||||
|
||||
struct is_call_possible_udt3
|
||||
{
|
||||
int operator()(int);
|
||||
};
|
||||
|
||||
static_assert(is_call_possible<
|
||||
is_call_possible_udt1, void(int)>::value, "");
|
||||
|
||||
static_assert(! is_call_possible<
|
||||
is_call_possible_udt1, void(void)>::value, "");
|
||||
|
||||
static_assert(is_call_possible<
|
||||
is_call_possible_udt2, int(int)>::value, "");
|
||||
|
||||
static_assert(! is_call_possible<
|
||||
is_call_possible_udt2, int(void)>::value, "");
|
||||
|
||||
static_assert(! is_call_possible<
|
||||
is_call_possible_udt2, void(void)>::value, "");
|
||||
|
||||
static_assert(is_call_possible<
|
||||
is_call_possible_udt3, int(int)>::value, "");
|
||||
|
||||
static_assert(! is_call_possible<
|
||||
is_call_possible_udt3 const, int(int)>::value, "");
|
||||
|
||||
} // test
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
309
include/beast/core/detail/sha1.hpp
Normal file
309
include/beast/core/detail/sha1.hpp
Normal file
@@ -0,0 +1,309 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_SHA1_HPP
|
||||
#define BEAST_DETAIL_SHA1_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
// Based on https://github.com/vog/sha1
|
||||
/*
|
||||
Original authors:
|
||||
Steve Reid (Original C Code)
|
||||
Bruce Guenter (Small changes to fit into bglibs)
|
||||
Volker Grabsch (Translation to simpler C++ Code)
|
||||
Eugene Hopkinson (Safety improvements)
|
||||
Vincent Falco (beast adaptation)
|
||||
*/
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
namespace sha1 {
|
||||
|
||||
static std::size_t constexpr BLOCK_INTS = 16;
|
||||
static std::size_t constexpr BLOCK_BYTES = 64;
|
||||
static std::size_t constexpr DIGEST_BYTES = 20;
|
||||
|
||||
inline
|
||||
std::uint32_t
|
||||
rol(std::uint32_t value, std::size_t bits)
|
||||
{
|
||||
return (value << bits) | (value >> (32 - bits));
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint32_t
|
||||
blk(std::uint32_t block[BLOCK_INTS], std::size_t i)
|
||||
{
|
||||
return rol(
|
||||
block[(i+13)&15] ^ block[(i+8)&15] ^
|
||||
block[(i+2)&15] ^ block[i], 1);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
R0(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
|
||||
std::uint32_t &w, std::uint32_t x, std::uint32_t y,
|
||||
std::uint32_t &z, std::size_t i)
|
||||
{
|
||||
z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void
|
||||
R1(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
|
||||
std::uint32_t &w, std::uint32_t x, std::uint32_t y,
|
||||
std::uint32_t &z, std::size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
R2(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
|
||||
std::uint32_t &w, std::uint32_t x, std::uint32_t y,
|
||||
std::uint32_t &z, std::size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
R3(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
|
||||
std::uint32_t &w, std::uint32_t x, std::uint32_t y,
|
||||
std::uint32_t &z, std::size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += (((w|x)&y)|(w&x)) + block[i] + 0x8f1bbcdc + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
R4(std::uint32_t block[BLOCK_INTS], std::uint32_t v,
|
||||
std::uint32_t &w, std::uint32_t x, std::uint32_t y,
|
||||
std::uint32_t &z, std::size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += (w^x^y) + block[i] + 0xca62c1d6 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
make_block(std::uint8_t const* p,
|
||||
std::uint32_t block[BLOCK_INTS])
|
||||
{
|
||||
for(std::size_t i = 0; i < BLOCK_INTS; i++)
|
||||
block[i] =
|
||||
(static_cast<std::uint32_t>(p[4*i+3])) |
|
||||
(static_cast<std::uint32_t>(p[4*i+2]))<< 8 |
|
||||
(static_cast<std::uint32_t>(p[4*i+1]))<<16 |
|
||||
(static_cast<std::uint32_t>(p[4*i+0]))<<24;
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
transform(
|
||||
std::uint32_t digest[], std::uint32_t block[BLOCK_INTS])
|
||||
{
|
||||
std::uint32_t a = digest[0];
|
||||
std::uint32_t b = digest[1];
|
||||
std::uint32_t c = digest[2];
|
||||
std::uint32_t d = digest[3];
|
||||
std::uint32_t e = digest[4];
|
||||
|
||||
R0(block, a, b, c, d, e, 0);
|
||||
R0(block, e, a, b, c, d, 1);
|
||||
R0(block, d, e, a, b, c, 2);
|
||||
R0(block, c, d, e, a, b, 3);
|
||||
R0(block, b, c, d, e, a, 4);
|
||||
R0(block, a, b, c, d, e, 5);
|
||||
R0(block, e, a, b, c, d, 6);
|
||||
R0(block, d, e, a, b, c, 7);
|
||||
R0(block, c, d, e, a, b, 8);
|
||||
R0(block, b, c, d, e, a, 9);
|
||||
R0(block, a, b, c, d, e, 10);
|
||||
R0(block, e, a, b, c, d, 11);
|
||||
R0(block, d, e, a, b, c, 12);
|
||||
R0(block, c, d, e, a, b, 13);
|
||||
R0(block, b, c, d, e, a, 14);
|
||||
R0(block, a, b, c, d, e, 15);
|
||||
R1(block, e, a, b, c, d, 0);
|
||||
R1(block, d, e, a, b, c, 1);
|
||||
R1(block, c, d, e, a, b, 2);
|
||||
R1(block, b, c, d, e, a, 3);
|
||||
R2(block, a, b, c, d, e, 4);
|
||||
R2(block, e, a, b, c, d, 5);
|
||||
R2(block, d, e, a, b, c, 6);
|
||||
R2(block, c, d, e, a, b, 7);
|
||||
R2(block, b, c, d, e, a, 8);
|
||||
R2(block, a, b, c, d, e, 9);
|
||||
R2(block, e, a, b, c, d, 10);
|
||||
R2(block, d, e, a, b, c, 11);
|
||||
R2(block, c, d, e, a, b, 12);
|
||||
R2(block, b, c, d, e, a, 13);
|
||||
R2(block, a, b, c, d, e, 14);
|
||||
R2(block, e, a, b, c, d, 15);
|
||||
R2(block, d, e, a, b, c, 0);
|
||||
R2(block, c, d, e, a, b, 1);
|
||||
R2(block, b, c, d, e, a, 2);
|
||||
R2(block, a, b, c, d, e, 3);
|
||||
R2(block, e, a, b, c, d, 4);
|
||||
R2(block, d, e, a, b, c, 5);
|
||||
R2(block, c, d, e, a, b, 6);
|
||||
R2(block, b, c, d, e, a, 7);
|
||||
R3(block, a, b, c, d, e, 8);
|
||||
R3(block, e, a, b, c, d, 9);
|
||||
R3(block, d, e, a, b, c, 10);
|
||||
R3(block, c, d, e, a, b, 11);
|
||||
R3(block, b, c, d, e, a, 12);
|
||||
R3(block, a, b, c, d, e, 13);
|
||||
R3(block, e, a, b, c, d, 14);
|
||||
R3(block, d, e, a, b, c, 15);
|
||||
R3(block, c, d, e, a, b, 0);
|
||||
R3(block, b, c, d, e, a, 1);
|
||||
R3(block, a, b, c, d, e, 2);
|
||||
R3(block, e, a, b, c, d, 3);
|
||||
R3(block, d, e, a, b, c, 4);
|
||||
R3(block, c, d, e, a, b, 5);
|
||||
R3(block, b, c, d, e, a, 6);
|
||||
R3(block, a, b, c, d, e, 7);
|
||||
R3(block, e, a, b, c, d, 8);
|
||||
R3(block, d, e, a, b, c, 9);
|
||||
R3(block, c, d, e, a, b, 10);
|
||||
R3(block, b, c, d, e, a, 11);
|
||||
R4(block, a, b, c, d, e, 12);
|
||||
R4(block, e, a, b, c, d, 13);
|
||||
R4(block, d, e, a, b, c, 14);
|
||||
R4(block, c, d, e, a, b, 15);
|
||||
R4(block, b, c, d, e, a, 0);
|
||||
R4(block, a, b, c, d, e, 1);
|
||||
R4(block, e, a, b, c, d, 2);
|
||||
R4(block, d, e, a, b, c, 3);
|
||||
R4(block, c, d, e, a, b, 4);
|
||||
R4(block, b, c, d, e, a, 5);
|
||||
R4(block, a, b, c, d, e, 6);
|
||||
R4(block, e, a, b, c, d, 7);
|
||||
R4(block, d, e, a, b, c, 8);
|
||||
R4(block, c, d, e, a, b, 9);
|
||||
R4(block, b, c, d, e, a, 10);
|
||||
R4(block, a, b, c, d, e, 11);
|
||||
R4(block, e, a, b, c, d, 12);
|
||||
R4(block, d, e, a, b, c, 13);
|
||||
R4(block, c, d, e, a, b, 14);
|
||||
R4(block, b, c, d, e, a, 15);
|
||||
|
||||
digest[0] += a;
|
||||
digest[1] += b;
|
||||
digest[2] += c;
|
||||
digest[3] += d;
|
||||
digest[4] += e;
|
||||
}
|
||||
|
||||
} // sha1
|
||||
|
||||
struct sha1_context
|
||||
{
|
||||
static unsigned int constexpr block_size = sha1::BLOCK_BYTES;
|
||||
static unsigned int constexpr digest_size = 20;
|
||||
|
||||
std::size_t buflen;
|
||||
std::size_t blocks;
|
||||
std::uint32_t digest[5];
|
||||
std::uint8_t buf[block_size];
|
||||
};
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
init(sha1_context& ctx) noexcept
|
||||
{
|
||||
ctx.buflen = 0;
|
||||
ctx.blocks = 0;
|
||||
ctx.digest[0] = 0x67452301;
|
||||
ctx.digest[1] = 0xefcdab89;
|
||||
ctx.digest[2] = 0x98badcfe;
|
||||
ctx.digest[3] = 0x10325476;
|
||||
ctx.digest[4] = 0xc3d2e1f0;
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
update(sha1_context& ctx,
|
||||
void const* message, std::size_t size) noexcept
|
||||
{
|
||||
auto p = reinterpret_cast<
|
||||
std::uint8_t const*>(message);
|
||||
for(;;)
|
||||
{
|
||||
auto const n = std::min(
|
||||
size, sizeof(ctx.buf) - ctx.buflen);
|
||||
std::memcpy(ctx.buf + ctx.buflen, p, n);
|
||||
ctx.buflen += n;
|
||||
if(ctx.buflen != 64)
|
||||
return;
|
||||
p += n;
|
||||
size -= n;
|
||||
ctx.buflen = 0;
|
||||
std::uint32_t block[sha1::BLOCK_INTS];
|
||||
sha1::make_block(ctx.buf, block);
|
||||
sha1::transform(ctx.digest, block);
|
||||
++ctx.blocks;
|
||||
}
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
finish(sha1_context& ctx, void* digest) noexcept
|
||||
{
|
||||
using sha1::BLOCK_INTS;
|
||||
using sha1::BLOCK_BYTES;
|
||||
|
||||
std::uint64_t total_bits =
|
||||
(ctx.blocks*64 + ctx.buflen) * 8;
|
||||
// pad
|
||||
ctx.buf[ctx.buflen++] = 0x80;
|
||||
auto const buflen = ctx.buflen;
|
||||
while(ctx.buflen < 64)
|
||||
ctx.buf[ctx.buflen++] = 0x00;
|
||||
std::uint32_t block[BLOCK_INTS];
|
||||
sha1::make_block(ctx.buf, block);
|
||||
if (buflen > BLOCK_BYTES - 8)
|
||||
{
|
||||
sha1::transform(ctx.digest, block);
|
||||
for (size_t i = 0; i < BLOCK_INTS - 2; i++)
|
||||
block[i] = 0;
|
||||
}
|
||||
|
||||
/* Append total_bits, split this uint64_t into two uint32_t */
|
||||
block[BLOCK_INTS - 1] = total_bits & 0xffffffff;
|
||||
block[BLOCK_INTS - 2] = (total_bits >> 32);
|
||||
sha1::transform(ctx.digest, block);
|
||||
for(std::size_t i = 0; i < sha1::DIGEST_BYTES/4; i++)
|
||||
{
|
||||
std::uint8_t* d =
|
||||
reinterpret_cast<std::uint8_t*>(digest) + 4 * i;
|
||||
d[3] = ctx.digest[i] & 0xff;
|
||||
d[2] = (ctx.digest[i] >> 8) & 0xff;
|
||||
d[1] = (ctx.digest[i] >> 16) & 0xff;
|
||||
d[0] = (ctx.digest[i] >> 24) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
140
include/beast/core/detail/stream_concepts.hpp
Normal file
140
include/beast/core/detail/stream_concepts.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_STREAM_CONCEPTS_HPP
|
||||
#define BEAST_DETAIL_STREAM_CONCEPTS_HPP
|
||||
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
// Types that meet the requirements,
|
||||
// for use with std::declval only.
|
||||
struct StreamHandler
|
||||
{
|
||||
StreamHandler(StreamHandler const&) = default;
|
||||
void operator()(boost::system::error_code ec, std::size_t);
|
||||
};
|
||||
using ReadHandler = StreamHandler;
|
||||
using WriteHandler = StreamHandler;
|
||||
|
||||
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(...);
|
||||
public:
|
||||
using type = decltype(check<T>(0));
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class is_AsyncReadStream
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().async_read_some(
|
||||
std::declval<MutableBufferSequence>(),
|
||||
std::declval<ReadHandler>()),
|
||||
std::true_type{})>
|
||||
static R check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
using type1 = decltype(check<T>(0));
|
||||
public:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value &&
|
||||
has_get_io_service<T>::type::value>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class is_AsyncWriteStream
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().async_write_some(
|
||||
std::declval<ConstBufferSequence>(),
|
||||
std::declval<WriteHandler>()),
|
||||
std::true_type{})>
|
||||
static R check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
using type1 = decltype(check<T>(0));
|
||||
public:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value &&
|
||||
has_get_io_service<T>::type::value>;
|
||||
};
|
||||
|
||||
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<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<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:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value && type2::value>;
|
||||
};
|
||||
|
||||
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<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<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:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value && type2::value>;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
73
include/beast/core/detail/temp_dir.hpp
Normal file
73
include/beast/core/detail/temp_dir.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_TEMP_DIR_H_INCLUDED
|
||||
#define BEAST_DETAIL_TEMP_DIR_H_INCLUDED
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
/** RAII temporary directory.
|
||||
|
||||
The directory and all its contents are deleted when
|
||||
the instance of `temp_dir` is destroyed.
|
||||
*/
|
||||
class temp_dir
|
||||
{
|
||||
boost::filesystem::path path_;
|
||||
|
||||
public:
|
||||
#if ! GENERATING_DOCS
|
||||
temp_dir(const temp_dir&) = delete;
|
||||
temp_dir& operator=(const temp_dir&) = delete;
|
||||
#endif
|
||||
|
||||
/// Construct a temporary directory.
|
||||
temp_dir()
|
||||
{
|
||||
auto const dir =
|
||||
boost::filesystem::temp_directory_path();
|
||||
do
|
||||
{
|
||||
path_ =
|
||||
dir / boost::filesystem::unique_path();
|
||||
}
|
||||
while(boost::filesystem::exists(path_));
|
||||
boost::filesystem::create_directory (path_);
|
||||
}
|
||||
|
||||
/// Destroy a temporary directory.
|
||||
~temp_dir()
|
||||
{
|
||||
boost::filesystem::remove_all (path_);
|
||||
}
|
||||
|
||||
/// Get the native path for the temporary directory
|
||||
std::string
|
||||
path() const
|
||||
{
|
||||
return path_.string();
|
||||
}
|
||||
|
||||
/** Get the native path for the a file.
|
||||
|
||||
The file does not need to exist.
|
||||
*/
|
||||
std::string
|
||||
file(std::string const& name) const
|
||||
{
|
||||
return (path_ / name).string();
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
23
include/beast/core/detail/unit_test.h
Normal file
23
include/beast/core/detail/unit_test.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_UNIT_TEST_H_INCLUDED
|
||||
#define BEAST_DETAIL_UNIT_TEST_H_INCLUDED
|
||||
|
||||
#include <beast/detail/unit_test/amount.h>
|
||||
#include <beast/detail/unit_test/print.h>
|
||||
#include <beast/detail/unit_test/global_suites.h>
|
||||
#include <beast/detail/unit_test/match.h>
|
||||
#include <beast/detail/unit_test/recorder.h>
|
||||
#include <beast/detail/unit_test/reporter.h>
|
||||
#include <beast/detail/unit_test/results.h>
|
||||
#include <beast/detail/unit_test/runner.h>
|
||||
#include <beast/detail/unit_test/suite.h>
|
||||
#include <beast/detail/unit_test/suite_info.h>
|
||||
#include <beast/detail/unit_test/suite_list.h>
|
||||
|
||||
#endif
|
||||
140
include/beast/core/detail/write_streambuf.hpp
Normal file
140
include/beast/core/detail/write_streambuf.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_WRITE_STREAMBUF_HPP
|
||||
#define BEAST_DETAIL_WRITE_STREAMBUF_HPP
|
||||
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
// detects string literals.
|
||||
template<class T>
|
||||
struct is_string_literal : std::integral_constant<bool,
|
||||
! std::is_same<T, typename std::remove_extent<T>::type>::value &&
|
||||
std::is_same<char, typename std::remove_extent<T>::type>::value>
|
||||
{
|
||||
};
|
||||
|
||||
// `true` if a call to boost::asio::buffer(T const&) is possible
|
||||
// note: we exclude string literals because boost::asio::buffer()
|
||||
// will include the null terminator, which we don't want.
|
||||
template<class T>
|
||||
class is_BufferConvertible
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
boost::asio::buffer(std::declval<U const&>()),
|
||||
std::true_type{})>
|
||||
static R check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
using type = decltype(check<T>(0));
|
||||
public:
|
||||
static bool const value = type::value &&
|
||||
! is_string_literal<T>::value;
|
||||
};
|
||||
|
||||
template<class Streambuf>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf,
|
||||
boost::asio::const_buffer const& buffer)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(buffer_size(buffer)),
|
||||
buffer));
|
||||
}
|
||||
|
||||
template<class Streambuf>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf,
|
||||
boost::asio::mutable_buffer const& buffer)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(buffer_size(buffer)),
|
||||
buffer));
|
||||
}
|
||||
|
||||
template<class Streambuf, class T>
|
||||
typename std::enable_if<
|
||||
is_BufferConvertible<T>::value &&
|
||||
! std::is_convertible<T, boost::asio::const_buffer>::value &&
|
||||
! std::is_convertible<T, boost::asio::mutable_buffer>::value
|
||||
>::type
|
||||
write_streambuf(Streambuf& streambuf, T const& t)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
auto const buffers = boost::asio::buffer(t);
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(buffer_size(buffers)),
|
||||
buffers));
|
||||
}
|
||||
|
||||
template<class Streambuf, class Buffers>
|
||||
typename std::enable_if<
|
||||
is_ConstBufferSequence<Buffers>::value &&
|
||||
! is_BufferConvertible<Buffers>::value &&
|
||||
! std::is_convertible<Buffers, boost::asio::const_buffer>::value &&
|
||||
! std::is_convertible<Buffers, boost::asio::mutable_buffer>::value
|
||||
>::type
|
||||
write_streambuf(Streambuf& streambuf, Buffers const& buffers)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(buffer_size(buffers)),
|
||||
buffers));
|
||||
}
|
||||
|
||||
template<class Streambuf, std::size_t N>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf, const char (&s)[N])
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(N - 1),
|
||||
boost::asio::buffer(s, N - 1)));
|
||||
}
|
||||
|
||||
template<class Streambuf, class T>
|
||||
typename std::enable_if<
|
||||
! is_string_literal<T>::value &&
|
||||
! is_ConstBufferSequence<T>::value &&
|
||||
! is_BufferConvertible<T>::value &&
|
||||
! std::is_convertible<T, boost::asio::const_buffer>::value &&
|
||||
! std::is_convertible<T, boost::asio::mutable_buffer>::value
|
||||
>::type
|
||||
write_streambuf(Streambuf& streambuf, T const& t)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
auto const s = boost::lexical_cast<std::string>(t);
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(s.size()), buffer(s)));
|
||||
}
|
||||
|
||||
template<class Streambuf, class T0, class T1, class... TN>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf,
|
||||
T0 const& t0, T1 const& t1, TN const&... tn)
|
||||
{
|
||||
write_streambuf(streambuf, t0);
|
||||
write_streambuf(streambuf, t1, tn...);
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
24
include/beast/core/error.hpp
Normal file
24
include/beast/core/error.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_ERROR_HPP
|
||||
#define BEAST_ERROR_HPP
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/// The type of error code used by the library
|
||||
using error_code = boost::system::error_code;
|
||||
|
||||
/// The type of system error thrown by the library
|
||||
using system_error = boost::system::system_error;
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
148
include/beast/core/handler_alloc.hpp
Normal file
148
include/beast/core/handler_alloc.hpp
Normal file
@@ -0,0 +1,148 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_HANDLER_ALLOC_HPP
|
||||
#define BEAST_HANDLER_ALLOC_HPP
|
||||
|
||||
#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. It meets the requirements
|
||||
of `Allocator` and can be used anywhere a `std::allocator` is
|
||||
accepted.
|
||||
|
||||
@tparam T The type of objects allocated by the allocator.
|
||||
|
||||
@tparam CompletionHandler The type of handler.
|
||||
|
||||
@note Allocated memory is only valid until the handler is called. The
|
||||
caller is still responsible for freeing memory.
|
||||
*/
|
||||
#if GENERATING_DOCS
|
||||
template <class T, class CompletionHandler>
|
||||
class handler_alloc;
|
||||
#else
|
||||
template <class T, class CompletionHandler>
|
||||
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 CompletionHandler is not
|
||||
// constructible from H.
|
||||
//
|
||||
template <class U, class H>
|
||||
friend class handler_alloc;
|
||||
|
||||
CompletionHandler 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(CompletionHandler&& h)
|
||||
: h_(std::move(h))
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct the allocator.
|
||||
|
||||
A copy of the handler is made.
|
||||
*/
|
||||
explicit
|
||||
handler_alloc(CompletionHandler const& h)
|
||||
: h_(h)
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
handler_alloc(
|
||||
handler_alloc<U, CompletionHandler>&& other)
|
||||
: h_(std::move(other.h_))
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
handler_alloc(
|
||||
handler_alloc<U, CompletionHandler> 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, CompletionHandler> const& rhs)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U>
|
||||
friend
|
||||
bool
|
||||
operator!=(handler_alloc const& lhs,
|
||||
handler_alloc<U, CompletionHandler> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
27
include/beast/core/handler_concepts.hpp
Normal file
27
include/beast/core/handler_concepts.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_HANDLER_CONCEPTS_HPP
|
||||
#define BEAST_HANDLER_CONCEPTS_HPP
|
||||
|
||||
#include <beast/core/detail/is_call_possible.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `CompletionHandler`.
|
||||
template<class T, class Signature>
|
||||
#if GENERATING_DOCS
|
||||
using is_CompletionHandler = std::integral_constant<bool, ...>;
|
||||
#else
|
||||
using is_CompletionHandler = std::integral_constant<bool,
|
||||
std::is_copy_constructible<typename std::decay<T>::type>::value &&
|
||||
detail::is_call_possible<T, Signature>::value>;
|
||||
#endif
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
872
include/beast/core/impl/basic_streambuf.ipp
Normal file
872
include/beast/core/impl/basic_streambuf.ipp
Normal file
@@ -0,0 +1,872 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_IMPL_BASIC_STREAMBUF_IPP
|
||||
#define BEAST_IMPL_BASIC_STREAMBUF_IPP
|
||||
|
||||
#include <beast/core/detail/write_streambuf.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/* These diagrams illustrate the layout and state variables.
|
||||
|
||||
1 Input and output contained entirely in one element:
|
||||
|
||||
0 out_
|
||||
|<-------------+------------------------------------------->|
|
||||
in_pos_ out_pos_ out_end_
|
||||
|
||||
|
||||
2 Output contained in first and second elements:
|
||||
|
||||
out_
|
||||
|<------+----------+------->| |<----------+-------------->|
|
||||
in_pos_ out_pos_ out_end_
|
||||
|
||||
|
||||
3 Output contained in the second element:
|
||||
|
||||
out_
|
||||
|<------------+------------>| |<----+-------------------->|
|
||||
in_pos_ out_pos_ out_end_
|
||||
|
||||
|
||||
4 Output contained in second and third elements:
|
||||
|
||||
out_
|
||||
|<-----+-------->| |<-------+------>| |<--------------->|
|
||||
in_pos_ out_pos_ out_end_
|
||||
|
||||
|
||||
5 Input sequence is empty:
|
||||
|
||||
out_
|
||||
|<------+------------------>| |<-----------+------------->|
|
||||
out_pos_ out_end_
|
||||
in_pos_
|
||||
|
||||
|
||||
6 Output sequence is empty:
|
||||
|
||||
out_
|
||||
|<------+------------------>| |<------+------------------>|
|
||||
in_pos_ out_pos_
|
||||
out_end_
|
||||
|
||||
|
||||
7 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_
|
||||
|
||||
|
||||
8 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
|
||||
{
|
||||
basic_streambuf const* sb_;
|
||||
|
||||
friend class basic_streambuf;
|
||||
|
||||
explicit
|
||||
const_buffers_type(basic_streambuf const& sb);
|
||||
|
||||
public:
|
||||
// Why?
|
||||
using value_type = boost::asio::const_buffer;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
const_buffers_type() = delete;
|
||||
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;
|
||||
};
|
||||
|
||||
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() = delete;
|
||||
mutable_buffers_type(mutable_buffers_type const&) = default;
|
||||
mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
|
||||
|
||||
const_iterator
|
||||
begin() const;
|
||||
|
||||
const_iterator
|
||||
end() const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
class basic_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)
|
||||
: detail::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)
|
||||
: detail::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
|
||||
{
|
||||
list_type reuse;
|
||||
if(out_ != list_.end())
|
||||
{
|
||||
if(out_ != list_.iterator_to(list_.back()))
|
||||
{
|
||||
out_end_ = out_->size();
|
||||
reuse.splice(reuse.end(), list_,
|
||||
std::next(out_), list_.end());
|
||||
debug_check();
|
||||
}
|
||||
auto const avail = out_->size() - out_pos_;
|
||||
if(n > avail)
|
||||
{
|
||||
out_end_ = out_->size();
|
||||
n -= avail;
|
||||
}
|
||||
else
|
||||
{
|
||||
out_end_ = out_pos_ + n;
|
||||
n = 0;
|
||||
}
|
||||
debug_check();
|
||||
}
|
||||
while(n > 0 && ! reuse.empty())
|
||||
{
|
||||
auto& e = reuse.front();
|
||||
reuse.erase(reuse.iterator_to(e));
|
||||
list_.push_back(e);
|
||||
if(n > e.size())
|
||||
{
|
||||
out_end_ = e.size();
|
||||
n -= e.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
out_end_ = n;
|
||||
n = 0;
|
||||
}
|
||||
debug_check();
|
||||
}
|
||||
while(n > 0)
|
||||
{
|
||||
auto const size = std::max(alloc_size_, n);
|
||||
auto& e = *reinterpret_cast<element*>(
|
||||
alloc_traits::allocate(this->member(),
|
||||
sizeof(element) + size));
|
||||
alloc_traits::construct(this->member(), &e, size);
|
||||
list_.push_back(e);
|
||||
if(out_ == list_.end())
|
||||
out_ = list_.iterator_to(e);
|
||||
if(n >= e.size())
|
||||
{
|
||||
out_end_ = e.size();
|
||||
n -= e.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
out_end_ = n;
|
||||
n = 0;
|
||||
}
|
||||
debug_check();
|
||||
}
|
||||
for(auto it = reuse.begin(); it != reuse.end();)
|
||||
{
|
||||
auto& e = *it++;
|
||||
reuse.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);
|
||||
}
|
||||
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 back =
|
||||
list_.iterator_to(list_.back());
|
||||
while(out_ != back)
|
||||
{
|
||||
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;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(list_.begin() != out_)
|
||||
{
|
||||
auto const avail = list_.front().size() - in_pos_;
|
||||
if(n < avail)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
debug_check();
|
||||
break;
|
||||
}
|
||||
n -= avail;
|
||||
in_size_ -= avail;
|
||||
in_pos_ = 0;
|
||||
auto& e = list_.front();
|
||||
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();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const avail = out_pos_ - in_pos_;
|
||||
if(n < avail)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_size_ = 0;
|
||||
if(out_ != list_.iterator_to(list_.back()) ||
|
||||
out_pos_ != out_end_)
|
||||
{
|
||||
in_pos_ = out_pos_;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Input and output sequences are empty, reuse buffer.
|
||||
// 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
|
||||
using boost::asio::buffer_size;
|
||||
assert(buffer_size(data()) == in_size_);
|
||||
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 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 Alloc, class T>
|
||||
basic_streambuf<Alloc>&
|
||||
operator<<(basic_streambuf<Alloc>& streambuf, T const& t)
|
||||
{
|
||||
detail::write_streambuf(streambuf, t);
|
||||
return streambuf;
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
503
include/beast/core/impl/buffers_adapter.ipp
Normal file
503
include/beast/core/impl/buffers_adapter.ipp
Normal file
@@ -0,0 +1,503 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_IMPL_BUFFERS_ADAPTER_IPP
|
||||
#define BEAST_IMPL_BUFFERS_ADAPTER_IPP
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter<MutableBufferSequence>::
|
||||
const_buffers_type
|
||||
{
|
||||
buffers_adapter const* ba_;
|
||||
|
||||
public:
|
||||
using value_type = boost::asio::const_buffer;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
const_buffers_type() = delete;
|
||||
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 MutableBufferSequence>
|
||||
class buffers_adapter<MutableBufferSequence>::
|
||||
const_buffers_type::const_iterator
|
||||
{
|
||||
iter_type it_;
|
||||
buffers_adapter const* ba_ = nullptr;
|
||||
|
||||
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 MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<MutableBufferSequence>::const_buffers_type::begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*ba_, ba_->begin_};
|
||||
}
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<MutableBufferSequence>::const_buffers_type::end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*ba_, ba_->out_ ==
|
||||
ba_->end_ ? ba_->end_ : std::next(ba_->out_)};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter<MutableBufferSequence>::
|
||||
mutable_buffers_type
|
||||
{
|
||||
buffers_adapter const* ba_;
|
||||
|
||||
public:
|
||||
using value_type = boost::asio::mutable_buffer;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
mutable_buffers_type() = delete;
|
||||
mutable_buffers_type(
|
||||
mutable_buffers_type const&) = default;
|
||||
mutable_buffers_type& operator=(
|
||||
mutable_buffers_type const&) = default;
|
||||
|
||||
const_iterator
|
||||
begin() const;
|
||||
|
||||
const_iterator
|
||||
end() const;
|
||||
|
||||
private:
|
||||
friend class buffers_adapter;
|
||||
|
||||
mutable_buffers_type(
|
||||
buffers_adapter const& ba)
|
||||
: ba_(&ba)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter<MutableBufferSequence>::
|
||||
mutable_buffers_type::const_iterator
|
||||
{
|
||||
iter_type it_;
|
||||
buffers_adapter const* ba_ = nullptr;
|
||||
|
||||
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 MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<MutableBufferSequence>::mutable_buffers_type::begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*ba_, ba_->out_};
|
||||
}
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<MutableBufferSequence>::mutable_buffers_type::end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*ba_, ba_->end_};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
buffers_adapter<MutableBufferSequence>::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 MutableBufferSequence>
|
||||
buffers_adapter<MutableBufferSequence>::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 MutableBufferSequence>
|
||||
auto
|
||||
buffers_adapter<MutableBufferSequence>::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 MutableBufferSequence>
|
||||
auto
|
||||
buffers_adapter<MutableBufferSequence>::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 MutableBufferSequence>
|
||||
buffers_adapter<MutableBufferSequence>::buffers_adapter(
|
||||
MutableBufferSequence const& bs)
|
||||
: bs_(bs)
|
||||
, begin_(bs_.begin())
|
||||
, out_(bs_.begin())
|
||||
, end_(bs_.begin())
|
||||
, max_size_(boost::asio::buffer_size(bs_))
|
||||
{
|
||||
}
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
auto
|
||||
buffers_adapter<MutableBufferSequence>::prepare(std::size_t n) ->
|
||||
mutable_buffers_type
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
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 MutableBufferSequence>
|
||||
void
|
||||
buffers_adapter<MutableBufferSequence>::commit(std::size_t n)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
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 MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<MutableBufferSequence>::data() const ->
|
||||
const_buffers_type
|
||||
{
|
||||
return const_buffers_type{*this};
|
||||
}
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
void
|
||||
buffers_adapter<MutableBufferSequence>::consume(std::size_t n)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
while(begin_ != out_)
|
||||
{
|
||||
auto const avail =
|
||||
buffer_size(*begin_) - in_pos_;
|
||||
if(n < avail)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
return;
|
||||
}
|
||||
n -= avail;
|
||||
in_size_ -= avail;
|
||||
in_pos_ = 0;
|
||||
++begin_;
|
||||
}
|
||||
auto const avail = out_pos_ - in_pos_;
|
||||
if(n < avail)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_size_ -= avail;
|
||||
in_pos_ = out_pos_;
|
||||
}
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
210
include/beast/core/impl/consuming_buffers.ipp
Normal file
210
include/beast/core/impl/consuming_buffers.ipp
Normal file
@@ -0,0 +1,210 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_IMPL_CONSUMING_BUFFERS_IPP
|
||||
#define BEAST_IMPL_CONSUMING_BUFFERS_IPP
|
||||
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template<class BufferSequence, class ValueType>
|
||||
class consuming_buffers<BufferSequence, ValueType>::const_iterator
|
||||
{
|
||||
friend class consuming_buffers<BufferSequence, ValueType>;
|
||||
|
||||
using iter_type =
|
||||
typename BufferSequence::const_iterator;
|
||||
|
||||
iter_type it_;
|
||||
consuming_buffers const* b_ = nullptr;
|
||||
|
||||
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
|
||||
{
|
||||
return it_ == b_->begin_ ?
|
||||
*it_ + b_->skip_ : *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 BufferSequence, class ValueType>
|
||||
consuming_buffers<BufferSequence, ValueType>::
|
||||
consuming_buffers(consuming_buffers&& other)
|
||||
: consuming_buffers(std::move(other),
|
||||
std::distance<iter_type>(
|
||||
other.bs_.begin(), other.begin_))
|
||||
{
|
||||
}
|
||||
|
||||
template<class BufferSequence, class ValueType>
|
||||
consuming_buffers<BufferSequence, ValueType>::
|
||||
consuming_buffers(consuming_buffers const& other)
|
||||
: consuming_buffers(other,
|
||||
std::distance<iter_type>(
|
||||
other.bs_.begin(), other.begin_))
|
||||
{
|
||||
}
|
||||
|
||||
template<class BufferSequence, class ValueType>
|
||||
auto
|
||||
consuming_buffers<BufferSequence, 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 BufferSequence, class ValueType>
|
||||
auto
|
||||
consuming_buffers<BufferSequence, 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 BufferSequence, class ValueType>
|
||||
consuming_buffers<BufferSequence, ValueType>::
|
||||
consuming_buffers(BufferSequence const& bs)
|
||||
: bs_(bs)
|
||||
, begin_(bs_.begin())
|
||||
{
|
||||
static_assert(is_BufferSequence<BufferSequence, ValueType>::value,
|
||||
"BufferSequence requirements not met");
|
||||
}
|
||||
|
||||
template<class BufferSequence, class ValueType>
|
||||
auto
|
||||
consuming_buffers<BufferSequence, ValueType>::begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*this, begin_};
|
||||
}
|
||||
|
||||
template<class BufferSequence, class ValueType>
|
||||
auto
|
||||
consuming_buffers<BufferSequence, ValueType>::end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*this, bs_.end()};
|
||||
}
|
||||
|
||||
template<class BufferSequence, class ValueType>
|
||||
void
|
||||
consuming_buffers<BufferSequence, 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;
|
||||
}
|
||||
}
|
||||
|
||||
template<class BufferSequence>
|
||||
consuming_buffers<BufferSequence, typename BufferSequence::value_type>
|
||||
consumed_buffers(BufferSequence const& bs, std::size_t n)
|
||||
{
|
||||
consuming_buffers<BufferSequence> cb(bs);
|
||||
cb.consume(n);
|
||||
return cb;
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
215
include/beast/core/impl/prepare_buffers.ipp
Normal file
215
include/beast/core/impl/prepare_buffers.ipp
Normal file
@@ -0,0 +1,215 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_IMPL_PREPARE_BUFFERS_IPP
|
||||
#define BEAST_IMPL_PREPARE_BUFFERS_IPP
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template<class BufferSequence>
|
||||
void
|
||||
prepared_buffers<BufferSequence>::
|
||||
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_;
|
||||
}
|
||||
|
||||
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_ = nullptr;
|
||||
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};
|
||||
}
|
||||
|
||||
template<class BufferSequence>
|
||||
inline
|
||||
prepared_buffers<BufferSequence>
|
||||
prepare_buffers(std::size_t n, BufferSequence const& buffers)
|
||||
{
|
||||
return prepared_buffers<BufferSequence>(n, buffers);
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
304
include/beast/core/impl/static_streambuf.ipp
Normal file
304
include/beast/core/impl/static_streambuf.ipp
Normal file
@@ -0,0 +1,304 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_IMPL_STATIC_STREAMBUF_IPP
|
||||
#define BEAST_IMPL_STATIC_STREAMBUF_IPP
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace beast {
|
||||
|
||||
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() = delete;
|
||||
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_ = 0;
|
||||
std::uint8_t const* p_ = nullptr;
|
||||
|
||||
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_};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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() = delete;
|
||||
mutable_buffers_type(
|
||||
mutable_buffers_type const&) = default;
|
||||
mutable_buffers_type& operator=(
|
||||
mutable_buffers_type const&) = default;
|
||||
|
||||
const_iterator
|
||||
begin() const;
|
||||
|
||||
const_iterator
|
||||
end() const;
|
||||
|
||||
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_ = 0;
|
||||
std::uint8_t* p_ = nullptr;
|
||||
|
||||
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_)};
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
263
include/beast/core/impl/streambuf_readstream.ipp
Normal file
263
include/beast/core/impl/streambuf_readstream.ipp
Normal file
@@ -0,0 +1,263 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_IMPL_STREAMBUF_READSTREAM_IPP
|
||||
#define BEAST_IMPL_STREAMBUF_READSTREAM_IPP
|
||||
|
||||
#include <beast/core/bind_handler.hpp>
|
||||
#include <beast/core/handler_concepts.hpp>
|
||||
#include <beast/core/handler_alloc.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
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& srs;
|
||||
MutableBufferSequence bs;
|
||||
Handler h;
|
||||
int state = 0;
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_,
|
||||
streambuf_readstream& srs_,
|
||||
MutableBufferSequence const& bs_)
|
||||
: srs(srs_)
|
||||
, 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,
|
||||
streambuf_readstream& srs, Args&&... args)
|
||||
: d_(std::allocate_shared<data>(alloc_type{h},
|
||||
std::forward<DeducedHandler>(h), srs,
|
||||
std::forward<Args>(args)...))
|
||||
{
|
||||
(*this)(error_code{}, 0);
|
||||
}
|
||||
|
||||
void
|
||||
operator()(error_code const& ec,
|
||||
std::size_t bytes_transferred);
|
||||
|
||||
friend
|
||||
void* asio_handler_allocate(
|
||||
std::size_t size, read_some_op* op)
|
||||
{
|
||||
return boost_asio_handler_alloc_helpers::
|
||||
allocate(size, op->d_->h);
|
||||
}
|
||||
|
||||
friend
|
||||
void 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
|
||||
bool asio_handler_is_continuation(read_some_op* op)
|
||||
{
|
||||
return boost_asio_handler_cont_helpers::
|
||||
is_continuation(op->d_->h);
|
||||
}
|
||||
|
||||
template <class Function>
|
||||
friend
|
||||
void 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.srs.sb_.size() == 0)
|
||||
{
|
||||
d.state =
|
||||
d.srs.size_ > 0 ? 2 : 1;
|
||||
break;
|
||||
}
|
||||
d.state = 4;
|
||||
d.srs.get_io_service().post(
|
||||
bind_handler(std::move(*this), ec, 0));
|
||||
return;
|
||||
|
||||
case 1:
|
||||
// read (unbuffered)
|
||||
d.state = 99;
|
||||
d.srs.next_layer_.async_read_some(
|
||||
d.bs, std::move(*this));
|
||||
return;
|
||||
|
||||
case 2:
|
||||
// read
|
||||
d.state = 3;
|
||||
d.srs.next_layer_.async_read_some(
|
||||
d.srs.sb_.prepare(d.srs.size_),
|
||||
std::move(*this));
|
||||
return;
|
||||
|
||||
// got data
|
||||
case 3:
|
||||
d.state = 4;
|
||||
d.srs.sb_.commit(bytes_transferred);
|
||||
break;
|
||||
|
||||
// copy
|
||||
case 4:
|
||||
bytes_transferred =
|
||||
boost::asio::buffer_copy(
|
||||
d.bs, d.srs.sb_.data());
|
||||
d.srs.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)...)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Stream, class Streambuf>
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
auto
|
||||
streambuf_readstream<Stream, Streambuf>::
|
||||
async_write_some(ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler) ->
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
{
|
||||
static_assert(is_AsyncWriteStream<next_layer_type>::value,
|
||||
"AsyncWriteStream requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(is_CompletionHandler<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_SyncReadStream<next_layer_type>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_MutableBufferSequence<
|
||||
MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
error_code ec;
|
||||
auto n = read_some(buffers, ec);
|
||||
if(ec)
|
||||
throw 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_SyncReadStream<next_layer_type>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
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) ->
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
{
|
||||
static_assert(is_AsyncReadStream<next_layer_type>::value,
|
||||
"Stream requirements not met");
|
||||
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
|
||||
29
include/beast/core/placeholders.hpp
Normal file
29
include/beast/core/placeholders.hpp
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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_PLACEHOLDERS_HPP
|
||||
#define BEAST_PLACEHOLDERS_HPP
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace beast {
|
||||
namespace asio {
|
||||
|
||||
namespace placeholders {
|
||||
// asio placeholders that work with std::bind
|
||||
namespace {
|
||||
static auto const error (std::placeholders::_1);
|
||||
static auto const bytes_transferred (std::placeholders::_2);
|
||||
static auto const iterator (std::placeholders::_2);
|
||||
static auto const signal_number (std::placeholders::_2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
157
include/beast/core/prepare_buffers.hpp
Normal file
157
include/beast/core/prepare_buffers.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_PREPARE_BUFFERS_HPP
|
||||
#define BEAST_PREPARE_BUFFERS_HPP
|
||||
|
||||
#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;
|
||||
|
||||
#if GENERATING_DOCS
|
||||
/// A bidirectional iterator type that may be used to read elements.
|
||||
using const_iterator = implementation_defined;
|
||||
|
||||
#else
|
||||
class const_iterator;
|
||||
|
||||
#endif
|
||||
|
||||
/// 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);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** 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>
|
||||
prepared_buffers<BufferSequence>
|
||||
prepare_buffers(std::size_t n, BufferSequence const& buffers);
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/prepare_buffers.ipp>
|
||||
|
||||
#endif
|
||||
189
include/beast/core/static_streambuf.hpp
Normal file
189
include/beast/core/static_streambuf.hpp
Normal file
@@ -0,0 +1,189 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_STATIC_STREAMBUF_HPP
|
||||
#define BEAST_STATIC_STREAMBUF_HPP
|
||||
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A @b `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
|
||||
@ref 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
|
||||
@ref 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:
|
||||
#if GENERATING_DOCS
|
||||
/// The type used to represent the input sequence as a list of buffers.
|
||||
using const_buffers_type = implementation_defined;
|
||||
|
||||
/// The type used to represent the output sequence as a list of buffers.
|
||||
using mutable_buffers_type = implementation_defined;
|
||||
|
||||
#else
|
||||
class const_buffers_type;
|
||||
class mutable_buffers_type;
|
||||
|
||||
static_streambuf(
|
||||
static_streambuf const& other) noexcept = delete;
|
||||
|
||||
static_streambuf& operator=(
|
||||
static_streambuf const&) noexcept = delete;
|
||||
|
||||
#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.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(std::size_t n);
|
||||
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
void
|
||||
commit(std::size_t n)
|
||||
{
|
||||
out_ += std::min<std::size_t>(n, last_ - out_);
|
||||
}
|
||||
|
||||
/** Get a list of buffers that represents the input sequence.
|
||||
|
||||
@note These buffers remain valid across subsequent calls to `prepare`.
|
||||
*/
|
||||
const_buffers_type
|
||||
data() const;
|
||||
|
||||
/// 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;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** 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
|
||||
: public static_streambuf
|
||||
#if ! GENERATING_DOCS
|
||||
, private boost::base_from_member<
|
||||
std::array<std::uint8_t, N>>
|
||||
#endif
|
||||
{
|
||||
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
|
||||
|
||||
#include <beast/core/impl/static_streambuf.ipp>
|
||||
|
||||
#endif
|
||||
691
include/beast/core/static_string.hpp
Normal file
691
include/beast/core/static_string.hpp
Normal file
@@ -0,0 +1,691 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_WEBSOCKET_STATIC_STRING_HPP
|
||||
#define BEAST_WEBSOCKET_STATIC_STRING_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A string with a fixed-size storage area.
|
||||
|
||||
These objects behave like `std::string` except that the storage
|
||||
is not dynamically allocated but rather fixed in size.
|
||||
|
||||
These strings offer performance advantages when a protocol
|
||||
imposes a natural small upper limit on the size of a value.
|
||||
|
||||
@note The stored string is always null-terminated.
|
||||
*/
|
||||
template<
|
||||
std::size_t N,
|
||||
class CharT = char,
|
||||
class Traits = std::char_traits<CharT>>
|
||||
class static_string
|
||||
{
|
||||
template<std::size_t, class, class>
|
||||
friend class static_string;
|
||||
|
||||
std::size_t n_;
|
||||
std::array<CharT, N+1> s_;
|
||||
|
||||
public:
|
||||
using traits_type = Traits;
|
||||
using value_type = typename Traits::char_type;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using const_pointer = value_type const*;
|
||||
using const_reference = value_type const&;
|
||||
using iterator = value_type*;
|
||||
using const_iterator = value_type const*;
|
||||
using reverse_iterator =
|
||||
std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator =
|
||||
std::reverse_iterator<const_iterator>;
|
||||
|
||||
/** Default constructor.
|
||||
|
||||
The string is initially empty, and null terminated.
|
||||
*/
|
||||
static_string();
|
||||
|
||||
/// Copy constructor.
|
||||
static_string(static_string const& s);
|
||||
|
||||
/// Copy constructor.
|
||||
template<std::size_t M>
|
||||
static_string(static_string<M, CharT, Traits> const& s);
|
||||
|
||||
/// Copy assignment.
|
||||
static_string&
|
||||
operator=(static_string const& s);
|
||||
|
||||
/// Copy assignment.
|
||||
template<std::size_t M>
|
||||
static_string&
|
||||
operator=(static_string<M, CharT, Traits> const& s);
|
||||
|
||||
/// Construct from string literal.
|
||||
template<std::size_t M>
|
||||
static_string(const CharT (&s)[M]);
|
||||
|
||||
/// Assign from string literal.
|
||||
template<std::size_t M>
|
||||
static_string& operator=(const CharT (&s)[M]);
|
||||
|
||||
/// Access specified character with bounds checking.
|
||||
reference
|
||||
at(size_type pos);
|
||||
|
||||
/// Access specified character with bounds checking.
|
||||
const_reference
|
||||
at(size_type pos) const;
|
||||
|
||||
/// Access specified character.
|
||||
reference
|
||||
operator[](size_type pos)
|
||||
{
|
||||
return s_[pos];
|
||||
}
|
||||
|
||||
/// Access specified character.
|
||||
const_reference
|
||||
operator[](size_type pos) const
|
||||
{
|
||||
return s_[pos];
|
||||
}
|
||||
|
||||
/// Accesses the first character.
|
||||
CharT&
|
||||
front()
|
||||
{
|
||||
return s_[0];
|
||||
}
|
||||
|
||||
/// Accesses the first character.
|
||||
CharT const&
|
||||
front() const
|
||||
{
|
||||
return s_[0];
|
||||
}
|
||||
|
||||
/// Accesses the last character.
|
||||
CharT&
|
||||
back()
|
||||
{
|
||||
return s_[n_-1];
|
||||
}
|
||||
|
||||
/// Accesses the last character.
|
||||
CharT const&
|
||||
back() const
|
||||
{
|
||||
return s_[n_-1];
|
||||
}
|
||||
|
||||
/// Returns a pointer to the first character of a string.
|
||||
CharT*
|
||||
data()
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns a pointer to the first character of a string.
|
||||
CharT const*
|
||||
data() const
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns a non-modifiable standard C character array version of the string.
|
||||
CharT const*
|
||||
c_str() const
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the beginning.
|
||||
iterator
|
||||
begin()
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the beginning.
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the beginning.
|
||||
const_iterator
|
||||
cbegin() const
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the end.
|
||||
iterator
|
||||
end()
|
||||
{
|
||||
return &s_[n_];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the end.
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return &s_[n_];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the end.
|
||||
const_iterator
|
||||
cend() const
|
||||
{
|
||||
return &s_[n_];
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the beginning.
|
||||
reverse_iterator
|
||||
rbegin()
|
||||
{
|
||||
return reverse_iterator{end()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the beginning.
|
||||
const_reverse_iterator
|
||||
rbegin() const
|
||||
{
|
||||
return const_reverse_iterator{cend()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the beginning.
|
||||
const_reverse_iterator
|
||||
crbegin() const
|
||||
{
|
||||
return const_reverse_iterator{cend()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the end.
|
||||
reverse_iterator
|
||||
rend()
|
||||
{
|
||||
return reverse_iterator{begin()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the end.
|
||||
const_reverse_iterator
|
||||
rend() const
|
||||
{
|
||||
return const_reverse_iterator{cbegin()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the end.
|
||||
const_reverse_iterator
|
||||
crend() const
|
||||
{
|
||||
return const_reverse_iterator{cbegin()};
|
||||
}
|
||||
|
||||
/// Returns `true` if the string is empty.
|
||||
bool
|
||||
empty() const
|
||||
{
|
||||
return n_ == 0;
|
||||
}
|
||||
|
||||
/// Returns the number of characters, excluding the null terminator.
|
||||
size_type
|
||||
size() const
|
||||
{
|
||||
return n_;
|
||||
}
|
||||
|
||||
/// Returns the maximum number of characters that can be stored, excluding the null terminator.
|
||||
size_type constexpr
|
||||
max_size() const
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
/// Returns the number of characters that can be held in currently allocated storage.
|
||||
size_type
|
||||
capacity() const
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
/// Clears the contents.
|
||||
void
|
||||
clear()
|
||||
{
|
||||
resize(0);
|
||||
}
|
||||
|
||||
/** Changes the number of characters stored.
|
||||
|
||||
@note No value-initialization is performed.
|
||||
*/
|
||||
void
|
||||
resize(std::size_t n);
|
||||
|
||||
/** Changes the number of characters stored.
|
||||
|
||||
If the resulting string is larger, the new
|
||||
characters are initialized to the value of `c`.
|
||||
*/
|
||||
void
|
||||
resize(std::size_t n, CharT c);
|
||||
|
||||
/// Compare two character sequences.
|
||||
template<std::size_t M>
|
||||
int
|
||||
compare(static_string<M, CharT, Traits> const& rhs) const;
|
||||
|
||||
/// Return the characters as a `basic_string`.
|
||||
std::basic_string<CharT, Traits>
|
||||
to_string() const
|
||||
{
|
||||
return std::basic_string<
|
||||
CharT, Traits>{&s_[0], n_};
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
assign(CharT const* s);
|
||||
};
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
static_string<N, CharT, Traits>::
|
||||
static_string()
|
||||
: n_(0)
|
||||
{
|
||||
s_[0] = 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
static_string<N, CharT, Traits>::
|
||||
static_string(static_string const& s)
|
||||
: n_(s.n_)
|
||||
{
|
||||
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
static_string<N, CharT, Traits>::
|
||||
static_string(static_string<M, CharT, Traits> const& s)
|
||||
{
|
||||
if(s.size() > N)
|
||||
throw std::length_error("static_string overflow");
|
||||
n_ = s.size();
|
||||
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
operator=(static_string const& s) ->
|
||||
static_string&
|
||||
{
|
||||
n_ = s.n_;
|
||||
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
operator=(static_string<M, CharT, Traits> const& s) ->
|
||||
static_string&
|
||||
{
|
||||
if(s.size() > N)
|
||||
throw std::length_error("static_string overflow");
|
||||
n_ = s.size();
|
||||
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
static_string<N, CharT, Traits>::
|
||||
static_string(const CharT (&s)[M])
|
||||
: n_(M-1)
|
||||
{
|
||||
static_assert(M-1 <= N,
|
||||
"static_string overflow");
|
||||
Traits::copy(&s_[0], &s[0], M);
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
operator=(const CharT (&s)[M]) ->
|
||||
static_string&
|
||||
{
|
||||
static_assert(M-1 <= N,
|
||||
"static_string overflow");
|
||||
n_ = M-1;
|
||||
Traits::copy(&s_[0], &s[0], M);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
at(size_type pos) ->
|
||||
reference
|
||||
{
|
||||
if(pos >= n_)
|
||||
throw std::out_of_range("static_string::at");
|
||||
return s_[pos];
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
at(size_type pos) const ->
|
||||
const_reference
|
||||
{
|
||||
if(pos >= n_)
|
||||
throw std::out_of_range("static_string::at");
|
||||
return s_[pos];
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
void
|
||||
static_string<N, CharT, Traits>::
|
||||
resize(std::size_t n)
|
||||
{
|
||||
if(n > N)
|
||||
throw std::length_error("static_string overflow");
|
||||
n_ = n;
|
||||
s_[n_] = 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
void
|
||||
static_string<N, CharT, Traits>::
|
||||
resize(std::size_t n, CharT c)
|
||||
{
|
||||
if(n > N)
|
||||
throw std::length_error("static_string overflow");
|
||||
if(n > n_)
|
||||
Traits::assign(&s_[n_], n - n_, c);
|
||||
n_ = n;
|
||||
s_[n_] = 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
int
|
||||
static_string<N, CharT, Traits>::
|
||||
compare(static_string<M, CharT, Traits> const& rhs) const
|
||||
{
|
||||
if(size() < rhs.size())
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
data(), rhs.data(), size());
|
||||
if(v == 0)
|
||||
return -1;
|
||||
return v;
|
||||
}
|
||||
else if(size() > rhs.size())
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
data(), rhs.data(), rhs.size());
|
||||
if(v == 0)
|
||||
return 1;
|
||||
return v;
|
||||
}
|
||||
return Traits::compare(data(), rhs.data(), size());
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
void
|
||||
static_string<N, CharT, Traits>::
|
||||
assign(CharT const* s)
|
||||
{
|
||||
auto const n = Traits::length(s);
|
||||
if(n > N)
|
||||
throw std::out_of_range("too large");
|
||||
n_ = n;
|
||||
Traits::copy(&s_[0], s, n_ + 1);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
int
|
||||
compare(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
if(lhs.size() < M-1)
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
lhs.data(), &s[0], lhs.size());
|
||||
if(v == 0)
|
||||
return -1;
|
||||
return v;
|
||||
}
|
||||
else if(lhs.size() > M-1)
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
lhs.data(), &s[0], M-1);
|
||||
if(v == 0)
|
||||
return 1;
|
||||
return v;
|
||||
}
|
||||
return Traits::compare(lhs.data(), &s[0], lhs.size());
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
inline
|
||||
int
|
||||
compare(
|
||||
const CharT (&s)[M],
|
||||
static_string<N, CharT, Traits> const& rhs)
|
||||
{
|
||||
return -compare(rhs, s);
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator==(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) == 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator!=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) != 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator<(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) < 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator<=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) <= 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator>(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) > 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator>=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) >= 0;
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator==(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) == 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool
|
||||
operator==(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) == 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator!=(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) != 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool
|
||||
operator!=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) != 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator<(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) < 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool
|
||||
operator<(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) < 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator<=(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) <= 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool
|
||||
operator<=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) <= 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator>(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) > 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool
|
||||
operator>(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) > 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool
|
||||
operator>=(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) >= 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool
|
||||
operator>=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) >= 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
76
include/beast/core/stream_concepts.hpp
Normal file
76
include/beast/core/stream_concepts.hpp
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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_STREAM_CONCEPTS_HPP
|
||||
#define BEAST_STREAM_CONCEPTS_HPP
|
||||
|
||||
#include <beast/core/detail/stream_concepts.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/// Determine if `T` has the `get_io_service` member.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct has_get_io_service : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using has_get_io_service = typename detail::has_get_io_service<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `AsyncReadStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_AsyncReadStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_AsyncReadStream = typename detail::is_AsyncReadStream<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `AsyncWriteStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_AsyncWriteStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_AsyncWriteStream = typename detail::is_AsyncWriteStream<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `SyncReadStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_SyncReadStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_SyncReadStream = typename detail::is_SyncReadStream<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `SyncWriterStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_SyncWriteStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_SyncWriteStream = typename detail::is_SyncWriteStream<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `AsyncStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_AsyncStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_AsyncStream = std::integral_constant<bool,
|
||||
is_AsyncReadStream<T>::value && is_AsyncWriteStream<T>::value>;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `SyncStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_SyncStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_SyncStream = std::integral_constant<bool,
|
||||
is_SyncReadStream<T>::value && is_SyncWriteStream<T>::value>;
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
28
include/beast/core/streambuf.hpp
Normal file
28
include/beast/core/streambuf.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_STREAMBUF_HPP
|
||||
#define BEAST_STREAMBUF_HPP
|
||||
|
||||
#include <beast/core/basic_streambuf.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A @b `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.
|
||||
|
||||
@note Meets the requirements of @b `Streambuf`.
|
||||
*/
|
||||
using streambuf = basic_streambuf<std::allocator<char>>;
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
282
include/beast/core/streambuf_readstream.hpp
Normal file
282
include/beast/core/streambuf_readstream.hpp
Normal file
@@ -0,0 +1,282 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_STREAMBUF_READSTREAM_HPP
|
||||
#define BEAST_STREAMBUF_READSTREAM_HPP
|
||||
|
||||
#include <beast/core/async_completion.hpp>
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/stream_concepts.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/core/detail/get_lowest_layer.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A @b `Stream` with attached @b `Streambuf` to buffer reads.
|
||||
|
||||
This wraps a @b `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 @b `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:
|
||||
|
||||
@li Transparently leave untouched input acquired in calls
|
||||
to `boost::asio::read_until` behind for subsequent callers.
|
||||
|
||||
@li "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>
|
||||
class streambuf_readstream
|
||||
{
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
|
||||
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 =
|
||||
typename std::remove_reference<Stream>::type;
|
||||
|
||||
/// The type of the lowest layer.
|
||||
using lowest_layer_type =
|
||||
#if GENERATING_DOCS
|
||||
implementation_defined;
|
||||
#else
|
||||
typename detail::get_lowest_layer<
|
||||
next_layer_type>::type;
|
||||
#endif
|
||||
|
||||
/** Move constructor.
|
||||
|
||||
@note The behavior of move assignment on or from streams
|
||||
with active or pending operations is undefined.
|
||||
*/
|
||||
streambuf_readstream(streambuf_readstream&&) = default;
|
||||
|
||||
/** Move assignment.
|
||||
|
||||
@note The behavior of move assignment on or from streams
|
||||
with active or pending operations is undefined.
|
||||
*/
|
||||
streambuf_readstream& operator=(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)
|
||||
{
|
||||
static_assert(is_SyncWriteStream<next_layer_type>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
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)
|
||||
{
|
||||
static_assert(is_SyncWriteStream<next_layer_type>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
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>
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
typename async_completion<WriteHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
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>
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
typename async_completion<ReadHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_read_some(MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler);
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/streambuf_readstream.ipp>
|
||||
|
||||
#endif
|
||||
51
include/beast/core/to_string.hpp
Normal file
51
include/beast/core/to_string.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_TO_STRING_HPP
|
||||
#define BEAST_TO_STRING_HPP
|
||||
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Convert a @b `ConstBufferSequence` to a `std::string`.
|
||||
|
||||
This function will convert the octets in a buffer sequence to a string.
|
||||
All octets will be inserted into the resulting string, including null
|
||||
or unprintable characters.
|
||||
|
||||
@param buffers The buffer sequence to convert.
|
||||
|
||||
@return A string representing the contents of the input area.
|
||||
|
||||
@note This function participates in overload resolution only if
|
||||
the streambuf parameter meets the requirements of @b `Streambuf`.
|
||||
*/
|
||||
template<class ConstBufferSequence
|
||||
#if ! GENERATING_DOCS
|
||||
,class = std::enable_if<is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value>
|
||||
#endif
|
||||
>
|
||||
std::string
|
||||
to_string(ConstBufferSequence const& buffers)
|
||||
{
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
std::string s;
|
||||
s.reserve(buffer_size(buffers));
|
||||
for(auto const& buffer : buffers)
|
||||
s.append(buffer_cast<char const*>(buffer),
|
||||
buffer_size(buffer));
|
||||
return s;
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
63
include/beast/core/write_streambuf.hpp
Normal file
63
include/beast/core/write_streambuf.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_WRITE_STREAMBUF_HPP
|
||||
#define BEAST_WRITE_STREAMBUF_HPP
|
||||
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
#include <beast/core/detail/write_streambuf.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Write to a Streambuf.
|
||||
|
||||
This function appends the serialized representation of each provided
|
||||
argument into the stream buffer. It is capable of converting the
|
||||
following types of arguments:
|
||||
|
||||
@li `boost::asio::const_buffer`
|
||||
|
||||
@li `boost::asio::mutable_buffer`
|
||||
|
||||
@li A type meeting the requirements of @b `ConvertibleToConstBuffer`
|
||||
|
||||
@li A type meeting the requirements of @b `ConstBufferSequence`
|
||||
|
||||
@li A type meeting the requirements of @b `MutableBufferSequence`
|
||||
|
||||
For all types not listed above, the function will invoke
|
||||
`boost::lexical_cast` on the argument in an attempt to convert to
|
||||
a string, which is then appended to the stream buffer.
|
||||
|
||||
When this function serializes numbers, it converts them to
|
||||
their text representation as if by a call to `std::to_string`.
|
||||
|
||||
@param streambuf The stream buffer to write to.
|
||||
|
||||
@param args A list of one or more arguments to write.
|
||||
|
||||
@throws unspecified Any exceptions thrown by `boost::lexical_cast`.
|
||||
|
||||
@note This function participates in overload resolution only if
|
||||
the `streambuf` parameter meets the requirements of @b `Streambuf`.
|
||||
*/
|
||||
template<class Streambuf, class... Args>
|
||||
#if GENERATING_DOCS
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<is_Streambuf<Streambuf>::value>::type
|
||||
#endif
|
||||
write(Streambuf& streambuf, Args const&... args)
|
||||
{
|
||||
detail::write_streambuf(streambuf, args...);
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user