summaryrefslogtreecommitdiff
path: root/boost/beast/core/impl
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/core/impl')
-rw-r--r--boost/beast/core/impl/async_base.hpp156
-rw-r--r--boost/beast/core/impl/basic_stream.hpp995
-rw-r--r--boost/beast/core/impl/buffered_read_stream.hpp242
-rw-r--r--boost/beast/core/impl/buffered_read_stream.ipp261
-rw-r--r--boost/beast/core/impl/buffers_adaptor.hpp (renamed from boost/beast/core/impl/buffers_adapter.ipp)363
-rw-r--r--boost/beast/core/impl/buffers_cat.hpp443
-rw-r--r--boost/beast/core/impl/buffers_cat.ipp389
-rw-r--r--boost/beast/core/impl/buffers_prefix.hpp326
-rw-r--r--boost/beast/core/impl/buffers_prefix.ipp277
-rw-r--r--boost/beast/core/impl/buffers_suffix.hpp (renamed from boost/beast/core/impl/buffers_suffix.ipp)112
-rw-r--r--boost/beast/core/impl/error.hpp44
-rw-r--r--boost/beast/core/impl/error.ipp99
-rw-r--r--boost/beast/core/impl/file_posix.ipp164
-rw-r--r--boost/beast/core/impl/file_stdio.ipp123
-rw-r--r--boost/beast/core/impl/file_win32.ipp61
-rw-r--r--boost/beast/core/impl/flat_buffer.hpp (renamed from boost/beast/core/impl/flat_buffer.ipp)303
-rw-r--r--boost/beast/core/impl/flat_static_buffer.hpp43
-rw-r--r--boost/beast/core/impl/flat_static_buffer.ipp99
-rw-r--r--boost/beast/core/impl/flat_stream.hpp276
-rw-r--r--boost/beast/core/impl/handler_ptr.hpp (renamed from boost/beast/core/impl/handler_ptr.ipp)57
-rw-r--r--boost/beast/core/impl/multi_buffer.hpp (renamed from boost/beast/core/impl/multi_buffer.ipp)748
-rw-r--r--boost/beast/core/impl/read_size.hpp (renamed from boost/beast/core/impl/read_size.ipp)18
-rw-r--r--boost/beast/core/impl/saved_handler.hpp151
-rw-r--r--boost/beast/core/impl/saved_handler.ipp76
-rw-r--r--boost/beast/core/impl/static_buffer.hpp50
-rw-r--r--boost/beast/core/impl/static_buffer.ipp156
-rw-r--r--boost/beast/core/impl/static_string.hpp (renamed from boost/beast/core/impl/static_string.ipp)36
-rw-r--r--boost/beast/core/impl/string_param.hpp (renamed from boost/beast/core/impl/string_param.ipp)6
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 {