зеркало из https://github.com/microsoft/STL.git
Library support for C++20 coroutines (#894)
* Library support for C++20 coroutines Implements most of <coroutine>. Usefulness of this header is dependent on a compatible compiler (e.g. Visual Studio 2019 16.8 Preview 1 or later) that defines `__cpp_impl_coroutine`. With such a compiler this header exposes the coroutine library support in the `std` namespace without the need for an `/await` switch. This implementation is not yet complete: - noop coroutines are not yet implemented - symmetric transfer is not yet implemented The value of `__cpp_lib_coroutine` is defined to a value less than the Standard-mandated value to represent the incomplete feature. Co-authored-by: Daniel Marshall <xandan@gmail.com>
This commit is contained in:
Родитель
c64e60bae8
Коммит
0cdf5fbfac
|
@ -28,6 +28,7 @@ set(HEADERS
|
|||
${CMAKE_CURRENT_LIST_DIR}/inc/complex
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc/concepts
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc/condition_variable
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc/coroutine
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc/csetjmp
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc/csignal
|
||||
${CMAKE_CURRENT_LIST_DIR}/inc/cstdalign
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include <compare>
|
||||
#include <complex>
|
||||
#include <concepts>
|
||||
#include <coroutine>
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
// coroutine standard header (core)
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#pragma once
|
||||
#ifndef _COROUTINE_
|
||||
#define _COROUTINE_
|
||||
#include <yvals_core.h>
|
||||
#if _STL_COMPILER_PREPROCESSOR
|
||||
|
||||
#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED
|
||||
#pragma message("The contents of <coroutine> are not available with /await.")
|
||||
#pragma message("Remove /await for standard coroutines or use <experimental/coroutine> for legacy /await support.")
|
||||
#else // ^^^ /await ^^^ / vvv no /await vvv
|
||||
#ifndef __cpp_lib_coroutine
|
||||
#pragma message("The contents of <coroutine> are available only with C++20 or later.")
|
||||
#else // ^^^ __cpp_lib_coroutine not defined / __cpp_lib_coroutine defined vvv
|
||||
#ifndef _ALLOW_COROUTINE_ABI_MISMATCH
|
||||
#pragma detect_mismatch("_COROUTINE_ABI", "2")
|
||||
#endif // _ALLOW_COROUTINE_ABI_MISMATCH
|
||||
|
||||
#include <compare>
|
||||
#include <type_traits>
|
||||
|
||||
#pragma pack(push, _CRT_PACKING)
|
||||
#pragma warning(push, _STL_WARNING_LEVEL)
|
||||
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
||||
_STL_DISABLE_CLANG_WARNINGS
|
||||
#pragma push_macro("new")
|
||||
#undef new
|
||||
|
||||
_STD_BEGIN
|
||||
|
||||
// STRUCT TEMPLATE coroutine_traits
|
||||
template <class _Ret, class = void>
|
||||
struct _Coroutine_traits {};
|
||||
|
||||
template <class _Ret>
|
||||
struct _Coroutine_traits<_Ret, void_t<typename _Ret::promise_type>> {
|
||||
using promise_type = typename _Ret::promise_type;
|
||||
};
|
||||
|
||||
template <class _Ret, class...>
|
||||
struct coroutine_traits : _Coroutine_traits<_Ret> {};
|
||||
|
||||
// STRUCT TEMPLATE coroutine_handle
|
||||
template <class = void>
|
||||
struct coroutine_handle;
|
||||
|
||||
template <>
|
||||
struct coroutine_handle<void> {
|
||||
constexpr coroutine_handle() noexcept = default;
|
||||
constexpr coroutine_handle(nullptr_t) noexcept {}
|
||||
|
||||
coroutine_handle& operator=(nullptr_t) noexcept {
|
||||
_Ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_NODISCARD constexpr void* address() const noexcept {
|
||||
return _Ptr;
|
||||
}
|
||||
|
||||
_NODISCARD static constexpr coroutine_handle from_address(void* const _Addr) noexcept { // strengthened
|
||||
coroutine_handle _Result;
|
||||
_Result._Ptr = _Addr;
|
||||
return _Result;
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return _Ptr != nullptr;
|
||||
}
|
||||
|
||||
_NODISCARD bool done() const noexcept { // strengthened
|
||||
return __builtin_coro_done(_Ptr);
|
||||
}
|
||||
|
||||
void operator()() const noexcept { // strengthened
|
||||
__builtin_coro_resume(_Ptr);
|
||||
}
|
||||
|
||||
void resume() const noexcept { // strengthened
|
||||
__builtin_coro_resume(_Ptr);
|
||||
}
|
||||
|
||||
void destroy() const noexcept { // strengthened
|
||||
__builtin_coro_destroy(_Ptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
void* _Ptr = nullptr;
|
||||
};
|
||||
|
||||
template <class _Promise>
|
||||
struct coroutine_handle : coroutine_handle<> {
|
||||
using coroutine_handle<>::coroutine_handle;
|
||||
|
||||
_NODISCARD static coroutine_handle from_promise(_Promise& _Prom) noexcept { // strengthened
|
||||
const auto _Prom_ptr = const_cast<void*>(static_cast<const volatile void*>(_STD addressof(_Prom)));
|
||||
const auto _Frame_ptr = __builtin_coro_promise(_Prom_ptr, 0, true);
|
||||
coroutine_handle _Result;
|
||||
_Result._Ptr = _Frame_ptr;
|
||||
return _Result;
|
||||
}
|
||||
|
||||
coroutine_handle& operator=(nullptr_t) noexcept {
|
||||
_Ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_NODISCARD static constexpr coroutine_handle from_address(void* const _Addr) noexcept { // strengthened
|
||||
coroutine_handle _Result;
|
||||
_Result._Ptr = _Addr;
|
||||
return _Result;
|
||||
}
|
||||
|
||||
_NODISCARD _Promise& promise() const noexcept { // strengthened
|
||||
return *reinterpret_cast<_Promise*>(__builtin_coro_promise(_Ptr, 0, false));
|
||||
}
|
||||
};
|
||||
|
||||
_NODISCARD constexpr bool operator==(const coroutine_handle<> _Left, const coroutine_handle<> _Right) noexcept {
|
||||
return _Left.address() == _Right.address();
|
||||
}
|
||||
|
||||
_NODISCARD constexpr strong_ordering operator<=>(
|
||||
const coroutine_handle<> _Left, const coroutine_handle<> _Right) noexcept {
|
||||
return compare_three_way()(_Left.address(), _Right.address());
|
||||
}
|
||||
|
||||
template <class _Promise>
|
||||
struct hash<coroutine_handle<_Promise>> {
|
||||
_NODISCARD size_t operator()(const coroutine_handle<_Promise>& _Coro) noexcept {
|
||||
return _Hash_representation(_Coro.address());
|
||||
}
|
||||
};
|
||||
|
||||
// STRUCT suspend_never
|
||||
struct suspend_never {
|
||||
_NODISCARD constexpr bool await_ready() const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr void await_suspend(coroutine_handle<>) const noexcept {}
|
||||
constexpr void await_resume() const noexcept {}
|
||||
};
|
||||
|
||||
// STRUCT suspend_always
|
||||
struct suspend_always {
|
||||
_NODISCARD constexpr bool await_ready() const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr void await_suspend(coroutine_handle<>) const noexcept {}
|
||||
constexpr void await_resume() const noexcept {}
|
||||
};
|
||||
|
||||
_STD_END
|
||||
|
||||
#pragma pop_macro("new")
|
||||
_STL_RESTORE_CLANG_WARNINGS
|
||||
#pragma warning(pop)
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // __cpp_lib_coroutine
|
||||
#endif // _RESUMABLE_FUNCTIONS_SUPPORTED
|
||||
#endif // _STL_COMPILER_PREPROCESSOR
|
||||
#endif // _COROUTINE_
|
|
@ -9,14 +9,19 @@
|
|||
#include <yvals_core.h>
|
||||
#if _STL_COMPILER_PREPROCESSOR
|
||||
|
||||
#ifndef __cpp_coroutines
|
||||
#error <experimental/generator> requires /std:c++latest or /await compiler option
|
||||
#endif // __cpp_coroutines
|
||||
#if !defined(__cpp_coroutines) && !defined(__cpp_impl_coroutine)
|
||||
#error <experimental/generator> requires /std:c++latest or /await compiler options
|
||||
#endif // !defined(__cpp_coroutines) && !defined(__cpp_impl_coroutine)
|
||||
|
||||
#ifdef _CPPUNWIND
|
||||
#include <exception>
|
||||
#endif
|
||||
#include <memory>
|
||||
#ifdef __cpp_coroutines
|
||||
#include <experimental/resumable>
|
||||
#else // __cpp_coroutines
|
||||
#include <coroutine>
|
||||
#endif // __cpp_coroutines
|
||||
|
||||
#pragma pack(push, _CRT_PACKING)
|
||||
#pragma warning(push, _STL_WARNING_LEVEL)
|
||||
|
|
|
@ -31,6 +31,11 @@ support Clang. You can define _SILENCE_CLANG_COROUTINE_MESSAGE to silence this m
|
|||
unsupported.
|
||||
#endif // defined(__clang__) && !defined(_SILENCE_CLANG_COROUTINE_MESSAGE)
|
||||
|
||||
#if defined(_MSC_VER) && defined(__cpp_impl_coroutine)
|
||||
#error The <experimental/coroutine> and <experimental/resumable> headers are only supported \
|
||||
with /await and implement pre-C++20 coroutine support. Use <coroutine> for standard C++20 coroutines.
|
||||
#endif // defined(_MSC_VER) && defined(__cpp_impl_coroutine)
|
||||
|
||||
// intrinsics used in implementation of coroutine_handle
|
||||
extern "C" size_t _coro_resume(void*);
|
||||
extern "C" void _coro_destroy(void*);
|
||||
|
@ -39,6 +44,10 @@ extern "C" size_t _coro_done(void*);
|
|||
#pragma intrinsic(_coro_destroy)
|
||||
#pragma intrinsic(_coro_done)
|
||||
|
||||
#ifndef _ALLOW_COROUTINE_ABI_MISMATCH
|
||||
#pragma detect_mismatch("_COROUTINE_ABI", "1")
|
||||
#endif // _ALLOW_COROUTINE_ABI_MISMATCH
|
||||
|
||||
_STD_BEGIN
|
||||
|
||||
namespace experimental {
|
||||
|
|
|
@ -170,6 +170,8 @@
|
|||
// P0896R4 Ranges
|
||||
// (partially implemented)
|
||||
// P0898R3 Standard Library Concepts
|
||||
// P0912R5 Library Support For Coroutines
|
||||
// (partially implemented, missing noop coroutines)
|
||||
// P0919R3 Heterogeneous Lookup For Unordered Containers
|
||||
// P0966R1 string::reserve() Should Not Shrink
|
||||
// P1006R1 constexpr For pointer_traits<T*>::pointer_to()
|
||||
|
@ -1164,6 +1166,10 @@
|
|||
#define __cpp_lib_constexpr_tuple 201811L
|
||||
#define __cpp_lib_constexpr_utility 201811L
|
||||
|
||||
#ifdef __cpp_impl_coroutine // TRANSITION, VS 2019 16.8 Preview 1
|
||||
#define __cpp_lib_coroutine 197000L
|
||||
#endif // __cpp_impl_coroutine
|
||||
|
||||
#ifdef __cpp_impl_destroying_delete
|
||||
#define __cpp_lib_destroying_delete 201806L
|
||||
#endif // __cpp_impl_destroying_delete
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
RUNALL_INCLUDE ..\prefix.lst
|
||||
RUNALL_CROSSLIST
|
||||
PM_CL="/EHsc /MT /d1await:strict /std:c++latest"
|
||||
# PM_CL="/EHsc /MT /std:c++latest" # TRANSITION, VS 2019 16.8 Preview 1
|
||||
PM_CL="/EHsc /MT /await /std:c++latest"
|
||||
PM_CL="/BE /c /EHsc /MD /await /std:c++latest /permissive-"
|
||||
PM_CL="/BE /c /EHsc /MD /await /std:c++latest"
|
||||
PM_CL="/BE /c /EHsc /MD /std:c++latest"
|
||||
|
|
|
@ -18,6 +18,7 @@ PM_CL="/DMEOW_HEADER=compare"
|
|||
PM_CL="/DMEOW_HEADER=complex"
|
||||
PM_CL="/DMEOW_HEADER=concepts"
|
||||
PM_CL="/DMEOW_HEADER=condition_variable"
|
||||
PM_CL="/DMEOW_HEADER=coroutine"
|
||||
PM_CL="/DMEOW_HEADER=deque"
|
||||
PM_CL="/DMEOW_HEADER=exception"
|
||||
PM_CL="/DMEOW_HEADER=execution"
|
||||
|
|
Загрузка…
Ссылка в новой задаче