1 //
2 // awaitable.hpp
3 // ~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef BOOST_ASIO_AWAITABLE_HPP
12 #define BOOST_ASIO_AWAITABLE_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 
20 #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
21 
22 #include <experimental/coroutine>
23 #include <boost/asio/executor.hpp>
24 
25 #include <boost/asio/detail/push_options.hpp>
26 
27 namespace boost {
28 namespace asio {
29 namespace detail {
30 
31 using std::experimental::coroutine_handle;
32 using std::experimental::suspend_always;
33 
34 template <typename> class awaitable_thread;
35 template <typename, typename> class awaitable_frame;
36 
37 } // namespace detail
38 
39 /// The return type of a coroutine or asynchronous operation.
40 template <typename T, typename Executor = executor>
41 class awaitable
42 {
43 public:
44   /// The type of the awaited value.
45   typedef T value_type;
46 
47   /// The executor type that will be used for the coroutine.
48   typedef Executor executor_type;
49 
50   /// Default constructor.
awaitable()51   constexpr awaitable() noexcept
52     : frame_(nullptr)
53   {
54   }
55 
56   /// Move constructor.
awaitable(awaitable && other)57   awaitable(awaitable&& other) noexcept
58     : frame_(std::exchange(other.frame_, nullptr))
59   {
60   }
61 
62   /// Destructor
~awaitable()63   ~awaitable()
64   {
65     if (frame_)
66       frame_->destroy();
67   }
68 
69   /// Checks if the awaitable refers to a future result.
valid() const70   bool valid() const noexcept
71   {
72     return !!frame_;
73   }
74 
75 #if !defined(GENERATING_DOCUMENTATION)
76 
77   // Support for co_await keyword.
await_ready() const78   bool await_ready() const noexcept
79   {
80     return false;
81   }
82 
83   // Support for co_await keyword.
84   template <class U>
await_suspend(detail::coroutine_handle<detail::awaitable_frame<U,Executor>> h)85   void await_suspend(
86       detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h)
87   {
88     frame_->push_frame(&h.promise());
89   }
90 
91   // Support for co_await keyword.
await_resume()92   T await_resume()
93   {
94     return frame_->get();
95   }
96 
97 #endif // !defined(GENERATING_DOCUMENTATION)
98 
99 private:
100   template <typename> friend class detail::awaitable_thread;
101   template <typename, typename> friend class detail::awaitable_frame;
102 
103   // Not copy constructible or copy assignable.
104   awaitable(const awaitable&) = delete;
105   awaitable& operator=(const awaitable&) = delete;
106 
107   // Construct the awaitable from a coroutine's frame object.
awaitable(detail::awaitable_frame<T,Executor> * a)108   explicit awaitable(detail::awaitable_frame<T, Executor>* a)
109     : frame_(a)
110   {
111   }
112 
113   detail::awaitable_frame<T, Executor>* frame_;
114 };
115 
116 } // namespace asio
117 } // namespace boost
118 
119 #include <boost/asio/detail/pop_options.hpp>
120 
121 #include <boost/asio/impl/awaitable.hpp>
122 
123 #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
124 
125 #endif // BOOST_ASIO_AWAITABLE_HPP
126