• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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