proxygen
InlineTask.h
Go to the documentation of this file.
1 /*
2  * Copyright 2018-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 <folly/ScopeGuard.h>
19 #include <folly/Try.h>
20 
21 #include <cassert>
22 #include <experimental/coroutine>
23 #include <utility>
24 
25 namespace folly {
26 namespace coro {
27 namespace detail {
28 
41 template <typename T>
42 class InlineTask;
43 
45  struct FinalAwaiter {
47  return false;
48  }
49 
50  template <typename Promise>
51  std::experimental::coroutine_handle<> await_suspend(
52  std::experimental::coroutine_handle<Promise> h) noexcept {
53  InlineTaskPromiseBase& promise = h.promise();
54  return promise.continuation_;
55  }
56 
58  };
59 
60  protected:
61  InlineTaskPromiseBase() noexcept = default;
62 
67 
68  public:
69  std::experimental::suspend_always initial_suspend() noexcept {
70  return {};
71  }
72 
74  return FinalAwaiter{};
75  }
76 
78  std::experimental::coroutine_handle<> continuation) noexcept {
79  assert(!continuation_);
80  continuation_ = continuation;
81  }
82 
83  private:
84  std::experimental::coroutine_handle<> continuation_;
85 };
86 
87 template <typename T>
89  public:
90  static_assert(
92  "InlineTask<T> only supports types that are move-constructible.");
93  static_assert(
95  "InlineTask<T&&> is not supported");
96 
97  InlineTaskPromise() noexcept = default;
98 
99  ~InlineTaskPromise() = default;
100 
101  InlineTask<T> get_return_object() noexcept;
102 
103  template <
104  typename Value,
106  void return_value(Value&& value) noexcept(
107  std::is_nothrow_constructible<T, Value&&>::value) {
108  result_.emplace(static_cast<Value&&>(value));
109  }
110 
111  // Also provide non-template overload for T&& so that we can do
112  // 'co_return {arg1, arg2}' as shorthand for 'co_return T{arg1, arg2}'.
113  void return_value(T&& value) noexcept(
114  std::is_nothrow_move_constructible<T>::value) {
115  result_.emplace(static_cast<T&&>(value));
116  }
117 
118  void unhandled_exception() noexcept {
119  result_.emplaceException(
120  folly::exception_wrapper::from_exception_ptr(std::current_exception()));
121  }
122 
123  T result() {
124  return std::move(result_).value();
125  }
126 
127  private:
128  // folly::Try<T> doesn't support storing reference types so we store a
129  // std::reference_wrapper instead.
130  using StorageType = std::conditional_t<
132  std::reference_wrapper<std::remove_reference_t<T>>,
133  T>;
134 
136 };
137 
138 template <>
140  public:
141  InlineTaskPromise() noexcept = default;
142 
143  InlineTask<void> get_return_object() noexcept;
144 
145  void return_void() noexcept {}
146 
147  void unhandled_exception() noexcept {
148  result_.emplaceException(
149  folly::exception_wrapper::from_exception_ptr(std::current_exception()));
150  }
151 
152  void result() {
153  return result_.value();
154  }
155 
156  private:
158 };
159 
160 template <typename T>
161 class InlineTask {
162  public:
164 
165  private:
166  using handle_t = std::experimental::coroutine_handle<promise_type>;
167 
168  public:
170  : coro_(std::exchange(other.coro_, {})) {}
171 
173  if (coro_) {
174  coro_.destroy();
175  }
176  }
177 
178  class Awaiter {
179  public:
181  if (coro_) {
182  coro_.destroy();
183  }
184  }
185 
187  return false;
188  }
189 
191  std::experimental::coroutine_handle<> awaitingCoroutine) noexcept {
192  assert(coro_ && !coro_.done());
193  coro_.promise().set_continuation(awaitingCoroutine);
194  return coro_;
195  }
196 
198  auto destroyOnExit =
199  folly::makeGuard([this] { std::exchange(coro_, {}).destroy(); });
200  return coro_.promise().result();
201  }
202 
203  private:
204  friend class InlineTask<T>;
205  explicit Awaiter(handle_t coro) noexcept : coro_(coro) {}
207  };
208 
209  Awaiter operator co_await() && {
210  assert(coro_ && !coro_.done());
211  return Awaiter{std::exchange(coro_, {})};
212  }
213 
214  private:
215  friend class InlineTaskPromise<T>;
216  explicit InlineTask(handle_t coro) noexcept : coro_(coro) {}
218 };
219 
220 template <typename T>
222  return InlineTask<T>{
223  std::experimental::coroutine_handle<InlineTaskPromise<T>>::from_promise(
224  *this)};
225 }
226 
228  return InlineTask<void>{std::experimental::coroutine_handle<
229  InlineTaskPromise<void>>::from_promise(*this)};
230 }
231 
232 } // namespace detail
233 } // namespace coro
234 } // namespace folly
*than *hazptr_holder h
Definition: Hazptr.h:116
InlineTask(handle_t coro) noexcept
Definition: InlineTask.h:216
handle_t await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine) noexcept
Definition: InlineTask.h:190
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::experimental::coroutine_handle await_suspend(std::experimental::coroutine_handle< Promise > h) noexcept
Definition: InlineTask.h:51
STL namespace.
static exception_wrapper from_exception_ptr(std::exception_ptr const &eptr) noexcept
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
std::experimental::coroutine_handle continuation_
Definition: InlineTask.h:84
void set_continuation(std::experimental::coroutine_handle<> continuation) noexcept
Definition: InlineTask.h:77
static void destroy()
folly::Try< StorageType > result_
Definition: InlineTask.h:135
InlineTask(InlineTask &&other) noexcept
Definition: InlineTask.h:169
bool Value(const T &value, M matcher)
InlineTask< T > get_return_object() noexcept
Definition: InlineTask.h:221
std::experimental::coroutine_handle< promise_type > handle_t
Definition: InlineTask.h:166
static const char *const value
Definition: Conv.cpp:50
std::conditional_t< std::is_lvalue_reference< T >::value, std::reference_wrapper< std::remove_reference_t< T >>, T > StorageType
Definition: InlineTask.h:133
FOLLY_NODISCARD detail::ScopeGuardImplDecay< F, true > makeGuard(F &&f) noexcept(noexcept(detail::ScopeGuardImplDecay< F, true >(static_cast< F && >(f))))
Definition: ScopeGuard.h:184
T exchange(T &obj, U &&new_value)
Definition: Utility.h:120
void return_value(Value &&value) noexcept(std::is_nothrow_constructible< T, Value && >::value)
Definition: InlineTask.h:106
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
InlineTaskPromiseBase & operator=(const InlineTaskPromiseBase &)=delete
void return_value(T &&value) noexcept(std::is_nothrow_move_constructible< T >::value)
Definition: InlineTask.h:113
std::experimental::suspend_always initial_suspend() noexcept
Definition: InlineTask.h:69