task.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //
  2. // Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net)
  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. constexpr task(noop<Return> n) : receiver_(std::move(n)){}
  29. private:
  30. template<typename>
  31. friend struct detail::task_promise;
  32. task(detail::task_promise<Return> * task) : receiver_(task)
  33. {
  34. }
  35. detail::task_receiver<Return> receiver_;
  36. friend struct detail::async_initiate_spawn;
  37. // tag::outline[]
  38. };
  39. // end::outline[]
  40. struct use_task_t
  41. {
  42. /// Default constructor.
  43. constexpr use_task_t()
  44. {
  45. }
  46. /// Adapts an executor to add the @c use_task_t completion token as the
  47. /// default.
  48. template <typename InnerExecutor>
  49. struct executor_with_default : InnerExecutor
  50. {
  51. /// Specify @c use_task_t as the default completion token type.
  52. typedef use_task_t default_completion_token_type;
  53. executor_with_default(const InnerExecutor& ex) noexcept
  54. : InnerExecutor(ex)
  55. {
  56. }
  57. /// Construct the adapted executor from the inner executor type.
  58. template <typename InnerExecutor1>
  59. executor_with_default(const InnerExecutor1& ex,
  60. typename std::enable_if<
  61. std::conditional<
  62. !std::is_same<InnerExecutor1, executor_with_default>::value,
  63. std::is_convertible<InnerExecutor1, InnerExecutor>,
  64. std::false_type
  65. >::type::value>::type = 0) noexcept
  66. : InnerExecutor(ex)
  67. {
  68. }
  69. };
  70. /// Type alias to adapt an I/O object to use @c use_task_t as its
  71. /// default completion token type.
  72. template <typename T>
  73. using as_default_on_t = typename T::template rebind_executor<
  74. executor_with_default<typename T::executor_type> >::other;
  75. /// Function helper to adapt an I/O object to use @c use_task_t as its
  76. /// default completion token type.
  77. template <typename T>
  78. static typename std::decay_t<T>::template rebind_executor<
  79. executor_with_default<typename std::decay_t<T>::executor_type>
  80. >::other
  81. as_default_on(T && object)
  82. {
  83. return typename std::decay_t<T>::template rebind_executor<
  84. executor_with_default<typename std::decay_t<T>::executor_type>
  85. >::other(std::forward<T>(object));
  86. }
  87. };
  88. constexpr use_task_t use_task{};
  89. template<typename T>
  90. inline auto task<T>::operator co_await () {return receiver_.get_awaitable();}
  91. }
  92. namespace boost::asio
  93. {
  94. template<typename ... Args>
  95. struct async_result<boost::cobalt::use_task_t, void(Args...)>
  96. {
  97. using return_type = cobalt::task<
  98. typename decltype(cobalt::interpret_as_result(std::declval<std::tuple<Args...>>()))::value_type>;
  99. template <typename Initiation, typename... InitArgs>
  100. static auto initiate(Initiation initiation,
  101. boost::cobalt::use_task_t,
  102. InitArgs ... args) -> return_type
  103. {
  104. co_return co_await async_initiate<
  105. const cobalt::use_op_t&, void(Args...)>(
  106. std::move(initiation),
  107. cobalt::use_op, std::move(args)...);
  108. }
  109. };
  110. }
  111. #endif //BOOST_COBALT_COBALT_HPP