wait_group.hpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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_DETAIL_WAIT_GROUP_HPP
  8. #define BOOST_COBALT_DETAIL_WAIT_GROUP_HPP
  9. #include <boost/cobalt/promise.hpp>
  10. #include <boost/cobalt/race.hpp>
  11. #include <boost/cobalt/gather.hpp>
  12. #include <list>
  13. namespace boost::cobalt::detail
  14. {
  15. struct race_wrapper
  16. {
  17. using impl_type = decltype(race(std::declval<std::list<promise<void>> &>()));
  18. std::list<promise<void>> &waitables_;
  19. race_wrapper(std::list<promise<void>> &waitables) : waitables_(waitables)
  20. {
  21. }
  22. struct awaitable_type
  23. {
  24. bool await_ready()
  25. {
  26. if (waitables_.empty())
  27. return true;
  28. else
  29. return impl_->await_ready();
  30. }
  31. template<typename Promise>
  32. auto await_suspend(std::coroutine_handle<Promise> h)
  33. {
  34. return impl_->await_suspend(h);
  35. }
  36. void await_resume()
  37. {
  38. if (waitables_.empty())
  39. return;
  40. auto idx = impl_->await_resume();
  41. if (idx != std::numeric_limits<std::size_t>::max())
  42. waitables_.erase(std::next(waitables_.begin(), idx));
  43. }
  44. awaitable_type(std::list<promise<void>> &waitables) : waitables_(waitables)
  45. {
  46. if (!waitables_.empty())
  47. impl_.emplace(waitables_, random_);
  48. }
  49. private:
  50. std::optional<impl_type::awaitable> impl_;
  51. std::list<promise<void>> &waitables_;
  52. std::default_random_engine &random_{detail::prng()};
  53. };
  54. awaitable_type operator co_await() &&
  55. {
  56. return awaitable_type(waitables_);
  57. }
  58. };
  59. struct gather_wrapper
  60. {
  61. using impl_type = decltype(gather(std::declval<std::list<promise<void>> &>()));
  62. std::list<promise<void>> &waitables_;
  63. gather_wrapper(std::list<promise<void>> &waitables) : waitables_(waitables)
  64. {
  65. }
  66. struct awaitable_type
  67. {
  68. bool await_ready()
  69. {
  70. if (waitables_.empty())
  71. return true;
  72. else
  73. return impl_->await_ready();
  74. }
  75. template<typename Promise>
  76. auto await_suspend(std::coroutine_handle<Promise> h)
  77. {
  78. return impl_->await_suspend(h);
  79. }
  80. void await_resume()
  81. {
  82. if (waitables_.empty())
  83. return;
  84. BOOST_ASSERT(impl_);
  85. impl_->await_resume();
  86. waitables_.clear();
  87. }
  88. awaitable_type(std::list<promise<void>> &waitables) : waitables_(waitables)
  89. {
  90. if (!waitables_.empty())
  91. impl_.emplace(waitables_);
  92. }
  93. private:
  94. std::list<promise<void>> &waitables_;
  95. std::optional<decltype(gather(waitables_).operator co_await())> impl_;
  96. };
  97. awaitable_type operator co_await()
  98. {
  99. return awaitable_type(waitables_);
  100. }
  101. };
  102. }
  103. #endif //BOOST_COBALT_DETAIL_WAIT_GROUP_HPP