This provides the interfaces mandated by the standard and implements the interaction with the coroutine frame by means of inline use of builtins expanded at compile-time. There should be a 1:1 correspondence with the standard sections which are cross-referenced.
There is no runtime content. At this stage we have the content in an inline namespace "n4835" for the current CD. libstdc++-v3/ChangeLog: 2019-11-17 Iain Sandoe <i...@sandoe.co.uk> * include/Makefile.am: Add coroutine to the experimental set. * include/Makefile.in: Regnerated. * include/experimental/coroutine: New file. --- libstdc++-v3/include/Makefile.am | 1 + libstdc++-v3/include/Makefile.in | 1 + libstdc++-v3/include/experimental/coroutine | 268 ++++++++++++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 libstdc++-v3/include/experimental/coroutine diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 49fd413..4ffe209 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -708,6 +708,7 @@ experimental_headers = \ ${experimental_srcdir}/array \ ${experimental_srcdir}/buffer \ ${experimental_srcdir}/chrono \ + ${experimental_srcdir}/coroutine \ ${experimental_srcdir}/deque \ ${experimental_srcdir}/executor \ ${experimental_srcdir}/forward_list \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index acc4fe5..fdb7d3d 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -1052,6 +1052,7 @@ experimental_headers = \ ${experimental_srcdir}/array \ ${experimental_srcdir}/buffer \ ${experimental_srcdir}/chrono \ + ${experimental_srcdir}/coroutine \ ${experimental_srcdir}/deque \ ${experimental_srcdir}/executor \ ${experimental_srcdir}/forward_list \ diff --git a/libstdc++-v3/include/experimental/coroutine b/libstdc++-v3/include/experimental/coroutine new file mode 100644 index 0000000..d903352 --- /dev/null +++ b/libstdc++-v3/include/experimental/coroutine @@ -0,0 +1,268 @@ +// <experimental/coroutine> -*- C++ -*- + +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file experimental/coroutine + * This is an experimental C++ Library header against the C++20 CD n4835. + * @ingroup coroutine-ts + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_COROUTINE +#define _GLIBCXX_EXPERIMENTAL_COROUTINE 1 + +#pragma GCC system_header + +// It is very likely that earlier versions would work, but they are untested. +#if __cplusplus >= 201402L + +#include <bits/c++config.h> + +#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L +# include <compare> +# define THE_SPACESHIP_HAS_LANDED 1 +#else +# include <bits/stl_function.h> +# define THE_SPACESHIP_HAS_LANDED 0 +#endif + +namespace std _GLIBCXX_VISIBILITY (default) +{ + _GLIBCXX_BEGIN_NAMESPACE_VERSION + +#if __cpp_coroutines + + namespace experimental { + inline namespace coroutines_n4835 { + + // [coroutine.traits] + // [coroutine.traits.primary] + // 17.12.2 coroutine traits + template <typename _R, typename...> struct coroutine_traits + { + using promise_type = typename _R::promise_type; + }; + + // 17.12.3 Class template coroutine_handle + // [coroutine.handle] + template <typename _Promise = void> struct coroutine_handle; + + template <> struct coroutine_handle<void> + { + public: + // 17.12.3.1, construct/reset + constexpr coroutine_handle () noexcept : __fr_ptr (0) {} + constexpr coroutine_handle (decltype (nullptr) __h) noexcept + : __fr_ptr (__h) + {} + coroutine_handle &operator= (decltype (nullptr)) noexcept + { + __fr_ptr = nullptr; + return *this; + } + + public: + // 17.12.3.2, export/import + constexpr void *address () const noexcept { return __fr_ptr; } + constexpr static coroutine_handle from_address (void *__a) noexcept + { + coroutine_handle __self; + __self.__fr_ptr = __a; + return __self; + } + + public: + // 17.12.3.3, observers + constexpr explicit operator bool () const noexcept + { + return bool(__fr_ptr); + } + bool done () const noexcept { return __builtin_coro_done (__fr_ptr); } + // 17.12.3.4, resumption + void operator() () const { resume (); } + void resume () const { __builtin_coro_resume (__fr_ptr); } + void destroy () const { __builtin_coro_destroy (__fr_ptr); } + + protected: + void *__fr_ptr; + }; + + // [coroutine.handle.compare] + // 17.12.3.6 Comparison operators + constexpr bool operator== (coroutine_handle<> __a, + coroutine_handle<> __b) noexcept + { + return __a.address () == __b.address (); + } + +#if THE_SPACESHIP_HAS_LANDED + constexpr strong_ordering + operator<=> (coroutine_handle<> __a, coroutine_handle<> __b) noexcept; +#else + // These are from the TS. + constexpr bool operator!= (coroutine_handle<> __a, + coroutine_handle<> __b) noexcept + { + return !(__a == __b); + } + + constexpr bool operator< (coroutine_handle<> __a, + coroutine_handle<> __b) noexcept + { + return less<void *> () (__a.address (), __b.address ()); + } + + constexpr bool operator> (coroutine_handle<> __a, + coroutine_handle<> __b) noexcept + { + return __b < __a; + } + + constexpr bool operator<= (coroutine_handle<> __a, + coroutine_handle<> __b) noexcept + { + return !(__a > __b); + } + + constexpr bool operator>= (coroutine_handle<> __a, + coroutine_handle<> __b) noexcept + { + return !(__a < __b); + } +#endif + + template <class _Promise> struct coroutine_handle : coroutine_handle<> + { + // 17.12.3.1, construct/reset + using coroutine_handle<>::coroutine_handle; + static coroutine_handle from_promise (_Promise &p) + { + coroutine_handle __self; + __self.__fr_ptr + = __builtin_coro_promise ((char *) &p, __alignof(_Promise), true); + return __self; + } + coroutine_handle &operator= (decltype (nullptr)) noexcept + { + coroutine_handle<>::operator= (nullptr); + return *this; + } + // 17.12.3.2, export/import + constexpr static coroutine_handle from_address (void *__a) + { + coroutine_handle __self; + __self.__fr_ptr = __a; + return __self; + } + // 17.12.3.5, promise accesss + _Promise &promise () const + { + void *__t + = __builtin_coro_promise (this->__fr_ptr, __alignof(_Promise), false); + return *static_cast<_Promise *> (__t); + } + }; + + // [coroutine.noop] + struct noop_coroutine_promise + { + }; + + void __dummy_resume_destroy () __attribute__ ((__weak__)); + void __dummy_resume_destroy () {} + + struct __noop_coro_frame + { + void (*__r) () = __dummy_resume_destroy; + void (*__d) () = __dummy_resume_destroy; + struct noop_coroutine_promise __p; + } __noop_coro_fr __attribute__ ((__weak__)); + + // [coroutine.promise.noop] + // 17.12.4.1 Class noop_coroutine_promise + template <> + class coroutine_handle<noop_coroutine_promise> : public coroutine_handle<> + { + using _Promise = noop_coroutine_promise; + + public: + // // 17.12.4.2.1, observers + constexpr explicit operator bool () const noexcept { return true; } + constexpr bool done () const noexcept { return false; } + + // 17.12.4.2.2, resumption + void operator() () const noexcept {} + void resume () const noexcept {} + void destroy () const noexcept {} + + // 17.12.4.2.3, promise access + _Promise &promise () const + { + return *static_cast<_Promise *> ( + __builtin_coro_promise (this->__fr_ptr, __alignof(_Promise), false)); + } + + // 17.12.4.2.4, address + // constexpr void* address() const noexcept; + private: + friend coroutine_handle<noop_coroutine_promise> noop_coroutine () noexcept; + + coroutine_handle () noexcept { this->__fr_ptr = (void *) &__noop_coro_fr; } + }; + + using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; + + inline noop_coroutine_handle noop_coroutine () noexcept + { + return noop_coroutine_handle (); + } + + // [coroutine.trivial.awaitables] + // 17.12.5 Trivial awaitables + + struct suspend_always + { + bool await_ready () { return false; } + void await_suspend (coroutine_handle<>) {} + void await_resume () {} + }; + + struct suspend_never + { + bool await_ready () { return true; } + void await_suspend (coroutine_handle<>) {} + void await_resume () {} + }; + + } // namespace coroutines_n4835 + } // namespace experimental + +#else +#error "the coroutine header requires -fcoroutines" +#endif + + _GLIBCXX_END_NAMESPACE_VERSION +} // namespace std_GLIBCXX_VISIBILITY(default) + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_COROUTINE -- 2.8.1