Add redirect_error.
diff --git a/asio/include/asio.hpp b/asio/include/asio.hpp
index ae15132..cb46bde 100644
--- a/asio/include/asio.hpp
+++ b/asio/include/asio.hpp
@@ -108,6 +108,7 @@
#include "asio/read.hpp"
#include "asio/read_at.hpp"
#include "asio/read_until.hpp"
+#include "asio/redirect_error.hpp"
#include "asio/seq_packet_socket_service.hpp"
#include "asio/serial_port.hpp"
#include "asio/serial_port_base.hpp"
diff --git a/asio/include/asio/impl/await.hpp b/asio/include/asio/impl/await.hpp
index 3630875..a253a1e 100644
--- a/asio/include/asio/impl/await.hpp
+++ b/asio/include/asio/impl/await.hpp
@@ -396,7 +396,7 @@
void operator()(std::exception_ptr ex)
{
awaiter_ptr ptr(std::move(awaiter_));
- if (ec)
+ if (ex)
awaitee_->set_exception(ex);
else
awaitee_->return_void();
@@ -415,10 +415,7 @@
void operator()(T t)
{
awaiter_ptr ptr(std::move(awaiter_));
- if (ec)
- awaitee_->set_exception(ex);
- else
- awaitee_->return_value(std::forward<T>(t));
+ awaitee_->return_value(std::forward<T>(t));
awaitee_->wake_caller();
ptr->rethrow_exception();
}
@@ -453,7 +450,7 @@
void operator()(std::exception_ptr ex, T t)
{
awaiter_ptr ptr(std::move(awaiter_));
- if (ec)
+ if (ex)
awaitee_->set_exception(ex);
else
awaitee_->return_value(std::forward<T>(t));
diff --git a/asio/include/asio/impl/redirect_error.hpp b/asio/include/asio/impl/redirect_error.hpp
new file mode 100644
index 0000000..45a3c4f
--- /dev/null
+++ b/asio/include/asio/impl/redirect_error.hpp
@@ -0,0 +1,256 @@
+//
+// impl/redirect_error.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_IMPL_REDIRECT_ERROR_HPP
+#define ASIO_IMPL_REDIRECT_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/async_result.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/variadic_templates.hpp"
+#include "asio/handler_type.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+ // Class to adapt a redirect_error_t as a completion handler.
+ template <typename Handler>
+ class redirect_error_handler
+ {
+ public:
+ template <typename CompletionToken>
+ redirect_error_handler(redirect_error_t<CompletionToken> e)
+ : ec_(e.ec_),
+ handler_(ASIO_MOVE_CAST(CompletionToken)(e.token_))
+ {
+ }
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+ template <typename... Args>
+ void operator()(ASIO_MOVE_ARG(Args)... args)
+ {
+ handler_(ASIO_MOVE_CAST(Args)(args)...);
+ }
+
+ template <typename... Args>
+ void operator()(const asio::error_code& ec,
+ ASIO_MOVE_ARG(Args)... args)
+ {
+ ec_ = ec;
+ handler_(ASIO_MOVE_CAST(Args)(args)...);
+ }
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+ void operator()()
+ {
+ handler_();
+ }
+
+ void operator()(const asio::error_code& ec)
+ {
+ ec_ = ec;
+ handler_();
+ }
+
+#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \
+ template <ASIO_VARIADIC_TPARAMS(n)> \
+ void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \
+ { \
+ handler_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+ } \
+ \
+ template <ASIO_VARIADIC_TPARAMS(n)> \
+ void operator()(const asio::error_code& ec, \
+ ASIO_VARIADIC_MOVE_PARAMS(n)) \
+ { \
+ ec_ = ec; \
+ handler_(ASIO_VARIADIC_MOVE_ARGS(n)); \
+ } \
+ /**/
+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF)
+#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+ //private:
+ asio::error_code& ec_;
+ Handler handler_;
+ };
+
+ template <typename Handler>
+ inline void* asio_handler_allocate(std::size_t size,
+ redirect_error_handler<Handler>* this_handler)
+ {
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+ }
+
+ template <typename Handler>
+ inline void* asio_handler_deallocate(std::size_t size,
+ redirect_error_handler<Handler>* this_handler)
+ {
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+ }
+
+ template <typename Handler>
+ inline bool asio_handler_is_continuation(
+ redirect_error_handler<Handler>* this_handler)
+ {
+ return asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
+ }
+
+ template <typename Function, typename Handler>
+ inline void asio_handler_invoke(Function& function,
+ redirect_error_handler<Handler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+
+ template <typename Function, typename Handler>
+ inline void asio_handler_invoke(const Function& function,
+ redirect_error_handler<Handler>* this_handler)
+ {
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+ }
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+template <typename CompletionToken, typename Signature>
+struct handler_type<redirect_error_t<CompletionToken>, Signature>
+{
+ typedef detail::redirect_error_handler<
+ typename handler_type<CompletionToken,
+ Signature>::type> type;
+};
+
+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename CompletionToken, typename R, typename... Args>
+struct handler_type<redirect_error_t<CompletionToken>,
+ R(asio::error_code, Args...)>
+{
+ typedef detail::redirect_error_handler<
+ typename handler_type<CompletionToken,
+ R(Args...)>::type> type;
+};
+
+template <typename CompletionToken, typename R, typename... Args>
+struct handler_type<redirect_error_t<CompletionToken>,
+ R(const asio::error_code&, Args...)>
+{
+ typedef detail::redirect_error_handler<
+ typename handler_type<CompletionToken,
+ R(Args...)>::type> type;
+};
+
+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename CompletionToken, typename R>
+struct handler_type<redirect_error_t<CompletionToken>,
+ R(asio::error_code)>
+{
+ typedef detail::redirect_error_handler<
+ typename handler_type<CompletionToken,
+ R()>::type> type;
+};
+
+template <typename CompletionToken, typename R>
+struct handler_type<redirect_error_t<CompletionToken>,
+ R(const asio::error_code&)>
+{
+ typedef detail::redirect_error_handler<
+ typename handler_type<CompletionToken,
+ R()>::type> type;
+};
+
+#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \
+ template <typename CompletionToken, \
+ typename R, ASIO_VARIADIC_TPARAMS(n)> \
+ struct handler_type<redirect_error_t<CompletionToken>, \
+ R(asio::error_code, ASIO_VARIADIC_TARGS(n))> \
+ { \
+ typedef detail::redirect_error_handler< \
+ typename handler_type<CompletionToken, \
+ R(ASIO_VARIADIC_TARGS(n))>::type> type; \
+ }; \
+ \
+ template <typename CompletionToken, \
+ typename R, ASIO_VARIADIC_TPARAMS(n)> \
+ struct handler_type<redirect_error_t<CompletionToken>, \
+ R(const asio::error_code&, ASIO_VARIADIC_TARGS(n))> \
+ { \
+ typedef detail::redirect_error_handler< \
+ typename handler_type<CompletionToken, \
+ R(ASIO_VARIADIC_TARGS(n))>::type> type; \
+ }; \
+ /**/
+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF)
+#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF
+
+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename Handler>
+struct async_result<detail::redirect_error_handler<Handler> >
+ : async_result<Handler>
+{
+ explicit async_result(detail::redirect_error_handler<Handler>& h)
+ : async_result<Handler>(h.handler_)
+ {
+ }
+};
+
+template <typename Handler, typename Executor>
+struct associated_executor<detail::redirect_error_handler<Handler>, Executor>
+{
+ typedef typename associated_executor<Handler, Executor>::type type;
+
+ static type get(const detail::redirect_error_handler<Handler>& h,
+ const Executor& ex = Executor()) ASIO_NOEXCEPT
+ {
+ return associated_executor<Handler, Executor>::get(h.handler_, ex);
+ }
+};
+
+template <typename Handler, typename Allocator>
+struct associated_allocator<detail::redirect_error_handler<Handler>, Allocator>
+{
+ typedef typename associated_allocator<Handler, Allocator>::type type;
+
+ static type get(const detail::redirect_error_handler<Handler>& h,
+ const Allocator& a = Allocator()) ASIO_NOEXCEPT
+ {
+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+ }
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_IMPL_REDIRECT_ERROR_HPP
diff --git a/asio/include/asio/redirect_error.hpp b/asio/include/asio/redirect_error.hpp
new file mode 100644
index 0000000..b2da15c
--- /dev/null
+++ b/asio/include/asio/redirect_error.hpp
@@ -0,0 +1,63 @@
+//
+// redirect_error.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_REDIRECT_ERROR_HPP
+#define ASIO_REDIRECT_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+/// Completion token type used to specify that an error produced by an
+/// asynchronous operation is captured to an error_code variable.
+/**
+ * The redirect_error_t class is used to indicate that any error_code produced
+ * by an asynchronous operation is captured to a specified variable.
+ */
+template <typename CompletionToken>
+class redirect_error_t
+{
+public:
+ /// Constructor.
+ template <typename T>
+ redirect_error_t(ASIO_MOVE_ARG(T) completion_token, error_code& ec)
+ : token_(ASIO_MOVE_CAST(T)(completion_token)),
+ ec_(ec)
+ {
+ }
+
+//private:
+ CompletionToken token_;
+ error_code& ec_;
+};
+
+/// Create a completion token to capture error_code values to a variable.
+template <typename CompletionToken>
+inline redirect_error_t<typename decay<CompletionToken>::type>
+redirect_error(CompletionToken&& completion_token, error_code& ec)
+{
+ return redirect_error_t<typename decay<CompletionToken>::type>(
+ ASIO_MOVE_CAST(CompletionToken)(completion_token), ec);
+}
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/impl/redirect_error.hpp"
+
+#endif // ASIO_REDIRECT_ERROR_HPP
diff --git a/asio/src/examples/cpp1z/await/chat_server.cpp b/asio/src/examples/cpp1z/await/chat_server.cpp
new file mode 100644
index 0000000..88afb75
--- /dev/null
+++ b/asio/src/examples/cpp1z/await/chat_server.cpp
@@ -0,0 +1,209 @@
+//
+// chat_server.cpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff 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)
+//
+
+#include <cstdlib>
+#include <deque>
+#include <iostream>
+#include <list>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <asio/await.hpp>
+#include <asio/detached.hpp>
+#include <asio/redirect_error.hpp>
+#include <asio/signal_set.hpp>
+#include <asio/ts/networking.hpp>
+
+using asio::ip::tcp;
+
+//----------------------------------------------------------------------
+
+class chat_participant
+{
+public:
+ virtual ~chat_participant() {}
+ virtual void deliver(const std::string& msg) = 0;
+};
+
+typedef std::shared_ptr<chat_participant> chat_participant_ptr;
+
+//----------------------------------------------------------------------
+
+class chat_room
+{
+public:
+ void join(chat_participant_ptr participant)
+ {
+ participants_.insert(participant);
+ for (auto msg: recent_msgs_)
+ participant->deliver(msg);
+ }
+
+ void leave(chat_participant_ptr participant)
+ {
+ participants_.erase(participant);
+ }
+
+ void deliver(const std::string& msg)
+ {
+ recent_msgs_.push_back(msg);
+ while (recent_msgs_.size() > max_recent_msgs)
+ recent_msgs_.pop_front();
+
+ for (auto participant: participants_)
+ participant->deliver(msg);
+ }
+
+private:
+ std::set<chat_participant_ptr> participants_;
+ enum { max_recent_msgs = 100 };
+ std::deque<std::string> recent_msgs_;
+};
+
+//----------------------------------------------------------------------
+
+class chat_session
+ : public chat_participant,
+ public std::enable_shared_from_this<chat_session>
+{
+public:
+ chat_session(tcp::socket socket, chat_room& room)
+ : socket_(std::move(socket)),
+ timer_(socket_.get_executor().context()),
+ room_(room)
+ {
+ timer_.expires_at(std::chrono::steady_clock::time_point::max());
+ }
+
+ void start()
+ {
+ room_.join(shared_from_this());
+
+ asio::spawn(socket_.get_executor(),
+ &chat_session::reader, shared_from_this(), asio::detached);
+
+ asio::spawn(socket_.get_executor(),
+ &chat_session::writer, shared_from_this(), asio::detached);
+ }
+
+ void deliver(const std::string& msg)
+ {
+ write_msgs_.push_back(msg);
+ timer_.cancel_one();
+ }
+
+private:
+ asio::awaitable<void> reader(asio::await_context ctx)
+ {
+ try
+ {
+ for (std::string read_msg;;)
+ {
+ std::size_t n = co_await asio::async_read_until(socket_,
+ asio::dynamic_buffer(read_msg, 1024), "\n", ctx);
+
+ room_.deliver(read_msg.substr(0, n));
+ read_msg.erase(0, n);
+ }
+ }
+ catch (std::exception&)
+ {
+ stop();
+ }
+ }
+
+ asio::awaitable<void> writer(asio::await_context ctx)
+ {
+ try
+ {
+ while (socket_.is_open())
+ {
+ if (write_msgs_.empty())
+ {
+ asio::error_code ec;
+ co_await timer_.async_wait(asio::redirect_error(ctx, ec));
+ }
+ else
+ {
+ co_await asio::async_write(socket_,
+ asio::buffer(write_msgs_.front()), ctx);
+ write_msgs_.pop_front();
+ }
+ }
+ }
+ catch (std::exception&)
+ {
+ stop();
+ }
+ }
+
+ void stop()
+ {
+ room_.leave(shared_from_this());
+ socket_.close();
+ timer_.cancel();
+ }
+
+ tcp::socket socket_;
+ asio::steady_timer timer_;
+ chat_room& room_;
+ std::deque<std::string> write_msgs_;
+};
+
+//----------------------------------------------------------------------
+
+asio::awaitable<void> listener(tcp::acceptor acceptor, asio::await_context ctx)
+{
+ chat_room room;
+
+ for (;;)
+ {
+ std::make_shared<chat_session>(
+ co_await acceptor.async_accept(ctx),
+ room
+ )->start();
+ }
+}
+
+//----------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc < 2)
+ {
+ std::cerr << "Usage: chat_server <port> [<port> ...]\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ for (int i = 1; i < argc; ++i)
+ {
+ unsigned short port = std::atoi(argv[i]);
+ asio::spawn(io_context, listener,
+ tcp::acceptor(io_context, {tcp::v4(), port}),
+ asio::detached);
+ }
+
+ asio::signal_set signals(io_context, SIGINT, SIGTERM);
+ signals.async_wait([&](auto, auto){ io_context.stop(); });
+
+ io_context.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}