1 // 2 // awaitable.hpp 3 // ~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 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 #if defined(BOOST_ASIO_HAS_STD_COROUTINE) 23 # include <coroutine> 24 #else // defined(BOOST_ASIO_HAS_STD_COROUTINE) 25 # include <experimental/coroutine> 26 #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) 27 28 #include <boost/asio/any_io_executor.hpp> 29 30 #include <boost/asio/detail/push_options.hpp> 31 32 namespace boost { 33 namespace asio { 34 namespace detail { 35 36 #if defined(BOOST_ASIO_HAS_STD_COROUTINE) 37 using std::coroutine_handle; 38 using std::suspend_always; 39 #else // defined(BOOST_ASIO_HAS_STD_COROUTINE) 40 using std::experimental::coroutine_handle; 41 using std::experimental::suspend_always; 42 #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) 43 44 template <typename> class awaitable_thread; 45 template <typename, typename> class awaitable_frame; 46 47 } // namespace detail 48 49 /// The return type of a coroutine or asynchronous operation. 50 template <typename T, typename Executor = any_io_executor> 51 class awaitable 52 { 53 public: 54 /// The type of the awaited value. 55 typedef T value_type; 56 57 /// The executor type that will be used for the coroutine. 58 typedef Executor executor_type; 59 60 /// Default constructor. awaitable()61 constexpr awaitable() noexcept 62 : frame_(nullptr) 63 { 64 } 65 66 /// Move constructor. awaitable(awaitable && other)67 awaitable(awaitable&& other) noexcept 68 : frame_(std::exchange(other.frame_, nullptr)) 69 { 70 } 71 72 /// Destructor ~awaitable()73 ~awaitable() 74 { 75 if (frame_) 76 frame_->destroy(); 77 } 78 79 /// Checks if the awaitable refers to a future result. valid() const80 bool valid() const noexcept 81 { 82 return !!frame_; 83 } 84 85 #if !defined(GENERATING_DOCUMENTATION) 86 87 // Support for co_await keyword. await_ready() const88 bool await_ready() const noexcept 89 { 90 return false; 91 } 92 93 // Support for co_await keyword. 94 template <class U> await_suspend(detail::coroutine_handle<detail::awaitable_frame<U,Executor>> h)95 void await_suspend( 96 detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h) 97 { 98 frame_->push_frame(&h.promise()); 99 } 100 101 // Support for co_await keyword. await_resume()102 T await_resume() 103 { 104 return awaitable(static_cast<awaitable&&>(*this)).frame_->get(); 105 } 106 107 #endif // !defined(GENERATING_DOCUMENTATION) 108 109 private: 110 template <typename> friend class detail::awaitable_thread; 111 template <typename, typename> friend class detail::awaitable_frame; 112 113 // Not copy constructible or copy assignable. 114 awaitable(const awaitable&) = delete; 115 awaitable& operator=(const awaitable&) = delete; 116 117 // Construct the awaitable from a coroutine's frame object. awaitable(detail::awaitable_frame<T,Executor> * a)118 explicit awaitable(detail::awaitable_frame<T, Executor>* a) 119 : frame_(a) 120 { 121 } 122 123 detail::awaitable_frame<T, Executor>* frame_; 124 }; 125 126 } // namespace asio 127 } // namespace boost 128 129 #include <boost/asio/detail/pop_options.hpp> 130 131 #include <boost/asio/impl/awaitable.hpp> 132 133 #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) 134 135 #endif // BOOST_ASIO_AWAITABLE_HPP 136