add boost on mac

This commit is contained in:
Bassem Girgis
2019-08-10 16:38:17 -05:00
parent 861b918727
commit be945cb63b
14105 changed files with 2714968 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_ASYNC_BASE_HPP
#define BOOST_BEAST_CORE_IMPL_ASYNC_BASE_HPP
#include <boost/core/exchange.hpp>
namespace boost {
namespace beast {
namespace detail {
template<class State, class Allocator>
struct allocate_stable_state final
: stable_base
, boost::empty_value<Allocator>
{
State value;
template<class... Args>
explicit
allocate_stable_state(
Allocator const& alloc,
Args&&... args)
: boost::empty_value<Allocator>(
boost::empty_init_t{}, alloc)
, value{std::forward<Args>(args)...}
{
}
void destroy() override
{
using A = typename allocator_traits<
Allocator>::template rebind_alloc<
allocate_stable_state>;
A a(this->get());
detail::allocator_traits<A>::destroy(a, this);
detail::allocator_traits<A>::deallocate(a, this, 1);
}
};
} // detail
template<
class Handler,
class Executor1,
class Allocator,
class Function>
void asio_handler_invoke(
Function&& f,
async_base<Handler, Executor1, Allocator>* p)
{
using net::asio_handler_invoke;
asio_handler_invoke(f,
p->get_legacy_handler_pointer());
}
template<
class Handler,
class Executor1,
class Allocator>
void*
asio_handler_allocate(
std::size_t size,
async_base<Handler, Executor1, Allocator>* p)
{
using net::asio_handler_allocate;
return asio_handler_allocate(size,
p->get_legacy_handler_pointer());
}
template<
class Handler,
class Executor1,
class Allocator>
void
asio_handler_deallocate(
void* mem, std::size_t size,
async_base<Handler, Executor1, Allocator>* p)
{
using net::asio_handler_deallocate;
asio_handler_deallocate(mem, size,
p->get_legacy_handler_pointer());
}
template<
class Handler,
class Executor1,
class Allocator>
bool
asio_handler_is_continuation(
async_base<Handler, Executor1, Allocator>* p)
{
using net::asio_handler_is_continuation;
return asio_handler_is_continuation(
p->get_legacy_handler_pointer());
}
template<
class State,
class Handler,
class Executor1,
class Allocator,
class... Args>
State&
allocate_stable(
stable_async_base<
Handler, Executor1, Allocator>& base,
Args&&... args)
{
using allocator_type = typename stable_async_base<
Handler, Executor1, Allocator>::allocator_type;
using A = typename detail::allocator_traits<
allocator_type>::template rebind_alloc<
detail::allocate_stable_state<
State, allocator_type>>;
struct deleter
{
allocator_type alloc;
detail::allocate_stable_state<
State, allocator_type>* ptr;
~deleter()
{
if(ptr)
{
A a(alloc);
detail::allocator_traits<A>::deallocate(a, ptr, 1);
}
}
};
A a(base.get_allocator());
deleter d{base.get_allocator(), nullptr};
d.ptr = detail::allocator_traits<A>::allocate(a, 1);
detail::allocator_traits<A>::construct(a, d.ptr,
d.alloc, std::forward<Args>(args)...);
d.ptr->next_ = base.list_;
base.list_ = d.ptr;
return boost::exchange(d.ptr, nullptr)->value;
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,995 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
#define BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
#include <boost/beast/core/async_base.hpp>
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/websocket/teardown.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/assert.hpp>
#include <boost/make_shared.hpp>
#include <boost/core/exchange.hpp>
#include <cstdlib>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
template<class... Args>
basic_stream<Protocol, Executor, RatePolicy>::
impl_type::
impl_type(std::false_type, Args&&... args)
: socket(std::forward<Args>(args)...)
, read(ex())
, write(ex())
, timer(ex())
{
reset();
}
template<class Protocol, class Executor, class RatePolicy>
template<class RatePolicy_, class... Args>
basic_stream<Protocol, Executor, RatePolicy>::
impl_type::
impl_type(std::true_type,
RatePolicy_&& policy, Args&&... args)
: boost::empty_value<RatePolicy>(
boost::empty_init_t{},
std::forward<RatePolicy_>(policy))
, socket(std::forward<Args>(args)...)
, read(ex())
, write(ex())
, timer(ex())
{
reset();
}
template<class Protocol, class Executor, class RatePolicy>
template<class Executor2>
void
basic_stream<Protocol, Executor, RatePolicy>::
impl_type::
on_timer(Executor2 const& ex2)
{
BOOST_ASSERT(waiting > 0);
// the last waiter starts the new slice
if(--waiting > 0)
return;
// update the expiration time
BOOST_VERIFY(timer.expires_after(
std::chrono::seconds(1)) == 0);
rate_policy_access::on_timer(policy());
struct handler : boost::empty_value<Executor2>
{
boost::weak_ptr<impl_type> wp;
using executor_type = Executor2;
executor_type
get_executor() const noexcept
{
return this->get();
}
handler(
Executor2 const& ex2,
boost::shared_ptr<impl_type> const& sp)
: boost::empty_value<Executor2>(
boost::empty_init_t{}, ex2)
, wp(sp)
{
}
void
operator()(error_code ec)
{
auto sp = wp.lock();
if(! sp)
return;
if(ec == net::error::operation_aborted)
return;
BOOST_ASSERT(! ec);
if(ec)
return;
sp->on_timer(this->get());
}
};
// wait on the timer again
++waiting;
timer.async_wait(handler(ex2, this->shared_from_this()));
}
template<class Protocol, class Executor, class RatePolicy>
void
basic_stream<Protocol, Executor, RatePolicy>::
impl_type::
reset()
{
// If assert goes off, it means that there are
// already read or write (or connect) operations
// outstanding, so there is nothing to apply
// the expiration time to!
//
BOOST_ASSERT(! read.pending || ! write.pending);
if(! read.pending)
BOOST_VERIFY(
read.timer.expires_at(never()) == 0);
if(! write.pending)
BOOST_VERIFY(
write.timer.expires_at(never()) == 0);
}
template<class Protocol, class Executor, class RatePolicy>
void
basic_stream<Protocol, Executor, RatePolicy>::
impl_type::
close()
{
socket.close();
timer.cancel();
// have to let the read/write ops cancel the timer,
// otherwise we will get error::timeout on close when
// we actually want net::error::operation_aborted.
//
//read.timer.cancel();
//write.timer.cancel();
}
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
struct basic_stream<Protocol, Executor, RatePolicy>::
timeout_handler
{
op_state& state;
boost::weak_ptr<impl_type> wp;
tick_type tick;
void
operator()(error_code ec)
{
// timer canceled
if(ec == net::error::operation_aborted)
return;
BOOST_ASSERT(! ec);
auto sp = wp.lock();
// stream destroyed
if(! sp)
return;
// stale timer
if(tick < state.tick)
return;
BOOST_ASSERT(tick == state.tick);
// timeout
BOOST_ASSERT(! state.timeout);
sp->close();
state.timeout = true;
}
};
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
struct basic_stream<Protocol, Executor, RatePolicy>::ops
{
template<bool isRead, class Buffers, class Handler>
class transfer_op
: public async_base<Handler, Executor>
, public boost::asio::coroutine
{
boost::shared_ptr<impl_type> impl_;
pending_guard pg_;
Buffers b_;
using is_read = std::integral_constant<bool, isRead>;
op_state&
state(std::true_type)
{
return impl_->read;
}
op_state&
state(std::false_type)
{
return impl_->write;
}
op_state&
state()
{
return state(
std::integral_constant<bool, isRead>{});
}
std::size_t
available_bytes(std::true_type)
{
return rate_policy_access::
available_read_bytes(impl_->policy());
}
std::size_t
available_bytes(std::false_type)
{
return rate_policy_access::
available_write_bytes(impl_->policy());
}
std::size_t
available_bytes()
{
return available_bytes(is_read{});
}
void
transfer_bytes(std::size_t n, std::true_type)
{
rate_policy_access::
transfer_read_bytes(impl_->policy(), n);
}
void
transfer_bytes(std::size_t n, std::false_type)
{
rate_policy_access::
transfer_write_bytes(impl_->policy(), n);
}
void
transfer_bytes(std::size_t n)
{
transfer_bytes(n, is_read{});
}
void
async_perform(
std::size_t amount, std::true_type)
{
impl_->socket.async_read_some(
beast::buffers_prefix(amount, b_),
std::move(*this));
}
void
async_perform(
std::size_t amount, std::false_type)
{
impl_->socket.async_write_some(
beast::buffers_prefix(amount, b_),
std::move(*this));
}
public:
template<class Handler_>
transfer_op(
Handler_&& h,
basic_stream& s,
Buffers const& b)
: async_base<Handler, Executor>(
std::forward<Handler_>(h), s.get_executor())
, impl_(s.impl_)
, pg_(state().pending)
, b_(b)
{
(*this)({});
}
void
operator()(
error_code ec,
std::size_t bytes_transferred = 0)
{
BOOST_ASIO_CORO_REENTER(*this)
{
// handle empty buffers
if(detail::buffers_empty(b_))
{
// make sure we perform the no-op
BOOST_ASIO_CORO_YIELD
async_perform(0, is_read{});
// apply the timeout manually, otherwise
// behavior varies across platforms.
if(state().timer.expiry() <= clock_type::now())
{
impl_->close();
ec = beast::error::timeout;
}
goto upcall;
}
// if a timeout is active, wait on the timer
if(state().timer.expiry() != never())
state().timer.async_wait(
net::bind_executor(
this->get_executor(),
timeout_handler{
state(),
impl_,
state().tick
}));
// check rate limit, maybe wait
std::size_t amount;
amount = available_bytes();
if(amount == 0)
{
++impl_->waiting;
BOOST_ASIO_CORO_YIELD
impl_->timer.async_wait(std::move(*this));
if(ec)
{
// socket was closed, or a timeout
BOOST_ASSERT(ec ==
net::error::operation_aborted);
// timeout handler invoked?
if(state().timeout)
{
// yes, socket already closed
ec = beast::error::timeout;
state().timeout = false;
}
goto upcall;
}
impl_->on_timer(this->get_executor());
// Allow at least one byte, otherwise
// bytes_transferred could be 0.
amount = std::max<std::size_t>(
available_bytes(), 1);
}
BOOST_ASIO_CORO_YIELD
async_perform(amount, is_read{});
if(state().timer.expiry() != never())
{
++state().tick;
// try cancelling timer
auto const n =
state().timer.cancel();
if(n == 0)
{
// timeout handler invoked?
if(state().timeout)
{
// yes, socket already closed
ec = beast::error::timeout;
state().timeout = false;
}
}
else
{
BOOST_ASSERT(n == 1);
BOOST_ASSERT(! state().timeout);
}
}
upcall:
pg_.reset();
transfer_bytes(bytes_transferred);
this->complete_now(ec, bytes_transferred);
}
}
};
template<class Handler>
class connect_op
: public async_base<Handler, Executor>
{
boost::shared_ptr<impl_type> impl_;
pending_guard pg0_;
pending_guard pg1_;
op_state&
state() noexcept
{
return impl_->write;
}
public:
template<class Handler_>
connect_op(
Handler_&& h,
basic_stream& s,
endpoint_type ep)
: async_base<Handler, Executor>(
std::forward<Handler_>(h), s.get_executor())
, impl_(s.impl_)
, pg0_(impl_->read.pending)
, pg1_(impl_->write.pending)
{
if(state().timer.expiry() != stream_base::never())
impl_->write.timer.async_wait(
net::bind_executor(
this->get_executor(),
timeout_handler{
state(),
impl_,
state().tick}));
impl_->socket.async_connect(
ep, std::move(*this));
// *this is now moved-from
}
template<
class Endpoints, class Condition,
class Handler_>
connect_op(
Handler_&& h,
basic_stream& s,
Endpoints const& eps,
Condition const& cond)
: async_base<Handler, Executor>(
std::forward<Handler_>(h), s.get_executor())
, impl_(s.impl_)
, pg0_(impl_->read.pending)
, pg1_(impl_->write.pending)
{
if(state().timer.expiry() != stream_base::never())
impl_->write.timer.async_wait(
net::bind_executor(
this->get_executor(),
timeout_handler{
state(),
impl_,
state().tick}));
net::async_connect(impl_->socket,
eps, cond, std::move(*this));
// *this is now moved-from
}
template<
class Iterator, class Condition,
class Handler_>
connect_op(
Handler_&& h,
basic_stream& s,
Iterator begin, Iterator end,
Condition const& cond)
: async_base<Handler, Executor>(
std::forward<Handler_>(h), s.get_executor())
, impl_(s.impl_)
, pg0_(impl_->read.pending)
, pg1_(impl_->write.pending)
{
if(state().timer.expiry() != stream_base::never())
impl_->write.timer.async_wait(
net::bind_executor(
this->get_executor(),
timeout_handler{
state(),
impl_,
state().tick}));
net::async_connect(impl_->socket,
begin, end, cond, std::move(*this));
// *this is now moved-from
}
template<class... Args>
void
operator()(error_code ec, Args&&... args)
{
if(state().timer.expiry() != stream_base::never())
{
++state().tick;
// try cancelling timer
auto const n =
impl_->write.timer.cancel();
if(n == 0)
{
// timeout handler invoked?
if(state().timeout)
{
// yes, socket already closed
ec = beast::error::timeout;
state().timeout = false;
}
}
else
{
BOOST_ASSERT(n == 1);
BOOST_ASSERT(! state().timeout);
}
}
pg0_.reset();
pg1_.reset();
this->complete_now(ec, std::forward<Args>(args)...);
}
};
struct run_read_op
{
template<class ReadHandler, class Buffers>
void
operator()(
ReadHandler&& h,
basic_stream* s,
Buffers const& b)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
// requirements for the handler.
static_assert(
detail::is_invocable<ReadHandler,
void(error_code, std::size_t)>::value,
"ReadHandler type requirements not met");
transfer_op<
true,
Buffers,
typename std::decay<ReadHandler>::type>(
std::forward<ReadHandler>(h), *s, b);
}
};
struct run_write_op
{
template<class WriteHandler, class Buffers>
void
operator()(
WriteHandler&& h,
basic_stream* s,
Buffers const& b)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
// requirements for the handler.
static_assert(
detail::is_invocable<WriteHandler,
void(error_code, std::size_t)>::value,
"WriteHandler type requirements not met");
transfer_op<
false,
Buffers,
typename std::decay<WriteHandler>::type>(
std::forward<WriteHandler>(h), *s, b);
}
};
struct run_connect_op
{
template<class ConnectHandler>
void
operator()(
ConnectHandler&& h,
basic_stream* s,
endpoint_type const& ep)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
// requirements for the handler.
static_assert(
detail::is_invocable<ConnectHandler,
void(error_code)>::value,
"ConnectHandler type requirements not met");
connect_op<typename std::decay<ConnectHandler>::type>(
std::forward<ConnectHandler>(h), *s, ep);
}
};
struct run_connect_range_op
{
template<
class RangeConnectHandler,
class EndpointSequence,
class Condition>
void
operator()(
RangeConnectHandler&& h,
basic_stream* s,
EndpointSequence const& eps,
Condition const& cond)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
// requirements for the handler.
static_assert(
detail::is_invocable<RangeConnectHandler,
void(error_code, typename Protocol::endpoint)>::value,
"RangeConnectHandler type requirements not met");
connect_op<typename std::decay<RangeConnectHandler>::type>(
std::forward<RangeConnectHandler>(h), *s, eps, cond);
}
};
struct run_connect_iter_op
{
template<
class IteratorConnectHandler,
class Iterator,
class Condition>
void
operator()(
IteratorConnectHandler&& h,
basic_stream* s,
Iterator begin, Iterator end,
Condition const& cond)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
// requirements for the handler.
static_assert(
detail::is_invocable<IteratorConnectHandler,
void(error_code, Iterator)>::value,
"IteratorConnectHandler type requirements not met");
connect_op<typename std::decay<IteratorConnectHandler>::type>(
std::forward<IteratorConnectHandler>(h), *s, begin, end, cond);
}
};
};
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
basic_stream<Protocol, Executor, RatePolicy>::
~basic_stream()
{
// the shared object can outlive *this,
// cancel any operations so the shared
// object is destroyed as soon as possible.
impl_->close();
}
template<class Protocol, class Executor, class RatePolicy>
template<class Arg0, class... Args, class>
basic_stream<Protocol, Executor, RatePolicy>::
basic_stream(Arg0&& arg0, Args&&... args)
: impl_(boost::make_shared<impl_type>(
std::false_type{},
std::forward<Arg0>(arg0),
std::forward<Args>(args)...))
{
}
template<class Protocol, class Executor, class RatePolicy>
template<class RatePolicy_, class Arg0, class... Args, class>
basic_stream<Protocol, Executor, RatePolicy>::
basic_stream(
RatePolicy_&& policy, Arg0&& arg0, Args&&... args)
: impl_(boost::make_shared<impl_type>(
std::true_type{},
std::forward<RatePolicy_>(policy),
std::forward<Arg0>(arg0),
std::forward<Args>(args)...))
{
}
template<class Protocol, class Executor, class RatePolicy>
basic_stream<Protocol, Executor, RatePolicy>::
basic_stream(basic_stream&& other)
: impl_(boost::make_shared<impl_type>(
std::move(*other.impl_)))
{
// VFALCO I'm not sure this implementation is correct...
}
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
auto
basic_stream<Protocol, Executor, RatePolicy>::
release_socket() ->
socket_type
{
this->cancel();
return std::move(impl_->socket);
}
template<class Protocol, class Executor, class RatePolicy>
void
basic_stream<Protocol, Executor, RatePolicy>::
expires_after(std::chrono::nanoseconds expiry_time)
{
// If assert goes off, it means that there are
// already read or write (or connect) operations
// outstanding, so there is nothing to apply
// the expiration time to!
//
BOOST_ASSERT(
! impl_->read.pending ||
! impl_->write.pending);
if(! impl_->read.pending)
BOOST_VERIFY(
impl_->read.timer.expires_after(
expiry_time) == 0);
if(! impl_->write.pending)
BOOST_VERIFY(
impl_->write.timer.expires_after(
expiry_time) == 0);
}
template<class Protocol, class Executor, class RatePolicy>
void
basic_stream<Protocol, Executor, RatePolicy>::
expires_at(
net::steady_timer::time_point expiry_time)
{
// If assert goes off, it means that there are
// already read or write (or connect) operations
// outstanding, so there is nothing to apply
// the expiration time to!
//
BOOST_ASSERT(
! impl_->read.pending ||
! impl_->write.pending);
if(! impl_->read.pending)
BOOST_VERIFY(
impl_->read.timer.expires_at(
expiry_time) == 0);
if(! impl_->write.pending)
BOOST_VERIFY(
impl_->write.timer.expires_at(
expiry_time) == 0);
}
template<class Protocol, class Executor, class RatePolicy>
void
basic_stream<Protocol, Executor, RatePolicy>::
expires_never()
{
impl_->reset();
}
template<class Protocol, class Executor, class RatePolicy>
void
basic_stream<Protocol, Executor, RatePolicy>::
cancel()
{
error_code ec;
impl_->socket.cancel(ec);
impl_->timer.cancel();
}
template<class Protocol, class Executor, class RatePolicy>
void
basic_stream<Protocol, Executor, RatePolicy>::
close()
{
impl_->close();
}
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
template<class ConnectHandler>
BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)
basic_stream<Protocol, Executor, RatePolicy>::
async_connect(
endpoint_type const& ep,
ConnectHandler&& handler)
{
return net::async_initiate<
ConnectHandler,
void(error_code)>(
typename ops::run_connect_op{},
handler,
this,
ep);
}
template<class Protocol, class Executor, class RatePolicy>
template<
class EndpointSequence,
class RangeConnectHandler,
class>
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void(error_code, typename Protocol::endpoint))
basic_stream<Protocol, Executor, RatePolicy>::
async_connect(
EndpointSequence const& endpoints,
RangeConnectHandler&& handler)
{
return net::async_initiate<
RangeConnectHandler,
void(error_code, typename Protocol::endpoint)>(
typename ops::run_connect_range_op{},
handler,
this,
endpoints,
detail::any_endpoint{});
}
template<class Protocol, class Executor, class RatePolicy>
template<
class EndpointSequence,
class ConnectCondition,
class RangeConnectHandler,
class>
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
basic_stream<Protocol, Executor, RatePolicy>::
async_connect(
EndpointSequence const& endpoints,
ConnectCondition connect_condition,
RangeConnectHandler&& handler)
{
return net::async_initiate<
RangeConnectHandler,
void(error_code, typename Protocol::endpoint)>(
typename ops::run_connect_range_op{},
handler,
this,
endpoints,
connect_condition);
}
template<class Protocol, class Executor, class RatePolicy>
template<
class Iterator,
class IteratorConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
basic_stream<Protocol, Executor, RatePolicy>::
async_connect(
Iterator begin, Iterator end,
IteratorConnectHandler&& handler)
{
return net::async_initiate<
IteratorConnectHandler,
void(error_code, Iterator)>(
typename ops::run_connect_iter_op{},
handler,
this,
begin, end,
detail::any_endpoint{});
}
template<class Protocol, class Executor, class RatePolicy>
template<
class Iterator,
class ConnectCondition,
class IteratorConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
basic_stream<Protocol, Executor, RatePolicy>::
async_connect(
Iterator begin, Iterator end,
ConnectCondition connect_condition,
IteratorConnectHandler&& handler)
{
return net::async_initiate<
IteratorConnectHandler,
void(error_code, Iterator)>(
typename ops::run_connect_iter_op{},
handler,
this,
begin, end,
connect_condition);
}
//------------------------------------------------------------------------------
template<class Protocol, class Executor, class RatePolicy>
template<class MutableBufferSequence, class ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
basic_stream<Protocol, Executor, RatePolicy>::
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
return net::async_initiate<
ReadHandler,
void(error_code, std::size_t)>(
typename ops::run_read_op{},
handler,
this,
buffers);
}
template<class Protocol, class Executor, class RatePolicy>
template<class ConstBufferSequence, class WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
basic_stream<Protocol, Executor, RatePolicy>::
async_write_some(
ConstBufferSequence const& buffers,
WriteHandler&& handler)
{
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
return net::async_initiate<
WriteHandler,
void(error_code, std::size_t)>(
typename ops::run_write_op{},
handler,
this,
buffers);
}
//------------------------------------------------------------------------------
//
// Customization points
//
#if ! BOOST_BEAST_DOXYGEN
template<
class Protocol, class Executor, class RatePolicy>
void
beast_close_socket(
basic_stream<Protocol, Executor, RatePolicy>& stream)
{
error_code ec;
stream.socket().close(ec);
}
template<
class Protocol, class Executor, class RatePolicy>
void
teardown(
role_type role,
basic_stream<Protocol, Executor, RatePolicy>& stream,
error_code& ec)
{
using beast::websocket::teardown;
teardown(role, stream.socket(), ec);
}
template<
class Protocol, class Executor, class RatePolicy,
class TeardownHandler>
void
async_teardown(
role_type role,
basic_stream<Protocol, Executor, RatePolicy>& stream,
TeardownHandler&& handler)
{
using beast::websocket::async_teardown;
async_teardown(role, stream.socket(),
std::forward<TeardownHandler>(handler));
}
#endif
} // beast
} // boost
#endif

View File

@@ -0,0 +1,242 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERED_READ_STREAM_HPP
#define BOOST_BEAST_IMPL_BUFFERED_READ_STREAM_HPP
#include <boost/beast/core/async_base.hpp>
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp>
namespace boost {
namespace beast {
template<class Stream, class DynamicBuffer>
struct buffered_read_stream<Stream, DynamicBuffer>::ops
{
template<class MutableBufferSequence, class Handler>
class read_op
: public async_base<Handler,
beast::executor_type<buffered_read_stream>>
{
buffered_read_stream& s_;
MutableBufferSequence b_;
int step_ = 0;
public:
read_op(read_op&&) = default;
read_op(read_op const&) = delete;
template<class Handler_>
read_op(
Handler_&& h,
buffered_read_stream& s,
MutableBufferSequence const& b)
: async_base<
Handler, beast::executor_type<buffered_read_stream>>(
std::forward<Handler_>(h), s.get_executor())
, s_(s)
, b_(b)
{
(*this)({}, 0);
}
void
operator()(
error_code ec,
std::size_t bytes_transferred)
{
// VFALCO TODO Rewrite this using reenter/yield
switch(step_)
{
case 0:
if(s_.buffer_.size() == 0)
{
if(s_.capacity_ == 0)
{
// read (unbuffered)
step_ = 1;
return s_.next_layer_.async_read_some(
b_, std::move(*this));
}
// read
step_ = 2;
return s_.next_layer_.async_read_some(
s_.buffer_.prepare(read_size(
s_.buffer_, s_.capacity_)),
std::move(*this));
}
step_ = 3;
return net::post(
s_.get_executor(),
beast::bind_front_handler(
std::move(*this), ec, 0));
case 1:
// upcall
break;
case 2:
s_.buffer_.commit(bytes_transferred);
BOOST_FALLTHROUGH;
case 3:
bytes_transferred =
net::buffer_copy(b_, s_.buffer_.data());
s_.buffer_.consume(bytes_transferred);
break;
}
this->complete_now(ec, bytes_transferred);
}
};
struct run_read_op
{
template<class ReadHandler, class Buffers>
void
operator()(
ReadHandler&& h,
buffered_read_stream* s,
Buffers const& b)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
// requirements for the handler.
static_assert(
beast::detail::is_invocable<ReadHandler,
void(error_code, std::size_t)>::value,
"ReadHandler type requirements not met");
read_op<
Buffers,
typename std::decay<ReadHandler>::type>(
std::forward<ReadHandler>(h), *s, b);
}
};
};
//------------------------------------------------------------------------------
template<class Stream, class DynamicBuffer>
template<class... Args>
buffered_read_stream<Stream, DynamicBuffer>::
buffered_read_stream(Args&&... args)
: next_layer_(std::forward<Args>(args)...)
{
}
template<class Stream, class DynamicBuffer>
template<class ConstBufferSequence, class WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
buffered_read_stream<Stream, DynamicBuffer>::
async_write_some(
ConstBufferSequence const& buffers,
WriteHandler&& handler)
{
static_assert(is_async_write_stream<next_layer_type>::value,
"AsyncWriteStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
static_assert(detail::is_invocable<WriteHandler,
void(error_code, std::size_t)>::value,
"WriteHandler type requirements not met");
return next_layer_.async_write_some(buffers,
std::forward<WriteHandler>(handler));
}
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence>
std::size_t
buffered_read_stream<Stream, DynamicBuffer>::
read_some(
MutableBufferSequence const& buffers)
{
static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
error_code ec;
auto n = read_some(buffers, ec);
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
return n;
}
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence>
std::size_t
buffered_read_stream<Stream, DynamicBuffer>::
read_some(MutableBufferSequence const& buffers,
error_code& ec)
{
static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
if(buffer_.size() == 0)
{
if(capacity_ == 0)
return next_layer_.read_some(buffers, ec);
buffer_.commit(next_layer_.read_some(
buffer_.prepare(read_size(buffer_,
capacity_)), ec));
if(ec)
return 0;
}
else
{
ec = {};
}
auto bytes_transferred =
net::buffer_copy(buffers, buffer_.data());
buffer_.consume(bytes_transferred);
return bytes_transferred;
}
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence, class ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
buffered_read_stream<Stream, DynamicBuffer>::
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
static_assert(is_async_read_stream<next_layer_type>::value,
"AsyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
if(buffer_.size() == 0 && capacity_ == 0)
return next_layer_.async_read_some(buffers,
std::forward<ReadHandler>(handler));
return net::async_initiate<
ReadHandler,
void(error_code, std::size_t)>(
typename ops::run_read_op{},
handler,
this,
buffers);
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,608 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
#define BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/config/workaround.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
//------------------------------------------------------------------------------
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning (push)
# pragma warning (disable: 4521) // multiple copy constructors specified
# pragma warning (disable: 4522) // multiple assignment operators specified
#endif
template<class MutableBufferSequence>
template<bool isMutable>
class buffers_adaptor<MutableBufferSequence>::
readable_bytes
{
buffers_adaptor const* b_;
public:
using value_type = typename
std::conditional<isMutable,
net::mutable_buffer,
net::const_buffer>::type;
class const_iterator;
readable_bytes() = delete;
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
readable_bytes(
readable_bytes const& other)
: b_(other.b_)
{
}
readable_bytes& operator=(
readable_bytes const& other)
{
b_ = other.b_;
return *this;
}
#else
readable_bytes(
readable_bytes const&) = default;
readable_bytes& operator=(
readable_bytes const&) = default;
#endif
template<bool isMutable_ = isMutable, class =
typename std::enable_if<! isMutable_>::type>
readable_bytes(
readable_bytes<true> const& other) noexcept
: b_(other.b_)
{
}
template<bool isMutable_ = isMutable, class =
typename std::enable_if<! isMutable_>::type>
readable_bytes& operator=(
readable_bytes<true> const& other) noexcept
{
b_ = other.b_;
return *this;
}
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class buffers_adaptor;
readable_bytes(buffers_adaptor const& b)
: b_(&b)
{
}
};
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning (pop)
#endif
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
template<bool isMutable>
class buffers_adaptor<MutableBufferSequence>::
readable_bytes<isMutable>::
const_iterator
{
iter_type it_{};
buffers_adaptor const* b_ = nullptr;
public:
using value_type = typename
std::conditional<isMutable,
net::mutable_buffer,
net::const_buffer>::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 const& 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
{
value_type const b = *it_;
return value_type{b.data(),
(b_->out_ == net::buffer_sequence_end(b_->bs_) ||
it_ != b_->out_) ? b.size() : b_->out_pos_} +
(it_ == b_->begin_ ? b_->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 readable_bytes;
const_iterator(
buffers_adaptor const& b,
iter_type iter)
: it_(iter)
, b_(&b)
{
}
};
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
readable_bytes<isMutable>::
begin() const ->
const_iterator
{
return const_iterator{*b_, b_->begin_};
}
template<class MutableBufferSequence>
template<bool isMutable>
auto
buffers_adaptor<MutableBufferSequence>::
readable_bytes<isMutable>::
readable_bytes::end() const ->
const_iterator
{
return const_iterator{*b_, b_->end_impl()};
}
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
class buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type
{
buffers_adaptor const* b_;
public:
using value_type = net::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_adaptor;
mutable_buffers_type(
buffers_adaptor const& b)
: b_(&b)
{
}
};
template<class MutableBufferSequence>
class buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::const_iterator
{
iter_type it_{};
buffers_adaptor const* b_ = nullptr;
public:
using value_type = net::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 const& 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
{
value_type const b = *it_;
return value_type{b.data(),
it_ == std::prev(b_->end_) ?
b_->out_end_ : b.size()} +
(it_ == b_->out_ ? b_->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_adaptor const& b,
iter_type iter)
: it_(iter)
, b_(&b)
{
}
};
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::
begin() const ->
const_iterator
{
return const_iterator{*b_, b_->out_};
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
mutable_buffers_type::
end() const ->
const_iterator
{
return const_iterator{*b_, b_->end_};
}
//------------------------------------------------------------------------------
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
end_impl() const ->
iter_type
{
return out_ == end_ ? end_ : std::next(out_);
}
template<class MutableBufferSequence>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(
buffers_adaptor const& other,
std::size_t nbegin,
std::size_t nout,
std::size_t nend)
: 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_)
{
}
template<class MutableBufferSequence>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(MutableBufferSequence const& bs)
: bs_(bs)
, begin_(net::buffer_sequence_begin(bs_))
, out_ (net::buffer_sequence_begin(bs_))
, end_ (net::buffer_sequence_begin(bs_))
, max_size_(
[&bs]
{
return buffer_bytes(bs);
}())
{
}
template<class MutableBufferSequence>
template<class... Args>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(
boost::in_place_init_t, Args&&... args)
: bs_{std::forward<Args>(args)...}
, begin_(net::buffer_sequence_begin(bs_))
, out_ (net::buffer_sequence_begin(bs_))
, end_ (net::buffer_sequence_begin(bs_))
, max_size_(
[&]
{
return buffer_bytes(bs_);
}())
{
}
template<class MutableBufferSequence>
buffers_adaptor<MutableBufferSequence>::
buffers_adaptor(buffers_adaptor const& other)
: buffers_adaptor(
other,
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.begin_),
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.out_),
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_))
{
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
operator=(buffers_adaptor const& other) ->
buffers_adaptor&
{
if(this == &other)
return *this;
auto const nbegin = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.begin_);
auto const nout = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.out_);
auto const nend = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = other.bs_;
begin_ = std::next(
net::buffer_sequence_begin(bs_), nbegin);
out_ = std::next(
net::buffer_sequence_begin(bs_), nout);
end_ = std::next(
net::buffer_sequence_begin(bs_), 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_adaptor<MutableBufferSequence>::
data() const noexcept ->
const_buffers_type
{
return const_buffers_type{*this};
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
data() noexcept ->
mutable_data_type
{
return mutable_data_type{*this};
}
template<class MutableBufferSequence>
auto
buffers_adaptor<MutableBufferSequence>::
prepare(std::size_t n) ->
mutable_buffers_type
{
end_ = out_;
if(end_ != net::buffer_sequence_end(bs_))
{
auto size = buffer_bytes(*end_) - out_pos_;
if(n > size)
{
n -= size;
while(++end_ !=
net::buffer_sequence_end(bs_))
{
size = buffer_bytes(*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)
BOOST_THROW_EXCEPTION(std::length_error{
"buffers_adaptor too long"});
return mutable_buffers_type{*this};
}
template<class MutableBufferSequence>
void
buffers_adaptor<MutableBufferSequence>::
commit(std::size_t n) noexcept
{
if(out_ == end_)
return;
auto const last = std::prev(end_);
while(out_ != last)
{
auto const avail =
buffer_bytes(*out_) - out_pos_;
if(n < avail)
{
out_pos_ += n;
in_size_ += n;
return;
}
++out_;
n -= avail;
out_pos_ = 0;
in_size_ += avail;
}
n = std::min<std::size_t>(
n, out_end_ - out_pos_);
out_pos_ += n;
in_size_ += n;
if(out_pos_ == buffer_bytes(*out_))
{
++out_;
out_pos_ = 0;
out_end_ = 0;
}
}
template<class MutableBufferSequence>
void
buffers_adaptor<MutableBufferSequence>::
consume(std::size_t n) noexcept
{
while(begin_ != out_)
{
auto const avail =
buffer_bytes(*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
} // boost
#endif

View File

@@ -0,0 +1,443 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_CAT_HPP
#define BOOST_BEAST_IMPL_BUFFERS_CAT_HPP
#include <boost/beast/core/detail/tuple.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/beast/core/detail/variant.hpp>
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <iterator>
#include <new>
#include <stdexcept>
#include <utility>
namespace boost {
namespace beast {
#if defined(_MSC_VER) && ! defined(__clang__)
# define BOOST_BEAST_UNREACHABLE() __assume(false)
# define BOOST_BEAST_UNREACHABLE_RETURN(v) __assume(false)
#else
# define BOOST_BEAST_UNREACHABLE() __builtin_unreachable()
# define BOOST_BEAST_UNREACHABLE_RETURN(v) \
do { __builtin_unreachable(); return v; } while(false)
#endif
#ifdef BOOST_BEAST_TESTS
#define BOOST_BEAST_LOGIC_ERROR(s) \
do { \
BOOST_THROW_EXCEPTION(std::logic_error((s))); \
BOOST_BEAST_UNREACHABLE(); \
} while(false)
#define BOOST_BEAST_LOGIC_ERROR_RETURN(v, s) \
do { \
BOOST_THROW_EXCEPTION(std::logic_error(s)); \
BOOST_BEAST_UNREACHABLE_RETURN(v); \
} while(false)
#else
#define BOOST_BEAST_LOGIC_ERROR(s) \
do { \
BOOST_ASSERT_MSG(false, s); \
BOOST_BEAST_UNREACHABLE(); \
} while(false)
#define BOOST_BEAST_LOGIC_ERROR_RETURN(v, s) \
do { \
BOOST_ASSERT_MSG(false, (s)); \
BOOST_BEAST_UNREACHABLE_RETURN(v); \
} while(false)
#endif
namespace detail {
struct buffers_cat_view_iterator_base
{
struct past_end
{
char unused = 0; // make g++8 happy
net::mutable_buffer
operator*() const
{
BOOST_BEAST_LOGIC_ERROR_RETURN({},
"Dereferencing a one-past-the-end iterator");
}
operator bool() const noexcept
{
return true;
}
};
};
} // detail
template<class... Bn>
class buffers_cat_view<Bn...>::const_iterator
: private detail::buffers_cat_view_iterator_base
{
// VFALCO The logic to skip empty sequences fails
// if there is just one buffer in the list.
static_assert(sizeof...(Bn) >= 2,
"A minimum of two sequences are required");
detail::tuple<Bn...> const* bn_ = nullptr;
detail::variant<
buffers_iterator_type<Bn>..., past_end> it_{};
friend class buffers_cat_view<Bn...>;
template<std::size_t I>
using C = std::integral_constant<std::size_t, I>;
public:
using value_type = typename
buffers_cat_view<Bn...>::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 const& other) = default;
const_iterator& operator=(
const_iterator const& other) = default;
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);
const_iterator&
operator--();
const_iterator
operator--(int);
private:
const_iterator(
detail::tuple<Bn...> const& bn,
std::true_type);
const_iterator(
detail::tuple<Bn...> const& bn,
std::false_type);
struct dereference
{
const_iterator const& self;
reference
operator()(mp11::mp_size_t<0>)
{
BOOST_BEAST_LOGIC_ERROR_RETURN({},
"Dereferencing a default-constructed iterator");
}
template<class I>
reference operator()(I)
{
return *self.it_.template get<I::value>();
}
};
struct increment
{
const_iterator& self;
void
operator()(mp11::mp_size_t<0>)
{
BOOST_BEAST_LOGIC_ERROR(
"Incrementing a default-constructed iterator");
}
template<std::size_t I>
void
operator()(mp11::mp_size_t<I>)
{
++self.it_.template get<I>();
next(mp11::mp_size_t<I>{});
}
template<std::size_t I>
void
next(mp11::mp_size_t<I>)
{
auto& it = self.it_.template get<I>();
for(;;)
{
if (it == net::buffer_sequence_end(
detail::get<I-1>(*self.bn_)))
break;
if(net::const_buffer(*it).size() > 0)
return;
++it;
}
self.it_.template emplace<I+1>(
net::buffer_sequence_begin(
detail::get<I>(*self.bn_)));
next(mp11::mp_size_t<I+1>{});
}
void
operator()(mp11::mp_size_t<sizeof...(Bn)>)
{
auto constexpr I = sizeof...(Bn);
++self.it_.template get<I>();
next(mp11::mp_size_t<I>{});
}
void
next(mp11::mp_size_t<sizeof...(Bn)>)
{
auto constexpr I = sizeof...(Bn);
auto& it = self.it_.template get<I>();
for(;;)
{
if (it == net::buffer_sequence_end(
detail::get<I-1>(*self.bn_)))
break;
if(net::const_buffer(*it).size() > 0)
return;
++it;
}
// end
self.it_.template emplace<I+1>();
}
void
operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
{
BOOST_BEAST_LOGIC_ERROR(
"Incrementing a one-past-the-end iterator");
}
};
struct decrement
{
const_iterator& self;
void
operator()(mp11::mp_size_t<0>)
{
BOOST_BEAST_LOGIC_ERROR(
"Decrementing a default-constructed iterator");
}
void
operator()(mp11::mp_size_t<1>)
{
auto constexpr I = 1;
auto& it = self.it_.template get<I>();
for(;;)
{
if(it == net::buffer_sequence_begin(
detail::get<I-1>(*self.bn_)))
{
BOOST_BEAST_LOGIC_ERROR(
"Decrementing an iterator to the beginning");
}
--it;
if(net::const_buffer(*it).size() > 0)
return;
}
}
template<std::size_t I>
void
operator()(mp11::mp_size_t<I>)
{
auto& it = self.it_.template get<I>();
for(;;)
{
if(it == net::buffer_sequence_begin(
detail::get<I-1>(*self.bn_)))
break;
--it;
if(net::const_buffer(*it).size() > 0)
return;
}
self.it_.template emplace<I-1>(
net::buffer_sequence_end(
detail::get<I-2>(*self.bn_)));
(*this)(mp11::mp_size_t<I-1>{});
}
void
operator()(mp11::mp_size_t<sizeof...(Bn)+1>)
{
auto constexpr I = sizeof...(Bn)+1;
self.it_.template emplace<I-1>(
net::buffer_sequence_end(
detail::get<I-2>(*self.bn_)));
(*this)(mp11::mp_size_t<I-1>{});
}
};
};
//------------------------------------------------------------------------------
template<class... Bn>
buffers_cat_view<Bn...>::
const_iterator::
const_iterator(
detail::tuple<Bn...> const& bn,
std::true_type)
: bn_(&bn)
{
// one past the end
it_.template emplace<sizeof...(Bn)+1>();
}
template<class... Bn>
buffers_cat_view<Bn...>::
const_iterator::
const_iterator(
detail::tuple<Bn...> const& bn,
std::false_type)
: bn_(&bn)
{
it_.template emplace<1>(
net::buffer_sequence_begin(
detail::get<0>(*bn_)));
increment{*this}.next(
mp11::mp_size_t<1>{});
}
template<class... Bn>
bool
buffers_cat_view<Bn...>::
const_iterator::
operator==(const_iterator const& other) const
{
return bn_ == other.bn_ && it_ == other.it_;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator*() const ->
reference
{
return mp11::mp_with_index<
sizeof...(Bn) + 2>(
it_.index(),
dereference{*this});
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator++() ->
const_iterator&
{
mp11::mp_with_index<
sizeof...(Bn) + 2>(
it_.index(),
increment{*this});
return *this;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator++(int) ->
const_iterator
{
auto temp = *this;
++(*this);
return temp;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator--() ->
const_iterator&
{
mp11::mp_with_index<
sizeof...(Bn) + 2>(
it_.index(),
decrement{*this});
return *this;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
const_iterator::
operator--(int) ->
const_iterator
{
auto temp = *this;
--(*this);
return temp;
}
//------------------------------------------------------------------------------
template<class... Bn>
buffers_cat_view<Bn...>::
buffers_cat_view(Bn const&... bn)
: bn_(bn...)
{
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::begin() const ->
const_iterator
{
return const_iterator{bn_, std::false_type{}};
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::end() const->
const_iterator
{
return const_iterator{bn_, std::true_type{}};
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,326 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_PREFIX_HPP
#define BOOST_BEAST_IMPL_BUFFERS_PREFIX_HPP
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/config/workaround.hpp>
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
template<class Buffers>
class buffers_prefix_view<Buffers>::const_iterator
{
friend class buffers_prefix_view<Buffers>;
buffers_prefix_view const* b_ = nullptr;
std::size_t remain_ = 0;
iter_type it_{};
public:
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
using value_type = typename std::conditional<
boost::is_convertible<typename
std::iterator_traits<iter_type>::value_type,
net::mutable_buffer>::value,
net::mutable_buffer,
net::const_buffer>::type;
#else
using value_type = buffers_type<Buffers>;
#endif
BOOST_STATIC_ASSERT(std::is_same<
typename const_iterator::value_type,
typename buffers_prefix_view::value_type>::value);
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 const& 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
{
value_type v(*it_);
if(remain_ < v.size())
return {v.data(), remain_};
return v;
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
value_type const v = *it_++;
remain_ -= v.size();
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
value_type const v = *it_++;
remain_ -= v.size();
return temp;
}
const_iterator&
operator--()
{
value_type const v = *--it_;
remain_ += v.size();
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
value_type const v = *--it_;
remain_ += v.size();
return temp;
}
private:
const_iterator(
buffers_prefix_view const& b,
std::true_type)
: b_(&b)
, remain_(b.remain_)
, it_(b_->end_)
{
}
const_iterator(
buffers_prefix_view const& b,
std::false_type)
: b_(&b)
, remain_(b_->size_)
, it_(net::buffer_sequence_begin(b_->bs_))
{
}
};
//------------------------------------------------------------------------------
template<class Buffers>
void
buffers_prefix_view<Buffers>::
setup(std::size_t size)
{
size_ = 0;
remain_ = 0;
end_ = net::buffer_sequence_begin(bs_);
auto const last = bs_.end();
while(end_ != last)
{
auto const len = buffer_bytes(*end_++);
if(len >= size)
{
size_ += size;
// by design, this subtraction can wrap
BOOST_STATIC_ASSERT(std::is_unsigned<
decltype(remain_)>::value);
remain_ = size - len;
break;
}
size -= len;
size_ += len;
}
}
template<class Buffers>
buffers_prefix_view<Buffers>::
buffers_prefix_view(
buffers_prefix_view const& other,
std::size_t dist)
: bs_(other.bs_)
, size_(other.size_)
, remain_(other.remain_)
, end_(std::next(bs_.begin(), dist))
{
}
template<class Buffers>
buffers_prefix_view<Buffers>::
buffers_prefix_view(buffers_prefix_view const& other)
: buffers_prefix_view(other,
std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_))
{
}
template<class Buffers>
auto
buffers_prefix_view<Buffers>::
operator=(buffers_prefix_view const& other) ->
buffers_prefix_view&
{
auto const dist = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = other.bs_;
size_ = other.size_;
remain_ = other.remain_;
end_ = std::next(
net::buffer_sequence_begin(bs_),
dist);
return *this;
}
template<class Buffers>
buffers_prefix_view<Buffers>::
buffers_prefix_view(
std::size_t size,
Buffers const& bs)
: bs_(bs)
{
setup(size);
}
template<class Buffers>
template<class... Args>
buffers_prefix_view<Buffers>::
buffers_prefix_view(
std::size_t size,
boost::in_place_init_t,
Args&&... args)
: bs_(std::forward<Args>(args)...)
{
setup(size);
}
template<class Buffers>
auto
buffers_prefix_view<Buffers>::
begin() const ->
const_iterator
{
return const_iterator{
*this, std::false_type{}};
}
template<class Buffers>
auto
buffers_prefix_view<Buffers>::
end() const ->
const_iterator
{
return const_iterator{
*this, std::true_type{}};
}
//------------------------------------------------------------------------------
template<>
class buffers_prefix_view<net::const_buffer>
: public net::const_buffer
{
public:
using net::const_buffer::const_buffer;
buffers_prefix_view(buffers_prefix_view const&) = default;
buffers_prefix_view& operator=(buffers_prefix_view const&) = default;
buffers_prefix_view(
std::size_t size,
net::const_buffer buffer)
: net::const_buffer(
buffer.data(),
std::min<std::size_t>(size, buffer.size())
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
, buffer.get_debug_check()
#endif
)
{
}
template<class... Args>
buffers_prefix_view(
std::size_t size,
boost::in_place_init_t,
Args&&... args)
: buffers_prefix_view(size,
net::const_buffer(
std::forward<Args>(args)...))
{
}
};
//------------------------------------------------------------------------------
template<>
class buffers_prefix_view<net::mutable_buffer>
: public net::mutable_buffer
{
public:
using net::mutable_buffer::mutable_buffer;
buffers_prefix_view(buffers_prefix_view const&) = default;
buffers_prefix_view& operator=(buffers_prefix_view const&) = default;
buffers_prefix_view(
std::size_t size,
net::mutable_buffer buffer)
: net::mutable_buffer(
buffer.data(),
std::min<std::size_t>(size, buffer.size())
#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
, buffer.get_debug_check()
#endif
)
{
}
template<class... Args>
buffers_prefix_view(
std::size_t size,
boost::in_place_init_t,
Args&&... args)
: buffers_prefix_view(size,
net::mutable_buffer(
std::forward<Args>(args)...))
{
}
};
} // beast
} // boost
#endif

View File

@@ -0,0 +1,225 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_BUFFERS_SUFFIX_HPP
#define BOOST_BEAST_IMPL_BUFFERS_SUFFIX_HPP
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/buffer_traits.hpp>
#include <boost/type_traits.hpp>
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
template<class Buffers>
class buffers_suffix<Buffers>::const_iterator
{
friend class buffers_suffix<Buffers>;
using iter_type = buffers_iterator_type<Buffers>;
iter_type it_{};
buffers_suffix const* b_ = nullptr;
public:
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
using value_type = typename std::conditional<
boost::is_convertible<typename
std::iterator_traits<iter_type>::value_type,
net::mutable_buffer>::value,
net::mutable_buffer,
net::const_buffer>::type;
#else
using value_type = buffers_type<Buffers>;
#endif
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 const& other) = default;
const_iterator& operator=(
const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
if(it_ == b_->begin_)
return value_type(*it_) + b_->skip_;
return value_type(*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(
buffers_suffix const& b,
iter_type it)
: it_(it)
, b_(&b)
{
}
};
//------------------------------------------------------------------------------
template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix()
: begin_(net::buffer_sequence_begin(bs_))
{
}
template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix(buffers_suffix const& other)
: buffers_suffix(other,
std::distance<iter_type>(
net::buffer_sequence_begin(
other.bs_), other.begin_))
{
}
template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix(Buffers const& bs)
: bs_(bs)
, begin_(net::buffer_sequence_begin(bs_))
{
static_assert(
net::is_const_buffer_sequence<Buffers>::value ||
net::is_mutable_buffer_sequence<Buffers>::value,
"BufferSequence type requirements not met");
}
template<class Buffers>
template<class... Args>
buffers_suffix<Buffers>::
buffers_suffix(boost::in_place_init_t, Args&&... args)
: bs_(std::forward<Args>(args)...)
, begin_(net::buffer_sequence_begin(bs_))
{
static_assert(sizeof...(Args) > 0,
"Missing constructor arguments");
static_assert(
std::is_constructible<Buffers, Args...>::value,
"Buffers not constructible from arguments");
}
template<class Buffers>
auto
buffers_suffix<Buffers>::
operator=(buffers_suffix const& other) ->
buffers_suffix&
{
auto const dist = std::distance<iter_type>(
net::buffer_sequence_begin(other.bs_),
other.begin_);
bs_ = other.bs_;
begin_ = std::next(
net::buffer_sequence_begin(bs_), dist);
skip_ = other.skip_;
return *this;
}
template<class Buffers>
auto
buffers_suffix<Buffers>::
begin() const ->
const_iterator
{
return const_iterator{*this, begin_};
}
template<class Buffers>
auto
buffers_suffix<Buffers>::
end() const ->
const_iterator
{
return const_iterator{*this,
net::buffer_sequence_end(bs_)};
}
template<class Buffers>
void
buffers_suffix<Buffers>::
consume(std::size_t amount)
{
auto const end =
net::buffer_sequence_end(bs_);
for(;amount > 0 && begin_ != end; ++begin_)
{
auto const len =
buffer_bytes(*begin_) - skip_;
if(amount < len)
{
skip_ += amount;
break;
}
amount -= len;
skip_ = 0;
}
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,44 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_ERROR_HPP
#define BOOST_BEAST_IMPL_ERROR_HPP
#include <type_traits>
namespace boost {
namespace system {
template<>
struct is_error_code_enum<::boost::beast::error>
{
static bool const value = true;
};
template<>
struct is_error_condition_enum<::boost::beast::condition>
{
static bool const value = true;
};
} // system
} // boost
namespace boost {
namespace beast {
BOOST_BEAST_DECL
error_code
make_error_code(error e);
BOOST_BEAST_DECL
error_condition
make_error_condition(condition c);
} // beast
} // boost
#endif

View File

@@ -0,0 +1,99 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_ERROR_IPP
#define BOOST_BEAST_IMPL_ERROR_IPP
#include <boost/beast/core/error.hpp>
namespace boost {
namespace beast {
namespace detail {
class error_codes : public error_category
{
public:
const char*
name() const noexcept override
{
return "boost.beast";
}
BOOST_BEAST_DECL
std::string
message(int ev) const override
{
switch(static_cast<error>(ev))
{
default:
case error::timeout: return
"The socket was closed due to a timeout";
}
}
BOOST_BEAST_DECL
error_condition
default_error_condition(int ev) const noexcept override
{
switch(static_cast<error>(ev))
{
default:
// return {ev, *this};
case error::timeout:
return condition::timeout;
}
}
};
class error_conditions : public error_category
{
public:
BOOST_BEAST_DECL
const char*
name() const noexcept override
{
return "boost.beast";
}
BOOST_BEAST_DECL
std::string
message(int cv) const override
{
switch(static_cast<condition>(cv))
{
default:
case condition::timeout:
return "The operation timed out";
}
}
};
} // detail
error_code
make_error_code(error e)
{
static detail::error_codes const cat{};
return error_code{static_cast<
std::underlying_type<error>::type>(e), cat};
}
error_condition
make_error_condition(condition c)
{
static detail::error_conditions const cat{};
return error_condition{static_cast<
std::underlying_type<condition>::type>(c), cat};
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,331 @@
//
// Copyright (c) 2015-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_POSIX_IPP
#include <boost/beast/core/file_posix.hpp>
#if BOOST_BEAST_USE_POSIX_FILE
#include <boost/core/exchange.hpp>
#include <limits>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
# if defined(__APPLE__) || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
# define BOOST_BEAST_NO_POSIX_FADVISE
# endif
#endif
#if ! defined(BOOST_BEAST_USE_POSIX_FADVISE)
# if ! defined(BOOST_BEAST_NO_POSIX_FADVISE)
# define BOOST_BEAST_USE_POSIX_FADVISE 1
# else
# define BOOST_BEAST_USE_POSIX_FADVISE 0
# endif
#endif
namespace boost {
namespace beast {
int
file_posix::
native_close(native_handle_type& fd)
{
/* https://github.com/boostorg/beast/issues/1445
This function is tuned for Linux / Mac OS:
* only calls close() once
* returns the error directly to the caller
* does not loop on EINTR
If this is incorrect for the platform, then the
caller will need to implement their own type
meeting the File requirements and use the correct
behavior.
See:
http://man7.org/linux/man-pages/man2/close.2.html
*/
int ev = 0;
if(fd != -1)
{
if(::close(fd) != 0)
ev = errno;
fd = -1;
}
return ev;
}
file_posix::
~file_posix()
{
native_close(fd_);
}
file_posix::
file_posix(file_posix&& other)
: fd_(boost::exchange(other.fd_, -1))
{
}
file_posix&
file_posix::
operator=(file_posix&& other)
{
if(&other == this)
return *this;
native_close(fd_);
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
void
file_posix::
native_handle(native_handle_type fd)
{
native_close(fd_);
fd_ = fd;
}
void
file_posix::
close(error_code& ec)
{
auto const ev = native_close(fd_);
if(ev)
ec.assign(ev, system_category());
else
ec = {};
}
void
file_posix::
open(char const* path, file_mode mode, error_code& ec)
{
auto const ev = native_close(fd_);
if(ev)
ec.assign(ev, system_category());
else
ec = {};
int f = 0;
#if BOOST_BEAST_USE_POSIX_FADVISE
int advise = 0;
#endif
switch(mode)
{
default:
case file_mode::read:
f = O_RDONLY;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_RANDOM;
#endif
break;
case file_mode::scan:
f = O_RDONLY;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
break;
case file_mode::write:
f = O_RDWR | O_CREAT | O_TRUNC;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_RANDOM;
#endif
break;
case file_mode::write_new:
f = O_RDWR | O_CREAT | O_EXCL;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_RANDOM;
#endif
break;
case file_mode::write_existing:
f = O_RDWR | O_EXCL;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_RANDOM;
#endif
break;
case file_mode::append:
f = O_WRONLY | O_CREAT | O_TRUNC;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
break;
case file_mode::append_existing:
f = O_WRONLY;
#if BOOST_BEAST_USE_POSIX_FADVISE
advise = POSIX_FADV_SEQUENTIAL;
#endif
break;
}
for(;;)
{
fd_ = ::open(path, f, 0644);
if(fd_ != -1)
break;
auto const ev = errno;
if(ev != EINTR)
{
ec.assign(ev, system_category());
return;
}
}
#if BOOST_BEAST_USE_POSIX_FADVISE
if(::posix_fadvise(fd_, 0, 0, advise))
{
auto const ev = errno;
native_close(fd_);
ec.assign(ev, system_category());
return;
}
#endif
ec = {};
}
std::uint64_t
file_posix::
size(error_code& ec) const
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
struct stat st;
if(::fstat(fd_, &st) != 0)
{
ec.assign(errno, system_category());
return 0;
}
ec = {};
return st.st_size;
}
std::uint64_t
file_posix::
pos(error_code& ec) const
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto const result = ::lseek(fd_, 0, SEEK_CUR);
if(result == (off_t)-1)
{
ec.assign(errno, system_category());
return 0;
}
ec = {};
return result;
}
void
file_posix::
seek(std::uint64_t offset, error_code& ec)
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return;
}
auto const result = ::lseek(fd_, offset, SEEK_SET);
if(result == static_cast<off_t>(-1))
{
ec.assign(errno, system_category());
return;
}
ec = {};
}
std::size_t
file_posix::
read(void* buffer, std::size_t n, error_code& ec) const
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nread = 0;
while(n > 0)
{
auto const amount = static_cast<ssize_t>((std::min)(
n, static_cast<std::size_t>(SSIZE_MAX)));
auto const result = ::read(fd_, buffer, amount);
if(result == -1)
{
auto const ev = errno;
if(ev == EINTR)
continue;
ec.assign(ev, system_category());
return nread;
}
if(result == 0)
{
// short read
return nread;
}
n -= result;
nread += result;
buffer = static_cast<char*>(buffer) + result;
}
return nread;
}
std::size_t
file_posix::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(fd_ == -1)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nwritten = 0;
while(n > 0)
{
auto const amount = static_cast<ssize_t>((std::min)(
n, static_cast<std::size_t>(SSIZE_MAX)));
auto const result = ::write(fd_, buffer, amount);
if(result == -1)
{
auto const ev = errno;
if(ev == EINTR)
continue;
ec.assign(ev, system_category());
return nwritten;
}
n -= result;
nwritten += result;
buffer = static_cast<char const*>(buffer) + result;
}
return nwritten;
}
} // beast
} // boost
#endif
#endif

View File

@@ -0,0 +1,296 @@
//
// Copyright (c) 2015-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_STDIO_IPP
#include <boost/beast/core/file_stdio.hpp>
#include <boost/config/workaround.hpp>
#include <boost/core/exchange.hpp>
#include <limits>
namespace boost {
namespace beast {
file_stdio::
~file_stdio()
{
if(f_)
fclose(f_);
}
file_stdio::
file_stdio(file_stdio&& other)
: f_(boost::exchange(other.f_, nullptr))
{
}
file_stdio&
file_stdio::
operator=(file_stdio&& other)
{
if(&other == this)
return *this;
if(f_)
fclose(f_);
f_ = other.f_;
other.f_ = nullptr;
return *this;
}
void
file_stdio::
native_handle(FILE* f)
{
if(f_)
fclose(f_);
f_ = f;
}
void
file_stdio::
close(error_code& ec)
{
if(f_)
{
int failed = fclose(f_);
f_ = nullptr;
if(failed)
{
ec.assign(errno, generic_category());
return;
}
}
ec = {};
}
void
file_stdio::
open(char const* path, file_mode mode, error_code& ec)
{
if(f_)
{
fclose(f_);
f_ = nullptr;
}
char const* s;
switch(mode)
{
default:
case file_mode::read:
s = "rb";
break;
case file_mode::scan:
#ifdef BOOST_MSVC
s = "rbS";
#else
s = "rb";
#endif
break;
case file_mode::write:
s = "wb+";
break;
case file_mode::write_new:
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
FILE* f0;
auto const ev = ::fopen_s(&f0, path, "rb");
if(! ev)
{
std::fclose(f0);
ec = make_error_code(errc::file_exists);
return;
}
else if(ev !=
errc::no_such_file_or_directory)
{
ec.assign(ev, generic_category());
return;
}
s = "wb";
#else
s = "wbx";
#endif
break;
}
case file_mode::write_existing:
s = "rb+";
break;
case file_mode::append:
s = "ab";
break;
case file_mode::append_existing:
{
#ifdef BOOST_MSVC
FILE* f0;
auto const ev =
::fopen_s(&f0, path, "rb+");
if(ev)
{
ec.assign(ev, generic_category());
return;
}
#else
auto const f0 =
std::fopen(path, "rb+");
if(! f0)
{
ec.assign(errno, generic_category());
return;
}
#endif
std::fclose(f0);
s = "ab";
break;
}
}
#ifdef BOOST_MSVC
auto const ev = ::fopen_s(&f_, path, s);
if(ev)
{
f_ = nullptr;
ec.assign(ev, generic_category());
return;
}
#else
f_ = std::fopen(path, s);
if(! f_)
{
ec.assign(errno, generic_category());
return;
}
#endif
ec = {};
}
std::uint64_t
file_stdio::
size(error_code& ec) const
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
long pos = std::ftell(f_);
if(pos == -1L)
{
ec.assign(errno, generic_category());
return 0;
}
int result = std::fseek(f_, 0, SEEK_END);
if(result != 0)
{
ec.assign(errno, generic_category());
return 0;
}
long size = std::ftell(f_);
if(size == -1L)
{
ec.assign(errno, generic_category());
std::fseek(f_, pos, SEEK_SET);
return 0;
}
result = std::fseek(f_, pos, SEEK_SET);
if(result != 0)
ec.assign(errno, generic_category());
else
ec = {};
return size;
}
std::uint64_t
file_stdio::
pos(error_code& ec) const
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
long pos = std::ftell(f_);
if(pos == -1L)
{
ec.assign(errno, generic_category());
return 0;
}
ec = {};
return pos;
}
void
file_stdio::
seek(std::uint64_t offset, error_code& ec)
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return;
}
if(offset > (std::numeric_limits<long>::max)())
{
ec = make_error_code(errc::invalid_seek);
return;
}
int result = std::fseek(f_,
static_cast<long>(offset), SEEK_SET);
if(result != 0)
ec.assign(errno, generic_category());
else
ec = {};
}
std::size_t
file_stdio::
read(void* buffer, std::size_t n, error_code& ec) const
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto nread = std::fread(buffer, 1, n, f_);
if(std::ferror(f_))
{
ec.assign(errno, generic_category());
return 0;
}
return nread;
}
std::size_t
file_stdio::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(! f_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
auto nwritten = std::fwrite(buffer, 1, n, f_);
if(std::ferror(f_))
{
ec.assign(errno, generic_category());
return 0;
}
return nwritten;
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,353 @@
//
// Copyright (c) 2015-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_FILE_WIN32_IPP
#define BOOST_BEAST_CORE_IMPL_FILE_WIN32_IPP
#include <boost/beast/core/file_win32.hpp>
#if BOOST_BEAST_USE_WIN32_FILE
#include <boost/core/exchange.hpp>
#include <boost/winapi/access_rights.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/get_last_error.hpp>
#include <limits>
#include <utility>
namespace boost {
namespace beast {
namespace detail {
// VFALCO Can't seem to get boost/detail/winapi to work with
// this so use the non-Ex version for now.
BOOST_BEAST_DECL
boost::winapi::BOOL_
set_file_pointer_ex(
boost::winapi::HANDLE_ hFile,
boost::winapi::LARGE_INTEGER_ lpDistanceToMove,
boost::winapi::PLARGE_INTEGER_ lpNewFilePointer,
boost::winapi::DWORD_ dwMoveMethod)
{
auto dwHighPart = lpDistanceToMove.u.HighPart;
auto dwLowPart = boost::winapi::SetFilePointer(
hFile,
lpDistanceToMove.u.LowPart,
&dwHighPart,
dwMoveMethod);
if(dwLowPart == boost::winapi::INVALID_SET_FILE_POINTER_)
return 0;
if(lpNewFilePointer)
{
lpNewFilePointer->u.LowPart = dwLowPart;
lpNewFilePointer->u.HighPart = dwHighPart;
}
return 1;
}
} // detail
file_win32::
~file_win32()
{
if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
boost::winapi::CloseHandle(h_);
}
file_win32::
file_win32(file_win32&& other)
: h_(boost::exchange(other.h_,
boost::winapi::INVALID_HANDLE_VALUE_))
{
}
file_win32&
file_win32::
operator=(file_win32&& other)
{
if(&other == this)
return *this;
if(h_)
boost::winapi::CloseHandle(h_);
h_ = other.h_;
other.h_ = boost::winapi::INVALID_HANDLE_VALUE_;
return *this;
}
void
file_win32::
native_handle(native_handle_type h)
{
if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
boost::winapi::CloseHandle(h_);
h_ = h;
}
void
file_win32::
close(error_code& ec)
{
if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
{
if(! boost::winapi::CloseHandle(h_))
ec.assign(boost::winapi::GetLastError(),
system_category());
else
ec = {};
h_ = boost::winapi::INVALID_HANDLE_VALUE_;
}
else
{
ec = {};
}
}
void
file_win32::
open(char const* path, file_mode mode, error_code& ec)
{
if(h_ != boost::winapi::INVALID_HANDLE_VALUE_)
{
boost::winapi::CloseHandle(h_);
h_ = boost::winapi::INVALID_HANDLE_VALUE_;
}
boost::winapi::DWORD_ share_mode = 0;
boost::winapi::DWORD_ desired_access = 0;
boost::winapi::DWORD_ creation_disposition = 0;
boost::winapi::DWORD_ flags_and_attributes = 0;
/*
| When the file...
This argument: | Exists Does not exist
-------------------------+------------------------------------------------------
CREATE_ALWAYS | Truncates Creates
CREATE_NEW +-----------+ Fails Creates
OPEN_ALWAYS ===| does this |===> Opens Creates
OPEN_EXISTING +-----------+ Opens Fails
TRUNCATE_EXISTING | Truncates Fails
*/
switch(mode)
{
default:
case file_mode::read:
desired_access = boost::winapi::GENERIC_READ_;
share_mode = boost::winapi::FILE_SHARE_READ_;
creation_disposition = boost::winapi::OPEN_EXISTING_;
flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
break;
case file_mode::scan:
desired_access = boost::winapi::GENERIC_READ_;
share_mode = boost::winapi::FILE_SHARE_READ_;
creation_disposition = boost::winapi::OPEN_EXISTING_;
flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
break;
case file_mode::write:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::CREATE_ALWAYS_;
flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
break;
case file_mode::write_new:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::CREATE_NEW_;
flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
break;
case file_mode::write_existing:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::OPEN_EXISTING_;
flags_and_attributes = 0x10000000; // FILE_FLAG_RANDOM_ACCESS
break;
case file_mode::append:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::CREATE_ALWAYS_;
flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
break;
case file_mode::append_existing:
desired_access = boost::winapi::GENERIC_READ_ |
boost::winapi::GENERIC_WRITE_;
creation_disposition = boost::winapi::OPEN_EXISTING_;
flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN
break;
}
h_ = ::CreateFileA(
path,
desired_access,
share_mode,
NULL,
creation_disposition,
flags_and_attributes,
NULL);
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
ec.assign(boost::winapi::GetLastError(),
system_category());
else
ec = {};
}
std::uint64_t
file_win32::
size(error_code& ec) const
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
boost::winapi::LARGE_INTEGER_ fileSize;
if(! boost::winapi::GetFileSizeEx(h_, &fileSize))
{
ec.assign(boost::winapi::GetLastError(),
system_category());
return 0;
}
ec = {};
return fileSize.QuadPart;
}
std::uint64_t
file_win32::
pos(error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
boost::winapi::LARGE_INTEGER_ in;
boost::winapi::LARGE_INTEGER_ out;
in.QuadPart = 0;
if(! detail::set_file_pointer_ex(h_, in, &out,
boost::winapi::FILE_CURRENT_))
{
ec.assign(boost::winapi::GetLastError(),
system_category());
return 0;
}
ec = {};
return out.QuadPart;
}
void
file_win32::
seek(std::uint64_t offset, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return;
}
boost::winapi::LARGE_INTEGER_ in;
in.QuadPart = offset;
if(! detail::set_file_pointer_ex(h_, in, 0,
boost::winapi::FILE_BEGIN_))
{
ec.assign(boost::winapi::GetLastError(),
system_category());
return;
}
ec = {};
}
std::size_t
file_win32::
read(void* buffer, std::size_t n, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nread = 0;
while(n > 0)
{
boost::winapi::DWORD_ amount;
if(n > (std::numeric_limits<
boost::winapi::DWORD_>::max)())
amount = (std::numeric_limits<
boost::winapi::DWORD_>::max)();
else
amount = static_cast<
boost::winapi::DWORD_>(n);
boost::winapi::DWORD_ bytesRead;
if(! ::ReadFile(h_, buffer, amount, &bytesRead, 0))
{
auto const dwError = boost::winapi::GetLastError();
if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
ec.assign(dwError, system_category());
else
ec = {};
return nread;
}
if(bytesRead == 0)
return nread;
n -= bytesRead;
nread += bytesRead;
buffer = static_cast<char*>(buffer) + bytesRead;
}
ec = {};
return nread;
}
std::size_t
file_win32::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
ec = make_error_code(errc::bad_file_descriptor);
return 0;
}
std::size_t nwritten = 0;
while(n > 0)
{
boost::winapi::DWORD_ amount;
if(n > (std::numeric_limits<
boost::winapi::DWORD_>::max)())
amount = (std::numeric_limits<
boost::winapi::DWORD_>::max)();
else
amount = static_cast<
boost::winapi::DWORD_>(n);
boost::winapi::DWORD_ bytesWritten;
if(! ::WriteFile(h_, buffer, amount, &bytesWritten, 0))
{
auto const dwError = boost::winapi::GetLastError();
if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
ec.assign(dwError, system_category());
else
ec = {};
return nwritten;
}
if(bytesWritten == 0)
return nwritten;
n -= bytesWritten;
nwritten += bytesWritten;
buffer = static_cast<char const*>(buffer) + bytesWritten;
}
ec = {};
return nwritten;
}
} // beast
} // boost
#endif
#endif

View File

@@ -0,0 +1,533 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_FLAT_BUFFER_HPP
#define BOOST_BEAST_IMPL_FLAT_BUFFER_HPP
#include <boost/core/exchange.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include <memory>
#include <stdexcept>
namespace boost {
namespace beast {
/* Layout:
begin_ in_ out_ last_ end_
|<------->|<---------->|<---------->|<------->|
| readable | writable |
*/
template<class Allocator>
basic_flat_buffer<Allocator>::
~basic_flat_buffer()
{
if(! begin_)
return;
alloc_traits::deallocate(
this->get(), begin_, capacity());
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer() noexcept(default_nothrow)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(alloc_traits::max_size(
this->get()))
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
std::size_t limit) noexcept(default_nothrow)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(limit)
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(Allocator const& alloc) noexcept
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(alloc_traits::max_size(
this->get()))
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
std::size_t limit,
Allocator const& alloc) noexcept
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(limit)
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer&& other) noexcept
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, std::move(other.get()))
, begin_(boost::exchange(other.begin_, nullptr))
, in_(boost::exchange(other.in_, nullptr))
, out_(boost::exchange(other.out_, nullptr))
, last_(boost::exchange(other.last_, nullptr))
, end_(boost::exchange(other.end_, nullptr))
, max_(other.max_)
{
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer&& other,
Allocator const& alloc)
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
{
if(this->get() != other.get())
{
begin_ = nullptr;
in_ = nullptr;
out_ = nullptr;
last_ = nullptr;
end_ = nullptr;
max_ = other.max_;
copy_from(other);
other.clear();
other.shrink_to_fit();
return;
}
begin_ = other.begin_;
in_ = other.in_;
out_ = other.out_;
last_ = other.out_; // invalidate
end_ = other.end_;
max_ = other.max_;
BOOST_ASSERT(
alloc_traits::max_size(this->get()) ==
alloc_traits::max_size(other.get()));
other.begin_ = nullptr;
other.in_ = nullptr;
other.out_ = nullptr;
other.last_ = nullptr;
other.end_ = nullptr;
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(basic_flat_buffer const& other)
: boost::empty_value<base_alloc_type>(boost::empty_init_t{},
alloc_traits::select_on_container_copy_construction(
other.get()))
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer const& other,
Allocator const& alloc)
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
template<class OtherAlloc>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const& other)
noexcept(default_nothrow)
: begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
template<class OtherAlloc>
basic_flat_buffer<Allocator>::
basic_flat_buffer(
basic_flat_buffer<OtherAlloc> const& other,
Allocator const& alloc)
: boost::empty_value<base_alloc_type>(
boost::empty_init_t{}, alloc)
, begin_(nullptr)
, in_(nullptr)
, out_(nullptr)
, last_(nullptr)
, end_(nullptr)
, max_(other.max_)
{
copy_from(other);
}
template<class Allocator>
auto
basic_flat_buffer<Allocator>::
operator=(basic_flat_buffer&& other) noexcept ->
basic_flat_buffer&
{
if(this == &other)
return *this;
move_assign(other, pocma{});
return *this;
}
template<class Allocator>
auto
basic_flat_buffer<Allocator>::
operator=(basic_flat_buffer const& other) ->
basic_flat_buffer&
{
if(this == &other)
return *this;
copy_assign(other, pocca{});
return *this;
}
template<class Allocator>
template<class OtherAlloc>
auto
basic_flat_buffer<Allocator>::
operator=(
basic_flat_buffer<OtherAlloc> const& other) ->
basic_flat_buffer&
{
copy_from(other);
return *this;
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
reserve(std::size_t n)
{
if(max_ < n)
max_ = n;
if(n > capacity())
prepare(n - size());
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
shrink_to_fit()
{
auto const len = size();
if(len == capacity())
return;
char* p;
if(len > 0)
{
BOOST_ASSERT(begin_);
BOOST_ASSERT(in_);
p = alloc(len);
std::memcpy(p, in_, len);
}
else
{
p = nullptr;
}
alloc_traits::deallocate(
this->get(), begin_, this->capacity());
begin_ = p;
in_ = begin_;
out_ = begin_ + len;
last_ = out_;
end_ = out_;
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
clear() noexcept
{
in_ = begin_;
out_ = begin_;
last_ = begin_;
}
//------------------------------------------------------------------------------
template<class Allocator>
auto
basic_flat_buffer<Allocator>::
prepare(std::size_t n) ->
mutable_buffers_type
{
auto const len = size();
if(len > max_ || n > (max_ - len))
BOOST_THROW_EXCEPTION(std::length_error{
"basic_flat_buffer too long"});
if(n <= dist(out_, end_))
{
// existing capacity is sufficient
last_ = out_ + n;
return{out_, n};
}
if(n <= capacity() - len)
{
// after a memmove,
// existing capacity is sufficient
if(len > 0)
{
BOOST_ASSERT(begin_);
BOOST_ASSERT(in_);
std::memmove(begin_, in_, len);
}
in_ = begin_;
out_ = in_ + len;
last_ = out_ + n;
return {out_, n};
}
// allocate a new buffer
auto const new_size = (std::min<std::size_t>)(
max_,
(std::max<std::size_t>)(2 * len, len + n));
auto const p = alloc(new_size);
if(begin_)
{
BOOST_ASSERT(p);
BOOST_ASSERT(in_);
std::memcpy(p, in_, len);
alloc_traits::deallocate(
this->get(), begin_, capacity());
}
begin_ = p;
in_ = begin_;
out_ = in_ + len;
last_ = out_ + n;
end_ = begin_ + new_size;
return {out_, n};
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
consume(std::size_t n) noexcept
{
if(n >= dist(in_, out_))
{
in_ = begin_;
out_ = begin_;
return;
}
in_ += n;
}
//------------------------------------------------------------------------------
template<class Allocator>
template<class OtherAlloc>
void
basic_flat_buffer<Allocator>::
copy_from(
basic_flat_buffer<OtherAlloc> const& other)
{
std::size_t const n = other.size();
if(n == 0 || n > capacity())
{
if(begin_ != nullptr)
{
alloc_traits::deallocate(
this->get(), begin_,
this->capacity());
begin_ = nullptr;
in_ = nullptr;
out_ = nullptr;
last_ = nullptr;
end_ = nullptr;
}
if(n == 0)
return;
begin_ = alloc(n);
in_ = begin_;
out_ = begin_ + n;
last_ = begin_ + n;
end_ = begin_ + n;
}
in_ = begin_;
out_ = begin_ + n;
last_ = begin_ + n;
if(begin_)
{
BOOST_ASSERT(other.begin_);
std::memcpy(begin_, other.begin_, n);
}
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
move_assign(basic_flat_buffer& other, std::true_type)
{
clear();
shrink_to_fit();
this->get() = std::move(other.get());
begin_ = other.begin_;
in_ = other.in_;
out_ = other.out_;
last_ = out_;
end_ = other.end_;
max_ = other.max_;
other.begin_ = nullptr;
other.in_ = nullptr;
other.out_ = nullptr;
other.last_ = nullptr;
other.end_ = nullptr;
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
move_assign(basic_flat_buffer& other, std::false_type)
{
if(this->get() != other.get())
{
copy_from(other);
other.clear();
other.shrink_to_fit();
}
else
{
move_assign(other, std::true_type{});
}
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
copy_assign(basic_flat_buffer const& other, std::true_type)
{
max_ = other.max_;
this->get() = other.get();
copy_from(other);
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
copy_assign(basic_flat_buffer const& other, std::false_type)
{
clear();
shrink_to_fit();
max_ = other.max_;
copy_from(other);
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other)
{
swap(other, typename
alloc_traits::propagate_on_container_swap{});
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other, std::true_type)
{
using std::swap;
swap(this->get(), other.get());
swap(max_, other.max_);
swap(begin_, other.begin_);
swap(in_, other.in_);
swap(out_, other.out_);
last_ = this->out_;
other.last_ = other.out_;
swap(end_, other.end_);
}
template<class Allocator>
void
basic_flat_buffer<Allocator>::
swap(basic_flat_buffer& other, std::false_type)
{
BOOST_ASSERT(this->get() == other.get());
using std::swap;
swap(max_, other.max_);
swap(begin_, other.begin_);
swap(in_, other.in_);
swap(out_, other.out_);
last_ = this->out_;
other.last_ = other.out_;
swap(end_, other.end_);
}
template<class Allocator>
void
swap(
basic_flat_buffer<Allocator>& lhs,
basic_flat_buffer<Allocator>& rhs)
{
lhs.swap(rhs);
}
template<class Allocator>
char*
basic_flat_buffer<Allocator>::
alloc(std::size_t n)
{
if(n > alloc_traits::max_size(this->get()))
BOOST_THROW_EXCEPTION(std::length_error(
"A basic_flat_buffer exceeded the allocator's maximum size"));
return alloc_traits::allocate(this->get(), n);
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,43 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_HPP
#define BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_HPP
namespace boost {
namespace beast {
template<std::size_t N>
flat_static_buffer<N>::
flat_static_buffer(
flat_static_buffer const& other)
: flat_static_buffer_base(buf_, N)
{
this->commit(net::buffer_copy(
this->prepare(other.size()), other.data()));
}
template<std::size_t N>
auto
flat_static_buffer<N>::
operator=(flat_static_buffer const& other) ->
flat_static_buffer<N>&
{
if(this == &other)
return *this;
this->consume(this->size());
this->commit(net::buffer_copy(
this->prepare(other.size()), other.data()));
return *this;
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,89 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_IPP
#define BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_IPP
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <memory>
#include <stdexcept>
namespace boost {
namespace beast {
/* Layout:
begin_ in_ out_ last_ end_
|<------->|<---------->|<---------->|<------->|
| readable | writable |
*/
void
flat_static_buffer_base::
clear() noexcept
{
in_ = begin_;
out_ = begin_;
last_ = begin_;
}
auto
flat_static_buffer_base::
prepare(std::size_t n) ->
mutable_buffers_type
{
if(n <= dist(out_, end_))
{
last_ = out_ + n;
return {out_, n};
}
auto const len = size();
if(n > capacity() - len)
BOOST_THROW_EXCEPTION(std::length_error{
"buffer overflow"});
if(len > 0)
std::memmove(begin_, in_, len);
in_ = begin_;
out_ = in_ + len;
last_ = out_ + n;
return {out_, n};
}
void
flat_static_buffer_base::
consume(std::size_t n) noexcept
{
if(n >= size())
{
in_ = begin_;
out_ = in_;
return;
}
in_ += n;
}
void
flat_static_buffer_base::
reset(void* p, std::size_t n) noexcept
{
begin_ = static_cast<char*>(p);
in_ = begin_;
out_ = begin_;
last_ = begin_;
end_ = begin_ + n;
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,276 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_FLAT_STREAM_HPP
#define BOOST_BEAST_CORE_IMPL_FLAT_STREAM_HPP
#include <boost/beast/core/async_base.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/static_buffer.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/websocket/teardown.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/coroutine.hpp>
#include <memory>
namespace boost {
namespace beast {
template<class NextLayer>
struct flat_stream<NextLayer>::ops
{
template<class Handler>
class write_op
: public async_base<Handler,
beast::executor_type<flat_stream>>
, public net::coroutine
{
public:
template<
class ConstBufferSequence,
class Handler_>
write_op(
Handler_&& h,
flat_stream<NextLayer>& s,
ConstBufferSequence const& b)
: async_base<Handler,
beast::executor_type<flat_stream>>(
std::forward<Handler_>(h),
s.get_executor())
{
auto const result =
flatten(b, max_size);
if(result.flatten)
{
s.buffer_.clear();
s.buffer_.commit(net::buffer_copy(
s.buffer_.prepare(result.size),
b, result.size));
s.stream_.async_write_some(
s.buffer_.data(), std::move(*this));
}
else
{
s.buffer_.clear();
s.buffer_.shrink_to_fit();
s.stream_.async_write_some(
beast::buffers_prefix(
result.size, b), std::move(*this));
}
}
void
operator()(
boost::system::error_code ec,
std::size_t bytes_transferred)
{
this->complete_now(ec, bytes_transferred);
}
};
struct run_write_op
{
template<class WriteHandler, class Buffers>
void
operator()(
WriteHandler&& h,
flat_stream* s,
Buffers const& b)
{
// If you get an error on the following line it means
// that your handler does not meet the documented type
// requirements for the handler.
static_assert(
beast::detail::is_invocable<WriteHandler,
void(error_code, std::size_t)>::value,
"WriteHandler type requirements not met");
write_op<
typename std::decay<WriteHandler>::type>(
std::forward<WriteHandler>(h), *s, b);
}
};
};
//------------------------------------------------------------------------------
template<class NextLayer>
template<class... Args>
flat_stream<NextLayer>::
flat_stream(Args&&... args)
: stream_(std::forward<Args>(args)...)
{
}
template<class NextLayer>
template<class MutableBufferSequence>
std::size_t
flat_stream<NextLayer>::
read_some(MutableBufferSequence const& buffers)
{
static_assert(boost::beast::is_sync_read_stream<next_layer_type>::value,
"SyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
error_code ec;
auto n = read_some(buffers, ec);
if(ec)
BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
return n;
}
template<class NextLayer>
template<class MutableBufferSequence>
std::size_t
flat_stream<NextLayer>::
read_some(MutableBufferSequence const& buffers, error_code& ec)
{
static_assert(boost::beast::is_sync_read_stream<next_layer_type>::value,
"SyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met");
return stream_.read_some(buffers, ec);
}
template<class NextLayer>
template<
class MutableBufferSequence,
class ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
flat_stream<NextLayer>::
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
static_assert(boost::beast::is_async_read_stream<next_layer_type>::value,
"AsyncReadStream type requirements not met");
static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence >::value,
"MutableBufferSequence type requirements not met");
return stream_.async_read_some(
buffers, std::forward<ReadHandler>(handler));
}
template<class NextLayer>
template<class ConstBufferSequence>
std::size_t
flat_stream<NextLayer>::
write_some(ConstBufferSequence const& buffers)
{
static_assert(boost::beast::is_sync_write_stream<next_layer_type>::value,
"SyncWriteStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
error_code ec;
auto n = write_some(buffers, ec);
if(ec)
BOOST_THROW_EXCEPTION(boost::system::system_error{ec});
return n;
}
template<class NextLayer>
template<class ConstBufferSequence>
std::size_t
flat_stream<NextLayer>::
stack_write_some(
std::size_t size,
ConstBufferSequence const& buffers,
error_code& ec)
{
static_buffer<max_stack> b;
b.commit(net::buffer_copy(
b.prepare(size), buffers));
return stream_.write_some(b.data(), ec);
}
template<class NextLayer>
template<class ConstBufferSequence>
std::size_t
flat_stream<NextLayer>::
write_some(ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(boost::beast::is_sync_write_stream<next_layer_type>::value,
"SyncWriteStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
auto const result = flatten(buffers, max_size);
if(result.flatten)
{
if(result.size <= max_stack)
return stack_write_some(result.size, buffers, ec);
buffer_.clear();
buffer_.commit(net::buffer_copy(
buffer_.prepare(result.size),
buffers));
return stream_.write_some(buffer_.data(), ec);
}
buffer_.clear();
buffer_.shrink_to_fit();
return stream_.write_some(
boost::beast::buffers_prefix(result.size, buffers), ec);
}
template<class NextLayer>
template<
class ConstBufferSequence,
class WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
flat_stream<NextLayer>::
async_write_some(
ConstBufferSequence const& buffers,
WriteHandler&& handler)
{
static_assert(boost::beast::is_async_write_stream<next_layer_type>::value,
"AsyncWriteStream type requirements not met");
static_assert(net::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
return net::async_initiate<
WriteHandler,
void(error_code, std::size_t)>(
typename ops::run_write_op{},
handler,
this,
buffers);
}
template<class NextLayer>
void
teardown(
boost::beast::role_type role,
flat_stream<NextLayer>& s,
error_code& ec)
{
using boost::beast::websocket::teardown;
teardown(role, s.next_layer(), ec);
}
template<class NextLayer, class TeardownHandler>
void
async_teardown(
boost::beast::role_type role,
flat_stream<NextLayer>& s,
TeardownHandler&& handler)
{
using boost::beast::websocket::async_teardown;
async_teardown(role, s.next_layer(), std::move(handler));
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,132 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_HANDLER_PTR_HPP
#define BOOST_BEAST_IMPL_HANDLER_PTR_HPP
#include <boost/asio/associated_allocator.hpp>
#include <boost/assert.hpp>
#include <memory>
namespace boost {
namespace beast {
template<class T, class Handler>
void
handler_ptr<T, Handler>::
clear()
{
using A = typename detail::allocator_traits<
net::associated_allocator_t<
Handler>>::template rebind_alloc<T>;
using alloc_traits =
beast::detail::allocator_traits<A>;
A alloc(
net::get_associated_allocator(handler()));
alloc_traits::destroy(alloc, t_);
alloc_traits::deallocate(alloc, t_, 1);
t_ = nullptr;
}
template<class T, class Handler>
handler_ptr<T, Handler>::
~handler_ptr()
{
if(t_)
{
clear();
h_.~Handler();
}
}
template<class T, class Handler>
handler_ptr<T, Handler>::
handler_ptr(handler_ptr&& other)
: t_(other.t_)
{
if(other.t_)
{
::new(static_cast<void*>(std::addressof(h_)))
Handler(std::move(other.h_));
other.h_.~Handler();
other.t_ = nullptr;
}
}
template<class T, class Handler>
template<class DeducedHandler, class... Args>
handler_ptr<T, Handler>::
handler_ptr(DeducedHandler&& h, Args&&... args)
{
BOOST_STATIC_ASSERT(! std::is_array<T>::value);
using A = typename detail::allocator_traits<
net::associated_allocator_t<
Handler>>::template rebind_alloc<T>;
using alloc_traits =
beast::detail::allocator_traits<A>;
A alloc{net::get_associated_allocator(h)};
bool destroy = false;
auto deleter = [&alloc, &destroy](T* p)
{
if(destroy)
alloc_traits::destroy(alloc, p);
alloc_traits::deallocate(alloc, p, 1);
};
std::unique_ptr<T, decltype(deleter)> t{
alloc_traits::allocate(alloc, 1), deleter};
alloc_traits::construct(alloc, t.get(),
static_cast<DeducedHandler const&>(h),
std::forward<Args>(args)...);
destroy = true;
::new(static_cast<void*>(std::addressof(h_)))
Handler(std::forward<DeducedHandler>(h));
t_ = t.release();
}
template<class T, class Handler>
auto
handler_ptr<T, Handler>::
release_handler() ->
handler_type
{
BOOST_ASSERT(t_);
clear();
auto deleter = [](Handler* h)
{
h->~Handler();
};
std::unique_ptr<
Handler, decltype(deleter)> destroyer{
std::addressof(h_), deleter};
return std::move(h_);
}
template<class T, class Handler>
template<class... Args>
void
handler_ptr<T, Handler>::
invoke(Args&&... args)
{
BOOST_ASSERT(t_);
clear();
auto deleter = [](Handler* h)
{
boost::ignore_unused(h); // fix #1119
h->~Handler();
};
std::unique_ptr<
Handler, decltype(deleter)> destroyer{
std::addressof(h_), deleter};
h_(std::forward<Args>(args)...);
}
} // beast
} // boost
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_READ_SIZE_HPP
#define BOOST_BEAST_IMPL_READ_SIZE_HPP
#include <boost/asio/buffer.hpp>
#include <boost/assert.hpp>
#include <stdexcept>
#include <type_traits>
namespace boost {
namespace beast {
namespace detail {
template<class T, class = void>
struct has_read_size_helper : std::false_type {};
template<class T>
struct has_read_size_helper<T, decltype(
read_size_helper(std::declval<T&>(), 512),
(void)0)> : std::true_type
{
};
template<class DynamicBuffer>
std::size_t
read_size(DynamicBuffer& buffer,
std::size_t max_size, std::true_type)
{
return read_size_helper(buffer, max_size);
}
template<class DynamicBuffer>
std::size_t
read_size(DynamicBuffer& buffer,
std::size_t max_size, std::false_type)
{
static_assert(
net::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer type requirements not met");
BOOST_ASSERT(max_size >= 1);
auto const size = buffer.size();
auto const limit = buffer.max_size() - size;
BOOST_ASSERT(size <= buffer.max_size());
return std::min<std::size_t>(
std::max<std::size_t>(512, buffer.capacity() - size),
std::min<std::size_t>(max_size, limit));
}
} // detail
template<class DynamicBuffer>
std::size_t
read_size(
DynamicBuffer& buffer, std::size_t max_size)
{
return detail::read_size(buffer, max_size,
detail::has_read_size_helper<DynamicBuffer>{});
}
template<class DynamicBuffer>
std::size_t
read_size_or_throw(
DynamicBuffer& buffer, std::size_t max_size)
{
auto const n = read_size(buffer, max_size);
if(n == 0)
BOOST_THROW_EXCEPTION(std::length_error{
"buffer overflow"});
return n;
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,151 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
#define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
#include <boost/beast/core/detail/allocator.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/assert.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/core/exchange.hpp>
#include <utility>
namespace boost {
namespace beast {
//------------------------------------------------------------------------------
class saved_handler::base
{
protected:
~base() = default;
public:
base() = default;
virtual void destroy() = 0;
virtual void invoke() = 0;
};
//------------------------------------------------------------------------------
template<class Handler, class Alloc>
class saved_handler::impl final : public base
{
using alloc_type = typename
beast::detail::allocator_traits<
Alloc>::template rebind_alloc<impl>;
using alloc_traits =
beast::detail::allocator_traits<alloc_type>;
struct ebo_pair : boost::empty_value<alloc_type>
{
Handler h;
template<class Handler_>
ebo_pair(
alloc_type const& a,
Handler_&& h_)
: boost::empty_value<alloc_type>(
boost::empty_init_t{}, a)
, h(std::forward<Handler_>(h_))
{
}
};
ebo_pair v_;
net::executor_work_guard<
net::associated_executor_t<Handler>> wg2_;
public:
template<class Handler_>
impl(alloc_type const& a, Handler_&& h)
: v_(a, std::forward<Handler_>(h))
, wg2_(net::get_associated_executor(v_.h))
{
}
void
destroy() override
{
auto v = std::move(v_);
alloc_traits::destroy(v.get(), this);
alloc_traits::deallocate(v.get(), this, 1);
}
void
invoke() override
{
auto v = std::move(v_);
alloc_traits::destroy(v.get(), this);
alloc_traits::deallocate(v.get(), this, 1);
v.h();
}
};
//------------------------------------------------------------------------------
template<class Handler, class Allocator>
void
saved_handler::
emplace(Handler&& handler, Allocator const& alloc)
{
// Can't delete a handler before invoking
BOOST_ASSERT(! has_value());
using handler_type =
typename std::decay<Handler>::type;
using alloc_type = typename
detail::allocator_traits<Allocator>::
template rebind_alloc<impl<
handler_type, Allocator>>;
using alloc_traits =
beast::detail::allocator_traits<alloc_type>;
struct storage
{
alloc_type a;
impl<Handler, Allocator>* p;
explicit
storage(Allocator const& a_)
: a(a_)
, p(alloc_traits::allocate(a, 1))
{
}
~storage()
{
if(p)
alloc_traits::deallocate(a, p, 1);
}
};
storage s(alloc);
alloc_traits::construct(s.a, s.p,
s.a, std::forward<Handler>(handler));
p_ = boost::exchange(s.p, nullptr);
}
template<class Handler>
void
saved_handler::
emplace(Handler&& handler)
{
// Can't delete a handler before invoking
BOOST_ASSERT(! has_value());
emplace(
std::forward<Handler>(handler),
net::get_associated_allocator(handler));
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,76 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_IPP
#define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_IPP
#include <boost/beast/core/saved_handler.hpp>
#include <boost/core/exchange.hpp>
namespace boost {
namespace beast {
saved_handler::
~saved_handler()
{
if(p_)
p_->destroy();
}
saved_handler::
saved_handler(saved_handler&& other) noexcept
: p_(boost::exchange(other.p_, nullptr))
{
}
saved_handler&
saved_handler::
operator=(saved_handler&& other) noexcept
{
// Can't delete a handler before invoking
BOOST_ASSERT(! has_value());
p_ = boost::exchange(other.p_, nullptr);
return *this;
}
bool
saved_handler::
reset() noexcept
{
if(! p_)
return false;
boost::exchange(p_, nullptr)->destroy();
return true;
}
void
saved_handler::
invoke()
{
// Can't invoke without a value
BOOST_ASSERT(has_value());
boost::exchange(
p_, nullptr)->invoke();
}
bool
saved_handler::
maybe_invoke()
{
if(! p_)
return false;
boost::exchange(
p_, nullptr)->invoke();
return true;
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,50 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STATIC_BUFFER_HPP
#define BOOST_BEAST_IMPL_STATIC_BUFFER_HPP
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
namespace boost {
namespace beast {
template<std::size_t N>
static_buffer<N>::
static_buffer(static_buffer const& other) noexcept
: static_buffer_base(buf_, N)
{
this->commit(net::buffer_copy(
this->prepare(other.size()), other.data()));
}
template<std::size_t N>
auto
static_buffer<N>::
operator=(static_buffer const& other) noexcept ->
static_buffer<N>&
{
if(this == &other)
return *this;
this->consume(this->size());
this->commit(net::buffer_copy(
this->prepare(other.size()), other.data()));
return *this;
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,133 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STATIC_BUFFER_IPP
#define BOOST_BEAST_IMPL_STATIC_BUFFER_IPP
#include <boost/beast/core/static_buffer.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
namespace boost {
namespace beast {
static_buffer_base::
static_buffer_base(
void* p, std::size_t size) noexcept
: begin_(static_cast<char*>(p))
, capacity_(size)
{
}
void
static_buffer_base::
clear() noexcept
{
in_off_ = 0;
in_size_ = 0;
out_size_ = 0;
}
auto
static_buffer_base::
data() const noexcept ->
const_buffers_type
{
if(in_off_ + in_size_ <= capacity_)
return {
net::const_buffer{
begin_ + in_off_, in_size_},
net::const_buffer{
begin_, 0}};
return {
net::const_buffer{
begin_ + in_off_, capacity_ - in_off_},
net::const_buffer{
begin_, in_size_ - (capacity_ - in_off_)}};
}
auto
static_buffer_base::
data() noexcept ->
mutable_data_type
{
if(in_off_ + in_size_ <= capacity_)
return {
net::mutable_buffer{
begin_ + in_off_, in_size_},
net::mutable_buffer{
begin_, 0}};
return {
net::mutable_buffer{
begin_ + in_off_, capacity_ - in_off_},
net::mutable_buffer{
begin_, in_size_ - (capacity_ - in_off_)}};
}
auto
static_buffer_base::
prepare(std::size_t n) ->
mutable_buffers_type
{
using net::mutable_buffer;
if(n > capacity_ - in_size_)
BOOST_THROW_EXCEPTION(std::length_error{
"static_buffer overflow"});
out_size_ = n;
auto const out_off =
(in_off_ + in_size_) % capacity_;
if(out_off + out_size_ <= capacity_ )
return {
net::mutable_buffer{
begin_ + out_off, out_size_},
net::mutable_buffer{
begin_, 0}};
return {
net::mutable_buffer{
begin_ + out_off, capacity_ - out_off},
net::mutable_buffer{
begin_, out_size_ - (capacity_ - out_off)}};
}
void
static_buffer_base::
commit(std::size_t n) noexcept
{
in_size_ += (std::min)(n, out_size_);
out_size_ = 0;
}
void
static_buffer_base::
consume(std::size_t n) noexcept
{
if(n < in_size_)
{
in_off_ = (in_off_ + n) % capacity_;
in_size_ -= n;
}
else
{
// rewind the offset, so the next call to prepare
// can have a longer contiguous segment. this helps
// algorithms optimized for larger buffers.
in_off_ = 0;
in_size_ = 0;
}
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,642 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STATIC_STRING_HPP
#define BOOST_BEAST_IMPL_STATIC_STRING_HPP
#include <boost/beast/core/detail/static_string.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/throw_exception.hpp>
namespace boost {
namespace beast {
//
// (constructor)
//
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string()
{
n_ = 0;
term();
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(size_type count, CharT ch)
{
assign(count, ch);
}
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& other,
size_type pos)
{
assign(other, pos);
}
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& other,
size_type pos, size_type count)
{
assign(other, pos, count);
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(CharT const* s, size_type count)
{
assign(s, count);
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(CharT const* s)
{
auto const count = Traits::length(s);
if(count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"count > max_size()"});
n_ = count;
Traits::copy(&s_[0], s, n_ + 1);
}
template<std::size_t N, class CharT, class Traits>
template<class InputIt>
static_string<N, CharT, Traits>::
static_string(InputIt first, InputIt last)
{
assign(first, last);
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(static_string const& s)
{
assign(s);
}
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)
{
assign(s);
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(std::initializer_list<CharT> init)
{
assign(init.begin(), init.end());
}
template<std::size_t N, class CharT, class Traits>
static_string<N, CharT, Traits>::
static_string(string_view_type sv)
{
assign(sv);
}
template<std::size_t N, class CharT, class Traits>
template<class T, class>
static_string<N, CharT, Traits>::
static_string(T const& t, size_type pos, size_type n)
{
assign(t, pos, n);
}
//
// (assignment)
//
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
operator=(CharT const* s) ->
static_string&
{
auto const count = Traits::length(s);
if(count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"count > max_size()"});
n_ = count;
Traits::copy(&s_[0], s, n_ + 1);
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign(size_type count, CharT ch) ->
static_string&
{
if(count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"count > max_size()"});
n_ = count;
Traits::assign(&s_[0], n_, ch);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign(static_string const& str) ->
static_string&
{
n_ = str.n_;
auto const n = n_ + 1;
BOOST_BEAST_ASSUME(n != 0);
Traits::copy(&s_[0], &str.s_[0], n);
return *this;
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
auto
static_string<N, CharT, Traits>::
assign(static_string<M, CharT, Traits> const& str,
size_type pos, size_type count) ->
static_string&
{
auto const ss = str.substr(pos, count);
return assign(ss.data(), ss.size());
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign(CharT const* s, size_type count) ->
static_string&
{
if(count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"count > max_size()"});
n_ = count;
Traits::copy(&s_[0], s, n_);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
template<class InputIt>
auto
static_string<N, CharT, Traits>::
assign(InputIt first, InputIt last) ->
static_string&
{
std::size_t const n = std::distance(first, last);
if(n > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"n > max_size()"});
n_ = n;
for(auto it = &s_[0]; first != last; ++it, ++first)
Traits::assign(*it, *first);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
template<class T>
auto
static_string<N, CharT, Traits>::
assign(T const& t, size_type pos, size_type count) ->
typename std::enable_if<std::is_convertible<T,
string_view_type>::value, static_string&>::type
{
auto const sv = string_view_type(t).substr(pos, count);
if(sv.size() > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"sv.size() > max_size()"});
n_ = sv.size();
Traits::copy(&s_[0], &sv[0], n_);
term();
return *this;
}
//
// Element access
//
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
at(size_type pos) ->
reference
{
if(pos >= size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"pos >= size()"});
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 >= size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"pos >= size()"});
return s_[pos];
}
//
// Capacity
//
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
reserve(std::size_t n)
{
if(n > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"n > max_size()"});
}
//
// Operations
//
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
clear()
{
n_ = 0;
term();
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
insert(size_type index, size_type count, CharT ch) ->
static_string&
{
if(index > size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"index > size()"});
insert(begin() + index, count, ch);
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
insert(size_type index, CharT const* s, size_type count) ->
static_string&
{
if(index > size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"index > size()"});
if(size() + count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() + count > max_size()"});
Traits::move(
&s_[index + count], &s_[index], size() - index);
n_ += count;
Traits::copy(&s_[index], s, count);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
auto
static_string<N, CharT, Traits>::
insert(size_type index,
static_string<M, CharT, Traits> const& str,
size_type index_str, size_type count) ->
static_string&
{
auto const ss = str.substr(index_str, count);
return insert(index, ss.data(), ss.size());
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
insert(const_iterator pos, size_type count, CharT ch) ->
iterator
{
if(size() + count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() + count() > max_size()"});
auto const index = pos - &s_[0];
Traits::move(
&s_[index + count], &s_[index], size() - index);
n_ += count;
Traits::assign(&s_[index], count, ch);
term();
return &s_[index];
}
template<std::size_t N, class CharT, class Traits>
template<class InputIt>
auto
static_string<N, CharT, Traits>::
insert(const_iterator pos, InputIt first, InputIt last) ->
typename std::enable_if<
detail::is_input_iterator<InputIt>::value,
iterator>::type
{
std::size_t const count = std::distance(first, last);
if(size() + count > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() + count > max_size()"});
std::size_t const index = pos - begin();
Traits::move(
&s_[index + count], &s_[index], size() - index);
n_ += count;
for(auto it = begin() + index;
first != last; ++it, ++first)
Traits::assign(*it, *first);
term();
return begin() + index;
}
template<std::size_t N, class CharT, class Traits>
template<class T>
auto
static_string<N, CharT, Traits>::
insert(size_type index, const T& t,
size_type index_str, size_type count) ->
typename std::enable_if<std::is_convertible<
T const&, string_view_type>::value &&
! std::is_convertible<T const&, CharT const*>::value,
static_string&>::type
{
auto const str =
string_view_type(t).substr(index_str, count);
return insert(index, str.data(), str.size());
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
erase(size_type index, size_type count) ->
static_string&
{
if(index > size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"index > size()"});
auto const n = (std::min)(count, size() - index);
Traits::move(
&s_[index], &s_[index + n], size() - (index + n) + 1);
n_ -= n;
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
erase(const_iterator pos) ->
iterator
{
erase(pos - begin(), 1);
return begin() + (pos - begin());
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
erase(const_iterator first, const_iterator last) ->
iterator
{
erase(first - begin(),
std::distance(first, last));
return begin() + (first - begin());
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
push_back(CharT ch)
{
if(size() >= max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() >= max_size()"});
Traits::assign(s_[n_++], ch);
term();
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
auto
static_string<N, CharT, Traits>::
append(static_string<M, CharT, Traits> const& str,
size_type pos, size_type count) ->
static_string&
{
// Valid range is [0, size)
if(pos >= str.size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"pos > str.size()"});
string_view_type const ss{&str.s_[pos],
(std::min)(count, str.size() - pos)};
insert(size(), ss.data(), ss.size());
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
substr(size_type pos, size_type count) const ->
string_view_type
{
if(pos > size())
BOOST_THROW_EXCEPTION(std::out_of_range{
"pos > size()"});
return{&s_[pos], (std::min)(count, size() - pos)};
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
copy(CharT* dest, size_type count, size_type pos) const ->
size_type
{
auto const str = substr(pos, count);
Traits::copy(dest, str.data(), str.size());
return str.size();
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
resize(std::size_t n)
{
if(n > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"n > max_size()"});
if(n > n_)
Traits::assign(&s_[n_], n - n_, CharT{});
n_ = n;
term();
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
resize(std::size_t n, CharT c)
{
if(n > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"n > max_size()"});
if(n > n_)
Traits::assign(&s_[n_], n - n_, c);
n_ = n;
term();
}
template<std::size_t N, class CharT, class Traits>
void
static_string<N, CharT, Traits>::
swap(static_string& str)
{
static_string tmp(str);
str.n_ = n_;
Traits::copy(&str.s_[0], &s_[0], n_ + 1);
n_ = tmp.n_;
Traits::copy(&s_[0], &tmp.s_[0], n_ + 1);
}
template<std::size_t N, class CharT, class Traits>
template<std::size_t M>
void
static_string<N, CharT, Traits>::
swap(static_string<M, CharT, Traits>& str)
{
if(size() > str.max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"size() > str.max_size()"});
if(str.size() > max_size())
BOOST_THROW_EXCEPTION(std::length_error{
"str.size() > max_size()"});
static_string tmp(str);
str.n_ = n_;
Traits::copy(&str.s_[0], &s_[0], n_ + 1);
n_ = tmp.n_;
Traits::copy(&s_[0], &tmp.s_[0], n_ + 1);
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign_char(CharT ch, std::true_type) ->
static_string&
{
n_ = 1;
Traits::assign(s_[0], ch);
term();
return *this;
}
template<std::size_t N, class CharT, class Traits>
auto
static_string<N, CharT, Traits>::
assign_char(CharT, std::false_type) ->
static_string&
{
BOOST_THROW_EXCEPTION(std::length_error{
"max_size() == 0"});
}
namespace detail {
template<class Integer>
static_string<max_digits(sizeof(Integer))>
to_static_string(Integer x, std::true_type)
{
if(x == 0)
return {'0'};
static_string<detail::max_digits(
sizeof(Integer))> s;
if(x < 0)
{
x = -x;
char buf[max_digits(sizeof(x))];
char* p = buf;
for(;x > 0; x /= 10)
*p++ = "0123456789"[x % 10];
s.resize(1 + p - buf);
s[0] = '-';
auto d = &s[1];
while(p > buf)
*d++ = *--p;
}
else
{
char buf[max_digits(sizeof(x))];
char* p = buf;
for(;x > 0; x /= 10)
*p++ = "0123456789"[x % 10];
s.resize(p - buf);
auto d = &s[0];
while(p > buf)
*d++ = *--p;
}
return s;
}
template<class Integer>
static_string<max_digits(sizeof(Integer))>
to_static_string(Integer x, std::false_type)
{
if(x == 0)
return {'0'};
char buf[max_digits(sizeof(x))];
char* p = buf;
for(;x > 0; x /= 10)
*p++ = "0123456789"[x % 10];
static_string<detail::max_digits(
sizeof(Integer))> s;
s.resize(p - buf);
auto d = &s[0];
while(p > buf)
*d++ = *--p;
return s;
}
} // detail
template<class Integer, class>
static_string<detail::max_digits(sizeof(Integer))>
to_static_string(Integer x)
{
using CharT = char;
using Traits = std::char_traits<CharT>;
BOOST_STATIC_ASSERT(std::is_integral<Integer>::value);
char buf[detail::max_digits(sizeof(Integer))];
auto last = buf + sizeof(buf);
auto it = detail::raw_to_string<
CharT, Integer, Traits>(last, sizeof(buf), x);
static_string<detail::max_digits(sizeof(Integer))> s;
s.resize(static_cast<std::size_t>(last - it));
auto p = s.data();
while(it < last)
Traits::assign(*p++, *it++);
return s;
}
} // beast
} // boost
#endif

View File

@@ -0,0 +1,108 @@
//
// Copyright (c) 2016-2019 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)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_IMPL_STRING_PARAM_HPP
#define BOOST_BEAST_IMPL_STRING_PARAM_HPP
namespace boost {
namespace beast {
template<class T>
typename std::enable_if<
std::is_integral<T>::value>::type
string_param::
print(T const& t)
{
auto const last = buf_ + sizeof(buf_);
auto const it = detail::raw_to_string<
char, T, std::char_traits<char>>(
last, sizeof(buf_), t);
sv_ = {it, static_cast<std::size_t>(
last - it)};
}
template<class T>
typename std::enable_if<
! std::is_integral<T>::value &&
! std::is_convertible<T, string_view>::value
>::type
string_param::
print(T const& t)
{
os_.emplace(buf_, sizeof(buf_));
*os_ << t;
os_->flush();
sv_ = os_->str();
}
inline
void
string_param::
print(string_view sv)
{
sv_ = sv;
}
template<class T>
typename std::enable_if<
std::is_integral<T>::value>::type
string_param::
print_1(T const& t)
{
char buf[detail::max_digits(sizeof(T))];
auto const last = buf + sizeof(buf);
auto const it = detail::raw_to_string<
char, T, std::char_traits<char>>(
last, sizeof(buf), t);
*os_ << string_view{it,
static_cast<std::size_t>(last - it)};
}
template<class T>
typename std::enable_if<
! std::is_integral<T>::value>::type
string_param::
print_1(T const& t)
{
*os_ << t;
}
template<class T0, class... TN>
void
string_param::
print_n(T0 const& t0, TN const&... tn)
{
print_1(t0);
print_n(tn...);
}
template<class T0, class T1, class... TN>
void
string_param::
print(T0 const& t0, T1 const& t1, TN const&... tn)
{
os_.emplace(buf_, sizeof(buf_));
print_1(t0);
print_1(t1);
print_n(tn...);
os_->flush();
sv_ = os_->str();
}
template<class... Args>
string_param::
string_param(Args const&... args)
{
print(args...);
}
} // beast
} // boost
#endif