1 // Copyright 2023 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef GRPC_SRC_CORE_LIB_PROMISE_PRIORITIZED_RACE_H
16 #define GRPC_SRC_CORE_LIB_PROMISE_PRIORITIZED_RACE_H
17
18 #include <grpc/support/port_platform.h>
19
20 #include <utility>
21
22 namespace grpc_core {
23
24 namespace promise_detail {
25
26 template <typename A, typename B>
27 class TwoPartyPrioritizedRace {
28 public:
29 using Result = decltype(std::declval<A>()());
30
TwoPartyPrioritizedRace(A a,B b)31 explicit TwoPartyPrioritizedRace(A a, B b)
32 : a_(std::move(a)), b_(std::move(b)) {}
33
operator()34 Result operator()() {
35 // Check the priority promise.
36 auto p = a_();
37 if (p.ready()) return p;
38 // Check the other promise.
39 p = b_();
40 if (p.ready()) {
41 // re-poll a to see if it's also completed.
42 auto q = a_();
43 if (q.ready()) {
44 // both are ready, but a is prioritized
45 return q;
46 }
47 }
48 return p;
49 }
50
51 private:
52 A a_;
53 B b_;
54 };
55
56 template <typename... Promises>
57 class PrioritizedRace;
58
59 template <typename Promise, typename... Promises>
60 class PrioritizedRace<Promise, Promises...>
61 : public TwoPartyPrioritizedRace<Promise, PrioritizedRace<Promises...>> {
62 public:
63 using Result = decltype(std::declval<Promise>()());
PrioritizedRace(Promise promise,Promises...promises)64 explicit PrioritizedRace(Promise promise, Promises... promises)
65 : TwoPartyPrioritizedRace<Promise, PrioritizedRace<Promises...>>(
66 std::move(promise),
67 PrioritizedRace<Promises...>(std::move(promises)...)) {}
68 };
69
70 template <typename Promise>
71 class PrioritizedRace<Promise> {
72 public:
73 using Result = decltype(std::declval<Promise>()());
PrioritizedRace(Promise promise)74 explicit PrioritizedRace(Promise promise) : promise_(std::move(promise)) {}
operator()75 Result operator()() { return promise_(); }
76
77 private:
78 Promise promise_;
79 };
80
81 } // namespace promise_detail
82
83 /// Run all the promises until one is non-pending.
84 /// Once there's a non-pending promise, repoll all the promises before that.
85 /// Return the result from the lexically first non-pending promise.
86 template <typename... Promises>
PrioritizedRace(Promises...promises)87 promise_detail::PrioritizedRace<Promises...> PrioritizedRace(
88 Promises... promises) {
89 return promise_detail::PrioritizedRace<Promises...>(std::move(promises)...);
90 }
91
92 } // namespace grpc_core
93
94 #endif // GRPC_SRC_CORE_LIB_PROMISE_PRIORITIZED_RACE_H
95