race.hpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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_RACE_HPP
  8. #define BOOST_COBALT_RACE_HPP
  9. #include <boost/cobalt/concepts.hpp>
  10. #include <boost/cobalt/detail/race.hpp>
  11. #include <boost/cobalt/detail/wrapper.hpp>
  12. #include <random>
  13. namespace boost::cobalt
  14. {
  15. namespace detail
  16. {
  17. inline std::default_random_engine &prng()
  18. {
  19. thread_local static std::default_random_engine g(std::random_device{}());
  20. return g;
  21. }
  22. }
  23. // tag::concept[]
  24. template<typename G>
  25. concept uniform_random_bit_generator =
  26. requires ( G & g)
  27. {
  28. {typename std::decay_t<G>::result_type() } -> std::unsigned_integral; // is an unsigned integer type
  29. // T Returns the smallest value that G's operator() may return. The value is strictly less than G::max(). The function must be constexpr.
  30. {std::decay_t<G>::min()} -> std::same_as<typename std::decay_t<G>::result_type>;
  31. // T Returns the largest value that G's operator() may return. The value is strictly greater than G::min(). The function must be constexpr.
  32. {std::decay_t<G>::max()} -> std::same_as<typename std::decay_t<G>::result_type>;
  33. {g()} -> std::same_as<typename std::decay_t<G>::result_type>;
  34. } && (std::decay_t<G>::max() > std::decay_t<G>::min());
  35. // end::concept[]
  36. template<asio::cancellation_type Ct = asio::cancellation_type::all,
  37. uniform_random_bit_generator URBG,
  38. awaitable<detail::fork::promise_type> ... Promise>
  39. auto race(URBG && g, Promise && ... p) -> detail::race_variadic_impl<Ct, URBG, Promise ...>
  40. {
  41. return detail::race_variadic_impl<Ct, URBG, Promise ...>(std::forward<URBG>(g), static_cast<Promise&&>(p)...);
  42. }
  43. template<asio::cancellation_type Ct = asio::cancellation_type::all,
  44. uniform_random_bit_generator URBG,
  45. typename PromiseRange>
  46. requires awaitable<std::decay_t<decltype(*std::declval<PromiseRange>().begin())>,
  47. detail::fork::promise_type>
  48. auto race(URBG && g, PromiseRange && p) -> detail::race_ranged_impl<Ct, URBG, PromiseRange>
  49. {
  50. if (std::empty(p))
  51. throw_exception(std::invalid_argument("empty range raceed"));
  52. return detail::race_ranged_impl<Ct, URBG, PromiseRange>{std::forward<URBG>(g), static_cast<PromiseRange&&>(p)};
  53. }
  54. template<asio::cancellation_type Ct = asio::cancellation_type::all,
  55. awaitable<detail::fork::promise_type> ... Promise>
  56. auto race(Promise && ... p) -> detail::race_variadic_impl<Ct, std::default_random_engine&, Promise ...>
  57. {
  58. return race<Ct>(detail::prng(), static_cast<Promise&&>(p)...);
  59. }
  60. template<asio::cancellation_type Ct = asio::cancellation_type::all, typename PromiseRange>
  61. requires awaitable<std::decay_t<decltype(*std::declval<PromiseRange>().begin())>,
  62. detail::fork::promise_type>
  63. auto race(PromiseRange && p) -> detail::race_ranged_impl<Ct, std::default_random_engine&, PromiseRange>
  64. {
  65. if (std::empty(p))
  66. throw_exception(std::invalid_argument("empty range raceed"));
  67. return race<Ct>(detail::prng(), static_cast<PromiseRange&&>(p));
  68. }
  69. template<asio::cancellation_type Ct = asio::cancellation_type::all,
  70. awaitable<detail::fork::promise_type> ... Promise>
  71. auto left_race(Promise && ... p) -> detail::race_variadic_impl<Ct, detail::left_race_tag, Promise ...>
  72. {
  73. return detail::race_variadic_impl<Ct, detail::left_race_tag, Promise ...>(
  74. detail::left_race_tag{}, static_cast<Promise&&>(p)...);
  75. }
  76. template<asio::cancellation_type Ct = asio::cancellation_type::all, typename PromiseRange>
  77. requires awaitable<std::decay_t<decltype(*std::declval<PromiseRange>().begin())>,
  78. detail::fork::promise_type>
  79. auto left_race(PromiseRange && p) -> detail::race_ranged_impl<Ct, detail::left_race_tag, PromiseRange>
  80. {
  81. if (std::empty(p))
  82. throw_exception(std::invalid_argument("empty range left_raceed"));
  83. return detail::race_ranged_impl<Ct, detail::left_race_tag, PromiseRange>{
  84. detail::left_race_tag{}, static_cast<PromiseRange&&>(p)};
  85. }
  86. }
  87. #endif //BOOST_COBALT_RACE_HPP