basic_join.h
Go to the documentation of this file.
1 // Copyright 2021 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_CORE_LIB_PROMISE_DETAIL_BASIC_JOIN_H
16 #define GRPC_CORE_LIB_PROMISE_DETAIL_BASIC_JOIN_H
17 
19 
20 #include <assert.h>
21 #include <stddef.h>
22 
23 #include <array>
24 #include <tuple>
25 #include <type_traits>
26 #include <utility>
27 
28 #include "absl/types/variant.h"
29 #include "absl/utility/utility.h"
30 
35 
36 namespace grpc_core {
37 namespace promise_detail {
38 
39 // This union can either be a functor, or the result of the functor (after
40 // mapping via a trait). Allows us to remember the result of one joined functor
41 // until the rest are ready.
42 template <typename Traits, typename F>
43 union Fused {
44  explicit Fused(F&& f) : f(std::forward<F>(f)) {}
45  explicit Fused(PromiseLike<F>&& f) : f(std::forward<PromiseLike<F>>(f)) {}
46  ~Fused() {}
47  // Wrap the functor in a PromiseLike to handle immediately returning functors
48  // and the like.
51  // Compute the result type: We take the result of the promise, and pass it via
52  // our traits, so that, for example, TryJoin and take a StatusOr<T> and just
53  // store a T.
54  using Result = typename Traits::template ResultType<typename Promise::Result>;
56 };
57 
58 // A join gets composed of joints... these are just wrappers around a Fused for
59 // their data, with some machinery as methods to get the system working.
60 template <typename Traits, size_t kRemaining, typename... Fs>
61 struct Joint : public Joint<Traits, kRemaining - 1, Fs...> {
62  // The index into Fs for this Joint
63  static constexpr size_t kIdx = sizeof...(Fs) - kRemaining;
64  // The next join (the one we derive from)
65  using NextJoint = Joint<Traits, kRemaining - 1, Fs...>;
66  // From Fs, extract the functor for this joint.
67  using F = typename std::tuple_element<kIdx, std::tuple<Fs...>>::type;
68  // Generate the Fused type for this functor.
71  // Figure out what kind of bitmask will be used by the outer join.
72  using Bits = BitSet<sizeof...(Fs)>;
73  // Initialize from a tuple of pointers to Fs
74  explicit Joint(std::tuple<Fs*...> fs)
75  : NextJoint(fs), fused(std::move(*std::get<kIdx>(fs))) {}
76  // Copy: assume that the Fuse is still in the promise state (since it's not
77  // legal to copy after the first poll!)
78  Joint(const Joint& j) : NextJoint(j), fused(j.fused.f) {}
79  // Move: assume that the Fuse is still in the promise state (since it's not
80  // legal to move after the first poll!)
81  Joint(Joint&& j) noexcept
82  : NextJoint(std::forward<NextJoint>(j)), fused(std::move(j.fused.f)) {}
83  // Destruct: check bits to see if we're in promise or result state, and call
84  // the appropriate destructor. Recursively, call up through the join.
85  void DestructAll(const Bits& bits) {
86  if (!bits.is_set(kIdx)) {
87  Destruct(&fused.f);
88  } else {
90  }
92  }
93  // Poll all joints up, and then call finally.
94  template <typename F>
95  auto Run(Bits* bits, F finally) -> decltype(finally()) {
96  // If we're still in the promise state...
97  if (!bits->is_set(kIdx)) {
98  // Poll the promise
99  auto r = fused.f();
100  if (auto* p = absl::get_if<kPollReadyIdx>(&r)) {
101  // If it's done, then ask the trait to unwrap it and store that result
102  // in the Fused, and continue the iteration. Note that OnResult could
103  // instead choose to return a value instead of recursing through the
104  // iteration, in that case we continue returning the same result up.
105  // Here is where TryJoin can escape out.
106  return Traits::OnResult(
107  std::move(*p), [this, bits, &finally](typename Fsd::Result result) {
108  bits->set(kIdx);
109  Destruct(&fused.f);
111  return NextJoint::Run(bits, std::move(finally));
112  });
113  }
114  }
115  // That joint is still pending... we'll still poll the result of the joints.
116  return NextJoint::Run(bits, std::move(finally));
117  }
118 };
119 
120 // Terminating joint... for each of the recursions, do the thing we're supposed
121 // to do at the end.
122 template <typename Traits, typename... Fs>
123 struct Joint<Traits, 0, Fs...> {
124  explicit Joint(std::tuple<Fs*...>) {}
125  Joint(const Joint&) {}
126  Joint(Joint&&) noexcept {}
127  template <typename T>
128  void DestructAll(const T&) {}
129  template <typename F>
130  auto Run(BitSet<sizeof...(Fs)>*, F finally) -> decltype(finally()) {
131  return finally();
132  }
133 };
134 
135 template <typename Traits, typename... Fs>
136 class BasicJoin {
137  private:
138  // How many things are we joining?
139  static constexpr size_t N = sizeof...(Fs);
140  // Bitset: if a bit is 0, that joint is still in promise state. If it's 1,
141  // then the joint has a result.
143  // The actual joints, wrapped in an anonymous union to give us control of
144  // construction/destruction.
145  union {
146  GPR_NO_UNIQUE_ADDRESS Joint<Traits, sizeof...(Fs), Fs...> joints_;
147  };
148 
149  // Access joint index I
150  template <size_t I>
151  Joint<Traits, sizeof...(Fs) - I, Fs...>* GetJoint() {
152  return static_cast<Joint<Traits, sizeof...(Fs) - I, Fs...>*>(&joints_);
153  }
154 
155  // The tuple of results of all our promises
157 
158  // Collect up all the results and construct a tuple.
159  template <size_t... I>
161  return Tuple(std::move(GetJoint<I>()->fused.result)...);
162  }
163 
164  public:
165  explicit BasicJoin(Fs&&... fs) : joints_(std::tuple<Fs*...>(&fs...)) {}
166  BasicJoin& operator=(const BasicJoin&) = delete;
167  // Copy a join - only available before polling.
168  BasicJoin(const BasicJoin& other) {
169  assert(other.state_.none());
170  Construct(&joints_, other.joints_);
171  }
172  // Move a join - only available before polling.
173  BasicJoin(BasicJoin&& other) noexcept {
174  assert(other.state_.none());
175  Construct(&joints_, std::move(other.joints_));
176  }
178  using Result = decltype(Traits::Wrap(std::declval<Tuple>()));
179  // Poll the join
181  // Poll the joints...
182  return joints_.Run(&state_, [this]() -> Poll<Result> {
183  // If all of them are completed, collect the results, and then ask our
184  // traits to wrap them - allowing for example TryJoin to turn tuple<A,B,C>
185  // into StatusOr<tuple<A,B,C>>.
186  if (state_.all()) {
187  return Traits::Wrap(Finish(absl::make_index_sequence<N>()));
188  } else {
189  return Pending();
190  }
191  });
192  }
193 };
194 
195 } // namespace promise_detail
196 } // namespace grpc_core
197 
198 #endif // GRPC_CORE_LIB_PROMISE_DETAIL_BASIC_JOIN_H
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
grpc_core::promise_detail::Fused
Definition: basic_join.h:43
grpc_core::promise_detail::Joint::Joint
Joint(std::tuple< Fs *... > fs)
Definition: basic_join.h:74
grpc_core::promise_detail::Fused::~Fused
~Fused()
Definition: basic_join.h:46
get
absl::string_view get(const Cont &c)
Definition: abseil-cpp/absl/strings/str_replace_test.cc:185
grpc_core::promise_detail::Joint< Traits, 0, Fs... >::DestructAll
void DestructAll(const T &)
Definition: basic_join.h:128
grpc_core
Definition: call_metric_recorder.h:31
grpc_core::promise_detail::Joint::Joint
Joint(Joint &&j) noexcept
Definition: basic_join.h:81
grpc_core::promise_detail::Joint::fused
GPR_NO_UNIQUE_ADDRESS Fsd fused
Definition: basic_join.h:70
T
#define T(upbtypeconst, upbtype, ctype, default_value)
grpc_core::promise_detail::BasicJoin::state_
GPR_NO_UNIQUE_ADDRESS BitSet< N > state_
Definition: basic_join.h:142
grpc_core::promise_detail::Joint::Run
auto Run(Bits *bits, F finally) -> decltype(final ly())
Definition: basic_join.h:95
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
re2::Result
TestInstance::Result Result
Definition: bloaty/third_party/re2/re2/testing/tester.cc:96
grpc_core::promise_detail::Fused::Fused
Fused(PromiseLike< F > &&f)
Definition: basic_join.h:45
grpc_core::promise_detail::Joint::Joint
Joint(const Joint &j)
Definition: basic_join.h:78
absl::integer_sequence
Definition: abseil-cpp/absl/utility/utility.h:76
grpc_core::promise_detail::Joint< Traits, 0, Fs... >::Joint
Joint(Joint &&) noexcept
Definition: basic_join.h:126
grpc_core::promise_detail::BasicJoin::Finish
Tuple Finish(absl::index_sequence< I... >)
Definition: basic_join.h:160
bits
OPENSSL_EXPORT ASN1_BIT_STRING * bits
Definition: x509v3.h:482
grpc_core::promise_detail::Joint< Traits, 0, Fs... >::Joint
Joint(std::tuple< Fs *... >)
Definition: basic_join.h:124
grpc_core::promise_detail::Joint::kIdx
static constexpr size_t kIdx
Definition: basic_join.h:63
grpc_core::promise_detail::BasicJoin::Tuple
std::tuple< typename Fused< Traits, Fs >::Result... > Tuple
Definition: basic_join.h:156
grpc_core::promise_detail::Fused::Fused
Fused(F &&f)
Definition: basic_join.h:44
GPR_NO_UNIQUE_ADDRESS
#define GPR_NO_UNIQUE_ADDRESS
Definition: impl/codegen/port_platform.h:692
grpc_core::promise_detail::Fused::Result
typename Traits::template ResultType< typename Promise::Result > Result
Definition: basic_join.h:54
grpc_core::promise_detail::BasicJoin::~BasicJoin
~BasicJoin()
Definition: basic_join.h:177
F
#define F(b, c, d)
Definition: md4.c:112
grpc_core::promise_detail::BasicJoin::BasicJoin
BasicJoin(BasicJoin &&other) noexcept
Definition: basic_join.h:173
grpc_core::Construct
void Construct(T *p, Args &&... args)
Definition: construct_destruct.h:34
grpc_core::Destruct
void Destruct(T *p)
Definition: construct_destruct.h:27
grpc_core::promise_detail::Joint< Traits, 0, Fs... >::Run
auto Run(BitSet< sizeof...(Fs)> *, F finally) -> decltype(final ly())
Definition: basic_join.h:130
grpc_core::promise_detail::BasicJoin::Result
decltype(Traits::Wrap(std::declval< Tuple >())) Result
Definition: basic_join.h:178
grpc_core::promise_detail::Joint::DestructAll
void DestructAll(const Bits &bits)
Definition: basic_join.h:85
grpc_core::BitSet
Definition: bitset.h:85
I
#define I(b, c, d)
Definition: md5.c:120
grpc_core::promise_detail::BasicJoin::joints_
GPR_NO_UNIQUE_ADDRESS Joint< Traits, sizeof...(Fs), Fs... > joints_
Definition: basic_join.h:146
promise_like.h
poll.h
grpc_core::promise_detail::Fused::f
GPR_NO_UNIQUE_ADDRESS Promise f
Definition: basic_join.h:50
grpc_core::promise_detail::Joint::NextJoint
Joint< Traits, kRemaining - 1, Fs... > NextJoint
Definition: basic_join.h:65
grpc_core::promise_detail::BasicJoin::BasicJoin
BasicJoin(Fs &&... fs)
Definition: basic_join.h:165
fix_build_deps.r
r
Definition: fix_build_deps.py:491
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
grpc_core::BitSet::all
bool all() const
Definition: bitset.h:117
grpc_core::promise_detail::Joint< Traits, sizeof...(Fs), Fs... >::F
typename std::tuple_element< kIdx, std::tuple< Fs... > >::type F
Definition: basic_join.h:67
grpc_core::promise_detail::BasicJoin::BasicJoin
BasicJoin(const BasicJoin &other)
Definition: basic_join.h:168
grpc_core::BitSet::none
bool none() const
Definition: bitset.h:137
grpc_core::promise_detail::Joint
Definition: basic_join.h:61
absl::forward
constexpr T && forward(absl::remove_reference_t< T > &t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:230
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
setup.template
template
Definition: setup.py:47
grpc_core::promise_detail::BasicJoin::GetJoint
Joint< Traits, sizeof...(Fs) - I, Fs... > * GetJoint()
Definition: basic_join.h:151
grpc_core::promise_detail::Joint< Traits, 0, Fs... >::Joint
Joint(const Joint &)
Definition: basic_join.h:125
grpc_core::promise_detail::BasicJoin::N
static constexpr size_t N
Definition: basic_join.h:139
absl::variant
Definition: abseil-cpp/absl/types/internal/variant.h:46
grpc_core::promise_detail::PromiseLike
Definition: promise_like.h:67
construct_destruct.h
grpc_core::promise_detail::Fused::result
GPR_NO_UNIQUE_ADDRESS Result result
Definition: basic_join.h:55
grpc_core::promise_detail::BasicJoin::operator=
BasicJoin & operator=(const BasicJoin &)=delete
bitset.h
grpc_core::promise_detail::BasicJoin::operator()
Poll< Result > operator()()
Definition: basic_join.h:180
port_platform.h
grpc_core::promise_detail::BasicJoin
Definition: basic_join.h:136


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:36