xref: /aosp_15_r20/external/grpc-grpc/src/core/lib/promise/detail/join_state.h (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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_DETAIL_JOIN_STATE_H
16 #define GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H
17 
18 // This file is generated by tools/codegen/core/gen_seq.py
19 
20 #include <grpc/support/port_platform.h>
21 
22 #include <tuple>
23 #include <type_traits>
24 #include <utility>
25 
26 #include <grpc/support/log.h>
27 
28 #include "src/core/lib/gprpp/bitset.h"
29 #include "src/core/lib/gprpp/construct_destruct.h"
30 #include "src/core/lib/promise/detail/promise_like.h"
31 #include "src/core/lib/promise/poll.h"
32 #include "src/core/lib/promise/trace.h"
33 
34 namespace grpc_core {
35 namespace promise_detail {
36 template <class Traits, typename... Ps>
37 struct JoinState;
38 
39 template <class Traits, typename P0, typename P1>
40 struct JoinState<Traits, P0, P1> {
41   template <typename T>
42   using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
43   using Promise0 = PromiseLike<P0>;
44   using Result0 = UnwrappedType<typename Promise0::Result>;
45   union {
46     GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
47     GPR_NO_UNIQUE_ADDRESS Result0 result0;
48   };
49   using Promise1 = PromiseLike<P1>;
50   using Result1 = UnwrappedType<typename Promise1::Result>;
51   union {
52     GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
53     GPR_NO_UNIQUE_ADDRESS Result1 result1;
54   };
55   GPR_NO_UNIQUE_ADDRESS BitSet<2> ready;
56   JoinState(P0&& p0, P1&& p1) {
57     Construct(&promise0, std::forward<P0>(p0));
58     Construct(&promise1, std::forward<P1>(p1));
59   }
60   JoinState(const JoinState& other) {
61     GPR_ASSERT(other.ready.none());
62     Construct(&promise0, other.promise0);
63     Construct(&promise1, other.promise1);
64   }
65   JoinState& operator=(const JoinState& other) = delete;
66   JoinState& operator=(JoinState&& other) = delete;
67   JoinState(JoinState&& other) noexcept : ready(other.ready) {
68     if (ready.is_set(0)) {
69       Construct(&result0, std::move(other.result0));
70     } else {
71       Construct(&promise0, std::move(other.promise0));
72     }
73     if (ready.is_set(1)) {
74       Construct(&result1, std::move(other.result1));
75     } else {
76       Construct(&promise1, std::move(other.promise1));
77     }
78   }
79   ~JoinState() {
80     if (ready.is_set(0)) {
81       Destruct(&result0);
82     } else {
83       Destruct(&promise0);
84     }
85     if (ready.is_set(1)) {
86       Destruct(&result1);
87     } else {
88       Destruct(&promise1);
89     }
90   }
91   using Result =
92       typename Traits::template ResultType<std::tuple<Result0, Result1>>;
93   Poll<Result> PollOnce() {
94     if (!ready.is_set(0)) {
95       if (grpc_trace_promise_primitives.enabled()) {
96         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/2", this);
97       }
98       auto poll = promise0();
99       if (grpc_trace_promise_primitives.enabled()) {
100         auto* p = poll.value_if_ready();
101         gpr_log(GPR_DEBUG, "join[%p]: joint 1/2 %s", this,
102                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
103                              : "pending");
104       }
105       if (auto* p = poll.value_if_ready()) {
106         if (Traits::IsOk(*p)) {
107           ready.set(0);
108           Destruct(&promise0);
109           Construct(&result0, Traits::Unwrapped(std::move(*p)));
110         } else {
111           return Traits::template EarlyReturn<Result>(std::move(*p));
112         }
113       }
114     } else if (grpc_trace_promise_primitives.enabled()) {
115       gpr_log(GPR_DEBUG, "join[%p]: joint 1/2 already ready", this);
116     }
117     if (!ready.is_set(1)) {
118       if (grpc_trace_promise_primitives.enabled()) {
119         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/2", this);
120       }
121       auto poll = promise1();
122       if (grpc_trace_promise_primitives.enabled()) {
123         auto* p = poll.value_if_ready();
124         gpr_log(GPR_DEBUG, "join[%p]: joint 2/2 %s", this,
125                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
126                              : "pending");
127       }
128       if (auto* p = poll.value_if_ready()) {
129         if (Traits::IsOk(*p)) {
130           ready.set(1);
131           Destruct(&promise1);
132           Construct(&result1, Traits::Unwrapped(std::move(*p)));
133         } else {
134           return Traits::template EarlyReturn<Result>(std::move(*p));
135         }
136       }
137     } else if (grpc_trace_promise_primitives.enabled()) {
138       gpr_log(GPR_DEBUG, "join[%p]: joint 2/2 already ready", this);
139     }
140     if (ready.all()) {
141       return Traits::FinalReturn(std::move(result0), std::move(result1));
142     }
143     return Pending{};
144   }
145 };
146 
147 template <class Traits, typename P0, typename P1, typename P2>
148 struct JoinState<Traits, P0, P1, P2> {
149   template <typename T>
150   using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
151   using Promise0 = PromiseLike<P0>;
152   using Result0 = UnwrappedType<typename Promise0::Result>;
153   union {
154     GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
155     GPR_NO_UNIQUE_ADDRESS Result0 result0;
156   };
157   using Promise1 = PromiseLike<P1>;
158   using Result1 = UnwrappedType<typename Promise1::Result>;
159   union {
160     GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
161     GPR_NO_UNIQUE_ADDRESS Result1 result1;
162   };
163   using Promise2 = PromiseLike<P2>;
164   using Result2 = UnwrappedType<typename Promise2::Result>;
165   union {
166     GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
167     GPR_NO_UNIQUE_ADDRESS Result2 result2;
168   };
169   GPR_NO_UNIQUE_ADDRESS BitSet<3> ready;
170   JoinState(P0&& p0, P1&& p1, P2&& p2) {
171     Construct(&promise0, std::forward<P0>(p0));
172     Construct(&promise1, std::forward<P1>(p1));
173     Construct(&promise2, std::forward<P2>(p2));
174   }
175   JoinState(const JoinState& other) {
176     GPR_ASSERT(other.ready.none());
177     Construct(&promise0, other.promise0);
178     Construct(&promise1, other.promise1);
179     Construct(&promise2, other.promise2);
180   }
181   JoinState& operator=(const JoinState& other) = delete;
182   JoinState& operator=(JoinState&& other) = delete;
183   JoinState(JoinState&& other) noexcept : ready(other.ready) {
184     if (ready.is_set(0)) {
185       Construct(&result0, std::move(other.result0));
186     } else {
187       Construct(&promise0, std::move(other.promise0));
188     }
189     if (ready.is_set(1)) {
190       Construct(&result1, std::move(other.result1));
191     } else {
192       Construct(&promise1, std::move(other.promise1));
193     }
194     if (ready.is_set(2)) {
195       Construct(&result2, std::move(other.result2));
196     } else {
197       Construct(&promise2, std::move(other.promise2));
198     }
199   }
200   ~JoinState() {
201     if (ready.is_set(0)) {
202       Destruct(&result0);
203     } else {
204       Destruct(&promise0);
205     }
206     if (ready.is_set(1)) {
207       Destruct(&result1);
208     } else {
209       Destruct(&promise1);
210     }
211     if (ready.is_set(2)) {
212       Destruct(&result2);
213     } else {
214       Destruct(&promise2);
215     }
216   }
217   using Result = typename Traits::template ResultType<
218       std::tuple<Result0, Result1, Result2>>;
219   Poll<Result> PollOnce() {
220     if (!ready.is_set(0)) {
221       if (grpc_trace_promise_primitives.enabled()) {
222         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/3", this);
223       }
224       auto poll = promise0();
225       if (grpc_trace_promise_primitives.enabled()) {
226         auto* p = poll.value_if_ready();
227         gpr_log(GPR_DEBUG, "join[%p]: joint 1/3 %s", this,
228                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
229                              : "pending");
230       }
231       if (auto* p = poll.value_if_ready()) {
232         if (Traits::IsOk(*p)) {
233           ready.set(0);
234           Destruct(&promise0);
235           Construct(&result0, Traits::Unwrapped(std::move(*p)));
236         } else {
237           return Traits::template EarlyReturn<Result>(std::move(*p));
238         }
239       }
240     } else if (grpc_trace_promise_primitives.enabled()) {
241       gpr_log(GPR_DEBUG, "join[%p]: joint 1/3 already ready", this);
242     }
243     if (!ready.is_set(1)) {
244       if (grpc_trace_promise_primitives.enabled()) {
245         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/3", this);
246       }
247       auto poll = promise1();
248       if (grpc_trace_promise_primitives.enabled()) {
249         auto* p = poll.value_if_ready();
250         gpr_log(GPR_DEBUG, "join[%p]: joint 2/3 %s", this,
251                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
252                              : "pending");
253       }
254       if (auto* p = poll.value_if_ready()) {
255         if (Traits::IsOk(*p)) {
256           ready.set(1);
257           Destruct(&promise1);
258           Construct(&result1, Traits::Unwrapped(std::move(*p)));
259         } else {
260           return Traits::template EarlyReturn<Result>(std::move(*p));
261         }
262       }
263     } else if (grpc_trace_promise_primitives.enabled()) {
264       gpr_log(GPR_DEBUG, "join[%p]: joint 2/3 already ready", this);
265     }
266     if (!ready.is_set(2)) {
267       if (grpc_trace_promise_primitives.enabled()) {
268         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/3", this);
269       }
270       auto poll = promise2();
271       if (grpc_trace_promise_primitives.enabled()) {
272         auto* p = poll.value_if_ready();
273         gpr_log(GPR_DEBUG, "join[%p]: joint 3/3 %s", this,
274                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
275                              : "pending");
276       }
277       if (auto* p = poll.value_if_ready()) {
278         if (Traits::IsOk(*p)) {
279           ready.set(2);
280           Destruct(&promise2);
281           Construct(&result2, Traits::Unwrapped(std::move(*p)));
282         } else {
283           return Traits::template EarlyReturn<Result>(std::move(*p));
284         }
285       }
286     } else if (grpc_trace_promise_primitives.enabled()) {
287       gpr_log(GPR_DEBUG, "join[%p]: joint 3/3 already ready", this);
288     }
289     if (ready.all()) {
290       return Traits::FinalReturn(std::move(result0), std::move(result1),
291                                  std::move(result2));
292     }
293     return Pending{};
294   }
295 };
296 
297 template <class Traits, typename P0, typename P1, typename P2, typename P3>
298 struct JoinState<Traits, P0, P1, P2, P3> {
299   template <typename T>
300   using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
301   using Promise0 = PromiseLike<P0>;
302   using Result0 = UnwrappedType<typename Promise0::Result>;
303   union {
304     GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
305     GPR_NO_UNIQUE_ADDRESS Result0 result0;
306   };
307   using Promise1 = PromiseLike<P1>;
308   using Result1 = UnwrappedType<typename Promise1::Result>;
309   union {
310     GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
311     GPR_NO_UNIQUE_ADDRESS Result1 result1;
312   };
313   using Promise2 = PromiseLike<P2>;
314   using Result2 = UnwrappedType<typename Promise2::Result>;
315   union {
316     GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
317     GPR_NO_UNIQUE_ADDRESS Result2 result2;
318   };
319   using Promise3 = PromiseLike<P3>;
320   using Result3 = UnwrappedType<typename Promise3::Result>;
321   union {
322     GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
323     GPR_NO_UNIQUE_ADDRESS Result3 result3;
324   };
325   GPR_NO_UNIQUE_ADDRESS BitSet<4> ready;
326   JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3) {
327     Construct(&promise0, std::forward<P0>(p0));
328     Construct(&promise1, std::forward<P1>(p1));
329     Construct(&promise2, std::forward<P2>(p2));
330     Construct(&promise3, std::forward<P3>(p3));
331   }
332   JoinState(const JoinState& other) {
333     GPR_ASSERT(other.ready.none());
334     Construct(&promise0, other.promise0);
335     Construct(&promise1, other.promise1);
336     Construct(&promise2, other.promise2);
337     Construct(&promise3, other.promise3);
338   }
339   JoinState& operator=(const JoinState& other) = delete;
340   JoinState& operator=(JoinState&& other) = delete;
341   JoinState(JoinState&& other) noexcept : ready(other.ready) {
342     if (ready.is_set(0)) {
343       Construct(&result0, std::move(other.result0));
344     } else {
345       Construct(&promise0, std::move(other.promise0));
346     }
347     if (ready.is_set(1)) {
348       Construct(&result1, std::move(other.result1));
349     } else {
350       Construct(&promise1, std::move(other.promise1));
351     }
352     if (ready.is_set(2)) {
353       Construct(&result2, std::move(other.result2));
354     } else {
355       Construct(&promise2, std::move(other.promise2));
356     }
357     if (ready.is_set(3)) {
358       Construct(&result3, std::move(other.result3));
359     } else {
360       Construct(&promise3, std::move(other.promise3));
361     }
362   }
363   ~JoinState() {
364     if (ready.is_set(0)) {
365       Destruct(&result0);
366     } else {
367       Destruct(&promise0);
368     }
369     if (ready.is_set(1)) {
370       Destruct(&result1);
371     } else {
372       Destruct(&promise1);
373     }
374     if (ready.is_set(2)) {
375       Destruct(&result2);
376     } else {
377       Destruct(&promise2);
378     }
379     if (ready.is_set(3)) {
380       Destruct(&result3);
381     } else {
382       Destruct(&promise3);
383     }
384   }
385   using Result = typename Traits::template ResultType<
386       std::tuple<Result0, Result1, Result2, Result3>>;
387   Poll<Result> PollOnce() {
388     if (!ready.is_set(0)) {
389       if (grpc_trace_promise_primitives.enabled()) {
390         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/4", this);
391       }
392       auto poll = promise0();
393       if (grpc_trace_promise_primitives.enabled()) {
394         auto* p = poll.value_if_ready();
395         gpr_log(GPR_DEBUG, "join[%p]: joint 1/4 %s", this,
396                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
397                              : "pending");
398       }
399       if (auto* p = poll.value_if_ready()) {
400         if (Traits::IsOk(*p)) {
401           ready.set(0);
402           Destruct(&promise0);
403           Construct(&result0, Traits::Unwrapped(std::move(*p)));
404         } else {
405           return Traits::template EarlyReturn<Result>(std::move(*p));
406         }
407       }
408     } else if (grpc_trace_promise_primitives.enabled()) {
409       gpr_log(GPR_DEBUG, "join[%p]: joint 1/4 already ready", this);
410     }
411     if (!ready.is_set(1)) {
412       if (grpc_trace_promise_primitives.enabled()) {
413         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/4", this);
414       }
415       auto poll = promise1();
416       if (grpc_trace_promise_primitives.enabled()) {
417         auto* p = poll.value_if_ready();
418         gpr_log(GPR_DEBUG, "join[%p]: joint 2/4 %s", this,
419                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
420                              : "pending");
421       }
422       if (auto* p = poll.value_if_ready()) {
423         if (Traits::IsOk(*p)) {
424           ready.set(1);
425           Destruct(&promise1);
426           Construct(&result1, Traits::Unwrapped(std::move(*p)));
427         } else {
428           return Traits::template EarlyReturn<Result>(std::move(*p));
429         }
430       }
431     } else if (grpc_trace_promise_primitives.enabled()) {
432       gpr_log(GPR_DEBUG, "join[%p]: joint 2/4 already ready", this);
433     }
434     if (!ready.is_set(2)) {
435       if (grpc_trace_promise_primitives.enabled()) {
436         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/4", this);
437       }
438       auto poll = promise2();
439       if (grpc_trace_promise_primitives.enabled()) {
440         auto* p = poll.value_if_ready();
441         gpr_log(GPR_DEBUG, "join[%p]: joint 3/4 %s", this,
442                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
443                              : "pending");
444       }
445       if (auto* p = poll.value_if_ready()) {
446         if (Traits::IsOk(*p)) {
447           ready.set(2);
448           Destruct(&promise2);
449           Construct(&result2, Traits::Unwrapped(std::move(*p)));
450         } else {
451           return Traits::template EarlyReturn<Result>(std::move(*p));
452         }
453       }
454     } else if (grpc_trace_promise_primitives.enabled()) {
455       gpr_log(GPR_DEBUG, "join[%p]: joint 3/4 already ready", this);
456     }
457     if (!ready.is_set(3)) {
458       if (grpc_trace_promise_primitives.enabled()) {
459         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/4", this);
460       }
461       auto poll = promise3();
462       if (grpc_trace_promise_primitives.enabled()) {
463         auto* p = poll.value_if_ready();
464         gpr_log(GPR_DEBUG, "join[%p]: joint 4/4 %s", this,
465                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
466                              : "pending");
467       }
468       if (auto* p = poll.value_if_ready()) {
469         if (Traits::IsOk(*p)) {
470           ready.set(3);
471           Destruct(&promise3);
472           Construct(&result3, Traits::Unwrapped(std::move(*p)));
473         } else {
474           return Traits::template EarlyReturn<Result>(std::move(*p));
475         }
476       }
477     } else if (grpc_trace_promise_primitives.enabled()) {
478       gpr_log(GPR_DEBUG, "join[%p]: joint 4/4 already ready", this);
479     }
480     if (ready.all()) {
481       return Traits::FinalReturn(std::move(result0), std::move(result1),
482                                  std::move(result2), std::move(result3));
483     }
484     return Pending{};
485   }
486 };
487 
488 template <class Traits, typename P0, typename P1, typename P2, typename P3,
489           typename P4>
490 struct JoinState<Traits, P0, P1, P2, P3, P4> {
491   template <typename T>
492   using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
493   using Promise0 = PromiseLike<P0>;
494   using Result0 = UnwrappedType<typename Promise0::Result>;
495   union {
496     GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
497     GPR_NO_UNIQUE_ADDRESS Result0 result0;
498   };
499   using Promise1 = PromiseLike<P1>;
500   using Result1 = UnwrappedType<typename Promise1::Result>;
501   union {
502     GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
503     GPR_NO_UNIQUE_ADDRESS Result1 result1;
504   };
505   using Promise2 = PromiseLike<P2>;
506   using Result2 = UnwrappedType<typename Promise2::Result>;
507   union {
508     GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
509     GPR_NO_UNIQUE_ADDRESS Result2 result2;
510   };
511   using Promise3 = PromiseLike<P3>;
512   using Result3 = UnwrappedType<typename Promise3::Result>;
513   union {
514     GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
515     GPR_NO_UNIQUE_ADDRESS Result3 result3;
516   };
517   using Promise4 = PromiseLike<P4>;
518   using Result4 = UnwrappedType<typename Promise4::Result>;
519   union {
520     GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
521     GPR_NO_UNIQUE_ADDRESS Result4 result4;
522   };
523   GPR_NO_UNIQUE_ADDRESS BitSet<5> ready;
524   JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4) {
525     Construct(&promise0, std::forward<P0>(p0));
526     Construct(&promise1, std::forward<P1>(p1));
527     Construct(&promise2, std::forward<P2>(p2));
528     Construct(&promise3, std::forward<P3>(p3));
529     Construct(&promise4, std::forward<P4>(p4));
530   }
531   JoinState(const JoinState& other) {
532     GPR_ASSERT(other.ready.none());
533     Construct(&promise0, other.promise0);
534     Construct(&promise1, other.promise1);
535     Construct(&promise2, other.promise2);
536     Construct(&promise3, other.promise3);
537     Construct(&promise4, other.promise4);
538   }
539   JoinState& operator=(const JoinState& other) = delete;
540   JoinState& operator=(JoinState&& other) = delete;
541   JoinState(JoinState&& other) noexcept : ready(other.ready) {
542     if (ready.is_set(0)) {
543       Construct(&result0, std::move(other.result0));
544     } else {
545       Construct(&promise0, std::move(other.promise0));
546     }
547     if (ready.is_set(1)) {
548       Construct(&result1, std::move(other.result1));
549     } else {
550       Construct(&promise1, std::move(other.promise1));
551     }
552     if (ready.is_set(2)) {
553       Construct(&result2, std::move(other.result2));
554     } else {
555       Construct(&promise2, std::move(other.promise2));
556     }
557     if (ready.is_set(3)) {
558       Construct(&result3, std::move(other.result3));
559     } else {
560       Construct(&promise3, std::move(other.promise3));
561     }
562     if (ready.is_set(4)) {
563       Construct(&result4, std::move(other.result4));
564     } else {
565       Construct(&promise4, std::move(other.promise4));
566     }
567   }
568   ~JoinState() {
569     if (ready.is_set(0)) {
570       Destruct(&result0);
571     } else {
572       Destruct(&promise0);
573     }
574     if (ready.is_set(1)) {
575       Destruct(&result1);
576     } else {
577       Destruct(&promise1);
578     }
579     if (ready.is_set(2)) {
580       Destruct(&result2);
581     } else {
582       Destruct(&promise2);
583     }
584     if (ready.is_set(3)) {
585       Destruct(&result3);
586     } else {
587       Destruct(&promise3);
588     }
589     if (ready.is_set(4)) {
590       Destruct(&result4);
591     } else {
592       Destruct(&promise4);
593     }
594   }
595   using Result = typename Traits::template ResultType<
596       std::tuple<Result0, Result1, Result2, Result3, Result4>>;
597   Poll<Result> PollOnce() {
598     if (!ready.is_set(0)) {
599       if (grpc_trace_promise_primitives.enabled()) {
600         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/5", this);
601       }
602       auto poll = promise0();
603       if (grpc_trace_promise_primitives.enabled()) {
604         auto* p = poll.value_if_ready();
605         gpr_log(GPR_DEBUG, "join[%p]: joint 1/5 %s", this,
606                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
607                              : "pending");
608       }
609       if (auto* p = poll.value_if_ready()) {
610         if (Traits::IsOk(*p)) {
611           ready.set(0);
612           Destruct(&promise0);
613           Construct(&result0, Traits::Unwrapped(std::move(*p)));
614         } else {
615           return Traits::template EarlyReturn<Result>(std::move(*p));
616         }
617       }
618     } else if (grpc_trace_promise_primitives.enabled()) {
619       gpr_log(GPR_DEBUG, "join[%p]: joint 1/5 already ready", this);
620     }
621     if (!ready.is_set(1)) {
622       if (grpc_trace_promise_primitives.enabled()) {
623         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/5", this);
624       }
625       auto poll = promise1();
626       if (grpc_trace_promise_primitives.enabled()) {
627         auto* p = poll.value_if_ready();
628         gpr_log(GPR_DEBUG, "join[%p]: joint 2/5 %s", this,
629                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
630                              : "pending");
631       }
632       if (auto* p = poll.value_if_ready()) {
633         if (Traits::IsOk(*p)) {
634           ready.set(1);
635           Destruct(&promise1);
636           Construct(&result1, Traits::Unwrapped(std::move(*p)));
637         } else {
638           return Traits::template EarlyReturn<Result>(std::move(*p));
639         }
640       }
641     } else if (grpc_trace_promise_primitives.enabled()) {
642       gpr_log(GPR_DEBUG, "join[%p]: joint 2/5 already ready", this);
643     }
644     if (!ready.is_set(2)) {
645       if (grpc_trace_promise_primitives.enabled()) {
646         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/5", this);
647       }
648       auto poll = promise2();
649       if (grpc_trace_promise_primitives.enabled()) {
650         auto* p = poll.value_if_ready();
651         gpr_log(GPR_DEBUG, "join[%p]: joint 3/5 %s", this,
652                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
653                              : "pending");
654       }
655       if (auto* p = poll.value_if_ready()) {
656         if (Traits::IsOk(*p)) {
657           ready.set(2);
658           Destruct(&promise2);
659           Construct(&result2, Traits::Unwrapped(std::move(*p)));
660         } else {
661           return Traits::template EarlyReturn<Result>(std::move(*p));
662         }
663       }
664     } else if (grpc_trace_promise_primitives.enabled()) {
665       gpr_log(GPR_DEBUG, "join[%p]: joint 3/5 already ready", this);
666     }
667     if (!ready.is_set(3)) {
668       if (grpc_trace_promise_primitives.enabled()) {
669         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/5", this);
670       }
671       auto poll = promise3();
672       if (grpc_trace_promise_primitives.enabled()) {
673         auto* p = poll.value_if_ready();
674         gpr_log(GPR_DEBUG, "join[%p]: joint 4/5 %s", this,
675                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
676                              : "pending");
677       }
678       if (auto* p = poll.value_if_ready()) {
679         if (Traits::IsOk(*p)) {
680           ready.set(3);
681           Destruct(&promise3);
682           Construct(&result3, Traits::Unwrapped(std::move(*p)));
683         } else {
684           return Traits::template EarlyReturn<Result>(std::move(*p));
685         }
686       }
687     } else if (grpc_trace_promise_primitives.enabled()) {
688       gpr_log(GPR_DEBUG, "join[%p]: joint 4/5 already ready", this);
689     }
690     if (!ready.is_set(4)) {
691       if (grpc_trace_promise_primitives.enabled()) {
692         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/5", this);
693       }
694       auto poll = promise4();
695       if (grpc_trace_promise_primitives.enabled()) {
696         auto* p = poll.value_if_ready();
697         gpr_log(GPR_DEBUG, "join[%p]: joint 5/5 %s", this,
698                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
699                              : "pending");
700       }
701       if (auto* p = poll.value_if_ready()) {
702         if (Traits::IsOk(*p)) {
703           ready.set(4);
704           Destruct(&promise4);
705           Construct(&result4, Traits::Unwrapped(std::move(*p)));
706         } else {
707           return Traits::template EarlyReturn<Result>(std::move(*p));
708         }
709       }
710     } else if (grpc_trace_promise_primitives.enabled()) {
711       gpr_log(GPR_DEBUG, "join[%p]: joint 5/5 already ready", this);
712     }
713     if (ready.all()) {
714       return Traits::FinalReturn(std::move(result0), std::move(result1),
715                                  std::move(result2), std::move(result3),
716                                  std::move(result4));
717     }
718     return Pending{};
719   }
720 };
721 
722 template <class Traits, typename P0, typename P1, typename P2, typename P3,
723           typename P4, typename P5>
724 struct JoinState<Traits, P0, P1, P2, P3, P4, P5> {
725   template <typename T>
726   using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
727   using Promise0 = PromiseLike<P0>;
728   using Result0 = UnwrappedType<typename Promise0::Result>;
729   union {
730     GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
731     GPR_NO_UNIQUE_ADDRESS Result0 result0;
732   };
733   using Promise1 = PromiseLike<P1>;
734   using Result1 = UnwrappedType<typename Promise1::Result>;
735   union {
736     GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
737     GPR_NO_UNIQUE_ADDRESS Result1 result1;
738   };
739   using Promise2 = PromiseLike<P2>;
740   using Result2 = UnwrappedType<typename Promise2::Result>;
741   union {
742     GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
743     GPR_NO_UNIQUE_ADDRESS Result2 result2;
744   };
745   using Promise3 = PromiseLike<P3>;
746   using Result3 = UnwrappedType<typename Promise3::Result>;
747   union {
748     GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
749     GPR_NO_UNIQUE_ADDRESS Result3 result3;
750   };
751   using Promise4 = PromiseLike<P4>;
752   using Result4 = UnwrappedType<typename Promise4::Result>;
753   union {
754     GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
755     GPR_NO_UNIQUE_ADDRESS Result4 result4;
756   };
757   using Promise5 = PromiseLike<P5>;
758   using Result5 = UnwrappedType<typename Promise5::Result>;
759   union {
760     GPR_NO_UNIQUE_ADDRESS Promise5 promise5;
761     GPR_NO_UNIQUE_ADDRESS Result5 result5;
762   };
763   GPR_NO_UNIQUE_ADDRESS BitSet<6> ready;
764   JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5) {
765     Construct(&promise0, std::forward<P0>(p0));
766     Construct(&promise1, std::forward<P1>(p1));
767     Construct(&promise2, std::forward<P2>(p2));
768     Construct(&promise3, std::forward<P3>(p3));
769     Construct(&promise4, std::forward<P4>(p4));
770     Construct(&promise5, std::forward<P5>(p5));
771   }
772   JoinState(const JoinState& other) {
773     GPR_ASSERT(other.ready.none());
774     Construct(&promise0, other.promise0);
775     Construct(&promise1, other.promise1);
776     Construct(&promise2, other.promise2);
777     Construct(&promise3, other.promise3);
778     Construct(&promise4, other.promise4);
779     Construct(&promise5, other.promise5);
780   }
781   JoinState& operator=(const JoinState& other) = delete;
782   JoinState& operator=(JoinState&& other) = delete;
783   JoinState(JoinState&& other) noexcept : ready(other.ready) {
784     if (ready.is_set(0)) {
785       Construct(&result0, std::move(other.result0));
786     } else {
787       Construct(&promise0, std::move(other.promise0));
788     }
789     if (ready.is_set(1)) {
790       Construct(&result1, std::move(other.result1));
791     } else {
792       Construct(&promise1, std::move(other.promise1));
793     }
794     if (ready.is_set(2)) {
795       Construct(&result2, std::move(other.result2));
796     } else {
797       Construct(&promise2, std::move(other.promise2));
798     }
799     if (ready.is_set(3)) {
800       Construct(&result3, std::move(other.result3));
801     } else {
802       Construct(&promise3, std::move(other.promise3));
803     }
804     if (ready.is_set(4)) {
805       Construct(&result4, std::move(other.result4));
806     } else {
807       Construct(&promise4, std::move(other.promise4));
808     }
809     if (ready.is_set(5)) {
810       Construct(&result5, std::move(other.result5));
811     } else {
812       Construct(&promise5, std::move(other.promise5));
813     }
814   }
815   ~JoinState() {
816     if (ready.is_set(0)) {
817       Destruct(&result0);
818     } else {
819       Destruct(&promise0);
820     }
821     if (ready.is_set(1)) {
822       Destruct(&result1);
823     } else {
824       Destruct(&promise1);
825     }
826     if (ready.is_set(2)) {
827       Destruct(&result2);
828     } else {
829       Destruct(&promise2);
830     }
831     if (ready.is_set(3)) {
832       Destruct(&result3);
833     } else {
834       Destruct(&promise3);
835     }
836     if (ready.is_set(4)) {
837       Destruct(&result4);
838     } else {
839       Destruct(&promise4);
840     }
841     if (ready.is_set(5)) {
842       Destruct(&result5);
843     } else {
844       Destruct(&promise5);
845     }
846   }
847   using Result = typename Traits::template ResultType<
848       std::tuple<Result0, Result1, Result2, Result3, Result4, Result5>>;
849   Poll<Result> PollOnce() {
850     if (!ready.is_set(0)) {
851       if (grpc_trace_promise_primitives.enabled()) {
852         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/6", this);
853       }
854       auto poll = promise0();
855       if (grpc_trace_promise_primitives.enabled()) {
856         auto* p = poll.value_if_ready();
857         gpr_log(GPR_DEBUG, "join[%p]: joint 1/6 %s", this,
858                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
859                              : "pending");
860       }
861       if (auto* p = poll.value_if_ready()) {
862         if (Traits::IsOk(*p)) {
863           ready.set(0);
864           Destruct(&promise0);
865           Construct(&result0, Traits::Unwrapped(std::move(*p)));
866         } else {
867           return Traits::template EarlyReturn<Result>(std::move(*p));
868         }
869       }
870     } else if (grpc_trace_promise_primitives.enabled()) {
871       gpr_log(GPR_DEBUG, "join[%p]: joint 1/6 already ready", this);
872     }
873     if (!ready.is_set(1)) {
874       if (grpc_trace_promise_primitives.enabled()) {
875         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/6", this);
876       }
877       auto poll = promise1();
878       if (grpc_trace_promise_primitives.enabled()) {
879         auto* p = poll.value_if_ready();
880         gpr_log(GPR_DEBUG, "join[%p]: joint 2/6 %s", this,
881                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
882                              : "pending");
883       }
884       if (auto* p = poll.value_if_ready()) {
885         if (Traits::IsOk(*p)) {
886           ready.set(1);
887           Destruct(&promise1);
888           Construct(&result1, Traits::Unwrapped(std::move(*p)));
889         } else {
890           return Traits::template EarlyReturn<Result>(std::move(*p));
891         }
892       }
893     } else if (grpc_trace_promise_primitives.enabled()) {
894       gpr_log(GPR_DEBUG, "join[%p]: joint 2/6 already ready", this);
895     }
896     if (!ready.is_set(2)) {
897       if (grpc_trace_promise_primitives.enabled()) {
898         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/6", this);
899       }
900       auto poll = promise2();
901       if (grpc_trace_promise_primitives.enabled()) {
902         auto* p = poll.value_if_ready();
903         gpr_log(GPR_DEBUG, "join[%p]: joint 3/6 %s", this,
904                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
905                              : "pending");
906       }
907       if (auto* p = poll.value_if_ready()) {
908         if (Traits::IsOk(*p)) {
909           ready.set(2);
910           Destruct(&promise2);
911           Construct(&result2, Traits::Unwrapped(std::move(*p)));
912         } else {
913           return Traits::template EarlyReturn<Result>(std::move(*p));
914         }
915       }
916     } else if (grpc_trace_promise_primitives.enabled()) {
917       gpr_log(GPR_DEBUG, "join[%p]: joint 3/6 already ready", this);
918     }
919     if (!ready.is_set(3)) {
920       if (grpc_trace_promise_primitives.enabled()) {
921         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/6", this);
922       }
923       auto poll = promise3();
924       if (grpc_trace_promise_primitives.enabled()) {
925         auto* p = poll.value_if_ready();
926         gpr_log(GPR_DEBUG, "join[%p]: joint 4/6 %s", this,
927                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
928                              : "pending");
929       }
930       if (auto* p = poll.value_if_ready()) {
931         if (Traits::IsOk(*p)) {
932           ready.set(3);
933           Destruct(&promise3);
934           Construct(&result3, Traits::Unwrapped(std::move(*p)));
935         } else {
936           return Traits::template EarlyReturn<Result>(std::move(*p));
937         }
938       }
939     } else if (grpc_trace_promise_primitives.enabled()) {
940       gpr_log(GPR_DEBUG, "join[%p]: joint 4/6 already ready", this);
941     }
942     if (!ready.is_set(4)) {
943       if (grpc_trace_promise_primitives.enabled()) {
944         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/6", this);
945       }
946       auto poll = promise4();
947       if (grpc_trace_promise_primitives.enabled()) {
948         auto* p = poll.value_if_ready();
949         gpr_log(GPR_DEBUG, "join[%p]: joint 5/6 %s", this,
950                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
951                              : "pending");
952       }
953       if (auto* p = poll.value_if_ready()) {
954         if (Traits::IsOk(*p)) {
955           ready.set(4);
956           Destruct(&promise4);
957           Construct(&result4, Traits::Unwrapped(std::move(*p)));
958         } else {
959           return Traits::template EarlyReturn<Result>(std::move(*p));
960         }
961       }
962     } else if (grpc_trace_promise_primitives.enabled()) {
963       gpr_log(GPR_DEBUG, "join[%p]: joint 5/6 already ready", this);
964     }
965     if (!ready.is_set(5)) {
966       if (grpc_trace_promise_primitives.enabled()) {
967         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 6/6", this);
968       }
969       auto poll = promise5();
970       if (grpc_trace_promise_primitives.enabled()) {
971         auto* p = poll.value_if_ready();
972         gpr_log(GPR_DEBUG, "join[%p]: joint 6/6 %s", this,
973                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
974                              : "pending");
975       }
976       if (auto* p = poll.value_if_ready()) {
977         if (Traits::IsOk(*p)) {
978           ready.set(5);
979           Destruct(&promise5);
980           Construct(&result5, Traits::Unwrapped(std::move(*p)));
981         } else {
982           return Traits::template EarlyReturn<Result>(std::move(*p));
983         }
984       }
985     } else if (grpc_trace_promise_primitives.enabled()) {
986       gpr_log(GPR_DEBUG, "join[%p]: joint 6/6 already ready", this);
987     }
988     if (ready.all()) {
989       return Traits::FinalReturn(std::move(result0), std::move(result1),
990                                  std::move(result2), std::move(result3),
991                                  std::move(result4), std::move(result5));
992     }
993     return Pending{};
994   }
995 };
996 
997 template <class Traits, typename P0, typename P1, typename P2, typename P3,
998           typename P4, typename P5, typename P6>
999 struct JoinState<Traits, P0, P1, P2, P3, P4, P5, P6> {
1000   template <typename T>
1001   using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
1002   using Promise0 = PromiseLike<P0>;
1003   using Result0 = UnwrappedType<typename Promise0::Result>;
1004   union {
1005     GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
1006     GPR_NO_UNIQUE_ADDRESS Result0 result0;
1007   };
1008   using Promise1 = PromiseLike<P1>;
1009   using Result1 = UnwrappedType<typename Promise1::Result>;
1010   union {
1011     GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
1012     GPR_NO_UNIQUE_ADDRESS Result1 result1;
1013   };
1014   using Promise2 = PromiseLike<P2>;
1015   using Result2 = UnwrappedType<typename Promise2::Result>;
1016   union {
1017     GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
1018     GPR_NO_UNIQUE_ADDRESS Result2 result2;
1019   };
1020   using Promise3 = PromiseLike<P3>;
1021   using Result3 = UnwrappedType<typename Promise3::Result>;
1022   union {
1023     GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
1024     GPR_NO_UNIQUE_ADDRESS Result3 result3;
1025   };
1026   using Promise4 = PromiseLike<P4>;
1027   using Result4 = UnwrappedType<typename Promise4::Result>;
1028   union {
1029     GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
1030     GPR_NO_UNIQUE_ADDRESS Result4 result4;
1031   };
1032   using Promise5 = PromiseLike<P5>;
1033   using Result5 = UnwrappedType<typename Promise5::Result>;
1034   union {
1035     GPR_NO_UNIQUE_ADDRESS Promise5 promise5;
1036     GPR_NO_UNIQUE_ADDRESS Result5 result5;
1037   };
1038   using Promise6 = PromiseLike<P6>;
1039   using Result6 = UnwrappedType<typename Promise6::Result>;
1040   union {
1041     GPR_NO_UNIQUE_ADDRESS Promise6 promise6;
1042     GPR_NO_UNIQUE_ADDRESS Result6 result6;
1043   };
1044   GPR_NO_UNIQUE_ADDRESS BitSet<7> ready;
1045   JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6) {
1046     Construct(&promise0, std::forward<P0>(p0));
1047     Construct(&promise1, std::forward<P1>(p1));
1048     Construct(&promise2, std::forward<P2>(p2));
1049     Construct(&promise3, std::forward<P3>(p3));
1050     Construct(&promise4, std::forward<P4>(p4));
1051     Construct(&promise5, std::forward<P5>(p5));
1052     Construct(&promise6, std::forward<P6>(p6));
1053   }
1054   JoinState(const JoinState& other) {
1055     GPR_ASSERT(other.ready.none());
1056     Construct(&promise0, other.promise0);
1057     Construct(&promise1, other.promise1);
1058     Construct(&promise2, other.promise2);
1059     Construct(&promise3, other.promise3);
1060     Construct(&promise4, other.promise4);
1061     Construct(&promise5, other.promise5);
1062     Construct(&promise6, other.promise6);
1063   }
1064   JoinState& operator=(const JoinState& other) = delete;
1065   JoinState& operator=(JoinState&& other) = delete;
1066   JoinState(JoinState&& other) noexcept : ready(other.ready) {
1067     if (ready.is_set(0)) {
1068       Construct(&result0, std::move(other.result0));
1069     } else {
1070       Construct(&promise0, std::move(other.promise0));
1071     }
1072     if (ready.is_set(1)) {
1073       Construct(&result1, std::move(other.result1));
1074     } else {
1075       Construct(&promise1, std::move(other.promise1));
1076     }
1077     if (ready.is_set(2)) {
1078       Construct(&result2, std::move(other.result2));
1079     } else {
1080       Construct(&promise2, std::move(other.promise2));
1081     }
1082     if (ready.is_set(3)) {
1083       Construct(&result3, std::move(other.result3));
1084     } else {
1085       Construct(&promise3, std::move(other.promise3));
1086     }
1087     if (ready.is_set(4)) {
1088       Construct(&result4, std::move(other.result4));
1089     } else {
1090       Construct(&promise4, std::move(other.promise4));
1091     }
1092     if (ready.is_set(5)) {
1093       Construct(&result5, std::move(other.result5));
1094     } else {
1095       Construct(&promise5, std::move(other.promise5));
1096     }
1097     if (ready.is_set(6)) {
1098       Construct(&result6, std::move(other.result6));
1099     } else {
1100       Construct(&promise6, std::move(other.promise6));
1101     }
1102   }
1103   ~JoinState() {
1104     if (ready.is_set(0)) {
1105       Destruct(&result0);
1106     } else {
1107       Destruct(&promise0);
1108     }
1109     if (ready.is_set(1)) {
1110       Destruct(&result1);
1111     } else {
1112       Destruct(&promise1);
1113     }
1114     if (ready.is_set(2)) {
1115       Destruct(&result2);
1116     } else {
1117       Destruct(&promise2);
1118     }
1119     if (ready.is_set(3)) {
1120       Destruct(&result3);
1121     } else {
1122       Destruct(&promise3);
1123     }
1124     if (ready.is_set(4)) {
1125       Destruct(&result4);
1126     } else {
1127       Destruct(&promise4);
1128     }
1129     if (ready.is_set(5)) {
1130       Destruct(&result5);
1131     } else {
1132       Destruct(&promise5);
1133     }
1134     if (ready.is_set(6)) {
1135       Destruct(&result6);
1136     } else {
1137       Destruct(&promise6);
1138     }
1139   }
1140   using Result = typename Traits::template ResultType<std::tuple<
1141       Result0, Result1, Result2, Result3, Result4, Result5, Result6>>;
1142   Poll<Result> PollOnce() {
1143     if (!ready.is_set(0)) {
1144       if (grpc_trace_promise_primitives.enabled()) {
1145         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/7", this);
1146       }
1147       auto poll = promise0();
1148       if (grpc_trace_promise_primitives.enabled()) {
1149         auto* p = poll.value_if_ready();
1150         gpr_log(GPR_DEBUG, "join[%p]: joint 1/7 %s", this,
1151                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1152                              : "pending");
1153       }
1154       if (auto* p = poll.value_if_ready()) {
1155         if (Traits::IsOk(*p)) {
1156           ready.set(0);
1157           Destruct(&promise0);
1158           Construct(&result0, Traits::Unwrapped(std::move(*p)));
1159         } else {
1160           return Traits::template EarlyReturn<Result>(std::move(*p));
1161         }
1162       }
1163     } else if (grpc_trace_promise_primitives.enabled()) {
1164       gpr_log(GPR_DEBUG, "join[%p]: joint 1/7 already ready", this);
1165     }
1166     if (!ready.is_set(1)) {
1167       if (grpc_trace_promise_primitives.enabled()) {
1168         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/7", this);
1169       }
1170       auto poll = promise1();
1171       if (grpc_trace_promise_primitives.enabled()) {
1172         auto* p = poll.value_if_ready();
1173         gpr_log(GPR_DEBUG, "join[%p]: joint 2/7 %s", this,
1174                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1175                              : "pending");
1176       }
1177       if (auto* p = poll.value_if_ready()) {
1178         if (Traits::IsOk(*p)) {
1179           ready.set(1);
1180           Destruct(&promise1);
1181           Construct(&result1, Traits::Unwrapped(std::move(*p)));
1182         } else {
1183           return Traits::template EarlyReturn<Result>(std::move(*p));
1184         }
1185       }
1186     } else if (grpc_trace_promise_primitives.enabled()) {
1187       gpr_log(GPR_DEBUG, "join[%p]: joint 2/7 already ready", this);
1188     }
1189     if (!ready.is_set(2)) {
1190       if (grpc_trace_promise_primitives.enabled()) {
1191         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/7", this);
1192       }
1193       auto poll = promise2();
1194       if (grpc_trace_promise_primitives.enabled()) {
1195         auto* p = poll.value_if_ready();
1196         gpr_log(GPR_DEBUG, "join[%p]: joint 3/7 %s", this,
1197                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1198                              : "pending");
1199       }
1200       if (auto* p = poll.value_if_ready()) {
1201         if (Traits::IsOk(*p)) {
1202           ready.set(2);
1203           Destruct(&promise2);
1204           Construct(&result2, Traits::Unwrapped(std::move(*p)));
1205         } else {
1206           return Traits::template EarlyReturn<Result>(std::move(*p));
1207         }
1208       }
1209     } else if (grpc_trace_promise_primitives.enabled()) {
1210       gpr_log(GPR_DEBUG, "join[%p]: joint 3/7 already ready", this);
1211     }
1212     if (!ready.is_set(3)) {
1213       if (grpc_trace_promise_primitives.enabled()) {
1214         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/7", this);
1215       }
1216       auto poll = promise3();
1217       if (grpc_trace_promise_primitives.enabled()) {
1218         auto* p = poll.value_if_ready();
1219         gpr_log(GPR_DEBUG, "join[%p]: joint 4/7 %s", this,
1220                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1221                              : "pending");
1222       }
1223       if (auto* p = poll.value_if_ready()) {
1224         if (Traits::IsOk(*p)) {
1225           ready.set(3);
1226           Destruct(&promise3);
1227           Construct(&result3, Traits::Unwrapped(std::move(*p)));
1228         } else {
1229           return Traits::template EarlyReturn<Result>(std::move(*p));
1230         }
1231       }
1232     } else if (grpc_trace_promise_primitives.enabled()) {
1233       gpr_log(GPR_DEBUG, "join[%p]: joint 4/7 already ready", this);
1234     }
1235     if (!ready.is_set(4)) {
1236       if (grpc_trace_promise_primitives.enabled()) {
1237         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/7", this);
1238       }
1239       auto poll = promise4();
1240       if (grpc_trace_promise_primitives.enabled()) {
1241         auto* p = poll.value_if_ready();
1242         gpr_log(GPR_DEBUG, "join[%p]: joint 5/7 %s", this,
1243                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1244                              : "pending");
1245       }
1246       if (auto* p = poll.value_if_ready()) {
1247         if (Traits::IsOk(*p)) {
1248           ready.set(4);
1249           Destruct(&promise4);
1250           Construct(&result4, Traits::Unwrapped(std::move(*p)));
1251         } else {
1252           return Traits::template EarlyReturn<Result>(std::move(*p));
1253         }
1254       }
1255     } else if (grpc_trace_promise_primitives.enabled()) {
1256       gpr_log(GPR_DEBUG, "join[%p]: joint 5/7 already ready", this);
1257     }
1258     if (!ready.is_set(5)) {
1259       if (grpc_trace_promise_primitives.enabled()) {
1260         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 6/7", this);
1261       }
1262       auto poll = promise5();
1263       if (grpc_trace_promise_primitives.enabled()) {
1264         auto* p = poll.value_if_ready();
1265         gpr_log(GPR_DEBUG, "join[%p]: joint 6/7 %s", this,
1266                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1267                              : "pending");
1268       }
1269       if (auto* p = poll.value_if_ready()) {
1270         if (Traits::IsOk(*p)) {
1271           ready.set(5);
1272           Destruct(&promise5);
1273           Construct(&result5, Traits::Unwrapped(std::move(*p)));
1274         } else {
1275           return Traits::template EarlyReturn<Result>(std::move(*p));
1276         }
1277       }
1278     } else if (grpc_trace_promise_primitives.enabled()) {
1279       gpr_log(GPR_DEBUG, "join[%p]: joint 6/7 already ready", this);
1280     }
1281     if (!ready.is_set(6)) {
1282       if (grpc_trace_promise_primitives.enabled()) {
1283         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 7/7", this);
1284       }
1285       auto poll = promise6();
1286       if (grpc_trace_promise_primitives.enabled()) {
1287         auto* p = poll.value_if_ready();
1288         gpr_log(GPR_DEBUG, "join[%p]: joint 7/7 %s", this,
1289                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1290                              : "pending");
1291       }
1292       if (auto* p = poll.value_if_ready()) {
1293         if (Traits::IsOk(*p)) {
1294           ready.set(6);
1295           Destruct(&promise6);
1296           Construct(&result6, Traits::Unwrapped(std::move(*p)));
1297         } else {
1298           return Traits::template EarlyReturn<Result>(std::move(*p));
1299         }
1300       }
1301     } else if (grpc_trace_promise_primitives.enabled()) {
1302       gpr_log(GPR_DEBUG, "join[%p]: joint 7/7 already ready", this);
1303     }
1304     if (ready.all()) {
1305       return Traits::FinalReturn(std::move(result0), std::move(result1),
1306                                  std::move(result2), std::move(result3),
1307                                  std::move(result4), std::move(result5),
1308                                  std::move(result6));
1309     }
1310     return Pending{};
1311   }
1312 };
1313 
1314 template <class Traits, typename P0, typename P1, typename P2, typename P3,
1315           typename P4, typename P5, typename P6, typename P7>
1316 struct JoinState<Traits, P0, P1, P2, P3, P4, P5, P6, P7> {
1317   template <typename T>
1318   using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
1319   using Promise0 = PromiseLike<P0>;
1320   using Result0 = UnwrappedType<typename Promise0::Result>;
1321   union {
1322     GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
1323     GPR_NO_UNIQUE_ADDRESS Result0 result0;
1324   };
1325   using Promise1 = PromiseLike<P1>;
1326   using Result1 = UnwrappedType<typename Promise1::Result>;
1327   union {
1328     GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
1329     GPR_NO_UNIQUE_ADDRESS Result1 result1;
1330   };
1331   using Promise2 = PromiseLike<P2>;
1332   using Result2 = UnwrappedType<typename Promise2::Result>;
1333   union {
1334     GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
1335     GPR_NO_UNIQUE_ADDRESS Result2 result2;
1336   };
1337   using Promise3 = PromiseLike<P3>;
1338   using Result3 = UnwrappedType<typename Promise3::Result>;
1339   union {
1340     GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
1341     GPR_NO_UNIQUE_ADDRESS Result3 result3;
1342   };
1343   using Promise4 = PromiseLike<P4>;
1344   using Result4 = UnwrappedType<typename Promise4::Result>;
1345   union {
1346     GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
1347     GPR_NO_UNIQUE_ADDRESS Result4 result4;
1348   };
1349   using Promise5 = PromiseLike<P5>;
1350   using Result5 = UnwrappedType<typename Promise5::Result>;
1351   union {
1352     GPR_NO_UNIQUE_ADDRESS Promise5 promise5;
1353     GPR_NO_UNIQUE_ADDRESS Result5 result5;
1354   };
1355   using Promise6 = PromiseLike<P6>;
1356   using Result6 = UnwrappedType<typename Promise6::Result>;
1357   union {
1358     GPR_NO_UNIQUE_ADDRESS Promise6 promise6;
1359     GPR_NO_UNIQUE_ADDRESS Result6 result6;
1360   };
1361   using Promise7 = PromiseLike<P7>;
1362   using Result7 = UnwrappedType<typename Promise7::Result>;
1363   union {
1364     GPR_NO_UNIQUE_ADDRESS Promise7 promise7;
1365     GPR_NO_UNIQUE_ADDRESS Result7 result7;
1366   };
1367   GPR_NO_UNIQUE_ADDRESS BitSet<8> ready;
1368   JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6,
1369             P7&& p7) {
1370     Construct(&promise0, std::forward<P0>(p0));
1371     Construct(&promise1, std::forward<P1>(p1));
1372     Construct(&promise2, std::forward<P2>(p2));
1373     Construct(&promise3, std::forward<P3>(p3));
1374     Construct(&promise4, std::forward<P4>(p4));
1375     Construct(&promise5, std::forward<P5>(p5));
1376     Construct(&promise6, std::forward<P6>(p6));
1377     Construct(&promise7, std::forward<P7>(p7));
1378   }
1379   JoinState(const JoinState& other) {
1380     GPR_ASSERT(other.ready.none());
1381     Construct(&promise0, other.promise0);
1382     Construct(&promise1, other.promise1);
1383     Construct(&promise2, other.promise2);
1384     Construct(&promise3, other.promise3);
1385     Construct(&promise4, other.promise4);
1386     Construct(&promise5, other.promise5);
1387     Construct(&promise6, other.promise6);
1388     Construct(&promise7, other.promise7);
1389   }
1390   JoinState& operator=(const JoinState& other) = delete;
1391   JoinState& operator=(JoinState&& other) = delete;
1392   JoinState(JoinState&& other) noexcept : ready(other.ready) {
1393     if (ready.is_set(0)) {
1394       Construct(&result0, std::move(other.result0));
1395     } else {
1396       Construct(&promise0, std::move(other.promise0));
1397     }
1398     if (ready.is_set(1)) {
1399       Construct(&result1, std::move(other.result1));
1400     } else {
1401       Construct(&promise1, std::move(other.promise1));
1402     }
1403     if (ready.is_set(2)) {
1404       Construct(&result2, std::move(other.result2));
1405     } else {
1406       Construct(&promise2, std::move(other.promise2));
1407     }
1408     if (ready.is_set(3)) {
1409       Construct(&result3, std::move(other.result3));
1410     } else {
1411       Construct(&promise3, std::move(other.promise3));
1412     }
1413     if (ready.is_set(4)) {
1414       Construct(&result4, std::move(other.result4));
1415     } else {
1416       Construct(&promise4, std::move(other.promise4));
1417     }
1418     if (ready.is_set(5)) {
1419       Construct(&result5, std::move(other.result5));
1420     } else {
1421       Construct(&promise5, std::move(other.promise5));
1422     }
1423     if (ready.is_set(6)) {
1424       Construct(&result6, std::move(other.result6));
1425     } else {
1426       Construct(&promise6, std::move(other.promise6));
1427     }
1428     if (ready.is_set(7)) {
1429       Construct(&result7, std::move(other.result7));
1430     } else {
1431       Construct(&promise7, std::move(other.promise7));
1432     }
1433   }
1434   ~JoinState() {
1435     if (ready.is_set(0)) {
1436       Destruct(&result0);
1437     } else {
1438       Destruct(&promise0);
1439     }
1440     if (ready.is_set(1)) {
1441       Destruct(&result1);
1442     } else {
1443       Destruct(&promise1);
1444     }
1445     if (ready.is_set(2)) {
1446       Destruct(&result2);
1447     } else {
1448       Destruct(&promise2);
1449     }
1450     if (ready.is_set(3)) {
1451       Destruct(&result3);
1452     } else {
1453       Destruct(&promise3);
1454     }
1455     if (ready.is_set(4)) {
1456       Destruct(&result4);
1457     } else {
1458       Destruct(&promise4);
1459     }
1460     if (ready.is_set(5)) {
1461       Destruct(&result5);
1462     } else {
1463       Destruct(&promise5);
1464     }
1465     if (ready.is_set(6)) {
1466       Destruct(&result6);
1467     } else {
1468       Destruct(&promise6);
1469     }
1470     if (ready.is_set(7)) {
1471       Destruct(&result7);
1472     } else {
1473       Destruct(&promise7);
1474     }
1475   }
1476   using Result = typename Traits::template ResultType<std::tuple<
1477       Result0, Result1, Result2, Result3, Result4, Result5, Result6, Result7>>;
1478   Poll<Result> PollOnce() {
1479     if (!ready.is_set(0)) {
1480       if (grpc_trace_promise_primitives.enabled()) {
1481         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/8", this);
1482       }
1483       auto poll = promise0();
1484       if (grpc_trace_promise_primitives.enabled()) {
1485         auto* p = poll.value_if_ready();
1486         gpr_log(GPR_DEBUG, "join[%p]: joint 1/8 %s", this,
1487                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1488                              : "pending");
1489       }
1490       if (auto* p = poll.value_if_ready()) {
1491         if (Traits::IsOk(*p)) {
1492           ready.set(0);
1493           Destruct(&promise0);
1494           Construct(&result0, Traits::Unwrapped(std::move(*p)));
1495         } else {
1496           return Traits::template EarlyReturn<Result>(std::move(*p));
1497         }
1498       }
1499     } else if (grpc_trace_promise_primitives.enabled()) {
1500       gpr_log(GPR_DEBUG, "join[%p]: joint 1/8 already ready", this);
1501     }
1502     if (!ready.is_set(1)) {
1503       if (grpc_trace_promise_primitives.enabled()) {
1504         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/8", this);
1505       }
1506       auto poll = promise1();
1507       if (grpc_trace_promise_primitives.enabled()) {
1508         auto* p = poll.value_if_ready();
1509         gpr_log(GPR_DEBUG, "join[%p]: joint 2/8 %s", this,
1510                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1511                              : "pending");
1512       }
1513       if (auto* p = poll.value_if_ready()) {
1514         if (Traits::IsOk(*p)) {
1515           ready.set(1);
1516           Destruct(&promise1);
1517           Construct(&result1, Traits::Unwrapped(std::move(*p)));
1518         } else {
1519           return Traits::template EarlyReturn<Result>(std::move(*p));
1520         }
1521       }
1522     } else if (grpc_trace_promise_primitives.enabled()) {
1523       gpr_log(GPR_DEBUG, "join[%p]: joint 2/8 already ready", this);
1524     }
1525     if (!ready.is_set(2)) {
1526       if (grpc_trace_promise_primitives.enabled()) {
1527         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/8", this);
1528       }
1529       auto poll = promise2();
1530       if (grpc_trace_promise_primitives.enabled()) {
1531         auto* p = poll.value_if_ready();
1532         gpr_log(GPR_DEBUG, "join[%p]: joint 3/8 %s", this,
1533                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1534                              : "pending");
1535       }
1536       if (auto* p = poll.value_if_ready()) {
1537         if (Traits::IsOk(*p)) {
1538           ready.set(2);
1539           Destruct(&promise2);
1540           Construct(&result2, Traits::Unwrapped(std::move(*p)));
1541         } else {
1542           return Traits::template EarlyReturn<Result>(std::move(*p));
1543         }
1544       }
1545     } else if (grpc_trace_promise_primitives.enabled()) {
1546       gpr_log(GPR_DEBUG, "join[%p]: joint 3/8 already ready", this);
1547     }
1548     if (!ready.is_set(3)) {
1549       if (grpc_trace_promise_primitives.enabled()) {
1550         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/8", this);
1551       }
1552       auto poll = promise3();
1553       if (grpc_trace_promise_primitives.enabled()) {
1554         auto* p = poll.value_if_ready();
1555         gpr_log(GPR_DEBUG, "join[%p]: joint 4/8 %s", this,
1556                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1557                              : "pending");
1558       }
1559       if (auto* p = poll.value_if_ready()) {
1560         if (Traits::IsOk(*p)) {
1561           ready.set(3);
1562           Destruct(&promise3);
1563           Construct(&result3, Traits::Unwrapped(std::move(*p)));
1564         } else {
1565           return Traits::template EarlyReturn<Result>(std::move(*p));
1566         }
1567       }
1568     } else if (grpc_trace_promise_primitives.enabled()) {
1569       gpr_log(GPR_DEBUG, "join[%p]: joint 4/8 already ready", this);
1570     }
1571     if (!ready.is_set(4)) {
1572       if (grpc_trace_promise_primitives.enabled()) {
1573         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/8", this);
1574       }
1575       auto poll = promise4();
1576       if (grpc_trace_promise_primitives.enabled()) {
1577         auto* p = poll.value_if_ready();
1578         gpr_log(GPR_DEBUG, "join[%p]: joint 5/8 %s", this,
1579                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1580                              : "pending");
1581       }
1582       if (auto* p = poll.value_if_ready()) {
1583         if (Traits::IsOk(*p)) {
1584           ready.set(4);
1585           Destruct(&promise4);
1586           Construct(&result4, Traits::Unwrapped(std::move(*p)));
1587         } else {
1588           return Traits::template EarlyReturn<Result>(std::move(*p));
1589         }
1590       }
1591     } else if (grpc_trace_promise_primitives.enabled()) {
1592       gpr_log(GPR_DEBUG, "join[%p]: joint 5/8 already ready", this);
1593     }
1594     if (!ready.is_set(5)) {
1595       if (grpc_trace_promise_primitives.enabled()) {
1596         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 6/8", this);
1597       }
1598       auto poll = promise5();
1599       if (grpc_trace_promise_primitives.enabled()) {
1600         auto* p = poll.value_if_ready();
1601         gpr_log(GPR_DEBUG, "join[%p]: joint 6/8 %s", this,
1602                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1603                              : "pending");
1604       }
1605       if (auto* p = poll.value_if_ready()) {
1606         if (Traits::IsOk(*p)) {
1607           ready.set(5);
1608           Destruct(&promise5);
1609           Construct(&result5, Traits::Unwrapped(std::move(*p)));
1610         } else {
1611           return Traits::template EarlyReturn<Result>(std::move(*p));
1612         }
1613       }
1614     } else if (grpc_trace_promise_primitives.enabled()) {
1615       gpr_log(GPR_DEBUG, "join[%p]: joint 6/8 already ready", this);
1616     }
1617     if (!ready.is_set(6)) {
1618       if (grpc_trace_promise_primitives.enabled()) {
1619         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 7/8", this);
1620       }
1621       auto poll = promise6();
1622       if (grpc_trace_promise_primitives.enabled()) {
1623         auto* p = poll.value_if_ready();
1624         gpr_log(GPR_DEBUG, "join[%p]: joint 7/8 %s", this,
1625                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1626                              : "pending");
1627       }
1628       if (auto* p = poll.value_if_ready()) {
1629         if (Traits::IsOk(*p)) {
1630           ready.set(6);
1631           Destruct(&promise6);
1632           Construct(&result6, Traits::Unwrapped(std::move(*p)));
1633         } else {
1634           return Traits::template EarlyReturn<Result>(std::move(*p));
1635         }
1636       }
1637     } else if (grpc_trace_promise_primitives.enabled()) {
1638       gpr_log(GPR_DEBUG, "join[%p]: joint 7/8 already ready", this);
1639     }
1640     if (!ready.is_set(7)) {
1641       if (grpc_trace_promise_primitives.enabled()) {
1642         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 8/8", this);
1643       }
1644       auto poll = promise7();
1645       if (grpc_trace_promise_primitives.enabled()) {
1646         auto* p = poll.value_if_ready();
1647         gpr_log(GPR_DEBUG, "join[%p]: joint 8/8 %s", this,
1648                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1649                              : "pending");
1650       }
1651       if (auto* p = poll.value_if_ready()) {
1652         if (Traits::IsOk(*p)) {
1653           ready.set(7);
1654           Destruct(&promise7);
1655           Construct(&result7, Traits::Unwrapped(std::move(*p)));
1656         } else {
1657           return Traits::template EarlyReturn<Result>(std::move(*p));
1658         }
1659       }
1660     } else if (grpc_trace_promise_primitives.enabled()) {
1661       gpr_log(GPR_DEBUG, "join[%p]: joint 8/8 already ready", this);
1662     }
1663     if (ready.all()) {
1664       return Traits::FinalReturn(std::move(result0), std::move(result1),
1665                                  std::move(result2), std::move(result3),
1666                                  std::move(result4), std::move(result5),
1667                                  std::move(result6), std::move(result7));
1668     }
1669     return Pending{};
1670   }
1671 };
1672 
1673 template <class Traits, typename P0, typename P1, typename P2, typename P3,
1674           typename P4, typename P5, typename P6, typename P7, typename P8>
1675 struct JoinState<Traits, P0, P1, P2, P3, P4, P5, P6, P7, P8> {
1676   template <typename T>
1677   using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
1678   using Promise0 = PromiseLike<P0>;
1679   using Result0 = UnwrappedType<typename Promise0::Result>;
1680   union {
1681     GPR_NO_UNIQUE_ADDRESS Promise0 promise0;
1682     GPR_NO_UNIQUE_ADDRESS Result0 result0;
1683   };
1684   using Promise1 = PromiseLike<P1>;
1685   using Result1 = UnwrappedType<typename Promise1::Result>;
1686   union {
1687     GPR_NO_UNIQUE_ADDRESS Promise1 promise1;
1688     GPR_NO_UNIQUE_ADDRESS Result1 result1;
1689   };
1690   using Promise2 = PromiseLike<P2>;
1691   using Result2 = UnwrappedType<typename Promise2::Result>;
1692   union {
1693     GPR_NO_UNIQUE_ADDRESS Promise2 promise2;
1694     GPR_NO_UNIQUE_ADDRESS Result2 result2;
1695   };
1696   using Promise3 = PromiseLike<P3>;
1697   using Result3 = UnwrappedType<typename Promise3::Result>;
1698   union {
1699     GPR_NO_UNIQUE_ADDRESS Promise3 promise3;
1700     GPR_NO_UNIQUE_ADDRESS Result3 result3;
1701   };
1702   using Promise4 = PromiseLike<P4>;
1703   using Result4 = UnwrappedType<typename Promise4::Result>;
1704   union {
1705     GPR_NO_UNIQUE_ADDRESS Promise4 promise4;
1706     GPR_NO_UNIQUE_ADDRESS Result4 result4;
1707   };
1708   using Promise5 = PromiseLike<P5>;
1709   using Result5 = UnwrappedType<typename Promise5::Result>;
1710   union {
1711     GPR_NO_UNIQUE_ADDRESS Promise5 promise5;
1712     GPR_NO_UNIQUE_ADDRESS Result5 result5;
1713   };
1714   using Promise6 = PromiseLike<P6>;
1715   using Result6 = UnwrappedType<typename Promise6::Result>;
1716   union {
1717     GPR_NO_UNIQUE_ADDRESS Promise6 promise6;
1718     GPR_NO_UNIQUE_ADDRESS Result6 result6;
1719   };
1720   using Promise7 = PromiseLike<P7>;
1721   using Result7 = UnwrappedType<typename Promise7::Result>;
1722   union {
1723     GPR_NO_UNIQUE_ADDRESS Promise7 promise7;
1724     GPR_NO_UNIQUE_ADDRESS Result7 result7;
1725   };
1726   using Promise8 = PromiseLike<P8>;
1727   using Result8 = UnwrappedType<typename Promise8::Result>;
1728   union {
1729     GPR_NO_UNIQUE_ADDRESS Promise8 promise8;
1730     GPR_NO_UNIQUE_ADDRESS Result8 result8;
1731   };
1732   GPR_NO_UNIQUE_ADDRESS BitSet<9> ready;
1733   JoinState(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6,
1734             P7&& p7, P8&& p8) {
1735     Construct(&promise0, std::forward<P0>(p0));
1736     Construct(&promise1, std::forward<P1>(p1));
1737     Construct(&promise2, std::forward<P2>(p2));
1738     Construct(&promise3, std::forward<P3>(p3));
1739     Construct(&promise4, std::forward<P4>(p4));
1740     Construct(&promise5, std::forward<P5>(p5));
1741     Construct(&promise6, std::forward<P6>(p6));
1742     Construct(&promise7, std::forward<P7>(p7));
1743     Construct(&promise8, std::forward<P8>(p8));
1744   }
1745   JoinState(const JoinState& other) {
1746     GPR_ASSERT(other.ready.none());
1747     Construct(&promise0, other.promise0);
1748     Construct(&promise1, other.promise1);
1749     Construct(&promise2, other.promise2);
1750     Construct(&promise3, other.promise3);
1751     Construct(&promise4, other.promise4);
1752     Construct(&promise5, other.promise5);
1753     Construct(&promise6, other.promise6);
1754     Construct(&promise7, other.promise7);
1755     Construct(&promise8, other.promise8);
1756   }
1757   JoinState& operator=(const JoinState& other) = delete;
1758   JoinState& operator=(JoinState&& other) = delete;
1759   JoinState(JoinState&& other) noexcept : ready(other.ready) {
1760     if (ready.is_set(0)) {
1761       Construct(&result0, std::move(other.result0));
1762     } else {
1763       Construct(&promise0, std::move(other.promise0));
1764     }
1765     if (ready.is_set(1)) {
1766       Construct(&result1, std::move(other.result1));
1767     } else {
1768       Construct(&promise1, std::move(other.promise1));
1769     }
1770     if (ready.is_set(2)) {
1771       Construct(&result2, std::move(other.result2));
1772     } else {
1773       Construct(&promise2, std::move(other.promise2));
1774     }
1775     if (ready.is_set(3)) {
1776       Construct(&result3, std::move(other.result3));
1777     } else {
1778       Construct(&promise3, std::move(other.promise3));
1779     }
1780     if (ready.is_set(4)) {
1781       Construct(&result4, std::move(other.result4));
1782     } else {
1783       Construct(&promise4, std::move(other.promise4));
1784     }
1785     if (ready.is_set(5)) {
1786       Construct(&result5, std::move(other.result5));
1787     } else {
1788       Construct(&promise5, std::move(other.promise5));
1789     }
1790     if (ready.is_set(6)) {
1791       Construct(&result6, std::move(other.result6));
1792     } else {
1793       Construct(&promise6, std::move(other.promise6));
1794     }
1795     if (ready.is_set(7)) {
1796       Construct(&result7, std::move(other.result7));
1797     } else {
1798       Construct(&promise7, std::move(other.promise7));
1799     }
1800     if (ready.is_set(8)) {
1801       Construct(&result8, std::move(other.result8));
1802     } else {
1803       Construct(&promise8, std::move(other.promise8));
1804     }
1805   }
1806   ~JoinState() {
1807     if (ready.is_set(0)) {
1808       Destruct(&result0);
1809     } else {
1810       Destruct(&promise0);
1811     }
1812     if (ready.is_set(1)) {
1813       Destruct(&result1);
1814     } else {
1815       Destruct(&promise1);
1816     }
1817     if (ready.is_set(2)) {
1818       Destruct(&result2);
1819     } else {
1820       Destruct(&promise2);
1821     }
1822     if (ready.is_set(3)) {
1823       Destruct(&result3);
1824     } else {
1825       Destruct(&promise3);
1826     }
1827     if (ready.is_set(4)) {
1828       Destruct(&result4);
1829     } else {
1830       Destruct(&promise4);
1831     }
1832     if (ready.is_set(5)) {
1833       Destruct(&result5);
1834     } else {
1835       Destruct(&promise5);
1836     }
1837     if (ready.is_set(6)) {
1838       Destruct(&result6);
1839     } else {
1840       Destruct(&promise6);
1841     }
1842     if (ready.is_set(7)) {
1843       Destruct(&result7);
1844     } else {
1845       Destruct(&promise7);
1846     }
1847     if (ready.is_set(8)) {
1848       Destruct(&result8);
1849     } else {
1850       Destruct(&promise8);
1851     }
1852   }
1853   using Result = typename Traits::template ResultType<
1854       std::tuple<Result0, Result1, Result2, Result3, Result4, Result5, Result6,
1855                  Result7, Result8>>;
1856   Poll<Result> PollOnce() {
1857     if (!ready.is_set(0)) {
1858       if (grpc_trace_promise_primitives.enabled()) {
1859         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 1/9", this);
1860       }
1861       auto poll = promise0();
1862       if (grpc_trace_promise_primitives.enabled()) {
1863         auto* p = poll.value_if_ready();
1864         gpr_log(GPR_DEBUG, "join[%p]: joint 1/9 %s", this,
1865                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1866                              : "pending");
1867       }
1868       if (auto* p = poll.value_if_ready()) {
1869         if (Traits::IsOk(*p)) {
1870           ready.set(0);
1871           Destruct(&promise0);
1872           Construct(&result0, Traits::Unwrapped(std::move(*p)));
1873         } else {
1874           return Traits::template EarlyReturn<Result>(std::move(*p));
1875         }
1876       }
1877     } else if (grpc_trace_promise_primitives.enabled()) {
1878       gpr_log(GPR_DEBUG, "join[%p]: joint 1/9 already ready", this);
1879     }
1880     if (!ready.is_set(1)) {
1881       if (grpc_trace_promise_primitives.enabled()) {
1882         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 2/9", this);
1883       }
1884       auto poll = promise1();
1885       if (grpc_trace_promise_primitives.enabled()) {
1886         auto* p = poll.value_if_ready();
1887         gpr_log(GPR_DEBUG, "join[%p]: joint 2/9 %s", this,
1888                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1889                              : "pending");
1890       }
1891       if (auto* p = poll.value_if_ready()) {
1892         if (Traits::IsOk(*p)) {
1893           ready.set(1);
1894           Destruct(&promise1);
1895           Construct(&result1, Traits::Unwrapped(std::move(*p)));
1896         } else {
1897           return Traits::template EarlyReturn<Result>(std::move(*p));
1898         }
1899       }
1900     } else if (grpc_trace_promise_primitives.enabled()) {
1901       gpr_log(GPR_DEBUG, "join[%p]: joint 2/9 already ready", this);
1902     }
1903     if (!ready.is_set(2)) {
1904       if (grpc_trace_promise_primitives.enabled()) {
1905         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 3/9", this);
1906       }
1907       auto poll = promise2();
1908       if (grpc_trace_promise_primitives.enabled()) {
1909         auto* p = poll.value_if_ready();
1910         gpr_log(GPR_DEBUG, "join[%p]: joint 3/9 %s", this,
1911                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1912                              : "pending");
1913       }
1914       if (auto* p = poll.value_if_ready()) {
1915         if (Traits::IsOk(*p)) {
1916           ready.set(2);
1917           Destruct(&promise2);
1918           Construct(&result2, Traits::Unwrapped(std::move(*p)));
1919         } else {
1920           return Traits::template EarlyReturn<Result>(std::move(*p));
1921         }
1922       }
1923     } else if (grpc_trace_promise_primitives.enabled()) {
1924       gpr_log(GPR_DEBUG, "join[%p]: joint 3/9 already ready", this);
1925     }
1926     if (!ready.is_set(3)) {
1927       if (grpc_trace_promise_primitives.enabled()) {
1928         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 4/9", this);
1929       }
1930       auto poll = promise3();
1931       if (grpc_trace_promise_primitives.enabled()) {
1932         auto* p = poll.value_if_ready();
1933         gpr_log(GPR_DEBUG, "join[%p]: joint 4/9 %s", this,
1934                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1935                              : "pending");
1936       }
1937       if (auto* p = poll.value_if_ready()) {
1938         if (Traits::IsOk(*p)) {
1939           ready.set(3);
1940           Destruct(&promise3);
1941           Construct(&result3, Traits::Unwrapped(std::move(*p)));
1942         } else {
1943           return Traits::template EarlyReturn<Result>(std::move(*p));
1944         }
1945       }
1946     } else if (grpc_trace_promise_primitives.enabled()) {
1947       gpr_log(GPR_DEBUG, "join[%p]: joint 4/9 already ready", this);
1948     }
1949     if (!ready.is_set(4)) {
1950       if (grpc_trace_promise_primitives.enabled()) {
1951         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 5/9", this);
1952       }
1953       auto poll = promise4();
1954       if (grpc_trace_promise_primitives.enabled()) {
1955         auto* p = poll.value_if_ready();
1956         gpr_log(GPR_DEBUG, "join[%p]: joint 5/9 %s", this,
1957                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1958                              : "pending");
1959       }
1960       if (auto* p = poll.value_if_ready()) {
1961         if (Traits::IsOk(*p)) {
1962           ready.set(4);
1963           Destruct(&promise4);
1964           Construct(&result4, Traits::Unwrapped(std::move(*p)));
1965         } else {
1966           return Traits::template EarlyReturn<Result>(std::move(*p));
1967         }
1968       }
1969     } else if (grpc_trace_promise_primitives.enabled()) {
1970       gpr_log(GPR_DEBUG, "join[%p]: joint 5/9 already ready", this);
1971     }
1972     if (!ready.is_set(5)) {
1973       if (grpc_trace_promise_primitives.enabled()) {
1974         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 6/9", this);
1975       }
1976       auto poll = promise5();
1977       if (grpc_trace_promise_primitives.enabled()) {
1978         auto* p = poll.value_if_ready();
1979         gpr_log(GPR_DEBUG, "join[%p]: joint 6/9 %s", this,
1980                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
1981                              : "pending");
1982       }
1983       if (auto* p = poll.value_if_ready()) {
1984         if (Traits::IsOk(*p)) {
1985           ready.set(5);
1986           Destruct(&promise5);
1987           Construct(&result5, Traits::Unwrapped(std::move(*p)));
1988         } else {
1989           return Traits::template EarlyReturn<Result>(std::move(*p));
1990         }
1991       }
1992     } else if (grpc_trace_promise_primitives.enabled()) {
1993       gpr_log(GPR_DEBUG, "join[%p]: joint 6/9 already ready", this);
1994     }
1995     if (!ready.is_set(6)) {
1996       if (grpc_trace_promise_primitives.enabled()) {
1997         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 7/9", this);
1998       }
1999       auto poll = promise6();
2000       if (grpc_trace_promise_primitives.enabled()) {
2001         auto* p = poll.value_if_ready();
2002         gpr_log(GPR_DEBUG, "join[%p]: joint 7/9 %s", this,
2003                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
2004                              : "pending");
2005       }
2006       if (auto* p = poll.value_if_ready()) {
2007         if (Traits::IsOk(*p)) {
2008           ready.set(6);
2009           Destruct(&promise6);
2010           Construct(&result6, Traits::Unwrapped(std::move(*p)));
2011         } else {
2012           return Traits::template EarlyReturn<Result>(std::move(*p));
2013         }
2014       }
2015     } else if (grpc_trace_promise_primitives.enabled()) {
2016       gpr_log(GPR_DEBUG, "join[%p]: joint 7/9 already ready", this);
2017     }
2018     if (!ready.is_set(7)) {
2019       if (grpc_trace_promise_primitives.enabled()) {
2020         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 8/9", this);
2021       }
2022       auto poll = promise7();
2023       if (grpc_trace_promise_primitives.enabled()) {
2024         auto* p = poll.value_if_ready();
2025         gpr_log(GPR_DEBUG, "join[%p]: joint 8/9 %s", this,
2026                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
2027                              : "pending");
2028       }
2029       if (auto* p = poll.value_if_ready()) {
2030         if (Traits::IsOk(*p)) {
2031           ready.set(7);
2032           Destruct(&promise7);
2033           Construct(&result7, Traits::Unwrapped(std::move(*p)));
2034         } else {
2035           return Traits::template EarlyReturn<Result>(std::move(*p));
2036         }
2037       }
2038     } else if (grpc_trace_promise_primitives.enabled()) {
2039       gpr_log(GPR_DEBUG, "join[%p]: joint 8/9 already ready", this);
2040     }
2041     if (!ready.is_set(8)) {
2042       if (grpc_trace_promise_primitives.enabled()) {
2043         gpr_log(GPR_DEBUG, "join[%p]: begin poll joint 9/9", this);
2044       }
2045       auto poll = promise8();
2046       if (grpc_trace_promise_primitives.enabled()) {
2047         auto* p = poll.value_if_ready();
2048         gpr_log(GPR_DEBUG, "join[%p]: joint 9/9 %s", this,
2049                 p != nullptr ? (Traits::IsOk(*p) ? "ready" : "early-error")
2050                              : "pending");
2051       }
2052       if (auto* p = poll.value_if_ready()) {
2053         if (Traits::IsOk(*p)) {
2054           ready.set(8);
2055           Destruct(&promise8);
2056           Construct(&result8, Traits::Unwrapped(std::move(*p)));
2057         } else {
2058           return Traits::template EarlyReturn<Result>(std::move(*p));
2059         }
2060       }
2061     } else if (grpc_trace_promise_primitives.enabled()) {
2062       gpr_log(GPR_DEBUG, "join[%p]: joint 9/9 already ready", this);
2063     }
2064     if (ready.all()) {
2065       return Traits::FinalReturn(
2066           std::move(result0), std::move(result1), std::move(result2),
2067           std::move(result3), std::move(result4), std::move(result5),
2068           std::move(result6), std::move(result7), std::move(result8));
2069     }
2070     return Pending{};
2071   }
2072 };
2073 
2074 }  // namespace promise_detail
2075 }  // namespace grpc_core
2076 
2077 #endif  // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H
2078