proxygen
ViaIfAsync.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <experimental/coroutine>
19 #include <memory>
20 
21 #include <folly/Executor.h>
23 
24 #include <glog/logging.h>
25 
26 namespace folly {
27 
28 class InlineExecutor;
29 
30 namespace coro {
31 
32 namespace detail {
33 
34 class ViaCoroutine {
35  public:
36  class promise_type {
37  public:
39 
41  return ViaCoroutine{
42  std::experimental::coroutine_handle<promise_type>::from_promise(
43  *this)};
44  }
45 
46  std::experimental::suspend_always initial_suspend() {
47  return {};
48  }
49 
50  auto final_suspend() {
51  struct Awaiter {
52  bool await_ready() noexcept {
53  return false;
54  }
55  void await_suspend(
56  std::experimental::coroutine_handle<promise_type> coro) noexcept {
57  // Schedule resumption of the coroutine on the executor.
58  auto& promise = coro.promise();
59  promise.executor_->add(promise.continuation_);
60  }
61  void await_resume() noexcept {}
62  };
63 
64  return Awaiter{};
65  }
66 
67  [[noreturn]] void unhandled_exception() noexcept {
68  LOG(FATAL) << "ViaCoroutine threw an unhandled exception";
69  }
70 
72 
74  std::experimental::coroutine_handle<> continuation) noexcept {
75  DCHECK(!continuation_);
76  continuation_ = continuation;
77  }
78 
79  private:
81  std::experimental::coroutine_handle<> continuation_;
82  };
83 
85  : coro_(std::exchange(other.coro_, {})) {}
86 
88  destroy();
89  }
90 
92  swap(other);
93  return *this;
94  }
95 
96  void swap(ViaCoroutine& other) noexcept {
97  std::swap(coro_, other.coro_);
98  }
99 
100  std::experimental::coroutine_handle<> getWrappedCoroutine(
101  std::experimental::coroutine_handle<> continuation) noexcept {
102  if (coro_) {
103  coro_.promise().setContinuation(continuation);
104  return coro_;
105  } else {
106  return continuation;
107  }
108  }
109 
110  void destroy() {
111  if (coro_) {
112  std::exchange(coro_, {}).destroy();
113  }
114  }
115 
117  co_return;
118  }
119 
121  return ViaCoroutine{std::experimental::coroutine_handle<promise_type>{}};
122  }
123 
124  private:
125  friend class promise_type;
126 
127  explicit ViaCoroutine(
128  std::experimental::coroutine_handle<promise_type> coro) noexcept
129  : coro_(coro) {}
130 
131  std::experimental::coroutine_handle<promise_type> coro_;
132 };
133 
134 } // namespace detail
135 
136 template <typename Awaiter>
138  public:
139  static_assert(
140  folly::coro::is_awaiter_v<Awaiter>,
141  "Awaiter type does not implement the Awaiter interface.");
142 
143  template <typename Awaitable>
144  explicit ViaIfAsyncAwaiter(folly::InlineExecutor*, Awaitable&& awaitable)
145  : viaCoroutine_(detail::ViaCoroutine::createInline()),
146  awaiter_(
147  folly::coro::get_awaiter(static_cast<Awaitable&&>(awaitable))) {}
148 
149  template <typename Awaitable>
150  explicit ViaIfAsyncAwaiter(folly::Executor* executor, Awaitable&& awaitable)
151  : viaCoroutine_(detail::ViaCoroutine::create(executor)),
152  awaiter_(
153  folly::coro::get_awaiter(static_cast<Awaitable&&>(awaitable))) {}
154 
156  noexcept(std::declval<Awaiter&>().await_ready())) {
157  return awaiter_.await_ready();
158  }
159 
160  auto
161  await_suspend(std::experimental::coroutine_handle<> continuation) noexcept(
162  noexcept(std::declval<Awaiter&>().await_suspend(continuation))) {
163  return awaiter_.await_suspend(
164  viaCoroutine_.getWrappedCoroutine(continuation));
165  }
166 
167  decltype(auto) await_resume() noexcept(
168  noexcept(std::declval<Awaiter&>().await_resume())) {
169  viaCoroutine_.destroy();
170  return awaiter_.await_resume();
171  }
172 
174  Awaiter awaiter_;
175 };
176 
177 template <typename Awaitable>
179  public:
182  Awaitable&&
183  awaitable) noexcept(std::is_nothrow_move_constructible<Awaitable>::
184  value)
185  : executor_(executor), awaitable_(static_cast<Awaitable&&>(awaitable)) {}
186 
187  template <typename Awaitable2>
188  friend auto operator co_await(ViaIfAsyncAwaitable<Awaitable2>&& awaitable)
190 
191  template <typename Awaitable2>
192  friend auto operator co_await(ViaIfAsyncAwaitable<Awaitable2>& awaitable)
194 
195  template <typename Awaitable2>
196  friend auto operator co_await(
197  const ViaIfAsyncAwaitable<Awaitable2>&& awaitable)
199 
200  template <typename Awaitable2>
201  friend auto operator co_await(
202  const ViaIfAsyncAwaitable<Awaitable2>& awaitable)
204 
205  private:
207  Awaitable awaitable_;
208 };
209 
210 template <typename Awaitable>
211 auto operator co_await(ViaIfAsyncAwaitable<Awaitable>&& awaitable)
214  awaitable.executor_, static_cast<Awaitable&&>(awaitable.awaitable_)};
215 }
216 
217 template <typename Awaitable>
218 auto operator co_await(ViaIfAsyncAwaitable<Awaitable>& awaitable)
221  awaitable.executor_, awaitable.awaitable_};
222 }
223 
224 template <typename Awaitable>
225 auto operator co_await(const ViaIfAsyncAwaitable<Awaitable>&& awaitable)
228  awaitable.executor_,
229  static_cast<const Awaitable&&>(awaitable.awaitable_)};
230 }
231 
232 template <typename Awaitable>
233 auto operator co_await(const ViaIfAsyncAwaitable<Awaitable>& awaitable)
236  awaitable.executor_, awaitable.awaitable_};
237 }
238 
246 template <typename Awaitable>
247 auto co_viaIfAsync(folly::Executor* executor, Awaitable&& awaitable)
249  static_assert(
250  folly::coro::is_awaitable_v<Awaitable>,
251  "co_viaIfAsync() argument 2 is not awaitable.");
253  static_cast<Awaitable&&>(awaitable)};
254 }
255 
256 } // namespace coro
257 } // namespace folly
std::experimental::coroutine_handle continuation_
Definition: ViaIfAsync.h:81
bool await_ready() noexcept(noexcept(std::declval< Awaiter & >().await_ready()))
Definition: ViaIfAsync.h:155
auto await_suspend(std::experimental::coroutine_handle<> continuation) noexcept(noexcept(std::declval< Awaiter & >().await_suspend(continuation)))
Definition: ViaIfAsync.h:161
STL namespace.
auto co_viaIfAsync(folly::Executor *executor, Awaitable &&awaitable) -> ViaIfAsyncAwaitable< Awaitable >
Definition: ViaIfAsync.h:247
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void setContinuation(std::experimental::coroutine_handle<> continuation) noexcept
Definition: ViaIfAsync.h:73
ViaCoroutine(ViaCoroutine &&other) noexcept
Definition: ViaIfAsync.h:84
requires E e noexcept(noexcept(s.error(std::move(e))))
PUSHMI_INLINE_VAR constexpr __adl::get_executor_fn executor
std::experimental::coroutine_handle< promise_type > coro_
Definition: ViaIfAsync.h:131
static ViaCoroutine create(folly::Executor *executor)
Definition: ViaIfAsync.h:116
ViaIfAsyncAwaiter(folly::Executor *executor, Awaitable &&awaitable)
Definition: ViaIfAsync.h:150
ViaIfAsyncAwaiter(folly::InlineExecutor *, Awaitable &&awaitable)
Definition: ViaIfAsync.h:144
std::experimental::coroutine_handle getWrappedCoroutine(std::experimental::coroutine_handle<> continuation) noexcept
Definition: ViaIfAsync.h:100
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
std::experimental::suspend_always initial_suspend()
Definition: ViaIfAsync.h:46
static ViaCoroutine createInline() noexcept
Definition: ViaIfAsync.h:120
detail::ViaCoroutine viaCoroutine_
Definition: ViaIfAsync.h:173
Awaitable & get_awaiter(Awaitable &&awaitable)
Definition: Traits.h:138
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
ViaCoroutine(std::experimental::coroutine_handle< promise_type > coro) noexcept
Definition: ViaIfAsync.h:127
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
Definition: F14TestUtil.h:414
promise_type(folly::Executor *executor) noexcept
Definition: ViaIfAsync.h:38
void swap(ViaCoroutine &other) noexcept
Definition: ViaIfAsync.h:96
ViaCoroutine & operator=(ViaCoroutine other) noexcept
Definition: ViaIfAsync.h:91
ViaIfAsyncAwaitable(folly::Executor *executor, Awaitable &&awaitable) noexcept(std::is_nothrow_move_constructible< Awaitable >::value)
Definition: ViaIfAsync.h:180