1#!/usr/bin/env python3 2 3# Copyright 2023 gRPC authors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import sys 18 19from mako.template import Template 20 21join_state = Template( 22 """ 23template <class Traits, ${",".join(f"typename P{i}" for i in range(0,n))}> 24struct JoinState<Traits, ${",".join(f"P{i}" for i in range(0,n))}> { 25 template <typename T> 26 using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>())); 27% for i in range(0,n): 28 using Promise${i} = PromiseLike<P${i}>; 29 using Result${i} = UnwrappedType<typename Promise${i}::Result>; 30 union { 31 GPR_NO_UNIQUE_ADDRESS Promise${i} promise${i}; 32 GPR_NO_UNIQUE_ADDRESS Result${i} result${i}; 33 }; 34% endfor 35 GPR_NO_UNIQUE_ADDRESS BitSet<${n}> ready; 36 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION JoinState(${",".join(f"P{i}&& p{i}" for i in range(0,n))}) { 37% for i in range(0,n): 38 Construct(&promise${i}, std::forward<P${i}>(p${i})); 39% endfor 40 } 41 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION JoinState(const JoinState& other) { 42 DCHECK(other.ready.none()); 43% for i in range(0,n): 44 Construct(&promise${i}, other.promise${i}); 45% endfor 46 } 47 JoinState& operator=(const JoinState& other) = delete; 48 JoinState& operator=(JoinState&& other) = delete; 49 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION JoinState(JoinState&& other) noexcept { 50 DCHECK(other.ready.none()); 51% for i in range(0,n): 52 Construct(&promise${i}, std::move(other.promise${i})); 53% endfor 54 } 55 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION ~JoinState() { 56% for i in range(0,n): 57 if (ready.is_set(${i})) { 58 Destruct(&result${i}); 59 } else { 60 Destruct(&promise${i}); 61 } 62% endfor 63 } 64 using Result = typename Traits::template ResultType<std::tuple< 65 ${",".join(f"Result{i}" for i in range(0,n))}>>; 66 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION Poll<Result> PollOnce() { 67% for i in range(0,n): 68 if (!ready.is_set(${i})) { 69 GRPC_TRACE_VLOG(promise_primitives, 2) << "join[" << this << "]: begin poll joint ${i+1}/${n}"; 70 auto poll = promise${i}(); 71 GRPC_TRACE_VLOG(promise_primitives, 2) << "join[" << this << "]: end poll joint ${i+1}/${n} " 72 << (poll.pending()? "pending" : (Traits::IsOk(poll.value())? "ready" : "early-error")); 73 if (auto* p = poll.value_if_ready()) { 74 if (Traits::IsOk(*p)) { 75 ready.set(${i}); 76 Destruct(&promise${i}); 77 Construct(&result${i}, Traits::Unwrapped(std::move(*p))); 78 } else { 79 return Traits::template EarlyReturn<Result>(std::move(*p)); 80 } 81 } 82 } else { 83 GRPC_TRACE_VLOG(promise_primitives, 2) << "join[" << this << "]: joint ${i+1}/${n} already ready"; 84 } 85% endfor 86 if (ready.all()) { 87 return Traits::FinalReturn(${",".join(f"std::move(result{i})" for i in range(0,n))}); 88 } 89 return Pending{}; 90 } 91}; 92""" 93) 94 95front_matter = """ 96#ifndef GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H 97#define GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H 98 99// This file is generated by tools/codegen/core/gen_join.py 100 101#include <grpc/support/port_platform.h> 102 103#include "absl/log/check.h" 104#include "absl/log/log.h" 105 106#include "src/core/lib/debug/trace.h" 107#include "src/core/util/construct_destruct.h" 108#include "src/core/lib/promise/detail/promise_like.h" 109#include "src/core/lib/promise/poll.h" 110#include "src/core/util/bitset.h" 111#include <tuple> 112#include <type_traits> 113#include <utility> 114 115namespace grpc_core { 116namespace promise_detail { 117template <class Traits, typename... Ps> 118struct JoinState; 119""" 120 121end_matter = """ 122} // namespace promise_detail 123} // namespace grpc_core 124 125#endif // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H 126""" 127 128 129# utility: print a big comment block into a set of files 130def put_banner(files, banner): 131 for f in files: 132 for line in banner: 133 print("// %s" % line, file=f) 134 print("", file=f) 135 136 137with open(sys.argv[0]) as my_source: 138 copyright = [] 139 for line in my_source: 140 if line[0] != "#": 141 break 142 for line in my_source: 143 if line[0] == "#": 144 copyright.append(line) 145 break 146 for line in my_source: 147 if line[0] != "#": 148 break 149 copyright.append(line) 150 151copyright = [line[2:].rstrip() for line in copyright] 152 153with open("src/core/lib/promise/detail/join_state.h", "w") as f: 154 put_banner([f], copyright) 155 print(front_matter, file=f) 156 for n in range(2, 10): 157 print(join_state.render(n=n), file=f) 158 print(end_matter, file=f) 159