[libcxx] r304101 - [coroutines] Add end-to-end tests within libc++
Eric Fiselier via cfe-commits
cfe-commits at lists.llvm.org
Sun May 28 12:38:22 PDT 2017
Author: ericwf
Date: Sun May 28 14:38:21 2017
New Revision: 304101
URL: http://llvm.org/viewvc/llvm-project?rev=304101&view=rev
Log:
[coroutines] Add end-to-end tests within libc++
This patch adds end-to-end/breathing tests for coroutines
into libc++. The tests aren't specifically to test libc++ requirements
but instead are intented to ensure coroutines are working fine in general.
Although libc++ isn't exactly the most correct place for these tests
to live, there is one major advantage. The libc++ test suite is also
used by MSVC and by adding the tests here it ensures they will be
run against all currently available coroutine implementations.
Added:
libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/
libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.sh.cpp
libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.sh.cpp
libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/expected.sh.cpp
libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/fullexpr-dtor.sh.cpp
libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/generator.sh.cpp
libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/go.sh.cpp
libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/multishot_func.sh.cpp
libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.sh.cpp
libcxx/trunk/test/support/coroutine_types.h
Added: libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.sh.cpp?rev=304101&view=auto
==============================================================================
--- libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.sh.cpp (added)
+++ libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/await_result.sh.cpp Sun May 28 14:38:21 2017
@@ -0,0 +1,72 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+// REQUIRES: fcoroutines-ts
+
+// RUN: %build -fcoroutines-ts
+// RUN: %run
+
+#include <experimental/coroutine>
+#include <cassert>
+
+using namespace std::experimental;
+
+struct coro_t {
+ struct promise_type {
+ coro_t get_return_object() {
+ coroutine_handle<promise_type>{};
+ return {};
+ }
+ suspend_never initial_suspend() { return {}; }
+ suspend_never final_suspend() { return {}; }
+ void return_void(){}
+ static void unhandled_exception() {}
+ };
+};
+
+struct B {
+ ~B() {}
+ bool await_ready() { return true; }
+ B await_resume() { return {}; }
+ template <typename F> void await_suspend(F) {}
+};
+
+
+struct A {
+ ~A(){}
+ bool await_ready() { return true; }
+ int await_resume() { return 42; }
+ template <typename F> void await_suspend(F) {}
+};
+
+int last_value = -1;
+void set_value(int x) {
+ last_value = x;
+}
+
+coro_t f(int n) {
+ if (n == 0) {
+ set_value(0);
+ co_return;
+ }
+ int val = co_await A{};
+ set_value(42);
+}
+
+coro_t g() { B val = co_await B{}; }
+
+int main() {
+ last_value = -1;
+ f(0);
+ assert(last_value == 0);
+ f(1);
+ assert(last_value == 42);
+}
Added: libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.sh.cpp?rev=304101&view=auto
==============================================================================
--- libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.sh.cpp (added)
+++ libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/bool_await_suspend.sh.cpp Sun May 28 14:38:21 2017
@@ -0,0 +1,67 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+// REQUIRES: fcoroutines-ts
+
+// RUN: %build -fcoroutines-ts
+// RUN: %run
+
+#include <experimental/coroutine>
+#include <cassert>
+
+using namespace std::experimental;
+
+struct coro_t {
+ struct promise_type {
+ coro_t get_return_object() {
+ coroutine_handle<promise_type>{};
+ return {};
+ }
+ suspend_never initial_suspend() { return {}; }
+ suspend_never final_suspend() { return {}; }
+ void return_void(){}
+ void unhandled_exception() {}
+ };
+};
+
+struct NoSuspend {
+ bool await_ready() { return false; }
+ void await_resume() {}
+ template <typename F> bool await_suspend(F) { return false; }
+};
+
+struct DoSuspend {
+ bool await_ready() { return false; }
+ void await_resume() {}
+ template <typename F> bool await_suspend(F) { return true; }
+};
+
+bool f_started, f_resumed = false;
+coro_t f() {
+ f_started = true;
+ co_await DoSuspend{};
+ f_resumed = true;
+}
+
+bool g_started, g_resumed = false;
+coro_t g() {
+ g_started = true;
+ co_await NoSuspend{};
+ g_resumed = true;
+}
+
+int main() {
+ assert(!f_started && !f_resumed && !g_started && !g_resumed);
+ f();
+ assert(f_started && !f_resumed);
+ g();
+ assert(g_started && g_resumed);
+}
Added: libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/expected.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/expected.sh.cpp?rev=304101&view=auto
==============================================================================
--- libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/expected.sh.cpp (added)
+++ libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/expected.sh.cpp Sun May 28 14:38:21 2017
@@ -0,0 +1,93 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+// REQUIRES: fcoroutines-ts
+
+// RUN: %build -fcoroutines-ts
+// RUN: %run
+
+#include <experimental/coroutine>
+#include <cassert>
+using namespace std::experimental;
+
+struct error {};
+
+template <typename T, typename Error = int>
+struct expected {
+
+ struct Data {
+ T val;
+ Error error;
+ };
+ Data data;
+
+ struct DataPtr {
+ Data *p;
+ ~DataPtr() { delete p; }
+ };
+
+ expected() {}
+ expected(T val) : data{std::move(val),{}} {}
+ expected(struct error, Error error) : data{{}, std::move(error)} {}
+ expected(DataPtr & p) : data{std::move(p.p->val), std::move(p.p->error)} {}
+
+ struct promise_type {
+ Data* data;
+ DataPtr get_return_object() { data = new Data; return {data}; }
+ suspend_never initial_suspend() { return {}; }
+ suspend_never final_suspend() { return {}; }
+ void return_value(T v) { data->val = std::move(v); data->error = {};}
+ void unhandled_exception() {}
+ };
+
+ bool await_ready() { return !data.error; }
+ T await_resume() { return std::move(data.val); }
+ void await_suspend(coroutine_handle<promise_type> h) {
+ h.promise().data->error =std::move(data.error);
+ h.destroy();
+ }
+
+ T const& value() { return data.val; }
+ Error const& error() { return data.error; }
+};
+
+expected<int> g() { return {0}; }
+expected<int> h() { return {error{}, 42}; }
+
+extern "C" void print(int);
+
+bool f1_started, f1_resumed = false;
+expected<int> f1() {
+ f1_started = true;
+ (void)(co_await g());
+ f1_resumed = true;
+ co_return 100;
+}
+
+bool f2_started, f2_resumed = false;
+expected<int> f2() {
+ f2_started = true;
+ (void)(co_await h());
+ f2_resumed = true;
+ co_return 200;
+}
+
+int main() {
+ auto c1 = f1();
+ assert(f1_started && f1_resumed);
+ assert(c1.value() == 100);
+ assert(c1.error() == 0);
+
+ auto c2 = f2();
+ assert(f2_started && !f2_resumed);
+ assert(c2.value() == 0);
+ assert(c2.error() == 42);
+}
Added: libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/fullexpr-dtor.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/fullexpr-dtor.sh.cpp?rev=304101&view=auto
==============================================================================
--- libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/fullexpr-dtor.sh.cpp (added)
+++ libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/fullexpr-dtor.sh.cpp Sun May 28 14:38:21 2017
@@ -0,0 +1,113 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+// REQUIRES: fcoroutines-ts
+
+// RUN: %build -fcoroutines-ts
+// RUN: %run
+
+#include <experimental/coroutine>
+#include <cassert>
+
+using namespace std::experimental;
+
+int alive = 0;
+int ctor_called = 0;
+int dtor_called = 0;
+void reset() {
+ assert(alive == 0);
+ alive = 0;
+ ctor_called = 0;
+ dtor_called = 0;
+}
+struct Noisy {
+ Noisy() { ++alive; ++ctor_called; }
+ Noisy(Noisy const&) = delete;
+ ~Noisy() { --alive; ++dtor_called; }
+};
+
+struct Bug {
+ bool await_ready() { return true; }
+ void await_suspend(std::experimental::coroutine_handle<>) {}
+ Noisy await_resume() { return {}; }
+};
+struct coro2 {
+ struct promise_type {
+ suspend_never initial_suspend() { return{}; }
+ suspend_never final_suspend() { return{}; }
+ coro2 get_return_object() { return{}; }
+ void return_void() {}
+ Bug yield_value(int) { return {}; }
+ void unhandled_exception() {}
+ };
+};
+
+// Checks that destructors are correctly invoked for the object returned by
+// coawait.
+// CHECK-LABEL: @a(
+coro2 a() {
+ reset();
+ {
+ auto x = co_await Bug{};
+ assert(alive == 1);
+ assert(ctor_called == 1);
+ assert(dtor_called == 0);
+ }
+ assert(alive == 0);
+ assert(dtor_called == 1);
+}
+
+coro2 b() {
+ reset();
+ {
+ co_await Bug{};
+ assert(ctor_called == 1);
+ assert(dtor_called == 1);
+ assert(alive == 0);
+ }
+ assert(ctor_called == 1);
+ assert(dtor_called == 1);
+ assert(alive == 0);
+
+}
+
+coro2 c() {
+ reset();
+ {
+ auto x = co_yield 42;
+ assert(alive == 1);
+ assert(ctor_called == 1);
+ assert(dtor_called == 0);
+ }
+ assert(alive == 0);
+ assert(ctor_called == 1);
+ assert(dtor_called == 1);
+}
+
+coro2 d() {
+ reset();
+ {
+ co_yield 42;
+ assert(ctor_called == 1);
+ assert(dtor_called == 1);
+ assert(alive == 0);
+ }
+ assert(alive == 0);
+ assert(ctor_called == 1);
+ assert(dtor_called == 1);
+}
+
+int main() {
+ a();
+ b();
+ c();
+ d();
+}
Added: libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/generator.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/generator.sh.cpp?rev=304101&view=auto
==============================================================================
--- libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/generator.sh.cpp (added)
+++ libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/generator.sh.cpp Sun May 28 14:38:21 2017
@@ -0,0 +1,104 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+// REQUIRES: fcoroutines-ts
+
+// RUN: %build -fcoroutines-ts
+// RUN: %run
+
+#include <experimental/coroutine>
+#include <vector>
+#include <cassert>
+
+#include "coroutine_types.h"
+
+using namespace std::experimental;
+
+struct minig {
+ struct promise_type {
+ int current_value;
+ suspend_always yield_value(int value) {
+ this->current_value = value;
+ return {};
+ }
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() { return {}; }
+ minig get_return_object() { return minig{this}; };
+ void return_void() {}
+ void unhandled_exception() {}
+ };
+
+ bool move_next() {
+ p.resume();
+ return !p.done();
+ }
+ int current_value() { return p.promise().current_value; }
+
+ minig(minig &&rhs) : p(rhs.p) { rhs.p = nullptr; }
+
+ ~minig() {
+ if (p)
+ p.destroy();
+ }
+
+private:
+ explicit minig(promise_type *p)
+ : p(coroutine_handle<promise_type>::from_promise(*p)) {}
+
+ coroutine_handle<promise_type> p;
+};
+
+
+minig mini_count(int n) {
+ for (int i = 0; i < n; i++) {
+ co_yield i;
+ }
+}
+
+generator<int> count(int n) {
+ for (int i = 0; i < n; ++i)
+ co_yield i;
+}
+
+generator<int> range(int from, int n) {
+ for (int i = from; i < n; ++i)
+ co_yield i;
+}
+
+void test_count() {
+ const std::vector<int> expect = {0, 1, 2, 3, 4};
+ std::vector<int> got;
+ for (auto x : count(5))
+ got.push_back(x);
+ assert(expect == got);
+}
+
+void test_range() {
+ int sum = 0;
+ for (auto v: range(1, 20))
+ sum += v;
+ assert(sum == 190);
+}
+
+void test_mini_generator() {
+ int sum = 0;
+ auto g = mini_count(5);
+ while (g.move_next()) {
+ sum += g.current_value();
+ }
+ assert(sum == 10);
+}
+
+int main() {
+ test_count();
+ test_range();
+ test_mini_generator();
+}
Added: libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/go.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/go.sh.cpp?rev=304101&view=auto
==============================================================================
--- libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/go.sh.cpp (added)
+++ libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/go.sh.cpp Sun May 28 14:38:21 2017
@@ -0,0 +1,182 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+// REQUIRES: fcoroutines-ts
+
+// RUN: %build -fcoroutines-ts
+// RUN: %run
+
+#include <experimental/coroutine>
+#include <cassert>
+
+using namespace std::experimental;
+
+bool cancel = false;
+
+struct goroutine
+{
+ static int const N = 10;
+ static int count;
+ static coroutine_handle<> stack[N];
+
+ static void schedule(coroutine_handle<>& rh)
+ {
+ assert(count < N);
+ stack[count++] = rh;
+ rh = nullptr;
+ }
+
+ ~goroutine() {}
+
+ static void go(goroutine) {}
+
+ static void run_one()
+ {
+ assert(count > 0);
+ stack[--count]();
+ }
+
+ struct promise_type
+ {
+ suspend_never initial_suspend() {
+ return {};
+ }
+ suspend_never final_suspend() {
+ return {};
+ }
+ void return_void() {}
+ goroutine get_return_object() {
+ return{};
+ }
+ void unhandled_exception() {}
+ };
+};
+int goroutine::count;
+coroutine_handle<> goroutine::stack[N];
+
+coroutine_handle<goroutine::promise_type> workaround;
+
+class channel;
+
+struct push_awaiter {
+ channel* ch;
+ bool await_ready() {return false; }
+ void await_suspend(coroutine_handle<> rh);
+ void await_resume() {}
+};
+
+struct pull_awaiter {
+ channel * ch;
+
+ bool await_ready();
+ void await_suspend(coroutine_handle<> rh);
+ int await_resume();
+};
+
+class channel
+{
+ using T = int;
+
+ friend struct push_awaiter;
+ friend struct pull_awaiter;
+
+ T const* pvalue = nullptr;
+ coroutine_handle<> reader = nullptr;
+ coroutine_handle<> writer = nullptr;
+public:
+ push_awaiter push(T const& value)
+ {
+ assert(pvalue == nullptr);
+ assert(!writer);
+ pvalue = &value;
+
+ return { this };
+ }
+
+ pull_awaiter pull()
+ {
+ assert(!reader);
+
+ return { this };
+ }
+
+ void sync_push(T const& value)
+ {
+ assert(!pvalue);
+ pvalue = &value;
+ assert(reader);
+ reader();
+ assert(!pvalue);
+ reader = nullptr;
+ }
+
+ auto sync_pull()
+ {
+ while (!pvalue) goroutine::run_one();
+ auto result = *pvalue;
+ pvalue = nullptr;
+ if (writer)
+ {
+ auto wr = writer;
+ writer = nullptr;
+ wr();
+ }
+ return result;
+ }
+};
+
+void push_awaiter::await_suspend(coroutine_handle<> rh)
+{
+ ch->writer = rh;
+ if (ch->reader) goroutine::schedule(ch->reader);
+}
+
+
+bool pull_awaiter::await_ready() {
+ return !!ch->writer;
+}
+void pull_awaiter::await_suspend(coroutine_handle<> rh) {
+ ch->reader = rh;
+}
+int pull_awaiter::await_resume() {
+ auto result = *ch->pvalue;
+ ch->pvalue = nullptr;
+ if (ch->writer) {
+ //goroutine::schedule(ch->writer);
+ auto wr = ch->writer;
+ ch->writer = nullptr;
+ wr();
+ }
+ return result;
+}
+
+goroutine pusher(channel& left, channel& right)
+{
+ for (;;) {
+ auto val = co_await left.pull();
+ co_await right.push(val + 1);
+ }
+}
+
+const int N = 100; //100'000'000;
+const int repeat = 1;
+
+channel* c = new channel[N + 1];
+
+int main() {
+ for (int i = 0; i < N; ++i)
+ goroutine::go(pusher(c[i], c[i + 1]));
+
+ c[0].sync_push(0);
+ int result = c[N].sync_pull();
+
+ assert(result == 100);
+}
Added: libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/multishot_func.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/multishot_func.sh.cpp?rev=304101&view=auto
==============================================================================
--- libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/multishot_func.sh.cpp (added)
+++ libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/multishot_func.sh.cpp Sun May 28 14:38:21 2017
@@ -0,0 +1,91 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+// REQUIRES: fcoroutines-ts
+
+// RUN: %build -fcoroutines-ts
+// RUN: %run
+
+#include <experimental/coroutine>
+#include <cassert>
+
+using namespace std::experimental;
+
+// This file tests, multishot, movable std::function like thing using coroutine
+// for compile-time type erasure and unerasure.
+template <typename R> struct func {
+ struct Input {R a, b;};
+
+ struct promise_type {
+ Input* I;
+ R result;
+ func get_return_object() { return {this}; }
+ suspend_always initial_suspend() { return {}; }
+ suspend_never final_suspend() { return {}; }
+ void return_void() {}
+ template <typename F>
+ suspend_always yield_value(F&& f) {
+ result = f(I->a, I->b);
+ return {};
+ }
+ void unhandled_exception() {}
+ };
+
+ R operator()(Input I) {
+ h.promise().I = &I;
+ h.resume();
+ R result = h.promise().result;
+ return result;
+ };
+
+ func() {}
+ func(func &&rhs) : h(rhs.h) { rhs.h = nullptr; }
+ func(func const &) = delete;
+
+ func &operator=(func &&rhs) {
+ if (this != &rhs) {
+ if (h)
+ h.destroy();
+ h = rhs.h;
+ rhs.h = nullptr;
+ }
+ return *this;
+ }
+
+ template <typename F> static func Create(F f) {
+ for (;;) {
+ co_yield f;
+ }
+ }
+
+ template <typename F> func(F f) : func(Create(f)) {}
+
+ ~func() {
+ if (h)
+ h.destroy();
+ }
+
+private:
+ func(promise_type *promise)
+ : h(coroutine_handle<promise_type>::from_promise(*promise)) {}
+ coroutine_handle<promise_type> h;
+};
+
+int Do(int acc, int n, func<int> f) {
+ for (int i = 0; i < n; ++i)
+ acc = f({acc, i});
+ return acc;
+}
+
+int main() {
+ int result = Do(1, 10, [](int a, int b) {return a + b;});
+ assert(result == 46);
+}
Added: libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.sh.cpp?rev=304101&view=auto
==============================================================================
--- libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.sh.cpp (added)
+++ libcxx/trunk/test/std/experimental/language.support/support.coroutines/end.to.end/oneshot_func.sh.cpp Sun May 28 14:38:21 2017
@@ -0,0 +1,87 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+// REQUIRES: fcoroutines-ts
+
+// RUN: %build -fcoroutines-ts
+// RUN: %run
+
+#include <experimental/coroutine>
+#include <vector>
+#include <cassert>
+
+using namespace std::experimental;
+
+// This file tests, one shot, movable std::function like thing using coroutine
+// for compile-time type erasure and unerasure.
+
+template <typename R> struct func {
+ struct promise_type {
+ R result;
+ func get_return_object() { return {this}; }
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() { return {}; }
+ void return_value(R v) { result = v; }
+ void unhandled_exception() {}
+ };
+
+ R operator()() {
+ h.resume();
+ R result = h.promise().result;
+ h.destroy();
+ h = nullptr;
+ return result;
+ };
+
+ func() {}
+ func(func &&rhs) : h(rhs.h) { rhs.h = nullptr; }
+ func(func const &) = delete;
+
+ func &operator=(func &&rhs) {
+ if (this != &rhs) {
+ if (h)
+ h.destroy();
+ h = rhs.h;
+ rhs.h = nullptr;
+ }
+ return *this;
+ }
+
+ template <typename F> static func Create(F f) { co_return f(); }
+
+ template <typename F> func(F f) : func(Create(f)) {}
+
+ ~func() {
+ if (h)
+ h.destroy();
+ }
+
+private:
+ func(promise_type *promise)
+ : h(coroutine_handle<promise_type>::from_promise(*promise)) {}
+ coroutine_handle<promise_type> h;
+};
+
+std::vector<int> yielded_values = {};
+int yield(int x) { yielded_values.push_back(x); return x + 1; }
+float fyield(int x) { yielded_values.push_back(x); return x + 2; }
+
+void Do1(func<int> f) { yield(f()); }
+void Do2(func<double> f) { yield(f()); }
+
+int main() {
+ Do1([] { return yield(43); });
+ assert((yielded_values == std::vector<int>{43, 44}));
+
+ yielded_values = {};
+ Do2([] { return fyield(44); });
+ assert((yielded_values == std::vector<int>{44, 46}));
+}
Added: libcxx/trunk/test/support/coroutine_types.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/coroutine_types.h?rev=304101&view=auto
==============================================================================
--- libcxx/trunk/test/support/coroutine_types.h (added)
+++ libcxx/trunk/test/support/coroutine_types.h Sun May 28 14:38:21 2017
@@ -0,0 +1,75 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SUPPORT_COROUTINE_TYPES_H
+#define SUPPORT_COROUTINE_TYPES_H
+
+#include <experimental/coroutine>
+
+template <typename Ty> struct generator {
+ struct promise_type {
+ Ty current_value;
+ std::experimental::suspend_always yield_value(Ty value) {
+ this->current_value = value;
+ return {};
+ }
+ std::experimental::suspend_always initial_suspend() { return {}; }
+ std::experimental::suspend_always final_suspend() { return {}; }
+ generator get_return_object() { return generator{this}; };
+ void return_void() {}
+ void unhandled_exception() {}
+ };
+
+ struct iterator {
+ std::experimental::coroutine_handle<promise_type> _Coro;
+ bool _Done;
+
+ iterator(std::experimental::coroutine_handle<promise_type> Coro, bool Done)
+ : _Coro(Coro), _Done(Done) {}
+
+ iterator &operator++() {
+ _Coro.resume();
+ _Done = _Coro.done();
+ return *this;
+ }
+
+ bool operator==(iterator const &_Right) const {
+ return _Done == _Right._Done;
+ }
+
+ bool operator!=(iterator const &_Right) const { return !(*this == _Right); }
+
+ Ty const &operator*() const { return _Coro.promise().current_value; }
+
+ Ty const *operator->() const { return &(operator*()); }
+ };
+
+ iterator begin() {
+ p.resume();
+ return {p, p.done()};
+ }
+
+ iterator end() { return {p, true}; }
+
+ generator(generator &&rhs) : p(rhs.p) { rhs.p = nullptr; }
+
+ ~generator() {
+ if (p)
+ p.destroy();
+ }
+
+private:
+ explicit generator(promise_type *p)
+ : p(std::experimental::coroutine_handle<promise_type>::from_promise(*p)) {}
+
+ std::experimental::coroutine_handle<promise_type> p;
+};
+
+#endif // SUPPORT_COROUTINE_TYPES_H
More information about the cfe-commits
mailing list