Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions stl/inc/coroutine
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ private:
void* _Ptr = nullptr;
};

_EXPORT_STD template <class _Promise>
_EXPORT_STD template <class _CoroPromise>
struct coroutine_handle {
constexpr coroutine_handle() noexcept = default;
constexpr coroutine_handle(nullptr_t) noexcept {}

_NODISCARD static coroutine_handle from_promise(_Promise& _Prom) noexcept { // strengthened
_NODISCARD static coroutine_handle from_promise(_CoroPromise& _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;
Expand Down Expand Up @@ -144,8 +144,8 @@ struct coroutine_handle {
__builtin_coro_destroy(_Ptr);
}

_NODISCARD _Promise& promise() const noexcept { // strengthened
return *reinterpret_cast<_Promise*>(__builtin_coro_promise(_Ptr, 0, false));
_NODISCARD _CoroPromise& promise() const noexcept { // strengthened
return *reinterpret_cast<_CoroPromise*>(__builtin_coro_promise(_Ptr, 0, false));
}

private:
Expand Down Expand Up @@ -184,10 +184,10 @@ _NODISCARD constexpr bool operator>=(const coroutine_handle<> _Left, const corou
}
#endif // ^^^ !_HAS_CXX20 ^^^

template <class _Promise>
struct hash<coroutine_handle<_Promise>> {
template <class _CoroPromise>
struct hash<coroutine_handle<_CoroPromise>> {
_NODISCARD _STATIC_CALL_OPERATOR size_t operator()(
const coroutine_handle<_Promise>& _Coro) _CONST_CALL_OPERATOR noexcept {
const coroutine_handle<_CoroPromise>& _Coro) _CONST_CALL_OPERATOR noexcept {
return _Hash_representation(_Coro.address());
}
};
Expand Down
108 changes: 61 additions & 47 deletions stl/inc/generator
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ private:
return _Al.allocate(_Count);
} else {
// store stateful allocator
static constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block));
const size_t _Count = (_Size + sizeof(_Alloc) + _Align - 1) / sizeof(_Aligned_block);
void* const _Ptr = _Al.allocate(_Count);
constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block));
const size_t _Count = (_Size + sizeof(_Alloc) + _Align - 1) / sizeof(_Aligned_block);
void* const _Ptr = _Al.allocate(_Count);
const auto _Al_address =
(reinterpret_cast<uintptr_t>(_Ptr) + _Size + alignof(_Alloc) - 1) & ~(alignof(_Alloc) - 1);
::new (reinterpret_cast<void*>(_Al_address)) _Alloc(_STD move(_Al));
Expand Down Expand Up @@ -92,8 +92,8 @@ public:
_Alloc _Al{_STD move(_Stored_al)};
_Stored_al.~_Alloc();

static constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block));
const size_t _Count = (_Size + sizeof(_Alloc) + _Align - 1) / sizeof(_Aligned_block);
constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block));
const size_t _Count = (_Size + sizeof(_Alloc) + _Align - 1) / sizeof(_Aligned_block);
_Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count);
}
}
Expand All @@ -102,7 +102,33 @@ public:
template <>
class _Promise_allocator<void> { // type-erased allocator
private:
using _Dealloc_fn = void (*)(void*, size_t);
using _Dealloc_fn = void(__stdcall*)(void*, size_t) _NOEXCEPT_FNPTR;

template <class _Alloc>
static void __stdcall _Dealloc_stateless(void* const _Ptr, const size_t _Size) noexcept {
_Alloc _Al{};
const size_t _Count = (_Size + sizeof(_Dealloc_fn) + sizeof(_Aligned_block) - 1) / sizeof(_Aligned_block);
_Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count);
}

template <class _Alloc>
static void __stdcall _Dealloc_stateful(void* const _Ptr, size_t _Size) noexcept {
constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block));

_Size += sizeof(_Dealloc_fn);
const auto _Al_address =
(reinterpret_cast<uintptr_t>(_Ptr) + _Size + alignof(_Alloc) - 1) & ~(alignof(_Alloc) - 1);
auto& _Stored_al = *reinterpret_cast<_Alloc*>(_Al_address);
_Alloc _Al{_STD move(_Stored_al)};
_Stored_al.~_Alloc();

const size_t _Count = (_Size + sizeof(_Al) + _Align - 1) / sizeof(_Aligned_block);
_Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count);
}

static void __stdcall _Dealloc_delete(void* const _Ptr, const size_t _Size) noexcept {
::operator delete[](_Ptr, _Size + sizeof(_Dealloc_fn));
}

template <class _ProtoAlloc>
static void* _Allocate(const _ProtoAlloc& _Proto, size_t _Size) {
Expand All @@ -111,32 +137,17 @@ private:

if constexpr (default_initializable<_Alloc> && allocator_traits<_Alloc>::is_always_equal::value) {
// don't store stateless allocator
const _Dealloc_fn _Dealloc = [](void* const _Ptr, const size_t _Size) {
_Alloc _Al{};
const size_t _Count =
(_Size + sizeof(_Dealloc_fn) + sizeof(_Aligned_block) - 1) / sizeof(_Aligned_block);
_Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count);
};
const _Dealloc_fn _Dealloc = _Dealloc_stateless<_Alloc>;

const size_t _Count = (_Size + sizeof(_Dealloc_fn) + sizeof(_Aligned_block) - 1) / sizeof(_Aligned_block);
void* const _Ptr = _Al.allocate(_Count);
_CSTD memcpy(static_cast<char*>(_Ptr) + _Size, &_Dealloc, sizeof(_Dealloc));
return _Ptr;
} else {
// store stateful allocator
static constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block));

const _Dealloc_fn _Dealloc = [](void* const _Ptr, size_t _Size) {
_Size += sizeof(_Dealloc_fn);
const auto _Al_address =
(reinterpret_cast<uintptr_t>(_Ptr) + _Size + alignof(_Alloc) - 1) & ~(alignof(_Alloc) - 1);
auto& _Stored_al = *reinterpret_cast<const _Alloc*>(_Al_address);
_Alloc _Al{_STD move(_Stored_al)};
_Stored_al.~_Alloc();
constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block));

const size_t _Count = (_Size + sizeof(_Al) + _Align - 1) / sizeof(_Aligned_block);
_Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count);
};
const _Dealloc_fn _Dealloc = _Dealloc_stateful<_Alloc>;

const size_t _Count = (_Size + sizeof(_Dealloc_fn) + sizeof(_Al) + _Align - 1) / sizeof(_Aligned_block);
void* const _Ptr = _Al.allocate(_Count);
Expand All @@ -152,9 +163,7 @@ private:
public:
static void* operator new(const size_t _Size) { // default: new/delete
void* const _Ptr = ::operator new[](_Size + sizeof(_Dealloc_fn));
const _Dealloc_fn _Dealloc = [](void* const _Ptr, const size_t _Size) {
::operator delete[](_Ptr, _Size + sizeof(_Dealloc_fn));
};
const _Dealloc_fn _Dealloc = _Dealloc_delete;
_CSTD memcpy(static_cast<char*>(_Ptr) + _Size, &_Dealloc, sizeof(_Dealloc_fn));
return _Ptr;
}
Expand Down Expand Up @@ -231,20 +240,23 @@ public:
requires same_as<_Gen_yield_t<_Gen_reference_t<_Rty, _Vty>>, _Yielded>
_NODISCARD auto yield_value(_RANGES elements_of<generator<_Rty, _Vty, _Alloc>&&, _Unused> _Elem) noexcept {
using _Nested_awaitable = _Nested_awaitable_provider<_Rty, _Vty, _Alloc>::_Awaitable;
return _Nested_awaitable{std::move(_Elem.range)};
return _Nested_awaitable{_STD move(_Elem.range)};
}

template <_RANGES input_range _Rng, class _Alloc>
requires convertible_to<_RANGES range_reference_t<_Rng>, _Yielded>
_NODISCARD auto yield_value(_RANGES elements_of<_Rng, _Alloc> _Elem) {
using _Vty = _RANGES range_value_t<_Rng>;
using _Nested_awaitable = _Nested_awaitable_provider<_Yielded, _Vty, _Alloc>::_Awaitable;
return _Nested_awaitable{[](allocator_arg_t, _Alloc, _RANGES iterator_t<_Rng> _It,
const _RANGES sentinel_t<_Rng> _Se) -> generator<_Yielded, _Vty, _Alloc> {

auto _Lambda = [](allocator_arg_t, _Alloc, _RANGES iterator_t<_Rng> _It,
Comment thread
StephanTLavavej marked this conversation as resolved.
const _RANGES sentinel_t<_Rng> _Se) -> generator<_Yielded, _Vty, _Alloc> {
for (; _It != _Se; ++_It) {
co_yield static_cast<_Yielded>(*_It);
}
}(allocator_arg, _Elem.allocator, _RANGES begin(_Elem.range), _RANGES end(_Elem.range))};
};
return _Nested_awaitable{
_Lambda(allocator_arg, _Elem.allocator, _RANGES begin(_Elem.range), _RANGES end(_Elem.range))};
}

void await_transform() = delete;
Expand All @@ -255,7 +267,7 @@ public:
if (_Info) {
_Info->_Except = _STD current_exception();
} else {
throw;
_RERAISE;
}
}

Expand All @@ -267,10 +279,10 @@ private:
return false;
}

template <class _Promise>
constexpr void await_suspend(coroutine_handle<_Promise> _Handle) noexcept {
template <class _CoroPromise>
constexpr void await_suspend(coroutine_handle<_CoroPromise> _Handle) noexcept {
#ifdef __cpp_lib_is_pointer_interconvertible // TRANSITION, LLVM-48860
_STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _Promise>);
_STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _CoroPromise>);
#endif // ^^^ no workaround ^^^

_Base& _Current = _Handle.promise();
Expand All @@ -291,10 +303,10 @@ private:
return false;
}

template <class _Promise>
_NODISCARD coroutine_handle<> await_suspend(coroutine_handle<_Promise> _Handle) noexcept {
template <class _CoroPromise>
_NODISCARD coroutine_handle<> await_suspend(coroutine_handle<_CoroPromise> _Handle) noexcept {
#ifdef __cpp_lib_is_pointer_interconvertible // TRANSITION, LLVM-48860
_STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _Promise>);
_STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _CoroPromise>);
#endif // ^^^ no workaround ^^^

_Base& _Current = _Handle.promise();
Expand Down Expand Up @@ -325,10 +337,10 @@ private:
return !_Gen._Coro;
}

template <class _Promise>
_NODISCARD coroutine_handle<_Base> await_suspend(coroutine_handle<_Promise> _Current) noexcept {
template <class _CoroPromise>
_NODISCARD coroutine_handle<_Base> await_suspend(coroutine_handle<_CoroPromise> _Current) noexcept {
#ifdef __cpp_lib_is_pointer_interconvertible // TRANSITION, LLVM-48860
_STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _Promise>);
_STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _CoroPromise>);
#endif // ^^^ no workaround ^^^
auto _Target = coroutine_handle<_Base>::from_address(_Gen._Coro.address());
_Nested._Parent = coroutine_handle<_Base>::from_address(_Current.address());
Expand Down Expand Up @@ -409,25 +421,27 @@ private:
};

_EXPORT_STD template <class _Rty, class _Vty, class _Alloc>
class generator : public ranges::view_interface<generator<_Rty, _Vty, _Alloc>> {
class generator : public _RANGES view_interface<generator<_Rty, _Vty, _Alloc>> {
Comment thread
StephanTLavavej marked this conversation as resolved.
private:
using _Value = _Gen_value_t<_Rty, _Vty>;
static_assert(same_as<remove_cvref_t<_Value>, _Value> && is_object_v<_Value>,
"generator's value type must be a cv-unqualified object type");
"generator's value type must be a cv-unqualified object type (N4971 [coro.generator.class]/1.2)");

using _Ref = _Gen_reference_t<_Rty, _Vty>;
static_assert(
is_reference_v<_Ref> || (is_object_v<_Ref> && same_as<remove_cv_t<_Ref>, _Ref> && copy_constructible<_Ref>),
"generator's second argument must be a reference type or a cv-unqualified "
"copy-constructible object type");
"generator's selected reference type must be an actual reference type "
"or a cv-unqualified copy-constructible object type (N4971 [coro.generator.class]/1.3)");

using _RRef = conditional_t<is_lvalue_reference_v<_Ref>, remove_reference_t<_Ref>&&, _Ref>;

static_assert(common_reference_with<_Ref&&, _Value&> && common_reference_with<_Ref&&, _RRef&&>
&& common_reference_with<_RRef&&, const _Value&>,
"an iterator with the selected value and reference types cannot model indirectly_readable");
"generator's iterator type must model indirectly_readable, "
"but that's impossible with the selected value and reference types (N4971 [coro.generator.class]/1.4)");

static_assert(_Has_real_pointers<_Alloc>, "generator allocators must use raw pointers");
static_assert(_Has_real_pointers<_Alloc>, "generator allocators must use raw pointers "
"(N4971 [coro.generator.class]/1.1)");

friend _Gen_promise_base<_Gen_yield_t<_Ref>>;

Expand Down
1 change: 1 addition & 0 deletions tests/std/tests/P2502R2_generator/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <forward_list>
#include <generator>
Expand Down