Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r84313 - in trunk: boost/asio boost/asio/impl libs/asio/doc libs/asio/example/cpp11/futures
From: chris_at_[hidden]
Date: 2013-05-16 22:35:09


Author: chris_kohlhoff
Date: 2013-05-16 22:35:08 EDT (Thu, 16 May 2013)
New Revision: 84313
URL: http://svn.boost.org/trac/boost/changeset/84313

Log:
Add the asio::use_future special value, which adds first-class support
for returning a C++11 std::future from an asynchronous operation's
initiating function.

To use asio::use_future, pass it to an asynchronous operation instead of
a normal completion handler. For example:

  std::future<std::size_t> length =
    my_socket.async_read_some(my_buffer, asio::use_future);

Where a completion handler signature has the form:

  void handler(error_code ec, result_type result);

the initiating function returns a std::future templated on result_type.
In the above example, this is std::size_t. If the asynchronous operation
fails, the error_code is converted into a system_error exception and
passed back to the caller through the future.

Where a completion handler signature has the form:

  void handler(error_code ec);

the initiating function returns std::future<void>. As above, an error
is passed back in the future as a system_error exception.

Added:
   trunk/boost/asio/impl/use_future.hpp (contents, props changed)
   trunk/boost/asio/use_future.hpp (contents, props changed)
   trunk/libs/asio/example/cpp11/futures/
   trunk/libs/asio/example/cpp11/futures/Jamfile (contents, props changed)
   trunk/libs/asio/example/cpp11/futures/Jamfile.v2 (contents, props changed)
   trunk/libs/asio/example/cpp11/futures/daytime_client.cpp (contents, props changed)
Text files modified:
   trunk/libs/asio/doc/Jamfile.v2 | 2 +-
   trunk/libs/asio/doc/examples.qbk | 8 ++++++++
   2 files changed, 9 insertions(+), 1 deletions(-)

Added: trunk/boost/asio/impl/use_future.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/impl/use_future.hpp 2013-05-16 22:35:08 EDT (Thu, 16 May 2013)
@@ -0,0 +1,174 @@
+//
+// impl/use_future.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2012 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 BOOST_ASIO_IMPL_USE_FUTURE_HPP
+#define BOOST_ASIO_IMPL_USE_FUTURE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <future>
+#include <boost/asio/async_result.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/asio/handler_type.hpp>
+#include <boost/system/system_error.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+ // Completion handler to adapt a promise as a completion handler.
+ template <typename T>
+ class promise_handler
+ {
+ public:
+ // Construct from use_future special value.
+ template <typename Allocator>
+ promise_handler(use_future_t<Allocator> uf)
+ : promise_(std::allocate_shared<std::promise<T> >(
+ uf.get_allocator(), std::allocator_arg, uf.get_allocator()))
+ {
+ }
+
+ void operator()(T t)
+ {
+ promise_->set_value(t);
+ }
+
+ void operator()(const boost::system::error_code& ec, T t)
+ {
+ if (ec)
+ promise_->set_exception(
+ std::make_exception_ptr(
+ boost::system::system_error(ec)));
+ else
+ promise_->set_value(t);
+ }
+
+ //private:
+ std::shared_ptr<std::promise<T> > promise_;
+ };
+
+ // Completion handler to adapt a void promise as a completion handler.
+ template <>
+ class promise_handler<void>
+ {
+ public:
+ // Construct from use_future special value. Used during rebinding.
+ template <typename Allocator>
+ promise_handler(use_future_t<Allocator> uf)
+ : promise_(std::allocate_shared<std::promise<void> >(
+ uf.get_allocator(), std::allocator_arg, uf.get_allocator()))
+ {
+ }
+
+ void operator()()
+ {
+ promise_->set_value();
+ }
+
+ void operator()(const boost::system::error_code& ec)
+ {
+ if (ec)
+ promise_->set_exception(
+ std::make_exception_ptr(
+ boost::system::system_error(ec)));
+ else
+ promise_->set_value();
+ }
+
+ //private:
+ std::shared_ptr<std::promise<void> > promise_;
+ };
+
+ // Ensure any exceptions thrown from the handler are propagated back to the
+ // caller via the future.
+ template <typename Function, typename T>
+ void asio_handler_invoke(Function f, promise_handler<T>* h)
+ {
+ std::shared_ptr<std::promise<T> > p(h->promise_);
+ try
+ {
+ f();
+ }
+ catch (...)
+ {
+ p->set_exception(std::current_exception());
+ }
+ }
+
+} // namespace detail
+
+#if !defined(GENERATING_DOCUMENTATION)
+
+// Handler traits specialisation for promise_handler.
+template <typename T>
+class async_result<detail::promise_handler<T> >
+{
+public:
+ // The initiating function will return a future.
+ typedef std::future<T> type;
+
+ // Constructor creates a new promise for the async operation, and obtains the
+ // corresponding future.
+ explicit async_result(detail::promise_handler<T>& h)
+ {
+ value_ = h.promise_->get_future();
+ }
+
+ // Obtain the future to be returned from the initiating function.
+ type get() { return std::move(value_); }
+
+private:
+ type value_;
+};
+
+// Handler type specialisation for use_future.
+template <typename Allocator, typename ReturnType>
+struct handler_type<use_future_t<Allocator>, ReturnType()>
+{
+ typedef detail::promise_handler<void> type;
+};
+
+// Handler type specialisation for use_future.
+template <typename Allocator, typename ReturnType, typename Arg1>
+struct handler_type<use_future_t<Allocator>, ReturnType(Arg1)>
+{
+ typedef detail::promise_handler<Arg1> type;
+};
+
+// Handler type specialisation for use_future.
+template <typename Allocator, typename ReturnType>
+struct handler_type<use_future_t<Allocator>,
+ ReturnType(boost::system::error_code)>
+{
+ typedef detail::promise_handler<void> type;
+};
+
+// Handler type specialisation for use_future.
+template <typename Allocator, typename ReturnType, typename Arg2>
+struct handler_type<use_future_t<Allocator>,
+ ReturnType(boost::system::error_code, Arg2)>
+{
+ typedef detail::promise_handler<Arg2> type;
+};
+
+#endif // !defined(GENERATING_DOCUMENTATION)
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_IMPL_USE_FUTURE_HPP

Added: trunk/boost/asio/use_future.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/asio/use_future.hpp 2013-05-16 22:35:08 EDT (Thu, 16 May 2013)
@@ -0,0 +1,66 @@
+//
+// use_future.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2012 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 BOOST_ASIO_USE_FUTURE_HPP
+#define BOOST_ASIO_USE_FUTURE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <memory>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+template <typename Allocator = std::allocator<void> >
+class use_future_t
+{
+public:
+ typedef Allocator allocator_type;
+
+ constexpr use_future_t()
+ {
+ }
+
+ explicit use_future_t(const Allocator& allocator)
+ : allocator_(allocator)
+ {
+ }
+
+ template <typename OtherAllocator>
+ use_future_t<OtherAllocator> operator[](const OtherAllocator& allocator) const
+ {
+ return use_future_t<OtherAllocator>(allocator);
+ }
+
+ allocator_type get_allocator() const
+ {
+ return allocator_;
+ }
+
+private:
+ Allocator allocator_;
+};
+
+// A special value, similar to std::nothrow.
+constexpr use_future_t<> use_future;
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/impl/use_future.hpp>
+
+#endif // BOOST_ASIO_USE_FUTURE_HPP

Modified: trunk/libs/asio/doc/Jamfile.v2
==============================================================================
--- trunk/libs/asio/doc/Jamfile.v2 (original)
+++ trunk/libs/asio/doc/Jamfile.v2 2013-05-16 22:35:08 EDT (Thu, 16 May 2013)
@@ -31,7 +31,7 @@
   cpp03/iostreams cpp03/local cpp03/multicast cpp03/nonblocking cpp03/porthopper
   cpp03/serialization cpp03/services cpp03/socks4 cpp03/spawn cpp03/ssl
   cpp03/timeouts cpp03/timers cpp03/windows cpp11/allocaton cpp11/buffers
- cpp11/chat cpp11/echo cpp11/http/server cpp11/spawn ;
+ cpp11/chat cpp11/echo cpp11/futures cpp11/http/server cpp11/spawn ;
 
 for local l in $(example-names)
 {

Modified: trunk/libs/asio/doc/examples.qbk
==============================================================================
--- trunk/libs/asio/doc/examples.qbk (original)
+++ trunk/libs/asio/doc/examples.qbk 2013-05-16 22:35:08 EDT (Thu, 16 May 2013)
@@ -369,6 +369,14 @@
 * [@boost_asio/example/cpp11/echo/blocking_udp_echo_server.cpp]
 
 
+[heading Futures]
+
+This example demonstrates how to use std::future in conjunction with
+Boost.Asio's asynchronous operations.
+
+* [@boost_asio/example/cpp11/futures/daytime_client.cpp]
+
+
 [heading HTTP Server]
 
 This example illustrates the use of asio in a simple single-threaded server

Added: trunk/libs/asio/example/cpp11/futures/Jamfile
==============================================================================
--- (empty file)
+++ trunk/libs/asio/example/cpp11/futures/Jamfile 2013-05-16 22:35:08 EDT (Thu, 16 May 2013)
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2003-2012 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)
+#
+
+subproject libs/asio/example/buffers ;
+
+project boost : $(BOOST_ROOT) ;
+
+if $(UNIX)
+{
+ switch $(JAMUNAME)
+ {
+ case SunOS* :
+ {
+ SOCKET_LIBS = <find-library>socket <find-library>nsl ;
+ }
+ }
+}
+
+exe server
+ : <lib>@boost/libs/system/build/boost_system
+ daytime_client.cpp
+ : <include>$(BOOST_ROOT)
+ <include>../../../..
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <mingw><*><find-library>ws2_32
+ <mingw><*><find-library>mswsock
+ $(SOCKET_LIBS)
+ ;

Added: trunk/libs/asio/example/cpp11/futures/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/asio/example/cpp11/futures/Jamfile.v2 2013-05-16 22:35:08 EDT (Thu, 16 May 2013)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2003-2012 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)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+else if [ os.name ] = HPUX
+{
+ lib ipv6 ;
+}
+
+exe server
+ : daytime_client.cpp
+ /boost/system//boost_system
+ : <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT:<define>_WIN32_WINNT=0x0501
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ <os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
+ <os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
+ <os>HPUX:<library>ipv6
+ ;

Added: trunk/libs/asio/example/cpp11/futures/daytime_client.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/example/cpp11/futures/daytime_client.cpp 2013-05-16 22:35:08 EDT (Thu, 16 May 2013)
@@ -0,0 +1,94 @@
+//
+// daytime_client.cpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2012 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 <array>
+#include <future>
+#include <iostream>
+#include <thread>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/use_future.hpp>
+
+using boost::asio::ip::udp;
+
+void get_daytime(boost::asio::io_service& io_service, const char* hostname)
+{
+ try
+ {
+ udp::resolver resolver(io_service);
+
+ std::future<udp::resolver::iterator> iter =
+ resolver.async_resolve(
+ {udp::v4(), hostname, "daytime"},
+ boost::asio::use_future);
+
+ // The async_resolve operation above returns the endpoint iterator as a
+ // future value that is not retrieved ...
+
+ udp::socket socket(io_service, udp::v4());
+
+ std::array<char, 1> send_buf = {{ 0 }};
+ std::future<std::size_t> send_length =
+ socket.async_send_to(boost::asio::buffer(send_buf),
+ *iter.get(), // ... until here. This call may block.
+ boost::asio::use_future);
+
+ // Do other things here while the send completes.
+
+ send_length.get(); // Blocks until the send is complete. Throws any errors.
+
+ std::array<char, 128> recv_buf;
+ udp::endpoint sender_endpoint;
+ std::future<std::size_t> recv_length =
+ socket.async_receive_from(
+ boost::asio::buffer(recv_buf),
+ sender_endpoint,
+ boost::asio::use_future);
+
+ // Do other things here while the receive completes.
+
+ std::cout.write(
+ recv_buf.data(),
+ recv_length.get()); // Blocks until receive is complete.
+ }
+ catch (std::system_error& e)
+ {
+ std::cerr << e.what() << std::endl;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: daytime_client <host>" << std::endl;
+ return 1;
+ }
+
+ // We run the io_service off in its own thread so that it operates
+ // completely asynchronously with respect to the rest of the program.
+ boost::asio::io_service io_service;
+ boost::asio::io_service::work work(io_service);
+ std::thread thread([&io_service](){ io_service.run(); });
+
+ get_daytime(io_service, argv[1]);
+
+ io_service.stop();
+ thread.join();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ }
+
+ return 0;
+}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk