зеркало из https://github.com/microsoft/STL.git
201 строка
6.3 KiB
C++
201 строка
6.3 KiB
C++
// generator experimental header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef _EXPERIMENTAL_GENERATOR_
|
|
#define _EXPERIMENTAL_GENERATOR_
|
|
#include <yvals_core.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
|
|
#ifdef _CPPUNWIND
|
|
#include <exception>
|
|
#endif
|
|
#include <memory>
|
|
|
|
#if defined(__cpp_impl_coroutine)
|
|
#include <coroutine>
|
|
#elif defined(__cpp_coroutines)
|
|
#include <experimental/resumable>
|
|
#else // ^^^ legacy coroutines / no coroutine support vvv
|
|
#error <experimental/generator> requires /std:c++latest or /await compiler options
|
|
#endif // ^^^ no coroutine support ^^^
|
|
|
|
#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
|
|
|
|
namespace experimental {
|
|
// NOTE WELL: _CPPUNWIND currently affects the ABI of generator.
|
|
template <class _Ty, class _Alloc = allocator<char>>
|
|
struct generator {
|
|
struct promise_type {
|
|
const _Ty* _Value;
|
|
#ifdef _CPPUNWIND
|
|
exception_ptr _Exception;
|
|
#endif // defined(_CPPUNWIND)
|
|
|
|
generator get_return_object() noexcept {
|
|
return generator{*this};
|
|
}
|
|
|
|
suspend_always initial_suspend() noexcept {
|
|
return {};
|
|
}
|
|
|
|
suspend_always final_suspend() noexcept {
|
|
return {};
|
|
}
|
|
|
|
#ifndef _KERNEL_MODE
|
|
#ifdef _CPPUNWIND
|
|
void unhandled_exception() noexcept {
|
|
_Exception = _STD current_exception();
|
|
}
|
|
#else // ^^^ defined(_CPPUNWIND) / !defined(_CPPUNWIND) vvv
|
|
void unhandled_exception() noexcept {}
|
|
#endif // ^^^ !defined(_CPPUNWIND) ^^^
|
|
#endif // !defined(_KERNEL_MODE)
|
|
|
|
#ifdef _CPPUNWIND
|
|
void _Rethrow_if_exception() {
|
|
if (_Exception) {
|
|
_STD rethrow_exception(_Exception);
|
|
}
|
|
}
|
|
#endif // defined(_CPPUNWIND)
|
|
|
|
suspend_always yield_value(const _Ty& _Val) noexcept {
|
|
_Value = _STD addressof(_Val);
|
|
return {};
|
|
}
|
|
|
|
void return_void() noexcept {}
|
|
|
|
template <class _Uty>
|
|
_Uty&& await_transform(_Uty&& _Whatever) {
|
|
static_assert(false, "co_await is not supported in coroutines of type std::experimental::generator");
|
|
return _STD forward<_Uty>(_Whatever);
|
|
}
|
|
|
|
using _Alloc_char = _Rebind_alloc_t<_Alloc, char>;
|
|
static_assert(is_same_v<char*, typename allocator_traits<_Alloc_char>::pointer>,
|
|
"generator does not support allocators with fancy pointer types");
|
|
static_assert(
|
|
allocator_traits<_Alloc_char>::is_always_equal::value && is_default_constructible_v<_Alloc_char>,
|
|
"generator supports only stateless allocators");
|
|
|
|
static void* operator new(size_t _Size) {
|
|
_Alloc_char _Al{};
|
|
return allocator_traits<_Alloc_char>::allocate(_Al, _Size);
|
|
}
|
|
|
|
static void operator delete(void* _Ptr, size_t _Size) noexcept {
|
|
_Alloc_char _Al{};
|
|
return allocator_traits<_Alloc_char>::deallocate(_Al, static_cast<char*>(_Ptr), _Size);
|
|
}
|
|
};
|
|
|
|
struct iterator {
|
|
using iterator_category = input_iterator_tag;
|
|
using difference_type = ptrdiff_t;
|
|
using value_type = _Ty;
|
|
using reference = const _Ty&;
|
|
using pointer = const _Ty*;
|
|
|
|
coroutine_handle<promise_type> _Coro = nullptr;
|
|
|
|
iterator() = default;
|
|
explicit iterator(coroutine_handle<promise_type> _Coro_) noexcept : _Coro(_Coro_) {}
|
|
|
|
iterator& operator++() {
|
|
_Coro.resume();
|
|
if (_Coro.done()) {
|
|
#ifdef _CPPUNWIND
|
|
_STD exchange(_Coro, nullptr).promise()._Rethrow_if_exception();
|
|
#else // ^^^ defined(_CPPUNWIND) / !defined(_CPPUNWIND) vvv
|
|
_Coro = nullptr;
|
|
#endif // ^^^ !defined(_CPPUNWIND) ^^^
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
void operator++(int) {
|
|
// This operator meets the requirements of the C++20 input_iterator concept,
|
|
// but not the Cpp17InputIterator requirements.
|
|
++*this;
|
|
}
|
|
|
|
_NODISCARD bool operator==(const iterator& _Right) const noexcept {
|
|
return _Coro == _Right._Coro;
|
|
}
|
|
|
|
_NODISCARD bool operator!=(const iterator& _Right) const noexcept {
|
|
return !(*this == _Right);
|
|
}
|
|
|
|
_NODISCARD reference operator*() const noexcept {
|
|
return *_Coro.promise()._Value;
|
|
}
|
|
|
|
_NODISCARD pointer operator->() const noexcept {
|
|
return _Coro.promise()._Value;
|
|
}
|
|
};
|
|
|
|
_NODISCARD iterator begin() {
|
|
if (_Coro) {
|
|
_Coro.resume();
|
|
if (_Coro.done()) {
|
|
#ifdef _CPPUNWIND
|
|
_Coro.promise()._Rethrow_if_exception();
|
|
#endif // ^^^ defined(_CPPUNWIND) ^^^
|
|
return {};
|
|
}
|
|
}
|
|
|
|
return iterator{_Coro};
|
|
}
|
|
|
|
_NODISCARD iterator end() noexcept {
|
|
return {};
|
|
}
|
|
|
|
explicit generator(promise_type& _Prom) noexcept : _Coro(coroutine_handle<promise_type>::from_promise(_Prom)) {}
|
|
|
|
generator() = default;
|
|
|
|
generator(generator&& _Right) noexcept : _Coro(_STD exchange(_Right._Coro, nullptr)) {}
|
|
|
|
generator& operator=(generator&& _Right) noexcept {
|
|
_Coro = _STD exchange(_Right._Coro, nullptr);
|
|
return *this;
|
|
}
|
|
|
|
~generator() {
|
|
if (_Coro) {
|
|
_Coro.destroy();
|
|
}
|
|
}
|
|
|
|
private:
|
|
coroutine_handle<promise_type> _Coro = nullptr;
|
|
};
|
|
} // namespace experimental
|
|
|
|
_STD_END
|
|
|
|
#pragma pop_macro("new")
|
|
_STL_RESTORE_CLANG_WARNINGS
|
|
#pragma warning(pop)
|
|
#pragma pack(pop)
|
|
|
|
#endif // _STL_COMPILER_PREPROCESSOR
|
|
#endif // _EXPERIMENTAL_GENERATOR_
|