task.hpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //
  2. // Copyright (c) 2022 Klemens Morgenstern ([email protected])
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_COBALT_TASK_HPP
  8. #define BOOST_COBALT_TASK_HPP
  9. #include <boost/cobalt/detail/handler.hpp>
  10. #include <boost/cobalt/detail/task.hpp>
  11. #include <boost/cobalt/op.hpp>
  12. #include <boost/asio/append.hpp>
  13. #include <boost/asio/deferred.hpp>
  14. namespace boost::cobalt
  15. {
  16. // tag::outline[]
  17. template<typename Return>
  18. struct [[nodiscard]] task
  19. {
  20. task(task &&lhs) noexcept = default;
  21. task& operator=(task &&) noexcept = default;
  22. // enable `co_await`
  23. auto operator co_await ();
  24. // end::outline[]
  25. task(const task &) = delete;
  26. task& operator=(const task &) = delete;
  27. using promise_type = detail::task_promise<Return>;
  28. private:
  29. template<typename>
  30. friend struct detail::task_promise;
  31. task(detail::task_promise<Return> * task) : receiver_(task)
  32. {
  33. }
  34. detail::task_receiver<Return> receiver_;
  35. friend struct detail::async_initiate_spawn;
  36. // tag::outline[]
  37. };
  38. // end::outline[]
  39. struct use_task_t
  40. {
  41. /// Default constructor.
  42. constexpr use_task_t()
  43. {
  44. }
  45. /// Adapts an executor to add the @c use_task_t completion token as the
  46. /// default.
  47. template <typename InnerExecutor>
  48. struct executor_with_default : InnerExecutor
  49. {
  50. /// Specify @c use_task_t as the default completion token type.
  51. typedef use_task_t default_completion_token_type;
  52. executor_with_default(const InnerExecutor& ex) noexcept
  53. : InnerExecutor(ex)
  54. {
  55. }
  56. /// Construct the adapted executor from the inner executor type.
  57. template <typename InnerExecutor1>
  58. executor_with_default(const InnerExecutor1& ex,
  59. typename std::enable_if<
  60. std::conditional<
  61. !std::is_same<InnerExecutor1, executor_with_default>::value,
  62. std::is_convertible<InnerExecutor1, InnerExecutor>,
  63. std::false_type
  64. >::type::value>::type = 0) noexcept
  65. : InnerExecutor(ex)
  66. {
  67. }
  68. };
  69. /// Type alias to adapt an I/O object to use @c use_task_t as its
  70. /// default completion token type.
  71. template <typename T>
  72. using as_default_on_t = typename T::template rebind_executor<
  73. executor_with_default<typename T::executor_type> >::other;
  74. /// Function helper to adapt an I/O object to use @c use_task_t as its
  75. /// default completion token type.
  76. template <typename T>
  77. static typename std::decay_t<T>::template rebind_executor<
  78. executor_with_default<typename std::decay_t<T>::executor_type>
  79. >::other
  80. as_default_on(T && object)
  81. {
  82. return typename std::decay_t<T>::template rebind_executor<
  83. executor_with_default<typename std::decay_t<T>::executor_type>
  84. >::other(std::forward<T>(object));
  85. }
  86. };
  87. constexpr use_task_t use_task{};
  88. template<typename T>
  89. inline auto task<T>::operator co_await () {return receiver_.get_awaitable();}
  90. }
  91. namespace boost::asio
  92. {
  93. template<typename ... Args>
  94. struct async_result<boost::cobalt::use_task_t, void(Args...)>
  95. {
  96. using return_type = cobalt::task<
  97. typename decltype(cobalt::interpret_as_result(std::declval<std::tuple<Args...>>()))::value_type>;
  98. template <typename Initiation, typename... InitArgs>
  99. static auto initiate(Initiation initiation,
  100. boost::cobalt::use_task_t,
  101. InitArgs ... args) -> return_type
  102. {
  103. co_return co_await async_initiate<
  104. const cobalt::use_op_t&, void(Args...)>(
  105. std::move(initiation),
  106. cobalt::use_op, std::move(args)...);
  107. }
  108. };
  109. }
  110. #endif //BOOST_COBALT_COBALT_HPP