diff options
Diffstat (limited to 'boost/beast/core/impl')
28 files changed, 4147 insertions, 1927 deletions
diff --git a/boost/beast/core/impl/async_base.hpp b/boost/beast/core/impl/async_base.hpp new file mode 100644 index 0000000000..ec17b1cc1e --- /dev/null +++ b/boost/beast/core/impl/async_base.hpp @@ -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 diff --git a/boost/beast/core/impl/basic_stream.hpp b/boost/beast/core/impl/basic_stream.hpp new file mode 100644 index 0000000000..c871944552 --- /dev/null +++ b/boost/beast/core/impl/basic_stream.hpp @@ -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 diff --git a/boost/beast/core/impl/buffered_read_stream.hpp b/boost/beast/core/impl/buffered_read_stream.hpp new file mode 100644 index 0000000000..184881164f --- /dev/null +++ b/boost/beast/core/impl/buffered_read_stream.hpp @@ -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 diff --git a/boost/beast/core/impl/buffered_read_stream.ipp b/boost/beast/core/impl/buffered_read_stream.ipp deleted file mode 100644 index b199ea0687..0000000000 --- a/boost/beast/core/impl/buffered_read_stream.ipp +++ /dev/null @@ -1,261 +0,0 @@ -// -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/boostorg/beast -// - -#ifndef BOOST_BEAST_IMPL_BUFFERED_READ_STREAM_IPP -#define BOOST_BEAST_IMPL_BUFFERED_READ_STREAM_IPP - -#include <boost/beast/core/bind_handler.hpp> -#include <boost/beast/core/error.hpp> -#include <boost/beast/core/handler_ptr.hpp> -#include <boost/beast/core/read_size.hpp> -#include <boost/beast/core/type_traits.hpp> -#include <boost/beast/core/detail/config.hpp> -#include <boost/asio/associated_allocator.hpp> -#include <boost/asio/associated_executor.hpp> -#include <boost/asio/executor_work_guard.hpp> -#include <boost/asio/handler_continuation_hook.hpp> -#include <boost/asio/handler_invoke_hook.hpp> -#include <boost/asio/post.hpp> -#include <boost/throw_exception.hpp> - -namespace boost { -namespace beast { - -template<class Stream, class DynamicBuffer> -template<class MutableBufferSequence, class Handler> -class buffered_read_stream< - Stream, DynamicBuffer>::read_some_op -{ - buffered_read_stream& s_; - boost::asio::executor_work_guard<decltype( - std::declval<Stream&>().get_executor())> wg_; - MutableBufferSequence b_; - Handler h_; - int step_ = 0; - -public: - read_some_op(read_some_op&&) = default; - read_some_op(read_some_op const&) = delete; - - template<class DeducedHandler, class... Args> - read_some_op(DeducedHandler&& h, - buffered_read_stream& s, - MutableBufferSequence const& b) - : s_(s) - , wg_(s_.get_executor()) - , b_(b) - , h_(std::forward<DeducedHandler>(h)) - { - } - - using allocator_type = - boost::asio::associated_allocator_t<Handler>; - - allocator_type - get_allocator() const noexcept - { - return (boost::asio::get_associated_allocator)(h_); - } - - using executor_type = - boost::asio::associated_executor_t<Handler, decltype( - std::declval<buffered_read_stream&>().get_executor())>; - - executor_type - get_executor() const noexcept - { - return (boost::asio::get_associated_executor)( - h_, s_.get_executor()); - } - - void - operator()(error_code const& ec, - std::size_t bytes_transferred); - - friend - bool asio_handler_is_continuation(read_some_op* op) - { - using boost::asio::asio_handler_is_continuation; - return asio_handler_is_continuation( - std::addressof(op->h_)); - } - - template<class Function> - friend - void asio_handler_invoke(Function&& f, read_some_op* op) - { - using boost::asio::asio_handler_invoke; - asio_handler_invoke(f, std::addressof(op->h_)); - } -}; - -template<class Stream, class DynamicBuffer> -template<class MutableBufferSequence, class Handler> -void -buffered_read_stream<Stream, DynamicBuffer>:: -read_some_op<MutableBufferSequence, Handler>::operator()( - error_code const& ec, std::size_t bytes_transferred) -{ - 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 boost::asio::post( - s_.get_executor(), - bind_handler(std::move(*this), ec, 0)); - - case 1: - // upcall - break; - - case 2: - s_.buffer_.commit(bytes_transferred); - BOOST_FALLTHROUGH; - - case 3: - bytes_transferred = - boost::asio::buffer_copy(b_, s_.buffer_.data()); - s_.buffer_.consume(bytes_transferred); - break; - } - h_(ec, bytes_transferred); -} - -//------------------------------------------------------------------------------ - -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_ASIO_INITFN_RESULT_TYPE( - WriteHandler, void(error_code, std::size_t)) -buffered_read_stream<Stream, DynamicBuffer>:: -async_write_some( - ConstBufferSequence const& buffers, - WriteHandler&& handler) -{ - static_assert(is_async_write_stream<next_layer_type>::value, - "AsyncWriteStream requirements not met"); - static_assert(boost::asio::is_const_buffer_sequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - static_assert(is_completion_handler<WriteHandler, - void(error_code, std::size_t)>::value, - "WriteHandler requirements not met"); - return next_layer_.async_write_some(buffers, - std::forward<WriteHandler>(handler)); -} - -template<class Stream, class 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 requirements not met"); - static_assert(boost::asio::is_mutable_buffer_sequence< - MutableBufferSequence>::value, - "MutableBufferSequence 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 requirements not met"); - static_assert(boost::asio::is_mutable_buffer_sequence< - MutableBufferSequence>::value, - "MutableBufferSequence requirements not met"); - using boost::asio::buffer_size; - using boost::asio::buffer_copy; - 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.assign(0, ec.category()); - } - auto bytes_transferred = - buffer_copy(buffers, buffer_.data()); - buffer_.consume(bytes_transferred); - return bytes_transferred; -} - -template<class Stream, class DynamicBuffer> -template<class MutableBufferSequence, class ReadHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - ReadHandler, void(error_code, std::size_t)) -buffered_read_stream<Stream, DynamicBuffer>:: -async_read_some( - MutableBufferSequence const& buffers, - ReadHandler&& handler) -{ - static_assert(is_async_read_stream<next_layer_type>::value, - "AsyncReadStream requirements not met"); - static_assert(boost::asio::is_mutable_buffer_sequence< - MutableBufferSequence>::value, - "MutableBufferSequence requirements not met"); - if(buffer_.size() == 0 && capacity_ == 0) - return next_layer_.async_read_some(buffers, - std::forward<ReadHandler>(handler)); - BOOST_BEAST_HANDLER_INIT( - ReadHandler, void(error_code, std::size_t)); - read_some_op<MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE( - ReadHandler, void(error_code, std::size_t))>{ - std::move(init.completion_handler), *this, buffers}( - error_code{}, 0); - return init.result.get(); -} - -} // beast -} // boost - -#endif diff --git a/boost/beast/core/impl/buffers_adapter.ipp b/boost/beast/core/impl/buffers_adaptor.hpp index f077c521f0..91caad5463 100644 --- a/boost/beast/core/impl/buffers_adapter.ipp +++ b/boost/beast/core/impl/buffers_adaptor.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -7,37 +7,85 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP -#define BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP +#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> -class buffers_adapter<MutableBufferSequence>:: - const_buffers_type +template<bool isMutable> +class buffers_adaptor<MutableBufferSequence>:: + readable_bytes { - buffers_adapter const* b_; + buffers_adaptor const* b_; public: - using value_type = boost::asio::const_buffer; + using value_type = typename + std::conditional<isMutable, + net::mutable_buffer, + net::const_buffer>::type; class const_iterator; - const_buffers_type() = delete; - const_buffers_type( - const_buffers_type const&) = default; - const_buffers_type& operator=( - const_buffers_type const&) = default; + 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; @@ -46,23 +94,34 @@ public: end() const; private: - friend class buffers_adapter; + friend class buffers_adaptor; - const_buffers_type(buffers_adapter const& b) + readable_bytes(buffers_adaptor const& b) : b_(&b) { } }; +#if BOOST_WORKAROUND(BOOST_MSVC, < 1910) +# pragma warning (pop) +#endif + +//------------------------------------------------------------------------------ + template<class MutableBufferSequence> -class buffers_adapter<MutableBufferSequence>:: - const_buffers_type::const_iterator +template<bool isMutable> +class buffers_adaptor<MutableBufferSequence>:: + readable_bytes<isMutable>:: + const_iterator { - iter_type it_; - buffers_adapter const* b_ = nullptr; + iter_type it_{}; + buffers_adaptor const* b_ = nullptr; public: - using value_type = boost::asio::const_buffer; + 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; @@ -70,28 +129,13 @@ public: std::bidirectional_iterator_tag; const_iterator() = default; - const_iterator(const_iterator&& other) = default; const_iterator(const_iterator const& other) = default; - const_iterator& operator=(const_iterator&& other) = default; const_iterator& operator=(const_iterator const& other) = default; bool operator==(const_iterator const& other) const { - return - (b_ == nullptr) ? - ( - other.b_ == nullptr || - other.it_ == other.b_->end_impl() - ):( - (other.b_ == nullptr) ? - ( - it_ == b_->end_impl() - ): ( - b_ == other.b_ && - it_ == other.it_ - ) - ); + return b_ == other.b_ && it_ == other.it_; } bool @@ -105,7 +149,7 @@ public: { value_type const b = *it_; return value_type{b.data(), - (b_->out_ == boost::asio::buffer_sequence_end(b_->bs_) || + (b_->out_ == net::buffer_sequence_end(b_->bs_) || it_ != b_->out_) ? b.size() : b_->out_pos_} + (it_ == b_->begin_ ? b_->in_pos_ : 0); } @@ -144,10 +188,11 @@ public: } private: - friend class const_buffers_type; + friend class readable_bytes; - const_iterator(buffers_adapter const& b, - iter_type iter) + const_iterator( + buffers_adaptor const& b, + iter_type iter) : it_(iter) , b_(&b) { @@ -155,18 +200,22 @@ private: }; template<class MutableBufferSequence> +template<bool isMutable> auto -buffers_adapter<MutableBufferSequence>:: -const_buffers_type::begin() const -> +buffers_adaptor<MutableBufferSequence>:: +readable_bytes<isMutable>:: +begin() const -> const_iterator { return const_iterator{*b_, b_->begin_}; } template<class MutableBufferSequence> +template<bool isMutable> auto -buffers_adapter<MutableBufferSequence>:: -const_buffers_type::end() const -> +buffers_adaptor<MutableBufferSequence>:: +readable_bytes<isMutable>:: +readable_bytes::end() const -> const_iterator { return const_iterator{*b_, b_->end_impl()}; @@ -175,13 +224,13 @@ const_buffers_type::end() const -> //------------------------------------------------------------------------------ template<class MutableBufferSequence> -class buffers_adapter<MutableBufferSequence>:: +class buffers_adaptor<MutableBufferSequence>:: mutable_buffers_type { - buffers_adapter const* b_; + buffers_adaptor const* b_; public: - using value_type = boost::asio::mutable_buffer; + using value_type = net::mutable_buffer; class const_iterator; @@ -198,24 +247,24 @@ public: end() const; private: - friend class buffers_adapter; + friend class buffers_adaptor; mutable_buffers_type( - buffers_adapter const& b) + buffers_adaptor const& b) : b_(&b) { } }; template<class MutableBufferSequence> -class buffers_adapter<MutableBufferSequence>:: +class buffers_adaptor<MutableBufferSequence>:: mutable_buffers_type::const_iterator { - iter_type it_; - buffers_adapter const* b_ = nullptr; + iter_type it_{}; + buffers_adaptor const* b_ = nullptr; public: - using value_type = boost::asio::mutable_buffer; + using value_type = net::mutable_buffer; using pointer = value_type const*; using reference = value_type; using difference_type = std::ptrdiff_t; @@ -223,28 +272,13 @@ public: std::bidirectional_iterator_tag; const_iterator() = default; - const_iterator(const_iterator&& other) = default; const_iterator(const_iterator const& other) = default; - const_iterator& operator=(const_iterator&& other) = default; const_iterator& operator=(const_iterator const& other) = default; bool operator==(const_iterator const& other) const { - return - (b_ == nullptr) ? - ( - other.b_ == nullptr || - other.it_ == other.b_->end_ - ):( - (other.b_ == nullptr) ? - ( - it_ == b_->end_ - ): ( - b_ == other.b_ && - it_ == other.it_ - ) - ); + return b_ == other.b_ && it_ == other.it_; } bool @@ -299,7 +333,7 @@ public: private: friend class mutable_buffers_type; - const_iterator(buffers_adapter const& b, + const_iterator(buffers_adaptor const& b, iter_type iter) : it_(iter) , b_(&b) @@ -308,9 +342,8 @@ private: }; template<class MutableBufferSequence> -inline auto -buffers_adapter<MutableBufferSequence>:: +buffers_adaptor<MutableBufferSequence>:: mutable_buffers_type:: begin() const -> const_iterator @@ -319,9 +352,8 @@ begin() const -> } template<class MutableBufferSequence> -inline auto -buffers_adapter<MutableBufferSequence>:: +buffers_adaptor<MutableBufferSequence>:: mutable_buffers_type:: end() const -> const_iterator @@ -333,7 +365,7 @@ end() const -> template<class MutableBufferSequence> auto -buffers_adapter<MutableBufferSequence>:: +buffers_adaptor<MutableBufferSequence>:: end_impl() const -> iter_type { @@ -341,71 +373,97 @@ end_impl() const -> } template<class MutableBufferSequence> -buffers_adapter<MutableBufferSequence>:: -buffers_adapter(buffers_adapter&& other) - : buffers_adapter(std::move(other), - std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.begin_), - std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.out_), - std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.end_)) +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_adapter<MutableBufferSequence>:: -buffers_adapter(buffers_adapter const& other) - : buffers_adapter(other, - std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.begin_), - std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.out_), - std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.end_)) +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> -auto -buffers_adapter<MutableBufferSequence>:: -operator=(buffers_adapter&& other) -> - buffers_adapter& +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_)) { - auto const nbegin = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), - other.begin_); - auto const nout = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), - other.out_); - auto const nend = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), - other.end_); - bs_ = std::move(other.bs_); - begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin); - out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout); - end_ = std::next(boost::asio::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_adapter<MutableBufferSequence>:: -operator=(buffers_adapter const& other) -> - buffers_adapter& +buffers_adaptor<MutableBufferSequence>:: +operator=(buffers_adaptor const& other) -> + buffers_adaptor& { + if(this == &other) + return *this; auto const nbegin = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), + net::buffer_sequence_begin(other.bs_), other.begin_); auto const nout = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), + net::buffer_sequence_begin(other.bs_), other.out_); auto const nend = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), + net::buffer_sequence_begin(other.bs_), other.end_); bs_ = other.bs_; - begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin); - out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout); - end_ = std::next(boost::asio::buffer_sequence_begin(bs_), nend); + 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_; @@ -414,47 +472,43 @@ operator=(buffers_adapter const& other) -> return *this; } +// + template<class MutableBufferSequence> -buffers_adapter<MutableBufferSequence>:: -buffers_adapter(MutableBufferSequence const& bs) - : bs_(bs) - , begin_(boost::asio::buffer_sequence_begin(bs_)) - , out_ (boost::asio::buffer_sequence_begin(bs_)) - , end_ (boost::asio::buffer_sequence_begin(bs_)) - , max_size_(boost::asio::buffer_size(bs_)) +auto +buffers_adaptor<MutableBufferSequence>:: +data() const noexcept -> + const_buffers_type { + return const_buffers_type{*this}; } template<class MutableBufferSequence> -template<class... Args> -buffers_adapter<MutableBufferSequence>:: -buffers_adapter(boost::in_place_init_t, Args&&... args) - : bs_{std::forward<Args>(args)...} - , begin_(boost::asio::buffer_sequence_begin(bs_)) - , out_ (boost::asio::buffer_sequence_begin(bs_)) - , end_ (boost::asio::buffer_sequence_begin(bs_)) - , max_size_(boost::asio::buffer_size(bs_)) +auto +buffers_adaptor<MutableBufferSequence>:: +data() noexcept -> + mutable_data_type { + return mutable_data_type{*this}; } template<class MutableBufferSequence> auto -buffers_adapter<MutableBufferSequence>:: +buffers_adaptor<MutableBufferSequence>:: prepare(std::size_t n) -> mutable_buffers_type { - using boost::asio::buffer_size; end_ = out_; - if(end_ != boost::asio::buffer_sequence_end(bs_)) + if(end_ != net::buffer_sequence_end(bs_)) { - auto size = buffer_size(*end_) - out_pos_; + auto size = buffer_bytes(*end_) - out_pos_; if(n > size) { n -= size; while(++end_ != - boost::asio::buffer_sequence_end(bs_)) + net::buffer_sequence_end(bs_)) { - size = buffer_size(*end_); + size = buffer_bytes(*end_); if(n < size) { out_end_ = n; @@ -475,23 +529,22 @@ prepare(std::size_t n) -> } if(n > 0) BOOST_THROW_EXCEPTION(std::length_error{ - "buffer overflow"}); + "buffers_adaptor too long"}); return mutable_buffers_type{*this}; } template<class MutableBufferSequence> void -buffers_adapter<MutableBufferSequence>:: -commit(std::size_t n) +buffers_adaptor<MutableBufferSequence>:: +commit(std::size_t n) noexcept { - using boost::asio::buffer_size; if(out_ == end_) return; auto const last = std::prev(end_); while(out_ != last) { auto const avail = - buffer_size(*out_) - out_pos_; + buffer_bytes(*out_) - out_pos_; if(n < avail) { out_pos_ += n; @@ -504,10 +557,11 @@ commit(std::size_t n) in_size_ += avail; } - n = (std::min)(n, out_end_ - out_pos_); + n = std::min<std::size_t>( + n, out_end_ - out_pos_); out_pos_ += n; in_size_ += n; - if(out_pos_ == buffer_size(*out_)) + if(out_pos_ == buffer_bytes(*out_)) { ++out_; out_pos_ = 0; @@ -516,25 +570,14 @@ commit(std::size_t n) } template<class MutableBufferSequence> -inline -auto -buffers_adapter<MutableBufferSequence>:: -data() const -> - const_buffers_type -{ - return const_buffers_type{*this}; -} - -template<class MutableBufferSequence> void -buffers_adapter<MutableBufferSequence>:: -consume(std::size_t n) +buffers_adaptor<MutableBufferSequence>:: +consume(std::size_t n) noexcept { - using boost::asio::buffer_size; while(begin_ != out_) { auto const avail = - buffer_size(*begin_) - in_pos_; + buffer_bytes(*begin_) - in_pos_; if(n < avail) { in_size_ -= n; diff --git a/boost/beast/core/impl/buffers_cat.hpp b/boost/beast/core/impl/buffers_cat.hpp new file mode 100644 index 0000000000..255153f2bd --- /dev/null +++ b/boost/beast/core/impl/buffers_cat.hpp @@ -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 diff --git a/boost/beast/core/impl/buffers_cat.ipp b/boost/beast/core/impl/buffers_cat.ipp deleted file mode 100644 index 9de1187f36..0000000000 --- a/boost/beast/core/impl/buffers_cat.ipp +++ /dev/null @@ -1,389 +0,0 @@ -// -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/boostorg/beast -// - -#ifndef BOOST_BEAST_IMPL_BUFFERS_CAT_IPP -#define BOOST_BEAST_IMPL_BUFFERS_CAT_IPP - -#include <boost/beast/core/detail/type_traits.hpp> -#include <boost/beast/core/detail/variant.hpp> -#include <boost/asio/buffer.hpp> -#include <boost/throw_exception.hpp> -#include <cstdint> -#include <iterator> -#include <new> -#include <stdexcept> -#include <tuple> -#include <utility> - -namespace boost { -namespace beast { - -template<class... Bn> -class buffers_cat_view<Bn...>::const_iterator -{ - // 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"); - - struct past_end - { - char unused = 0; // make g++8 happy - - operator bool() const noexcept - { - return true; - } - }; - - std::tuple<Bn...> const* bn_ = nullptr; - detail::variant<typename - detail::buffer_sequence_iterator<Bn>::type..., - 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 - detail::common_buffers_type<Bn...>::type; - using pointer = value_type const*; - using reference = value_type; - using difference_type = std::ptrdiff_t; - using iterator_category = - std::bidirectional_iterator_tag; - - const_iterator() = default; - const_iterator(const_iterator&& other) = default; - const_iterator(const_iterator const& other) = default; - const_iterator& operator=(const_iterator&& other) = default; - const_iterator& operator=(const_iterator const& other) = default; - - bool - operator==(const_iterator const& other) const; - - bool - operator!=(const_iterator const& other) const - { - return ! (*this == other); - } - - reference - operator*() const; - - pointer - operator->() const = delete; - - const_iterator& - operator++(); - - const_iterator - operator++(int); - - // deprecated - const_iterator& - operator--(); - - // deprecated - const_iterator - operator--(int); - -private: - const_iterator( - std::tuple<Bn...> const& bn, bool at_end); - - template<std::size_t I> - void - construct(C<I> const&) - { - if(boost::asio::buffer_size( - std::get<I>(*bn_)) != 0) - { - it_.template emplace<I+1>( - boost::asio::buffer_sequence_begin( - std::get<I>(*bn_))); - return; - } - construct(C<I+1>{}); - } - - void - construct(C<sizeof...(Bn)-1> const&) - { - auto constexpr I = sizeof...(Bn)-1; - it_.template emplace<I+1>( - boost::asio::buffer_sequence_begin( - std::get<I>(*bn_))); - } - - void - construct(C<sizeof...(Bn)> const&) - { - // end - auto constexpr I = sizeof...(Bn); - it_.template emplace<I+1>(); - } - - template<std::size_t I> - void - next(C<I> const&) - { - if(boost::asio::buffer_size( - std::get<I>(*bn_)) != 0) - { - it_.template emplace<I+1>( - boost::asio::buffer_sequence_begin( - std::get<I>(*bn_))); - return; - } - next(C<I+1>{}); - } - - void - next(C<sizeof...(Bn)> const&) - { - // end - auto constexpr I = sizeof...(Bn); - it_.template emplace<I+1>(); - } - - template<std::size_t I> - void - prev(C<I> const&) - { - if(boost::asio::buffer_size( - std::get<I>(*bn_)) != 0) - { - it_.template emplace<I+1>( - boost::asio::buffer_sequence_end( - std::get<I>(*bn_))); - return; - } - prev(C<I-1>{}); - } - - void - prev(C<0> const&) - { - auto constexpr I = 0; - it_.template emplace<I+1>( - boost::asio::buffer_sequence_end( - std::get<I>(*bn_))); - } - - template<std::size_t I> - reference - dereference(C<I> const&) const - { - if(it_.index() == I+1) - return *it_.template get<I+1>(); - return dereference(C<I+1>{}); - } - - [[noreturn]] - reference - dereference(C<sizeof...(Bn)> const&) const - { - BOOST_THROW_EXCEPTION(std::logic_error{ - "invalid iterator"}); - } - - template<std::size_t I> - void - increment(C<I> const&) - { - if(it_.index() == I+1) - { - if(++it_.template get<I+1>() != - boost::asio::buffer_sequence_end( - std::get<I>(*bn_))) - return; - return next(C<I+1>{}); - } - increment(C<I+1>{}); - } - - [[noreturn]] - void - increment(C<sizeof...(Bn)> const&) - { - BOOST_THROW_EXCEPTION(std::logic_error{ - "invalid iterator"}); - } - - void - decrement(C<sizeof...(Bn)> const&) - { - auto constexpr I = sizeof...(Bn); - if(it_.index() == I+1) - prev(C<I-1>{}); - decrement(C<I-1>{}); - } - - template<std::size_t I> - void - decrement(C<I> const&) - { - if(it_.index() == I+1) - { - if(it_.template get<I+1>() != - boost::asio::buffer_sequence_begin( - std::get<I>(*bn_))) - { - --it_.template get<I+1>(); - return; - } - prev(C<I-1>{}); - } - decrement(C<I-1>{}); - } - - void - decrement(C<0> const&) - { - auto constexpr I = 0; - if(it_.template get<I+1>() != - boost::asio::buffer_sequence_begin( - std::get<I>(*bn_))) - { - --it_.template get<I+1>(); - return; - } - BOOST_THROW_EXCEPTION(std::logic_error{ - "invalid iterator"}); - } -}; - -//------------------------------------------------------------------------------ - -template<class... Bn> -buffers_cat_view<Bn...>:: -const_iterator:: -const_iterator( - std::tuple<Bn...> const& bn, bool at_end) - : bn_(&bn) -{ - if(! at_end) - construct(C<0>{}); - else - construct(C<sizeof...(Bn)>{}); -} - -template<class... Bn> -bool -buffers_cat_view<Bn...>:: -const_iterator:: -operator==(const_iterator const& other) const -{ - return - (bn_ == nullptr) ? - ( - other.bn_ == nullptr || - other.it_.index() == sizeof...(Bn) - ):( - (other.bn_ == nullptr) ? - ( - it_.index() == sizeof...(Bn) - ): ( - bn_ == other.bn_ && - it_ == other.it_ - ) - ); -} - -template<class... Bn> -auto -buffers_cat_view<Bn...>:: -const_iterator:: -operator*() const -> - reference -{ - return dereference(C<0>{}); -} - -template<class... Bn> -auto -buffers_cat_view<Bn...>:: -const_iterator:: -operator++() -> - const_iterator& -{ - increment(C<0>{}); - 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& -{ - decrement(C<sizeof...(Bn)>{}); - 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> -inline -auto -buffers_cat_view<Bn...>::begin() const -> - const_iterator -{ - return const_iterator{bn_, false}; -} - -template<class... Bn> -inline -auto -buffers_cat_view<Bn...>::end() const -> - const_iterator -{ - return const_iterator{bn_, true}; -} - -} // beast -} // boost - -#endif diff --git a/boost/beast/core/impl/buffers_prefix.hpp b/boost/beast/core/impl/buffers_prefix.hpp new file mode 100644 index 0000000000..e4a484bcee --- /dev/null +++ b/boost/beast/core/impl/buffers_prefix.hpp @@ -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 diff --git a/boost/beast/core/impl/buffers_prefix.ipp b/boost/beast/core/impl/buffers_prefix.ipp deleted file mode 100644 index c595455d60..0000000000 --- a/boost/beast/core/impl/buffers_prefix.ipp +++ /dev/null @@ -1,277 +0,0 @@ -// -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/boostorg/beast -// - -#ifndef BOOST_BEAST_IMPL_BUFFERS_PREFIX_IPP -#define BOOST_BEAST_IMPL_BUFFERS_PREFIX_IPP - -#include <algorithm> -#include <cstdint> -#include <iterator> -#include <stdexcept> -#include <type_traits> -#include <utility> - -namespace boost { -namespace beast { - -namespace detail { - -inline -boost::asio::const_buffer -buffers_prefix(std::size_t size, - boost::asio::const_buffer buffer) -{ - return {buffer.data(), - (std::min)(size, buffer.size())}; -} - -inline -boost::asio::mutable_buffer -buffers_prefix(std::size_t size, - boost::asio::mutable_buffer buffer) -{ - return {buffer.data(), - (std::min)(size, buffer.size())}; -} - -} // detail - -template<class BufferSequence> -class buffers_prefix_view<BufferSequence>::const_iterator -{ - friend class buffers_prefix_view<BufferSequence>; - - buffers_prefix_view const* b_ = nullptr; - std::size_t remain_; - iter_type it_; - -public: - using value_type = typename std::conditional< - boost::is_convertible<typename - std::iterator_traits<iter_type>::value_type, - boost::asio::mutable_buffer>::value, - boost::asio::mutable_buffer, - boost::asio::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&& other) = default; - const_iterator(const_iterator const& other) = default; - const_iterator& operator=(const_iterator&& other) = default; - const_iterator& operator=(const_iterator const& other) = default; - - bool - operator==(const_iterator const& other) const - { - return - (b_ == nullptr) ? - ( - other.b_ == nullptr || - other.it_ == other.b_->end_ - ):( - (other.b_ == nullptr) ? - ( - it_ == b_->end_ - ): ( - b_ == other.b_ && - it_ == other.it_ - ) - ); - } - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const - { - return detail::buffers_prefix(remain_, *it_); - } - - pointer - operator->() const = delete; - - const_iterator& - operator++() - { - remain_ -= boost::asio::buffer_size(*it_++); - return *this; - } - - const_iterator - operator++(int) - { - auto temp = *this; - remain_ -= boost::asio::buffer_size(*it_++); - return temp; - } - - const_iterator& - operator--() - { - remain_ += boost::asio::buffer_size(*--it_); - return *this; - } - - const_iterator - operator--(int) - { - auto temp = *this; - remain_ += boost::asio::buffer_size(*--it_); - 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_(boost::asio::buffer_sequence_begin(b_->bs_)) - { - } -}; - -//------------------------------------------------------------------------------ - -template<class BufferSequence> -void -buffers_prefix_view<BufferSequence>:: -setup(std::size_t size) -{ - size_ = 0; - remain_ = 0; - end_ = boost::asio::buffer_sequence_begin(bs_); - auto const last = bs_.end(); - while(end_ != last) - { - auto const len = - boost::asio::buffer_size(*end_++); - if(len >= size) - { - size_ += size; - remain_ = size - len; - break; - } - size -= len; - size_ += len; - } -} - -template<class BufferSequence> -buffers_prefix_view<BufferSequence>:: -buffers_prefix_view(buffers_prefix_view&& other) - : buffers_prefix_view(std::move(other), - std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), - other.end_)) -{ -} - -template<class BufferSequence> -buffers_prefix_view<BufferSequence>:: -buffers_prefix_view(buffers_prefix_view const& other) - : buffers_prefix_view(other, - std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), - other.end_)) -{ -} - -template<class BufferSequence> -auto -buffers_prefix_view<BufferSequence>:: -operator=(buffers_prefix_view&& other) -> - buffers_prefix_view& -{ - auto const dist = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), - other.end_); - bs_ = std::move(other.bs_); - size_ = other.size_; - remain_ = other.remain_; - end_ = std::next( - boost::asio::buffer_sequence_begin(bs_), - dist); - return *this; -} - -template<class BufferSequence> -auto -buffers_prefix_view<BufferSequence>:: -operator=(buffers_prefix_view const& other) -> - buffers_prefix_view& -{ - auto const dist = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), - other.end_); - bs_ = other.bs_; - size_ = other.size_; - remain_ = other.remain_; - end_ = std::next( - boost::asio::buffer_sequence_begin(bs_), - dist); - return *this; -} - -template<class BufferSequence> -buffers_prefix_view<BufferSequence>:: -buffers_prefix_view(std::size_t size, - BufferSequence const& bs) - : bs_(bs) -{ - setup(size); -} - -template<class BufferSequence> -template<class... Args> -buffers_prefix_view<BufferSequence>:: -buffers_prefix_view(std::size_t size, - boost::in_place_init_t, Args&&... args) - : bs_(std::forward<Args>(args)...) -{ - setup(size); -} - -template<class BufferSequence> -inline -auto -buffers_prefix_view<BufferSequence>::begin() const -> - const_iterator -{ - return const_iterator{*this, std::false_type{}}; -} - -template<class BufferSequence> -inline -auto -buffers_prefix_view<BufferSequence>::end() const -> - const_iterator -{ - return const_iterator{*this, std::true_type{}}; -} - -} // beast -} // boost - -#endif diff --git a/boost/beast/core/impl/buffers_suffix.ipp b/boost/beast/core/impl/buffers_suffix.hpp index 62b5f4634e..9822b4df70 100644 --- a/boost/beast/core/impl/buffers_suffix.ipp +++ b/boost/beast/core/impl/buffers_suffix.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -7,10 +7,11 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_IMPL_BUFFERS_SUFFIX_IPP -#define BOOST_BEAST_IMPL_BUFFERS_SUFFIX_IPP +#ifndef BOOST_BEAST_IMPL_BUFFERS_SUFFIX_HPP +#define BOOST_BEAST_IMPL_BUFFERS_SUFFIX_HPP -#include <boost/beast/core/type_traits.hpp> +#include <boost/beast/core/buffer_traits.hpp> +#include <boost/beast/core/buffer_traits.hpp> #include <boost/type_traits.hpp> #include <algorithm> #include <cstdint> @@ -26,19 +27,22 @@ class buffers_suffix<Buffers>::const_iterator { friend class buffers_suffix<Buffers>; - using iter_type = typename - detail::buffer_sequence_iterator<Buffers>::type; + using iter_type = buffers_iterator_type<Buffers>; - iter_type it_; + 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, - boost::asio::mutable_buffer>::value, - boost::asio::mutable_buffer, - boost::asio::const_buffer>::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; @@ -46,28 +50,15 @@ public: std::bidirectional_iterator_tag; const_iterator() = default; - const_iterator(const_iterator&& other) = default; - const_iterator(const_iterator const& other) = default; - const_iterator& operator=(const_iterator&& other) = default; - const_iterator& operator=(const_iterator const& other) = default; + const_iterator( + const_iterator const& other) = default; + const_iterator& operator=( + const_iterator const& other) = default; bool operator==(const_iterator const& other) const { - return - (b_ == nullptr) ? - ( - other.b_ == nullptr || - other.it_ == boost::asio::buffer_sequence_end(other.b_->bs_) - ):( - (other.b_ == nullptr) ? - ( - it_ == boost::asio::buffer_sequence_end(b_->bs_) - ): ( - b_ == other.b_ && - it_ == other.it_ - ) - ); + return b_ == other.b_ && it_ == other.it_; } bool @@ -79,9 +70,9 @@ public: reference operator*() const { - return it_ == b_->begin_ - ? value_type{*it_} + b_->skip_ - : *it_; + if(it_ == b_->begin_) + return value_type(*it_) + b_->skip_; + return value_type(*it_); } pointer @@ -118,8 +109,9 @@ public: } private: - const_iterator(buffers_suffix const& b, - iter_type it) + const_iterator( + buffers_suffix const& b, + iter_type it) : it_(it) , b_(&b) { @@ -131,17 +123,7 @@ private: template<class Buffers> buffers_suffix<Buffers>:: buffers_suffix() - : begin_(boost::asio::buffer_sequence_begin(bs_)) -{ -} - -template<class Buffers> -buffers_suffix<Buffers>:: -buffers_suffix(buffers_suffix&& other) - : buffers_suffix(std::move(other), - std::distance<iter_type>( - boost::asio::buffer_sequence_begin( - other.bs_), other.begin_)) + : begin_(net::buffer_sequence_begin(bs_)) { } @@ -150,7 +132,7 @@ buffers_suffix<Buffers>:: buffers_suffix(buffers_suffix const& other) : buffers_suffix(other, std::distance<iter_type>( - boost::asio::buffer_sequence_begin( + net::buffer_sequence_begin( other.bs_), other.begin_)) { } @@ -159,12 +141,12 @@ template<class Buffers> buffers_suffix<Buffers>:: buffers_suffix(Buffers const& bs) : bs_(bs) - , begin_(boost::asio::buffer_sequence_begin(bs_)) + , begin_(net::buffer_sequence_begin(bs_)) { static_assert( - boost::asio::is_const_buffer_sequence<Buffers>::value|| - boost::asio::is_mutable_buffer_sequence<Buffers>::value, - "BufferSequence requirements not met"); + net::is_const_buffer_sequence<Buffers>::value || + net::is_mutable_buffer_sequence<Buffers>::value, + "BufferSequence type requirements not met"); } template<class Buffers> @@ -172,7 +154,7 @@ template<class... Args> buffers_suffix<Buffers>:: buffers_suffix(boost::in_place_init_t, Args&&... args) : bs_(std::forward<Args>(args)...) - , begin_(boost::asio::buffer_sequence_begin(bs_)) + , begin_(net::buffer_sequence_begin(bs_)) { static_assert(sizeof...(Args) > 0, "Missing constructor arguments"); @@ -184,38 +166,20 @@ buffers_suffix(boost::in_place_init_t, Args&&... args) template<class Buffers> auto buffers_suffix<Buffers>:: -operator=(buffers_suffix&& other) -> - buffers_suffix& -{ - auto const dist = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), - other.begin_); - bs_ = std::move(other.bs_); - begin_ = std::next( - boost::asio::buffer_sequence_begin(bs_), - dist); - skip_ = other.skip_; - return *this; -} - -template<class Buffers> -auto -buffers_suffix<Buffers>:: operator=(buffers_suffix const& other) -> buffers_suffix& { auto const dist = std::distance<iter_type>( - boost::asio::buffer_sequence_begin(other.bs_), + net::buffer_sequence_begin(other.bs_), other.begin_); bs_ = other.bs_; begin_ = std::next( - boost::asio::buffer_sequence_begin(bs_), dist); + net::buffer_sequence_begin(bs_), dist); skip_ = other.skip_; return *this; } template<class Buffers> -inline auto buffers_suffix<Buffers>:: begin() const -> @@ -225,14 +189,13 @@ begin() const -> } template<class Buffers> -inline auto buffers_suffix<Buffers>:: end() const -> const_iterator { return const_iterator{*this, - boost::asio::buffer_sequence_end(bs_)}; + net::buffer_sequence_end(bs_)}; } template<class Buffers> @@ -240,13 +203,12 @@ void buffers_suffix<Buffers>:: consume(std::size_t amount) { - using boost::asio::buffer_size; auto const end = - boost::asio::buffer_sequence_end(bs_); + net::buffer_sequence_end(bs_); for(;amount > 0 && begin_ != end; ++begin_) { auto const len = - buffer_size(*begin_) - skip_; + buffer_bytes(*begin_) - skip_; if(amount < len) { skip_ += amount; diff --git a/boost/beast/core/impl/error.hpp b/boost/beast/core/impl/error.hpp new file mode 100644 index 0000000000..a02caeefe2 --- /dev/null +++ b/boost/beast/core/impl/error.hpp @@ -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 diff --git a/boost/beast/core/impl/error.ipp b/boost/beast/core/impl/error.ipp new file mode 100644 index 0000000000..0b3015775b --- /dev/null +++ b/boost/beast/core/impl/error.ipp @@ -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 diff --git a/boost/beast/core/impl/file_posix.ipp b/boost/beast/core/impl/file_posix.ipp index 8136bb83c2..0f7f42ac8d 100644 --- a/boost/beast/core/impl/file_posix.ipp +++ b/boost/beast/core/impl/file_posix.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -10,8 +10,21 @@ #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)) +# if defined(__APPLE__) || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) # define BOOST_BEAST_NO_POSIX_FADVISE # endif #endif @@ -24,112 +37,92 @@ # endif #endif -#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> - namespace boost { namespace beast { -namespace detail { - -inline int -file_posix_close(int fd) +file_posix:: +native_close(native_handle_type& fd) { - for(;;) +/* 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)) - break; - int const ev = errno; - if(errno != EINTR) - return ev; + if(::close(fd) != 0) + ev = errno; + fd = -1; } - return 0; + return ev; } -} // detail - -inline file_posix:: ~file_posix() { - if(fd_ != -1) - detail::file_posix_close(fd_); + native_close(fd_); } -inline file_posix:: file_posix(file_posix&& other) : fd_(boost::exchange(other.fd_, -1)) { } -inline file_posix& file_posix:: operator=(file_posix&& other) { if(&other == this) return *this; - if(fd_ != -1) - detail::file_posix_close(fd_); + native_close(fd_); fd_ = other.fd_; other.fd_ = -1; return *this; } -inline void file_posix:: native_handle(native_handle_type fd) { - if(fd_ != -1) - detail::file_posix_close(fd_); + native_close(fd_); fd_ = fd; } -inline void file_posix:: close(error_code& ec) { - if(fd_ != -1) - { - auto const ev = - detail::file_posix_close(fd_); - if(ev) - ec.assign(ev, generic_category()); - else - ec.assign(0, ec.category()); - fd_ = -1; - } + auto const ev = native_close(fd_); + if(ev) + ec.assign(ev, system_category()); else - { - ec.assign(0, ec.category()); - } + ec = {}; } -inline void file_posix:: open(char const* path, file_mode mode, error_code& ec) { - if(fd_ != -1) - { - auto const ev = - detail::file_posix_close(fd_); - if(ev) - ec.assign(ev, generic_category()); - else - ec.assign(0, ec.category()); - fd_ = -1; - } + 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; @@ -172,21 +165,14 @@ open(char const* path, file_mode mode, error_code& ec) break; case file_mode::append: - f = O_RDWR | O_CREAT | O_TRUNC; - #if BOOST_BEAST_USE_POSIX_FADVISE - advise = POSIX_FADV_SEQUENTIAL; - #endif - break; - - case file_mode::append_new: - f = O_RDWR | O_CREAT | O_EXCL; + 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_RDWR | O_EXCL; + f = O_WRONLY; #if BOOST_BEAST_USE_POSIX_FADVISE advise = POSIX_FADV_SEQUENTIAL; #endif @@ -200,7 +186,7 @@ open(char const* path, file_mode mode, error_code& ec) auto const ev = errno; if(ev != EINTR) { - ec.assign(ev, generic_category()); + ec.assign(ev, system_category()); return; } } @@ -208,82 +194,77 @@ open(char const* path, file_mode mode, error_code& ec) if(::posix_fadvise(fd_, 0, 0, advise)) { auto const ev = errno; - detail::file_posix_close(fd_); - fd_ = -1; - ec.assign(ev, generic_category()); + native_close(fd_); + ec.assign(ev, system_category()); return; } #endif - ec.assign(0, ec.category()); + ec = {}; } -inline std::uint64_t file_posix:: size(error_code& ec) const { if(fd_ == -1) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } struct stat st; if(::fstat(fd_, &st) != 0) { - ec.assign(errno, generic_category()); + ec.assign(errno, system_category()); return 0; } - ec.assign(0, ec.category()); + ec = {}; return st.st_size; } -inline std::uint64_t file_posix:: pos(error_code& ec) const { if(fd_ == -1) { - ec = make_error_code(errc::invalid_argument); + 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, generic_category()); + ec.assign(errno, system_category()); return 0; } - ec.assign(0, ec.category()); + ec = {}; return result; } -inline void file_posix:: seek(std::uint64_t offset, error_code& ec) { if(fd_ == -1) { - ec = make_error_code(errc::invalid_argument); + 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, generic_category()); + ec.assign(errno, system_category()); return; } - ec.assign(0, ec.category()); + ec = {}; } -inline std::size_t file_posix:: read(void* buffer, std::size_t n, error_code& ec) const { if(fd_ == -1) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } std::size_t nread = 0; @@ -297,7 +278,7 @@ read(void* buffer, std::size_t n, error_code& ec) const auto const ev = errno; if(ev == EINTR) continue; - ec.assign(ev, generic_category()); + ec.assign(ev, system_category()); return nread; } if(result == 0) @@ -312,14 +293,13 @@ read(void* buffer, std::size_t n, error_code& ec) const return nread; } -inline std::size_t file_posix:: write(void const* buffer, std::size_t n, error_code& ec) { if(fd_ == -1) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } std::size_t nwritten = 0; @@ -333,7 +313,7 @@ write(void const* buffer, std::size_t n, error_code& ec) auto const ev = errno; if(ev == EINTR) continue; - ec.assign(ev, generic_category()); + ec.assign(ev, system_category()); return nwritten; } n -= result; @@ -347,3 +327,5 @@ write(void const* buffer, std::size_t n, error_code& ec) } // boost #endif + +#endif diff --git a/boost/beast/core/impl/file_stdio.ipp b/boost/beast/core/impl/file_stdio.ipp index 531a8b4748..30adae621b 100644 --- a/boost/beast/core/impl/file_stdio.ipp +++ b/boost/beast/core/impl/file_stdio.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -10,13 +10,14 @@ #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 { -inline file_stdio:: ~file_stdio() { @@ -24,14 +25,12 @@ file_stdio:: fclose(f_); } -inline file_stdio:: file_stdio(file_stdio&& other) : f_(boost::exchange(other.f_, nullptr)) { } -inline file_stdio& file_stdio:: operator=(file_stdio&& other) @@ -45,7 +44,6 @@ operator=(file_stdio&& other) return *this; } -inline void file_stdio:: native_handle(FILE* f) @@ -55,7 +53,6 @@ native_handle(FILE* f) f_ = f; } -inline void file_stdio:: close(error_code& ec) @@ -70,10 +67,9 @@ close(error_code& ec) return; } } - ec.assign(0, ec.category()); + ec = {}; } -inline void file_stdio:: open(char const* path, file_mode mode, error_code& ec) @@ -87,17 +83,83 @@ open(char const* path, file_mode mode, error_code& ec) switch(mode) { default: - case file_mode::read: s = "rb"; break; - case file_mode::scan: s = "rb"; break; - case file_mode::write: s = "wb"; break; - case file_mode::write_new: s = "wbx"; break; - case file_mode::write_existing: s = "wb"; break; - case file_mode::append: s = "ab"; break; - case file_mode::append_new: s = "abx"; break; - case file_mode::append_existing: s = "ab"; break; - } -#if BOOST_MSVC - auto const ev = fopen_s(&f_, path, s); + 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; @@ -112,17 +174,16 @@ open(char const* path, file_mode mode, error_code& ec) return; } #endif - ec.assign(0, ec.category()); + ec = {}; } -inline std::uint64_t file_stdio:: size(error_code& ec) const { if(! f_) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } long pos = std::ftell(f_); @@ -148,18 +209,17 @@ size(error_code& ec) const if(result != 0) ec.assign(errno, generic_category()); else - ec.assign(0, ec.category()); + ec = {}; return size; } -inline std::uint64_t file_stdio:: pos(error_code& ec) const { if(! f_) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } long pos = std::ftell(f_); @@ -168,18 +228,17 @@ pos(error_code& ec) const ec.assign(errno, generic_category()); return 0; } - ec.assign(0, ec.category()); + ec = {}; return pos; } -inline void file_stdio:: seek(std::uint64_t offset, error_code& ec) { if(! f_) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return; } if(offset > (std::numeric_limits<long>::max)()) @@ -192,17 +251,16 @@ seek(std::uint64_t offset, error_code& ec) if(result != 0) ec.assign(errno, generic_category()); else - ec.assign(0, ec.category()); + ec = {}; } -inline std::size_t file_stdio:: read(void* buffer, std::size_t n, error_code& ec) const { if(! f_) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } auto nread = std::fread(buffer, 1, n, f_); @@ -214,14 +272,13 @@ read(void* buffer, std::size_t n, error_code& ec) const return nread; } -inline std::size_t file_stdio:: write(void const* buffer, std::size_t n, error_code& ec) { if(! f_) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } auto nwritten = std::fwrite(buffer, 1, n, f_); diff --git a/boost/beast/core/impl/file_win32.ipp b/boost/beast/core/impl/file_win32.ipp index 1183e3853f..8944a6bb45 100644 --- a/boost/beast/core/impl/file_win32.ipp +++ b/boost/beast/core/impl/file_win32.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -10,6 +10,10 @@ #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> @@ -25,7 +29,7 @@ namespace detail { // VFALCO Can't seem to get boost/detail/winapi to work with // this so use the non-Ex version for now. -inline +BOOST_BEAST_DECL boost::winapi::BOOL_ set_file_pointer_ex( boost::winapi::HANDLE_ hFile, @@ -51,7 +55,6 @@ set_file_pointer_ex( } // detail -inline file_win32:: ~file_win32() { @@ -59,14 +62,13 @@ file_win32:: boost::winapi::CloseHandle(h_); } -inline file_win32:: file_win32(file_win32&& other) - : h_(boost::exchange(other.h_, boost::winapi::INVALID_HANDLE_VALUE_)) + : h_(boost::exchange(other.h_, + boost::winapi::INVALID_HANDLE_VALUE_)) { } -inline file_win32& file_win32:: operator=(file_win32&& other) @@ -80,7 +82,6 @@ operator=(file_win32&& other) return *this; } -inline void file_win32:: native_handle(native_handle_type h) @@ -90,7 +91,6 @@ native_handle(native_handle_type h) h_ = h; } -inline void file_win32:: close(error_code& ec) @@ -101,16 +101,15 @@ close(error_code& ec) ec.assign(boost::winapi::GetLastError(), system_category()); else - ec.assign(0, ec.category()); + ec = {}; h_ = boost::winapi::INVALID_HANDLE_VALUE_; } else { - ec.assign(0, ec.category()); + ec = {}; } } -inline void file_win32:: open(char const* path, file_mode mode, error_code& ec) @@ -180,13 +179,6 @@ open(char const* path, file_mode mode, error_code& ec) flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN break; - case file_mode::append_new: - desired_access = boost::winapi::GENERIC_READ_ | - boost::winapi::GENERIC_WRITE_; - creation_disposition = boost::winapi::CREATE_NEW_; - flags_and_attributes = 0x08000000; // FILE_FLAG_SEQUENTIAL_SCAN - break; - case file_mode::append_existing: desired_access = boost::winapi::GENERIC_READ_ | boost::winapi::GENERIC_WRITE_; @@ -206,17 +198,16 @@ open(char const* path, file_mode mode, error_code& ec) ec.assign(boost::winapi::GetLastError(), system_category()); else - ec.assign(0, ec.category()); + ec = {}; } -inline std::uint64_t file_win32:: size(error_code& ec) const { if(h_ == boost::winapi::INVALID_HANDLE_VALUE_) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } boost::winapi::LARGE_INTEGER_ fileSize; @@ -226,18 +217,17 @@ size(error_code& ec) const system_category()); return 0; } - ec.assign(0, ec.category()); + ec = {}; return fileSize.QuadPart; } -inline std::uint64_t file_win32:: pos(error_code& ec) { if(h_ == boost::winapi::INVALID_HANDLE_VALUE_) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } boost::winapi::LARGE_INTEGER_ in; @@ -250,18 +240,17 @@ pos(error_code& ec) system_category()); return 0; } - ec.assign(0, ec.category()); + ec = {}; return out.QuadPart; } -inline void file_win32:: seek(std::uint64_t offset, error_code& ec) { if(h_ == boost::winapi::INVALID_HANDLE_VALUE_) { - ec = make_error_code(errc::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return; } boost::winapi::LARGE_INTEGER_ in; @@ -273,17 +262,16 @@ seek(std::uint64_t offset, error_code& ec) system_category()); return; } - ec.assign(0, ec.category()); + ec = {}; } -inline 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::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } std::size_t nread = 0; @@ -304,7 +292,7 @@ read(void* buffer, std::size_t n, error_code& ec) if(dwError != boost::winapi::ERROR_HANDLE_EOF_) ec.assign(dwError, system_category()); else - ec.assign(0, ec.category()); + ec = {}; return nread; } if(bytesRead == 0) @@ -313,18 +301,17 @@ read(void* buffer, std::size_t n, error_code& ec) nread += bytesRead; buffer = static_cast<char*>(buffer) + bytesRead; } - ec.assign(0, ec.category()); + ec = {}; return nread; } -inline 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::invalid_argument); + ec = make_error_code(errc::bad_file_descriptor); return 0; } std::size_t nwritten = 0; @@ -345,7 +332,7 @@ write(void const* buffer, std::size_t n, error_code& ec) if(dwError != boost::winapi::ERROR_HANDLE_EOF_) ec.assign(dwError, system_category()); else - ec.assign(0, ec.category()); + ec = {}; return nwritten; } if(bytesWritten == 0) @@ -354,7 +341,7 @@ write(void const* buffer, std::size_t n, error_code& ec) nwritten += bytesWritten; buffer = static_cast<char const*>(buffer) + bytesWritten; } - ec.assign(0, ec.category()); + ec = {}; return nwritten; } @@ -362,3 +349,5 @@ write(void const* buffer, std::size_t n, error_code& ec) } // boost #endif + +#endif diff --git a/boost/beast/core/impl/flat_buffer.ipp b/boost/beast/core/impl/flat_buffer.hpp index afc843ac0d..f7fd51673d 100644 --- a/boost/beast/core/impl/flat_buffer.ipp +++ b/boost/beast/core/impl/flat_buffer.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -13,40 +13,46 @@ #include <boost/core/exchange.hpp> #include <boost/assert.hpp> #include <boost/throw_exception.hpp> +#include <memory> #include <stdexcept> namespace boost { namespace beast { -/* Memory is laid out thusly: +/* Layout: - begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_ + begin_ in_ out_ last_ end_ + |<------->|<---------->|<---------->|<------->| + | readable | writable | */ template<class Allocator> basic_flat_buffer<Allocator>:: ~basic_flat_buffer() { - if(begin_) - alloc_traits::deallocate( - this->get(), begin_, dist(begin_, end_)); + if(! begin_) + return; + alloc_traits::deallocate( + this->get(), begin_, capacity()); } template<class Allocator> basic_flat_buffer<Allocator>:: -basic_flat_buffer() +basic_flat_buffer() noexcept(default_nothrow) : begin_(nullptr) , in_(nullptr) , out_(nullptr) , last_(nullptr) , end_(nullptr) - , max_((std::numeric_limits<std::size_t>::max)()) + , max_(alloc_traits::max_size( + this->get())) { } template<class Allocator> basic_flat_buffer<Allocator>:: -basic_flat_buffer(std::size_t limit) +basic_flat_buffer( + std::size_t limit) noexcept(default_nothrow) : begin_(nullptr) , in_(nullptr) , out_(nullptr) @@ -58,21 +64,26 @@ basic_flat_buffer(std::size_t limit) template<class Allocator> basic_flat_buffer<Allocator>:: -basic_flat_buffer(Allocator const& alloc) - : boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc) +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_((std::numeric_limits<std::size_t>::max)()) + , max_(alloc_traits::max_size( + this->get())) { } template<class Allocator> basic_flat_buffer<Allocator>:: -basic_flat_buffer(std::size_t limit, Allocator const& alloc) - : boost::empty_value<base_alloc_type>(boost::empty_init_t(), alloc) +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) @@ -84,24 +95,25 @@ basic_flat_buffer(std::size_t limit, Allocator const& alloc) template<class Allocator> basic_flat_buffer<Allocator>:: -basic_flat_buffer(basic_flat_buffer&& other) - : boost::empty_value<base_alloc_type>(boost::empty_init_t(), - std::move(other.get())) +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_(out_) + , last_(boost::exchange(other.last_, nullptr)) , end_(boost::exchange(other.end_, nullptr)) , max_(other.max_) { - other.last_ = nullptr; } 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) +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()) { @@ -112,28 +124,31 @@ basic_flat_buffer(basic_flat_buffer&& other, end_ = nullptr; max_ = other.max_; copy_from(other); - other.reset(); - } - else - { - 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; + 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(), + : boost::empty_value<base_alloc_type>(boost::empty_init_t{}, alloc_traits::select_on_container_copy_construction( other.get())) , begin_(nullptr) @@ -148,9 +163,11 @@ basic_flat_buffer(basic_flat_buffer const& 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) +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) @@ -165,7 +182,8 @@ template<class Allocator> template<class OtherAlloc> basic_flat_buffer<Allocator>:: basic_flat_buffer( - basic_flat_buffer<OtherAlloc> const& other) + basic_flat_buffer<OtherAlloc> const& other) + noexcept(default_nothrow) : begin_(nullptr) , in_(nullptr) , out_(nullptr) @@ -179,9 +197,11 @@ basic_flat_buffer( 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) +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) @@ -195,12 +215,12 @@ basic_flat_buffer(basic_flat_buffer<OtherAlloc> const& other, template<class Allocator> auto basic_flat_buffer<Allocator>:: -operator=(basic_flat_buffer&& other) -> +operator=(basic_flat_buffer&& other) noexcept -> basic_flat_buffer& { - if(this != &other) - move_assign(other, std::integral_constant<bool, - alloc_traits::propagate_on_container_move_assignment::value>{}); + if(this == &other) + return *this; + move_assign(other, pocma{}); return *this; } @@ -210,9 +230,9 @@ basic_flat_buffer<Allocator>:: operator=(basic_flat_buffer const& other) -> basic_flat_buffer& { - if(this != &other) - copy_assign(other, std::integral_constant<bool, - alloc_traits::propagate_on_container_copy_assignment::value>{}); + if(this == &other) + return *this; + copy_assign(other, pocca{}); return *this; } @@ -220,15 +240,64 @@ template<class Allocator> template<class OtherAlloc> auto basic_flat_buffer<Allocator>:: -operator=(basic_flat_buffer<OtherAlloc> const& other) -> +operator=( + basic_flat_buffer<OtherAlloc> const& other) -> basic_flat_buffer& { - reset(); - max_ = other.max_; 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> @@ -237,34 +306,36 @@ 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}; } - auto const len = size(); 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}; } - // enforce maximum capacity - if(n > max_ - len) - BOOST_THROW_EXCEPTION(std::length_error{ - "basic_flat_buffer overflow"}); // 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_traits::allocate( - this->get(), new_size); + auto const p = alloc(new_size); if(begin_) { BOOST_ASSERT(p); @@ -284,7 +355,7 @@ prepare(std::size_t n) -> template<class Allocator> void basic_flat_buffer<Allocator>:: -consume(std::size_t n) +consume(std::size_t n) noexcept { if(n >= dist(in_, out_)) { @@ -295,69 +366,54 @@ consume(std::size_t n) in_ += n; } +//------------------------------------------------------------------------------ + template<class Allocator> +template<class OtherAlloc> void basic_flat_buffer<Allocator>:: -shrink_to_fit() +copy_from( + basic_flat_buffer<OtherAlloc> const& other) { - auto const len = size(); - if(len == capacity()) - return; - char* p; - if(len > 0) + std::size_t const n = other.size(); + if(n == 0 || n > capacity()) { - BOOST_ASSERT(begin_); - BOOST_ASSERT(in_); - p = alloc_traits::allocate( - this->get(), len); - std::memcpy(p, in_, len); + 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; } - else + in_ = begin_; + out_ = begin_ + n; + last_ = begin_ + n; + if(begin_) { - p = nullptr; + BOOST_ASSERT(other.begin_); + std::memcpy(begin_, other.begin_, n); } - alloc_traits::deallocate( - this->get(), begin_, dist(begin_, end_)); - begin_ = p; - in_ = begin_; - out_ = begin_ + len; - last_ = out_; - end_ = out_; -} - -//------------------------------------------------------------------------------ - -template<class Allocator> -inline -void -basic_flat_buffer<Allocator>:: -reset() -{ - consume(size()); - shrink_to_fit(); } template<class Allocator> -template<class DynamicBuffer> -inline -void -basic_flat_buffer<Allocator>:: -copy_from(DynamicBuffer const& buffer) -{ - if(buffer.size() == 0) - return; - using boost::asio::buffer_copy; - commit(buffer_copy( - prepare(buffer.size()), buffer.data())); -} - -template<class Allocator> -inline void basic_flat_buffer<Allocator>:: move_assign(basic_flat_buffer& other, std::true_type) { - reset(); + clear(); + shrink_to_fit(); this->get() = std::move(other.get()); begin_ = other.begin_; in_ = other.in_; @@ -373,16 +429,15 @@ move_assign(basic_flat_buffer& other, std::true_type) } template<class Allocator> -inline void basic_flat_buffer<Allocator>:: move_assign(basic_flat_buffer& other, std::false_type) { - reset(); if(this->get() != other.get()) { copy_from(other); - other.reset(); + other.clear(); + other.shrink_to_fit(); } else { @@ -391,30 +446,27 @@ move_assign(basic_flat_buffer& other, std::false_type) } template<class Allocator> -inline void basic_flat_buffer<Allocator>:: copy_assign(basic_flat_buffer const& other, std::true_type) { - reset(); max_ = other.max_; this->get() = other.get(); copy_from(other); } template<class Allocator> -inline void basic_flat_buffer<Allocator>:: copy_assign(basic_flat_buffer const& other, std::false_type) { - reset(); + clear(); + shrink_to_fit(); max_ = other.max_; copy_from(other); } template<class Allocator> -inline void basic_flat_buffer<Allocator>:: swap(basic_flat_buffer& other) @@ -424,7 +476,6 @@ swap(basic_flat_buffer& other) } template<class Allocator> -inline void basic_flat_buffer<Allocator>:: swap(basic_flat_buffer& other, std::true_type) @@ -441,7 +492,6 @@ swap(basic_flat_buffer& other, std::true_type) } template<class Allocator> -inline void basic_flat_buffer<Allocator>:: swap(basic_flat_buffer& other, std::false_type) @@ -466,6 +516,17 @@ swap( 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 diff --git a/boost/beast/core/impl/flat_static_buffer.hpp b/boost/beast/core/impl/flat_static_buffer.hpp new file mode 100644 index 0000000000..c812dd0cfc --- /dev/null +++ b/boost/beast/core/impl/flat_static_buffer.hpp @@ -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
\ No newline at end of file diff --git a/boost/beast/core/impl/flat_static_buffer.ipp b/boost/beast/core/impl/flat_static_buffer.ipp index 54bf292116..31f158ebe7 100644 --- a/boost/beast/core/impl/flat_static_buffer.ipp +++ b/boost/beast/core/impl/flat_static_buffer.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -10,82 +10,36 @@ #ifndef BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_IPP #define BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_IPP -#include <boost/beast/core/detail/type_traits.hpp> -#include <boost/asio/buffer.hpp> +#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 { -/* Memory is laid out thusly: +/* Layout: - begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_ + begin_ in_ out_ last_ end_ + |<------->|<---------->|<---------->|<------->| + | readable | writable | */ -inline -auto -flat_static_buffer_base:: -data() const -> - const_buffers_type -{ - return {in_, dist(in_, out_)}; -} - -inline void flat_static_buffer_base:: -reset() -{ - reset_impl(); -} - -inline -auto -flat_static_buffer_base:: -prepare(std::size_t n) -> - mutable_buffers_type -{ - return prepare_impl(n); -} - -inline -void -flat_static_buffer_base:: -reset(void* p, std::size_t n) -{ - reset_impl(p, n); -} - -template<class> -void -flat_static_buffer_base:: -reset_impl() +clear() noexcept { in_ = begin_; out_ = begin_; last_ = begin_; } -template<class> -void -flat_static_buffer_base:: -reset_impl(void* p, std::size_t n) -{ - begin_ = static_cast<char*>(p); - in_ = begin_; - out_ = begin_; - last_ = begin_; - end_ = begin_ + n; -} - -template<class> auto flat_static_buffer_base:: -prepare_impl(std::size_t n) -> +prepare(std::size_t n) -> mutable_buffers_type { if(n <= dist(out_, end_)) @@ -105,10 +59,9 @@ prepare_impl(std::size_t n) -> return {out_, n}; } -template<class> void flat_static_buffer_base:: -consume_impl(std::size_t n) +consume(std::size_t n) noexcept { if(n >= size()) { @@ -119,32 +72,18 @@ consume_impl(std::size_t n) in_ += n; } -//------------------------------------------------------------------------------ - -template<std::size_t N> -flat_static_buffer<N>:: -flat_static_buffer(flat_static_buffer const& other) - : flat_static_buffer_base(buf_, N) -{ - using boost::asio::buffer_copy; - this->commit(buffer_copy( - this->prepare(other.size()), other.data())); -} - -template<std::size_t N> -auto -flat_static_buffer<N>:: -operator=(flat_static_buffer const& other) -> - flat_static_buffer<N>& +void +flat_static_buffer_base:: +reset(void* p, std::size_t n) noexcept { - using boost::asio::buffer_copy; - this->consume(this->size()); - this->commit(buffer_copy( - this->prepare(other.size()), other.data())); - return *this; + begin_ = static_cast<char*>(p); + in_ = begin_; + out_ = begin_; + last_ = begin_; + end_ = begin_ + n; } } // beast } // boost -#endif +#endif
\ No newline at end of file diff --git a/boost/beast/core/impl/flat_stream.hpp b/boost/beast/core/impl/flat_stream.hpp new file mode 100644 index 0000000000..2972131198 --- /dev/null +++ b/boost/beast/core/impl/flat_stream.hpp @@ -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 diff --git a/boost/beast/core/impl/handler_ptr.ipp b/boost/beast/core/impl/handler_ptr.hpp index 06bdd81c40..48260abc2b 100644 --- a/boost/beast/core/impl/handler_ptr.ipp +++ b/boost/beast/core/impl/handler_ptr.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -22,15 +22,15 @@ void handler_ptr<T, Handler>:: clear() { - typename beast::detail::allocator_traits< - boost::asio::associated_allocator_t< - Handler>>::template rebind_alloc<T> alloc( - boost::asio::get_associated_allocator( - handler())); - beast::detail::allocator_traits< - decltype(alloc)>::destroy(alloc, t_); - beast::detail::allocator_traits< - decltype(alloc)>::deallocate(alloc, t_, 1); + 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; } @@ -41,7 +41,7 @@ handler_ptr<T, Handler>:: if(t_) { clear(); - handler().~Handler(); + h_.~Handler(); } } @@ -52,8 +52,9 @@ handler_ptr(handler_ptr&& other) { if(other.t_) { - new(&h_) Handler(std::move(other.handler())); - other.handler().~Handler(); + ::new(static_cast<void*>(std::addressof(h_))) + Handler(std::move(other.h_)); + other.h_.~Handler(); other.t_ = nullptr; } } @@ -64,25 +65,27 @@ handler_ptr<T, Handler>:: handler_ptr(DeducedHandler&& h, Args&&... args) { BOOST_STATIC_ASSERT(! std::is_array<T>::value); - typename beast::detail::allocator_traits< - boost::asio::associated_allocator_t< - Handler>>::template rebind_alloc<T> alloc{ - boost::asio::get_associated_allocator(h)}; - using A = decltype(alloc); + 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) - beast::detail::allocator_traits<A>::destroy(alloc, p); - beast::detail::allocator_traits<A>::deallocate(alloc, p, 1); + alloc_traits::destroy(alloc, p); + alloc_traits::deallocate(alloc, p, 1); }; std::unique_ptr<T, decltype(deleter)> t{ - beast::detail::allocator_traits<A>::allocate(alloc, 1), deleter}; - beast::detail::allocator_traits<A>::construct(alloc, t.get(), + alloc_traits::allocate(alloc, 1), deleter}; + alloc_traits::construct(alloc, t.get(), static_cast<DeducedHandler const&>(h), std::forward<Args>(args)...); destroy = true; - new(&h_) Handler(std::forward<DeducedHandler>(h)); + ::new(static_cast<void*>(std::addressof(h_))) + Handler(std::forward<DeducedHandler>(h)); t_ = t.release(); } @@ -100,8 +103,8 @@ release_handler() -> }; std::unique_ptr< Handler, decltype(deleter)> destroyer{ - &handler(), deleter}; - return std::move(handler()); + std::addressof(h_), deleter}; + return std::move(h_); } template<class T, class Handler> @@ -119,8 +122,8 @@ invoke(Args&&... args) }; std::unique_ptr< Handler, decltype(deleter)> destroyer{ - &handler(), deleter}; - handler()(std::forward<Args>(args)...); + std::addressof(h_), deleter}; + h_(std::forward<Args>(args)...); } } // beast diff --git a/boost/beast/core/impl/multi_buffer.ipp b/boost/beast/core/impl/multi_buffer.hpp index fb48424a3a..643f60ce2b 100644 --- a/boost/beast/core/impl/multi_buffer.ipp +++ b/boost/beast/core/impl/multi_buffer.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -7,10 +7,12 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_IMPL_MULTI_BUFFER_IPP -#define BOOST_BEAST_IMPL_MULTI_BUFFER_IPP +#ifndef BOOST_BEAST_IMPL_MULTI_BUFFER_HPP +#define BOOST_BEAST_IMPL_MULTI_BUFFER_HPP +#include <boost/beast/core/buffer_traits.hpp> #include <boost/beast/core/detail/type_traits.hpp> +#include <boost/config/workaround.hpp> #include <boost/core/exchange.hpp> #include <boost/assert.hpp> #include <boost/throw_exception.hpp> @@ -18,6 +20,7 @@ #include <exception> #include <sstream> #include <string> +#include <type_traits> #include <utility> namespace boost { @@ -27,40 +30,39 @@ namespace beast { 1 Input and output contained entirely in one element: - 0 out_ - |<-------------+------------------------------------------->| - in_pos_ out_pos_ out_end_ + 0 out_ + |<------+-----------+--------------------------------+----->| + in_pos_ out_pos_ out_end_ 2 Output contained in first and second elements: - out_ - |<------+----------+------->| |<----------+-------------->| - in_pos_ out_pos_ out_end_ + out_ + |<------+-----------+------>| |<-------------------+----->| + in_pos_ out_pos_ out_end_ 3 Output contained in the second element: - out_ - |<------------+------------>| |<----+-------------------->| - in_pos_ out_pos_ out_end_ + out_ + |<------+------------------>| |<----+--------------+----->| + in_pos_ out_pos_ out_end_ 4 Output contained in second and third elements: - out_ - |<-----+-------->| |<-------+------>| |<--------------->| - in_pos_ out_pos_ out_end_ + out_ + |<------+------->| |<-------+------>| |<---------+----->| + in_pos_ out_pos_ out_end_ 5 Input sequence is empty: - out_ - |<------+------------------>| |<-----------+------------->| - out_pos_ out_end_ + out_ + |<------+------------------>| |<-------------------+----->| + out_pos_ out_end_ in_pos_ - 6 Output sequence is empty: out_ @@ -86,6 +88,7 @@ namespace beast { in_pos_ out_pos_ == 0 out_end_ == 0 */ +//------------------------------------------------------------------------------ template<class Allocator> class basic_multi_buffer<Allocator>::element @@ -93,105 +96,131 @@ class basic_multi_buffer<Allocator>::element boost::intrusive::link_mode< boost::intrusive::normal_link>> { - using size_type = - typename detail::allocator_traits<Allocator>::size_type; + using size_type = typename + detail::allocator_traits<Allocator>::size_type; size_type const size_; public: element(element const&) = delete; - element& operator=(element const&) = delete; explicit - element(size_type n) + element(size_type n) noexcept : size_(n) { } size_type - size() const + size() const noexcept { return size_; } char* - data() const + data() const noexcept { return const_cast<char*>( reinterpret_cast<char const*>(this + 1)); } }; +//------------------------------------------------------------------------------ + +#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 Allocator> -class basic_multi_buffer<Allocator>::const_buffers_type +template<bool isMutable> +class basic_multi_buffer<Allocator>::readable_bytes { basic_multi_buffer const* b_; friend class basic_multi_buffer; explicit - const_buffers_type(basic_multi_buffer const& b); + readable_bytes( + basic_multi_buffer const& b) noexcept + : b_(&b) + { + } public: - using value_type = boost::asio::const_buffer; + using value_type = typename + std::conditional< + isMutable, + net::mutable_buffer, + net::const_buffer>::type; class const_iterator; - const_buffers_type() = delete; - const_buffers_type(const_buffers_type const&) = default; - const_buffers_type& operator=(const_buffers_type const&) = default; - - const_iterator - begin() const; - - const_iterator - end() const; - - friend - std::size_t - buffer_size(const_buffers_type const& buffers) + readable_bytes() = delete; +#if BOOST_WORKAROUND(BOOST_MSVC, < 1910) + readable_bytes(readable_bytes const& other) + : b_(other.b_) { - return buffers.b_->size(); } -}; - -template<class Allocator> -class basic_multi_buffer<Allocator>::mutable_buffers_type -{ - basic_multi_buffer const* b_; - friend class basic_multi_buffer; - - explicit - mutable_buffers_type(basic_multi_buffer const& 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 -public: - using value_type = mutable_buffer; + template< + bool isMutable_ = isMutable, + class = typename std::enable_if<! isMutable_>::type> + readable_bytes( + readable_bytes<true> const& other) noexcept + : b_(other.b_) + { + } - class const_iterator; + 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; + } - 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 noexcept; + const_iterator end() const noexcept; - const_iterator - begin() const; - - const_iterator - end() const; + std::size_t + buffer_bytes() const noexcept + { + return b_->size(); + } }; +#if BOOST_WORKAROUND(BOOST_MSVC, < 1910) +# pragma warning (pop) +#endif + //------------------------------------------------------------------------------ template<class Allocator> -class basic_multi_buffer<Allocator>::const_buffers_type::const_iterator +template<bool isMutable> +class + basic_multi_buffer<Allocator>:: + readable_bytes<isMutable>:: + const_iterator { basic_multi_buffer const* b_ = nullptr; typename list_type::const_iterator it_; public: using value_type = - typename const_buffers_type::value_type; + typename readable_bytes::value_type; using pointer = value_type const*; using reference = value_type; using difference_type = std::ptrdiff_t; @@ -199,32 +228,33 @@ public: std::bidirectional_iterator_tag; const_iterator() = default; - const_iterator(const_iterator&& other) = default; - const_iterator(const_iterator const& other) = default; - const_iterator& operator=(const_iterator&& other) = default; - const_iterator& operator=(const_iterator const& other) = default; - - const_iterator(basic_multi_buffer const& b, - typename list_type::const_iterator const& it) + const_iterator( + const_iterator const& other) = default; + const_iterator& operator=( + const_iterator const& other) = default; + + const_iterator( + basic_multi_buffer const& b, typename + list_type::const_iterator const& it) noexcept : b_(&b) , it_(it) { } bool - operator==(const_iterator const& other) const + operator==(const_iterator const& other) const noexcept { return b_ == other.b_ && it_ == other.it_; } bool - operator!=(const_iterator const& other) const + operator!=(const_iterator const& other) const noexcept { return !(*this == other); } reference - operator*() const + operator*() const noexcept { auto const& e = *it_; return value_type{e.data(), @@ -237,14 +267,14 @@ public: operator->() const = delete; const_iterator& - operator++() + operator++() noexcept { ++it_; return *this; } const_iterator - operator++(int) + operator++(int) noexcept { auto temp = *this; ++(*this); @@ -252,14 +282,14 @@ public: } const_iterator& - operator--() + operator--() noexcept { --it_; return *this; } const_iterator - operator--(int) + operator--(int) noexcept { auto temp = *this; --(*this); @@ -267,36 +297,34 @@ public: } }; -template<class Allocator> -basic_multi_buffer<Allocator>:: -const_buffers_type:: -const_buffers_type( - basic_multi_buffer const& b) - : b_(&b) -{ -} +//------------------------------------------------------------------------------ template<class Allocator> -auto -basic_multi_buffer<Allocator>:: -const_buffers_type:: -begin() const -> - const_iterator +class basic_multi_buffer<Allocator>::mutable_buffers_type { - return const_iterator{*b_, b_->list_.begin()}; -} + basic_multi_buffer const* b_; -template<class Allocator> -auto -basic_multi_buffer<Allocator>:: -const_buffers_type:: -end() const -> - const_iterator -{ - return const_iterator{*b_, b_->out_ == - b_->list_.end() ? b_->list_.end() : - std::next(b_->out_)}; -} + friend class basic_multi_buffer; + + explicit + mutable_buffers_type( + basic_multi_buffer const& b) noexcept + : b_(&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 noexcept; + const_iterator end() const noexcept; +}; //------------------------------------------------------------------------------ @@ -307,8 +335,8 @@ class basic_multi_buffer<Allocator>::mutable_buffers_type::const_iterator typename list_type::const_iterator it_; public: - using value_type = - typename mutable_buffers_type::value_type; + using value_type = typename + mutable_buffers_type::value_type; using pointer = value_type const*; using reference = value_type; using difference_type = std::ptrdiff_t; @@ -316,32 +344,31 @@ public: std::bidirectional_iterator_tag; const_iterator() = default; - const_iterator(const_iterator&& other) = default; const_iterator(const_iterator const& other) = default; - const_iterator& operator=(const_iterator&& other) = default; const_iterator& operator=(const_iterator const& other) = default; - const_iterator(basic_multi_buffer const& b, - typename list_type::const_iterator const& it) + const_iterator( + basic_multi_buffer const& b, + typename list_type::const_iterator const& it) noexcept : b_(&b) , it_(it) { } bool - operator==(const_iterator const& other) const + operator==(const_iterator const& other) const noexcept { return b_ == other.b_ && it_ == other.it_; } bool - operator!=(const_iterator const& other) const + operator!=(const_iterator const& other) const noexcept { return !(*this == other); } reference - operator*() const + operator*() const noexcept { auto const& e = *it_; return value_type{e.data(), @@ -354,14 +381,14 @@ public: operator->() const = delete; const_iterator& - operator++() + operator++() noexcept { ++it_; return *this; } const_iterator - operator++(int) + operator++(int) noexcept { auto temp = *this; ++(*this); @@ -369,14 +396,14 @@ public: } const_iterator& - operator--() + operator--() noexcept { --it_; return *this; } const_iterator - operator--(int) + operator--(int) noexcept { auto temp = *this; --(*this); @@ -384,20 +411,37 @@ public: } }; +//------------------------------------------------------------------------------ + template<class Allocator> +template<bool isMutable> +auto basic_multi_buffer<Allocator>:: -mutable_buffers_type:: -mutable_buffers_type( - basic_multi_buffer const& b) - : b_(&b) +readable_bytes<isMutable>:: +begin() const noexcept -> + const_iterator { + return const_iterator{*b_, b_->list_.begin()}; +} + +template<class Allocator> +template<bool isMutable> +auto +basic_multi_buffer<Allocator>:: +readable_bytes<isMutable>:: +end() const noexcept -> + const_iterator +{ + return const_iterator{*b_, b_->out_ == + b_->list_.end() ? b_->list_.end() : + std::next(b_->out_)}; } template<class Allocator> auto basic_multi_buffer<Allocator>:: mutable_buffers_type:: -begin() const -> +begin() const noexcept -> const_iterator { return const_iterator{*b_, b_->out_}; @@ -407,7 +451,7 @@ template<class Allocator> auto basic_multi_buffer<Allocator>:: mutable_buffers_type:: -end() const -> +end() const noexcept -> const_iterator { return const_iterator{*b_, b_->list_.end()}; @@ -419,19 +463,21 @@ template<class Allocator> basic_multi_buffer<Allocator>:: ~basic_multi_buffer() { - delete_list(); + destroy(list_); } template<class Allocator> basic_multi_buffer<Allocator>:: -basic_multi_buffer() - : out_(list_.end()) +basic_multi_buffer() noexcept(default_nothrow) + : max_(alloc_traits::max_size(this->get())) + , out_(list_.end()) { } template<class Allocator> basic_multi_buffer<Allocator>:: -basic_multi_buffer(std::size_t limit) +basic_multi_buffer( + std::size_t limit) noexcept(default_nothrow) : max_(limit) , out_(list_.end()) { @@ -439,17 +485,20 @@ basic_multi_buffer(std::size_t limit) template<class Allocator> basic_multi_buffer<Allocator>:: -basic_multi_buffer(Allocator const& alloc) - : boost::empty_value< - base_alloc_type>(boost::empty_init_t(), alloc) +basic_multi_buffer( + Allocator const& alloc) noexcept + : boost::empty_value<base_alloc_type>( + boost::empty_init_t(), alloc) + , max_(alloc_traits::max_size(this->get())) , out_(list_.end()) { } template<class Allocator> basic_multi_buffer<Allocator>:: -basic_multi_buffer(std::size_t limit, - Allocator const& alloc) +basic_multi_buffer( + std::size_t limit, + Allocator const& alloc) noexcept : boost::empty_value< base_alloc_type>(boost::empty_init_t(), alloc) , max_(limit) @@ -459,9 +508,10 @@ basic_multi_buffer(std::size_t limit, template<class Allocator> basic_multi_buffer<Allocator>:: -basic_multi_buffer(basic_multi_buffer&& other) - : boost::empty_value< - base_alloc_type>(boost::empty_init_t(), std::move(other.get())) +basic_multi_buffer( + basic_multi_buffer&& other) noexcept + : boost::empty_value<base_alloc_type>( + boost::empty_init_t(), std::move(other.get())) , max_(other.max_) , in_size_(boost::exchange(other.in_size_, 0)) , in_pos_(boost::exchange(other.in_pos_, 0)) @@ -477,8 +527,9 @@ basic_multi_buffer(basic_multi_buffer&& other) template<class Allocator> basic_multi_buffer<Allocator>:: -basic_multi_buffer(basic_multi_buffer&& other, - Allocator const& alloc) +basic_multi_buffer( + basic_multi_buffer&& other, + Allocator const& alloc) : boost::empty_value< base_alloc_type>(boost::empty_init_t(), alloc) , max_(other.max_) @@ -487,33 +538,34 @@ basic_multi_buffer(basic_multi_buffer&& other, { out_ = list_.end(); copy_from(other); - other.reset(); - } - else - { - auto const at_end = - other.out_ == other.list_.end(); - list_ = std::move(other.list_); - out_ = at_end ? list_.end() : other.out_; - in_size_ = other.in_size_; - in_pos_ = other.in_pos_; - out_pos_ = other.out_pos_; - out_end_ = other.out_end_; - other.in_size_ = 0; - other.out_ = other.list_.end(); - other.in_pos_ = 0; - other.out_pos_ = 0; - other.out_end_ = 0; + other.clear(); + other.shrink_to_fit(); + return; } + + auto const at_end = + other.out_ == other.list_.end(); + list_ = std::move(other.list_); + out_ = at_end ? list_.end() : other.out_; + in_size_ = other.in_size_; + in_pos_ = other.in_pos_; + out_pos_ = other.out_pos_; + out_end_ = other.out_end_; + other.in_size_ = 0; + other.out_ = other.list_.end(); + other.in_pos_ = 0; + other.out_pos_ = 0; + other.out_end_ = 0; } template<class Allocator> basic_multi_buffer<Allocator>:: -basic_multi_buffer(basic_multi_buffer const& other) - : boost::empty_value< - base_alloc_type>(boost::empty_init_t(), alloc_traits:: - select_on_container_copy_construction( - other.get())) +basic_multi_buffer( + basic_multi_buffer const& other) + : boost::empty_value<base_alloc_type>( + boost::empty_init_t(), alloc_traits:: + select_on_container_copy_construction( + other.get())) , max_(other.max_) , out_(list_.end()) { @@ -522,10 +574,11 @@ basic_multi_buffer(basic_multi_buffer const& other) template<class Allocator> basic_multi_buffer<Allocator>:: -basic_multi_buffer(basic_multi_buffer const& other, - Allocator const& alloc) - : boost::empty_value< - base_alloc_type>(boost::empty_init_t(), alloc) +basic_multi_buffer( + basic_multi_buffer const& other, + Allocator const& alloc) + : boost::empty_value<base_alloc_type>( + boost::empty_init_t(), alloc) , max_(other.max_) , out_(list_.end()) { @@ -564,10 +617,9 @@ operator=(basic_multi_buffer&& other) -> { if(this == &other) return *this; - reset(); + clear(); max_ = other.max_; - move_assign(other, std::integral_constant<bool, - alloc_traits::propagate_on_container_move_assignment::value>{}); + move_assign(other, pocma{}); return *this; } @@ -579,8 +631,7 @@ basic_multi_buffer& { if(this == &other) return *this; - copy_assign(other, std::integral_constant<bool, - alloc_traits::propagate_on_container_copy_assignment::value>{}); + copy_assign(other, pocca{}); return *this; } @@ -592,16 +643,16 @@ operator=( basic_multi_buffer<OtherAlloc> const& other) -> basic_multi_buffer& { - reset(); - max_ = other.max_; copy_from(other); return *this; } +//------------------------------------------------------------------------------ + template<class Allocator> std::size_t basic_multi_buffer<Allocator>:: -capacity() const +capacity() const noexcept { auto pos = out_; if(pos == list_.end()) @@ -615,7 +666,7 @@ capacity() const template<class Allocator> auto basic_multi_buffer<Allocator>:: -data() const -> +data() const noexcept -> const_buffers_type { return const_buffers_type(*this); @@ -624,12 +675,190 @@ data() const -> template<class Allocator> auto basic_multi_buffer<Allocator>:: +data() noexcept -> + mutable_data_type +{ + return mutable_data_type(*this); +} + +template<class Allocator> +void +basic_multi_buffer<Allocator>:: +reserve(std::size_t n) +{ + // VFALCO The amount needs to be adjusted for + // the sizeof(element) plus padding + if(n > alloc_traits::max_size(this->get())) + BOOST_THROW_EXCEPTION(std::length_error( + "A basic_multi_buffer exceeded the allocator's maximum size")); + std::size_t total = in_size_; + if(n <= total) + return; + if(out_ != list_.end()) + { + total += out_->size() - out_pos_; + if(n <= total) + return; + for(auto it = out_;;) + { + if(++it == list_.end()) + break; + total += it->size(); + if(n <= total) + return; + } + } + BOOST_ASSERT(n > total); + (void)prepare(n - size()); +} + +template<class Allocator> +void +basic_multi_buffer<Allocator>:: +shrink_to_fit() +{ + // empty list + if(list_.empty()) + return; + + // zero readable bytes + if(in_size_ == 0) + { + destroy(list_); + list_.clear(); + out_ = list_.end(); + in_size_ = 0; + in_pos_ = 0; + out_pos_ = 0; + out_end_ = 0; + #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK + debug_check(); + #endif + return; + } + + // one or more unused output buffers + if(out_ != list_.end()) + { + if(out_ != list_.iterator_to(list_.back())) + { + // unused list + list_type extra; + extra.splice( + extra.end(), + list_, + std::next(out_), + list_.end()); + destroy(extra); + #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK + debug_check(); + #endif + } + + // unused out_ + BOOST_ASSERT(out_ == + list_.iterator_to(list_.back())); + if(out_pos_ == 0) + { + BOOST_ASSERT(out_ != list_.begin()); + auto& e = *out_; + list_.erase(out_); + out_ = list_.end(); + destroy(e); + out_end_ = 0; + #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK + debug_check(); + #endif + } + } + + auto const replace = + [&](iter pos, element& e) + { + auto it = + list_.insert(pos, e); + auto& e0 = *pos; + list_.erase(pos); + destroy(e0); + return it; + }; + + // partial last buffer + if(list_.size() > 1 && out_ != list_.end()) + { + BOOST_ASSERT(out_ == + list_.iterator_to(list_.back())); + BOOST_ASSERT(out_pos_ != 0); + auto& e = alloc(out_pos_); + std::memcpy( + e.data(), + out_->data(), + out_pos_); + replace(out_, e); + out_ = list_.end(); + out_pos_ = 0; + out_end_ = 0; + #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK + debug_check(); + #endif + } + + // partial first buffer + if(in_pos_ != 0) + { + if(out_ != list_.begin()) + { + auto const n = + list_.front().size() - in_pos_; + auto& e = alloc(n); + std::memcpy( + e.data(), + list_.front().data() + in_pos_, + n); + replace(list_.begin(), e); + in_pos_ = 0; + } + else + { + BOOST_ASSERT(list_.size() == 1); + BOOST_ASSERT(out_pos_ > in_pos_); + auto const n = out_pos_ - in_pos_; + auto& e = alloc(n); + std::memcpy( + e.data(), + list_.front().data() + in_pos_, + n); + replace(list_.begin(), e); + in_pos_ = 0; + out_ = list_.end(); + } + #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK + debug_check(); + #endif + } +} + +template<class Allocator> +void +basic_multi_buffer<Allocator>:: +clear() noexcept +{ + out_ = list_.begin(); + in_size_ = 0; + in_pos_ = 0; + out_pos_ = 0; + out_end_ = 0; +} + +template<class Allocator> +auto +basic_multi_buffer<Allocator>:: prepare(size_type n) -> mutable_buffers_type { - if(in_size_ + n > max_) + if(in_size_ > max_ || n > (max_ - in_size_)) BOOST_THROW_EXCEPTION(std::length_error{ - "dynamic buffer overflow"}); + "basic_multi_buffer too long"}); list_type reuse; std::size_t total = in_size_; // put all empty buffers on reuse list @@ -684,15 +913,7 @@ prepare(size_type n) -> BOOST_ASSERT(total <= max_); if(! reuse.empty() || n > 0) { - for(auto it = reuse.begin(); it != reuse.end();) - { - auto& e = *it++; - reuse.erase(list_.iterator_to(e)); - auto const len = sizeof(e) + e.size(); - alloc_traits::destroy(this->get(), &e); - alloc_traits::deallocate(this->get(), - reinterpret_cast<char*>(&e), len); - } + destroy(reuse); if(n > 0) { static auto const growth_factor = 2.0f; @@ -704,10 +925,7 @@ prepare(size_type n) -> in_size_ * growth_factor - in_size_), 512, n})); - auto& e = *reinterpret_cast<element*>(static_cast< - void*>(alloc_traits::allocate(this->get(), - sizeof(element) + size))); - alloc_traits::construct(this->get(), &e, size); + auto& e = alloc(size); list_.push_back(e); if(out_ == list_.end()) out_ = list_.iterator_to(e); @@ -723,7 +941,7 @@ prepare(size_type n) -> template<class Allocator> void basic_multi_buffer<Allocator>:: -commit(size_type n) +commit(size_type n) noexcept { if(list_.empty()) return; @@ -770,7 +988,7 @@ commit(size_type n) template<class Allocator> void basic_multi_buffer<Allocator>:: -consume(size_type n) +consume(size_type n) noexcept { if(list_.empty()) return; @@ -795,7 +1013,7 @@ consume(size_type n) auto& e = list_.front(); list_.erase(list_.iterator_to(e)); auto const len = sizeof(e) + e.size(); - alloc_traits::destroy(this->get(), &e); + e.~element(); alloc_traits::deallocate(this->get(), reinterpret_cast<char*>(&e), len); #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK @@ -836,72 +1054,23 @@ consume(size_type n) } template<class Allocator> -inline -void -basic_multi_buffer<Allocator>:: -delete_list() -{ - for(auto iter = list_.begin(); iter != list_.end();) - { - auto& e = *iter++; - auto const len = sizeof(e) + e.size(); - alloc_traits::destroy(this->get(), &e); - alloc_traits::deallocate(this->get(), - reinterpret_cast<char*>(&e), len); - } -} - -template<class Allocator> -inline -void -basic_multi_buffer<Allocator>:: -reset() -{ - delete_list(); - list_.clear(); - out_ = list_.end(); - in_size_ = 0; - in_pos_ = 0; - out_pos_ = 0; - out_end_ = 0; -} - -template<class Allocator> -template<class DynamicBuffer> -inline +template<class OtherAlloc> void basic_multi_buffer<Allocator>:: -copy_from(DynamicBuffer const& buffer) +copy_from(basic_multi_buffer<OtherAlloc> const& other) { - if(buffer.size() == 0) + clear(); + max_ = other.max_; + if(other.size() == 0) return; - using boost::asio::buffer_copy; - commit(buffer_copy( - prepare(buffer.size()), buffer.data())); + commit(net::buffer_copy( + prepare(other.size()), other.data())); } template<class Allocator> -inline void basic_multi_buffer<Allocator>:: -move_assign(basic_multi_buffer& other, std::false_type) -{ - if(this->get() != other.get()) - { - copy_from(other); - other.reset(); - } - else - { - move_assign(other, std::true_type{}); - } -} - -template<class Allocator> -inline -void -basic_multi_buffer<Allocator>:: -move_assign(basic_multi_buffer& other, std::true_type) +move_assign(basic_multi_buffer& other, std::true_type) noexcept { this->get() = std::move(other.get()); auto const at_end = @@ -913,6 +1082,7 @@ move_assign(basic_multi_buffer& other, std::true_type) in_pos_ = other.in_pos_; out_pos_ = other.out_pos_; out_end_ = other.out_end_; + max_ = other.max_; other.in_size_ = 0; other.out_ = other.list_.end(); @@ -922,45 +1092,55 @@ move_assign(basic_multi_buffer& other, std::true_type) } template<class Allocator> -inline +void +basic_multi_buffer<Allocator>:: +move_assign(basic_multi_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_multi_buffer<Allocator>:: copy_assign( basic_multi_buffer const& other, std::false_type) { - reset(); - max_ = other.max_; copy_from(other); } template<class Allocator> -inline void basic_multi_buffer<Allocator>:: copy_assign( basic_multi_buffer const& other, std::true_type) { - reset(); - max_ = other.max_; + clear(); this->get() = other.get(); copy_from(other); } template<class Allocator> -inline void basic_multi_buffer<Allocator>:: -swap(basic_multi_buffer& other) +swap(basic_multi_buffer& other) noexcept { swap(other, typename alloc_traits::propagate_on_container_swap{}); } template<class Allocator> -inline void basic_multi_buffer<Allocator>:: -swap(basic_multi_buffer& other, std::true_type) +swap(basic_multi_buffer& other, std::true_type) noexcept { using std::swap; auto const at_end0 = @@ -981,10 +1161,9 @@ swap(basic_multi_buffer& other, std::true_type) } template<class Allocator> -inline void basic_multi_buffer<Allocator>:: -swap(basic_multi_buffer& other, std::false_type) +swap(basic_multi_buffer& other, std::false_type) noexcept { BOOST_ASSERT(this->get() == other.get()); using std::swap; @@ -1008,7 +1187,7 @@ template<class Allocator> void swap( basic_multi_buffer<Allocator>& lhs, - basic_multi_buffer<Allocator>& rhs) + basic_multi_buffer<Allocator>& rhs) noexcept { lhs.swap(rhs); } @@ -1016,11 +1195,54 @@ swap( template<class Allocator> void basic_multi_buffer<Allocator>:: +destroy(list_type& list) noexcept +{ + for(auto it = list.begin(); + it != list.end();) + destroy(*it++); +} + +template<class Allocator> +void +basic_multi_buffer<Allocator>:: +destroy(const_iter it) +{ + auto& e = list_.erase(it); + destroy(e); +} + +template<class Allocator> +void +basic_multi_buffer<Allocator>:: +destroy(element& e) +{ + auto const len = sizeof(e) + e.size(); + e.~element(); + alloc_traits::deallocate(this->get(), + reinterpret_cast<char*>(&e), len); +} + +template<class Allocator> +auto +basic_multi_buffer<Allocator>:: +alloc(std::size_t size) -> + element& +{ + if(size > alloc_traits::max_size(this->get())) + BOOST_THROW_EXCEPTION(std::length_error( + "A basic_multi_buffer exceeded the allocator's maximum size")); + return *::new(alloc_traits::allocate( + this->get(), + sizeof(element) + size)) element(size); +} + +template<class Allocator> +void +basic_multi_buffer<Allocator>:: debug_check() const { #ifndef NDEBUG - using boost::asio::buffer_size; - BOOST_ASSERT(buffer_size(data()) == in_size_); + BOOST_ASSERT(buffer_bytes(data()) == in_size_); if(list_.empty()) { BOOST_ASSERT(in_pos_ == 0); diff --git a/boost/beast/core/impl/read_size.ipp b/boost/beast/core/impl/read_size.hpp index fa52571e09..1896c014b8 100644 --- a/boost/beast/core/impl/read_size.ipp +++ b/boost/beast/core/impl/read_size.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -7,9 +7,10 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_IMPL_READ_SIZE_IPP -#define BOOST_BEAST_IMPL_READ_SIZE_IPP +#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> @@ -43,21 +44,20 @@ read_size(DynamicBuffer& buffer, std::size_t max_size, std::false_type) { static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); + 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)); + 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> -inline std::size_t read_size( DynamicBuffer& buffer, std::size_t max_size) diff --git a/boost/beast/core/impl/saved_handler.hpp b/boost/beast/core/impl/saved_handler.hpp new file mode 100644 index 0000000000..a2642f59da --- /dev/null +++ b/boost/beast/core/impl/saved_handler.hpp @@ -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 diff --git a/boost/beast/core/impl/saved_handler.ipp b/boost/beast/core/impl/saved_handler.ipp new file mode 100644 index 0000000000..30ecbc8e15 --- /dev/null +++ b/boost/beast/core/impl/saved_handler.ipp @@ -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 diff --git a/boost/beast/core/impl/static_buffer.hpp b/boost/beast/core/impl/static_buffer.hpp new file mode 100644 index 0000000000..dee13bfbe5 --- /dev/null +++ b/boost/beast/core/impl/static_buffer.hpp @@ -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 diff --git a/boost/beast/core/impl/static_buffer.ipp b/boost/beast/core/impl/static_buffer.ipp index bd498c97a1..c26ff429b8 100644 --- a/boost/beast/core/impl/static_buffer.ipp +++ b/boost/beast/core/impl/static_buffer.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -10,6 +10,7 @@ #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> @@ -21,148 +22,111 @@ namespace boost { namespace beast { -inline static_buffer_base:: -static_buffer_base(void* p, std::size_t size) +static_buffer_base( + void* p, std::size_t size) noexcept : begin_(static_cast<char*>(p)) , capacity_(size) { } -inline +void +static_buffer_base:: +clear() noexcept +{ + in_off_ = 0; + in_size_ = 0; + out_size_ = 0; +} + auto static_buffer_base:: -data() const -> +data() const noexcept -> const_buffers_type { - using boost::asio::const_buffer; - const_buffers_type result; if(in_off_ + in_size_ <= capacity_) - { - result[0] = const_buffer{begin_ + in_off_, in_size_}; - result[1] = const_buffer{begin_, 0}; - } - else - { - result[0] = const_buffer{begin_ + in_off_, capacity_ - in_off_}; - result[1] = const_buffer{begin_, in_size_ - (capacity_ - in_off_)}; - } - return result; + 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_)}}; } -inline auto static_buffer_base:: -mutable_data() -> - mutable_buffers_type +data() noexcept -> + mutable_data_type { - using boost::asio::mutable_buffer; - mutable_buffers_type result; if(in_off_ + in_size_ <= capacity_) - { - result[0] = mutable_buffer{begin_ + in_off_, in_size_}; - result[1] = mutable_buffer{begin_, 0}; - } - else - { - result[0] = mutable_buffer{begin_ + in_off_, capacity_ - in_off_}; - result[1] = mutable_buffer{begin_, in_size_ - (capacity_ - in_off_)}; - } - return result; + 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_)}}; } -inline auto static_buffer_base:: -prepare(std::size_t size) -> +prepare(std::size_t n) -> mutable_buffers_type { - using boost::asio::mutable_buffer; - if(size > capacity_ - in_size_) + using net::mutable_buffer; + if(n > capacity_ - in_size_) BOOST_THROW_EXCEPTION(std::length_error{ - "buffer overflow"}); - out_size_ = size; - auto const out_off = (in_off_ + in_size_) % capacity_; - mutable_buffers_type result; + "static_buffer overflow"}); + out_size_ = n; + auto const out_off = + (in_off_ + in_size_) % capacity_; if(out_off + out_size_ <= capacity_ ) - { - result[0] = mutable_buffer{begin_ + out_off, out_size_}; - result[1] = mutable_buffer{begin_, 0}; - } - else - { - result[0] = mutable_buffer{begin_ + out_off, capacity_ - out_off}; - result[1] = mutable_buffer{begin_, out_size_ - (capacity_ - out_off)}; - } - return result; + 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)}}; } -inline void static_buffer_base:: -commit(std::size_t size) +commit(std::size_t n) noexcept { - in_size_ += (std::min)(size, out_size_); + in_size_ += (std::min)(n, out_size_); out_size_ = 0; } -inline void static_buffer_base:: -consume(std::size_t size) +consume(std::size_t n) noexcept { - if(size < in_size_) + if(n < in_size_) { - in_off_ = (in_off_ + size) % capacity_; - in_size_ -= 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 buffesr. + // algorithms optimized for larger buffers. in_off_ = 0; in_size_ = 0; } } -inline -void -static_buffer_base:: -reset(void* p, std::size_t size) -{ - begin_ = static_cast<char*>(p); - capacity_ = size; - in_off_ = 0; - in_size_ = 0; - out_size_ = 0; -} - -//------------------------------------------------------------------------------ - -template<std::size_t N> -static_buffer<N>:: -static_buffer(static_buffer const& other) - : static_buffer_base(buf_, N) -{ - using boost::asio::buffer_copy; - this->commit(buffer_copy( - this->prepare(other.size()), other.data())); -} - -template<std::size_t N> -auto -static_buffer<N>:: -operator=(static_buffer const& other) -> - static_buffer<N>& -{ - using boost::asio::buffer_copy; - this->consume(this->size()); - this->commit(buffer_copy( - this->prepare(other.size()), other.data())); - return *this; -} - } // beast } // boost diff --git a/boost/beast/core/impl/static_string.ipp b/boost/beast/core/impl/static_string.hpp index 29571dfeee..c668b837fa 100644 --- a/boost/beast/core/impl/static_string.ipp +++ b/boost/beast/core/impl/static_string.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -7,8 +7,8 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_IMPL_STATIC_STRING_IPP -#define BOOST_BEAST_IMPL_STATIC_STRING_IPP +#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> @@ -65,7 +65,12 @@ template<std::size_t N, class CharT, class Traits> static_string<N, CharT, Traits>:: static_string(CharT const* s) { - assign(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> @@ -120,6 +125,21 @@ static_string(T const& t, size_type pos, size_type n) 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& { @@ -139,7 +159,9 @@ assign(static_string const& str) -> static_string& { n_ = str.n_; - Traits::copy(&s_[0], &str.s_[0], n_ + 1); + auto const n = n_ + 1; + BOOST_BEAST_ASSUME(n != 0); + Traits::copy(&s_[0], &str.s_[0], n); return *this; } @@ -463,6 +485,8 @@ 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(); } @@ -593,7 +617,7 @@ to_static_string(Integer x, std::false_type) } // detail -template<class Integer> +template<class Integer, class> static_string<detail::max_digits(sizeof(Integer))> to_static_string(Integer x) { diff --git a/boost/beast/core/impl/string_param.ipp b/boost/beast/core/impl/string_param.hpp index a60771cc12..9d9278382a 100644 --- a/boost/beast/core/impl/string_param.ipp +++ b/boost/beast/core/impl/string_param.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// 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) @@ -7,8 +7,8 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_IMPL_STRING_PARAM_IPP -#define BOOST_BEAST_IMPL_STRING_PARAM_IPP +#ifndef BOOST_BEAST_IMPL_STRING_PARAM_HPP +#define BOOST_BEAST_IMPL_STRING_PARAM_HPP namespace boost { namespace beast { |