TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
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 : // Official repository: https://github.com/cppalliance/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_DETAIL_RESULTS_COMBINATORS_HPP
11 : #define BOOST_CAPY_DETAIL_RESULTS_COMBINATORS_HPP
12 :
13 : #include <boost/capy/concept/context_awaitable.hpp>
14 : #include <boost/capy/results.hpp>
15 :
16 : #include <system_error>
17 : #include <tuple>
18 : #include <type_traits>
19 : #include <utility>
20 :
21 : namespace boost {
22 : namespace capy {
23 : namespace detail {
24 :
25 : /// True when every awaitable in the pack returns a `results`.
26 : template<typename... As>
27 : concept all_results_awaitables =
28 : (is_results_v<awaitable_result_t<As>> && ...);
29 :
30 : /// True when the `results`-aware when_all overload should be used.
31 : template<typename... As>
32 : concept when_all_results_eligible =
33 : (sizeof...(As) > 0)
34 : && all_results_awaitables<As...>;
35 :
36 : /// True when the `results`-aware when_any overload should be used.
37 : template<typename... As>
38 : concept when_any_results_eligible =
39 : (sizeof...(As) > 0)
40 : && all_results_awaitables<As...>;
41 :
42 : /// Map a `results` specialization to its contributed payload type.
43 : ///
44 : /// results<T> -> T (unwrap single)
45 : /// results<Ts...> -> tuple<Ts...> (zero, two, or more)
46 : template<typename Result>
47 : struct results_payload;
48 :
49 : template<typename T>
50 : struct results_payload<results<T>>
51 : {
52 : using type = T;
53 : };
54 :
55 : template<typename... Ts>
56 : struct results_payload<results<Ts...>>
57 : {
58 : using type = std::tuple<Ts...>;
59 : };
60 :
61 : template<typename Result>
62 : using results_payload_t =
63 : typename results_payload<Result>::type;
64 :
65 : /// Extract the payload value(s) from a `results`,
66 : /// matching the type produced by results_payload_t.
67 : template<typename T>
68 : T
69 HIT 107 : extract_results_payload(results<T>&& r)
70 : {
71 107 : return std::get<1>(std::move(r));
72 : }
73 :
74 : template<typename... Ts>
75 : std::tuple<Ts...>
76 55 : extract_results_payload(results<Ts...>&& r)
77 : {
78 61 : return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
79 55 : return std::tuple<Ts...>(std::get<Is + 1>(std::move(r))...);
80 56 : }(std::index_sequence_for<Ts...>{});
81 : }
82 :
83 : /// Reconstruct a success `results` from a payload extracted by when_any.
84 : template<typename Result>
85 : struct results_from_payload;
86 :
87 : template<typename T>
88 : struct results_from_payload<results<T>>
89 : {
90 : static results<T> apply(T t)
91 : {
92 : return results<T>{std::error_code(), std::move(t)};
93 : }
94 : };
95 :
96 : template<typename... Ts>
97 : struct results_from_payload<results<Ts...>>
98 : {
99 : static results<Ts...> apply(std::tuple<Ts...> t)
100 : {
101 : return std::tuple_cat(
102 : std::tuple<std::error_code>(), std::move(t));
103 : }
104 : };
105 :
106 : /// Build the outer `results` for when_all from a tuple of child `results`.
107 : template<typename ResultType, typename Tuple, std::size_t... Is>
108 : ResultType
109 50 : build_when_all_results_impl(Tuple&& results, std::index_sequence<Is...>)
110 : {
111 50 : std::error_code ec;
112 109 : (void)((std::get<0>(std::get<Is>(results)) && !ec
113 23 : ? (ec = std::get<0>(std::get<Is>(results)), true)
114 36 : : false) || ...);
115 :
116 141 : return ResultType{ec, extract_results_payload(
117 147 : std::move(std::get<Is>(results)))...};
118 20 : }
119 :
120 : template<typename ResultType, typename... Results>
121 : ResultType
122 50 : build_when_all_results(std::tuple<Results...>&& results)
123 : {
124 : return build_when_all_results_impl<ResultType>(
125 50 : std::move(results),
126 50 : std::index_sequence_for<Results...>{});
127 : }
128 :
129 : } // namespace detail
130 : } // namespace capy
131 : } // namespace boost
132 :
133 : #endif
|