19 #if FOLLY_HAS_COROUTINES 20 #include <experimental/coroutine> 27 Wait get_return_object() {
31 std::experimental::suspend_never initial_suspend() {
35 std::experimental::suspend_never final_suspend() {
43 void unhandled_exception() {
44 promise_.set_exception(std::current_exception());
51 explicit Wait(std::future<void> future) : future_(
std::
move(future)) {}
53 Wait(Wait&&) =
default;
60 if (future_.valid()) {
66 std::future<void> future_;
72 InlineTask(
const InlineTask&) =
delete;
73 InlineTask(InlineTask&& other)
80 bool await_ready()
const {
84 std::experimental::coroutine_handle<> await_suspend(
85 std::experimental::coroutine_handle<> awaiter) {
88 return std::experimental::coroutine_handle<promise_type>::from_promise(
93 std::experimental::coroutine_handle<promise_type>::from_promise(
102 InlineTask get_return_object() {
103 return InlineTask(
this);
106 template <
typename U>
107 void return_value(U&&
value) {
108 *valuePtr_ = std::forward<U>(
value);
111 void unhandled_exception() {
115 std::experimental::suspend_always initial_suspend() {
119 class FinalSuspender {
121 explicit FinalSuspender(std::experimental::coroutine_handle<> awaiter)
122 : awaiter_(
std::
move(awaiter)) {}
128 void await_suspend(std::experimental::coroutine_handle<>) {
132 void await_resume() {}
135 std::experimental::coroutine_handle<> awaiter_;
138 FinalSuspender final_suspend() {
139 return FinalSuspender(
std::move(awaiter_));
143 friend class InlineTask;
146 std::experimental::coroutine_handle<> awaiter_;
150 friend class promise_type;
152 explicit InlineTask(promise_type* promise) :
promise_(promise) {}
158 class StackAllocator {
160 explicit StackAllocator(
size_t bytes) :
buffer_(new char[bytes]) {}
164 StackAllocator(
const StackAllocator&) =
delete;
166 void* allocate(
size_t bytes) {
172 void deallocate(
void*,
size_t bytes) {
182 StackAllocator defaultAllocator(1000 * 512);
184 template <
typename T>
185 class InlineTaskAllocator {
187 InlineTaskAllocator(
const InlineTaskAllocator&) =
delete;
188 InlineTaskAllocator(InlineTaskAllocator&& other)
191 ~InlineTaskAllocator() {
195 bool await_ready()
const {
199 std::experimental::coroutine_handle<> await_suspend(
200 std::experimental::coroutine_handle<> awaiter) {
203 return std::experimental::coroutine_handle<promise_type>::from_promise(
208 std::experimental::coroutine_handle<promise_type>::from_promise(
217 static void*
operator new(
size_t size) {
218 size +=
sizeof(StackAllocator*);
220 static_cast<StackAllocator**
>(defaultAllocator.allocate(
size));
221 buffer[0] = &defaultAllocator;
225 static void operator delete(
void*
ptr,
size_t size) {
226 size +=
sizeof(StackAllocator*);
227 StackAllocator** buffer =
static_cast<StackAllocator**
>(
ptr) - 1;
228 auto allocator = buffer[0];
229 allocator->deallocate(ptr,
size);
232 InlineTaskAllocator get_return_object() {
233 return InlineTaskAllocator(
this);
236 template <
typename U>
237 void return_value(U&&
value) {
238 *valuePtr_ = std::forward<U>(
value);
241 void unhandled_exception() {
245 std::experimental::suspend_always initial_suspend() {
249 class FinalSuspender {
251 explicit FinalSuspender(std::experimental::coroutine_handle<> awaiter)
252 : awaiter_(
std::
move(awaiter)) {}
258 void await_suspend(std::experimental::coroutine_handle<>) {
262 void await_resume() {}
265 std::experimental::coroutine_handle<> awaiter_;
268 FinalSuspender final_suspend() {
269 return FinalSuspender(
std::move(awaiter_));
273 friend class InlineTaskAllocator;
276 std::experimental::coroutine_handle<> awaiter_;
280 friend class promise_type;
282 explicit InlineTaskAllocator(promise_type* promise) :
promise_(promise) {}
290 static std::unique_ptr<Recursion> create(
size_t depth) {
292 return std::unique_ptr<Recursion>(
new Recursion(
nullptr));
294 return std::unique_ptr<Recursion>(
new Recursion(create(depth - 1)));
299 return (*child_)() + 1;
304 InlineTask<int>
operator co_await() {
306 co_return co_await* child_ + 1;
311 InlineTaskAllocator<int> co_allocator() {
313 co_return co_await child_->co_allocator() + 1;
319 explicit Recursion(std::unique_ptr<Recursion>
child)
322 std::unique_ptr<Recursion> child_;
325 void coroRecursion(
size_t times,
size_t iters) {
326 auto recursion = Recursion::create(times);
327 for (
size_t iter = 0; iter < iters; ++iter) {
329 CHECK_EQ(times, co_await recursion);
336 coroRecursion(10, iters);
339 BENCHMARK(coroRecursionDepth1000, iters) {
340 coroRecursion(1000, iters);
343 void coroRecursionAllocator(
size_t times,
size_t iters) {
344 auto recursion = Recursion::create(times);
345 for (
size_t iter = 0; iter < iters; ++iter) {
347 CHECK_EQ(times, co_await recursion.co_allocator());
353 BENCHMARK(coroRecursionAllocatorDepth10, iters) {
354 coroRecursionAllocator(10, iters);
357 BENCHMARK(coroRecursionAllocatorDepth1000, iters) {
358 coroRecursionAllocator(1000, iters);
361 void recursion(
size_t times,
size_t iters) {
362 auto recursion = Recursion::create(times);
363 for (
size_t iter = 0; iter < iters; ++iter) {
378 gflags::ParseCommandLineFlags(&argc, &argv,
true);
std::vector< uint8_t > buffer(kBufferSize+16)
int main(int argc, char **argv)
Future< int > recursion(Executor *executor, int depth)
constexpr detail::Map< Move > move
constexpr auto size(C const &c) -> decltype(c.size())
#define BENCHMARK(name,...)
static const char *const value
T exchange(T &obj, U &&new_value)
folly::Function< void()> child
Future< Unit > times(const int n, F &&thunk)
std::unique_ptr< unsigned char[]> buffer_