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/gprpp/construct_destruct.h" 21 #include "src/core/lib/promise/poll.h" 22 23 namespace grpc_core { 24 namespace promise_detail { 25 26 // Models a sequence of unknown size 27 // At each element, the accumulator A and the current value V is passed to some 28 // function of type IterTraits::Factory as f(V, IterTraits::Argument); f is 29 // expected to return a promise that resolves to IterTraits::Wrapped. 30 template <class IterTraits> 31 class BasicSeqIter { 32 private: 33 using Traits = typename IterTraits::Traits; 34 using Iter = typename IterTraits::Iter; 35 using Factory = typename IterTraits::Factory; 36 using Argument = typename IterTraits::Argument; 37 using IterValue = typename IterTraits::IterValue; 38 using StateCreated = typename IterTraits::StateCreated; 39 using State = typename IterTraits::State; 40 using Wrapped = typename IterTraits::Wrapped; 41 42 public: BasicSeqIter(Iter begin,Iter end,Factory f,Argument arg)43 BasicSeqIter(Iter begin, Iter end, Factory f, Argument arg) 44 : cur_(begin), end_(end), f_(std::move(f)) { 45 if (cur_ == end_) { 46 Construct(&result_, std::move(arg)); 47 } else { 48 Construct(&state_, f_(*cur_, std::move(arg))); 49 } 50 } 51 ~BasicSeqIter()52 ~BasicSeqIter() { 53 if (cur_ == end_) { 54 Destruct(&result_); 55 } else { 56 Destruct(&state_); 57 } 58 } 59 60 BasicSeqIter(const BasicSeqIter& other) = delete; 61 BasicSeqIter& operator=(const BasicSeqIter&) = delete; 62 BasicSeqIter(BasicSeqIter && other)63 BasicSeqIter(BasicSeqIter&& other) noexcept 64 : cur_(other.cur_), end_(other.end_), f_(std::move(other.f_)) { 65 if (cur_ == end_) { 66 Construct(&result_, std::move(other.result_)); 67 } else { 68 Construct(&state_, std::move(other.state_)); 69 } 70 } 71 BasicSeqIter& operator=(BasicSeqIter&& other) noexcept { 72 cur_ = other.cur_; 73 end_ = other.end_; 74 if (cur_ == end_) { 75 Construct(&result_, std::move(other.result_)); 76 } else { 77 Construct(&state_, std::move(other.state_)); 78 } 79 return *this; 80 } 81 operator()82 Poll<Wrapped> operator()() { 83 if (cur_ == end_) { 84 return std::move(result_); 85 } 86 return PollNonEmpty(); 87 } 88 89 private: PollNonEmpty()90 Poll<Wrapped> PollNonEmpty() { 91 Poll<Wrapped> r = state_(); 92 if (r.pending()) return r; 93 return Traits::template CheckResultAndRunNext<Wrapped>( 94 std::move(r.value()), [this](Wrapped arg) -> Poll<Wrapped> { 95 auto next = cur_; 96 ++next; 97 if (next == end_) { 98 return std::move(arg); 99 } 100 cur_ = next; 101 state_.~State(); 102 Construct(&state_, 103 Traits::template CallSeqFactory(f_, *cur_, std::move(arg))); 104 return PollNonEmpty(); 105 }); 106 } 107 108 Iter cur_; 109 const Iter end_; 110 GPR_NO_UNIQUE_ADDRESS Factory f_; 111 union { 112 GPR_NO_UNIQUE_ADDRESS State state_; 113 GPR_NO_UNIQUE_ADDRESS Argument result_; 114 }; 115 }; 116 117 } // namespace promise_detail 118 } // namespace grpc_core 119 120 #endif // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_BASIC_SEQ_H 121