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_SRC_CORE_LIB_PROMISE_DETAIL_BASIC_SEQ_H
16 #define GRPC_SRC_CORE_LIB_PROMISE_DETAIL_BASIC_SEQ_H
17
18 #include <grpc/support/port_platform.h>
19
20 #include "src/core/lib/promise/detail/promise_factory.h"
21 #include "src/core/lib/promise/poll.h"
22 #include "src/core/util/construct_destruct.h"
23
24 namespace grpc_core {
25 namespace promise_detail {
26
27 template <typename FactoryFn>
BindFactoryFnArgs(FactoryFn fn)28 auto BindFactoryFnArgs(FactoryFn fn) {
29 return [fn = std::move(fn)](auto x) mutable {
30 return fn(std::get<0>(x), std::move(std::get<1>(x)));
31 };
32 }
33
34 // Models a sequence of unknown size
35 // At each element, the accumulator A and the current value V is passed to some
36 // function of type IterTraits::Factory as f(V, IterTraits::Argument); f is
37 // expected to return a promise that resolves to IterTraits::Wrapped.
38 template <template <typename> class Traits, typename Iter, typename FactoryFn,
39 typename Argument>
40 class BasicSeqIter {
41 private:
42 using BoundFactoryFn = decltype(BindFactoryFnArgs(std::declval<FactoryFn>()));
43 using TplArg = std::tuple<decltype((*std::declval<Iter>())), Argument>;
44 using Factory = RepeatedPromiseFactory<TplArg, BoundFactoryFn>;
45 using State = typename Factory::Promise;
46 using StateResult = typename State::Result;
47
48 public:
BasicSeqIter(Iter begin,Iter end,FactoryFn f,Argument arg)49 BasicSeqIter(Iter begin, Iter end, FactoryFn f, Argument arg)
50 : cur_(begin), end_(end), f_(BindFactoryFnArgs(std::move(f))) {
51 if (cur_ == end_) {
52 Construct(&result_, std::move(arg));
53 } else {
54 Construct(&state_, f_.Make(TplArg(*cur_, std::move(arg))));
55 }
56 }
57
~BasicSeqIter()58 ~BasicSeqIter() {
59 if (cur_ == end_) {
60 Destruct(&result_);
61 } else {
62 Destruct(&state_);
63 }
64 }
65
66 BasicSeqIter(const BasicSeqIter& other) = delete;
67 BasicSeqIter& operator=(const BasicSeqIter&) = delete;
68
BasicSeqIter(BasicSeqIter && other)69 BasicSeqIter(BasicSeqIter&& other) noexcept
70 : cur_(other.cur_), end_(other.end_), f_(std::move(other.f_)) {
71 if (cur_ == end_) {
72 Construct(&result_, std::move(other.result_));
73 } else {
74 Construct(&state_, std::move(other.state_));
75 }
76 }
77 BasicSeqIter& operator=(BasicSeqIter&& other) noexcept {
78 cur_ = other.cur_;
79 end_ = other.end_;
80 if (cur_ == end_) {
81 Construct(&result_, std::move(other.result_));
82 } else {
83 Construct(&state_, std::move(other.state_));
84 }
85 return *this;
86 }
87
operator()88 Poll<StateResult> operator()() {
89 if (cur_ == end_) {
90 return std::move(result_);
91 }
92 return PollNonEmpty();
93 }
94
95 private:
PollNonEmpty()96 Poll<StateResult> PollNonEmpty() {
97 Poll<StateResult> r = state_();
98 if (r.pending()) return r;
99 using Tr = Traits<StateResult>;
100 return Tr::template CheckResultAndRunNext<StateResult>(
101 std::move(r.value()), [this](auto arg) -> Poll<StateResult> {
102 auto next = cur_;
103 ++next;
104 if (next == end_) {
105 return std::move(arg);
106 }
107 cur_ = next;
108 state_.~State();
109 struct WrapperFactory {
110 BasicSeqIter* owner;
111 State Make(typename Tr::UnwrappedType r) {
112 return owner->f_.Make(TplArg(*owner->cur_, std::move(r)));
113 }
114 };
115 WrapperFactory wrapper_factory{this};
116 Construct(&state_, Tr::CallFactory(&wrapper_factory, std::move(arg)));
117 return PollNonEmpty();
118 });
119 }
120
121 Iter cur_;
122 const Iter end_;
123 GPR_NO_UNIQUE_ADDRESS Factory f_;
124 union {
125 GPR_NO_UNIQUE_ADDRESS State state_;
126 GPR_NO_UNIQUE_ADDRESS Argument result_;
127 };
128 };
129
130 } // namespace promise_detail
131 } // namespace grpc_core
132
133 #endif // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_BASIC_SEQ_H
134