Skip to content

Commit

Permalink
<generator>: Test generator::promise_type (#4534)
Browse files Browse the repository at this point in the history
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
  • Loading branch information
JMazurkiewicz and StephanTLavavej authored Mar 27, 2024
1 parent ac3369a commit 7f04044
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 19 deletions.
41 changes: 22 additions & 19 deletions stl/inc/generator
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,22 @@ struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) _Aligned_block {
template <class _Alloc>
concept _Has_real_pointers = same_as<_Alloc, void> || is_pointer_v<typename allocator_traits<_Alloc>::pointer>;

template <class _Allocator = void>
template <class _Allocator>
class _Promise_allocator { // statically specified allocator type
private:
using _Alloc = _Rebind_alloc_t<_Allocator, _Aligned_block>;
using _Alloc = _Rebind_alloc_t<_Allocator, _Aligned_block>;
using _Alloc_size_type = allocator_traits<_Alloc>::size_type;

static void* _Allocate(_Alloc _Al, const size_t _Size) {
if constexpr (default_initializable<_Alloc> && allocator_traits<_Alloc>::is_always_equal::value) {
// do not store stateless allocator
const size_t _Count = (_Size + sizeof(_Aligned_block) - 1) / sizeof(_Aligned_block);
return _Al.allocate(_Count);
return _Al.allocate(_Convert_size<_Alloc_size_type>(_Count));
} else {
// store stateful allocator
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);
void* const _Ptr = _Al.allocate(_Convert_size<_Alloc_size_type>(_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 @@ -83,7 +84,7 @@ public:
// make stateless allocator
_Alloc _Al{};
const size_t _Count = (_Size + sizeof(_Aligned_block) - 1) / sizeof(_Aligned_block);
_Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count);
_Al.deallocate(static_cast<_Aligned_block*>(_Ptr), static_cast<_Alloc_size_type>(_Count));
} else {
// retrieve stateful allocator
const auto _Al_address =
Expand All @@ -94,7 +95,7 @@ public:

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);
_Al.deallocate(static_cast<_Aligned_block*>(_Ptr), static_cast<_Alloc_size_type>(_Count));
}
}
};
Expand All @@ -108,7 +109,7 @@ private:
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);
_Al.deallocate(static_cast<_Aligned_block*>(_Ptr), static_cast<allocator_traits<_Alloc>::size_type>(_Count));
}

template <class _Alloc>
Expand All @@ -123,7 +124,7 @@ private:
_Stored_al.~_Alloc();

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

static void __stdcall _Dealloc_delete(void* const _Ptr, const size_t _Size) noexcept {
Expand All @@ -132,15 +133,16 @@ private:

template <class _ProtoAlloc>
static void* _Allocate(const _ProtoAlloc& _Proto, size_t _Size) {
using _Alloc = _Rebind_alloc_t<_ProtoAlloc, _Aligned_block>;
auto _Al = static_cast<_Alloc>(_Proto);
using _Alloc = _Rebind_alloc_t<_ProtoAlloc, _Aligned_block>;
using _Alloc_size_type = allocator_traits<_Alloc>::size_type;
auto _Al = static_cast<_Alloc>(_Proto);

if constexpr (default_initializable<_Alloc> && allocator_traits<_Alloc>::is_always_equal::value) {
// don't store stateless allocator
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);
void* const _Ptr = _Al.allocate(_Convert_size<_Alloc_size_type>(_Count));
_CSTD memcpy(static_cast<char*>(_Ptr) + _Size, &_Dealloc, sizeof(_Dealloc));
return _Ptr;
} else {
Expand All @@ -150,7 +152,7 @@ private:
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);
void* const _Ptr = _Al.allocate(_Convert_size<_Alloc_size_type>(_Count));
_CSTD memcpy(static_cast<char*>(_Ptr) + _Size, &_Dealloc, sizeof(_Dealloc));
_Size += sizeof(_Dealloc_fn);
const auto _Al_address =
Expand Down Expand Up @@ -215,7 +217,7 @@ public:
#ifndef _PREFAST_ // TRANSITION, VSO-1662733
_NODISCARD
#endif // ^^^ no workaround ^^^
suspend_always initial_suspend() noexcept {
suspend_always initial_suspend() const noexcept {
return {};
}

Expand Down Expand Up @@ -443,18 +445,19 @@ private:
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>>;

public:
struct __declspec(empty_bases) promise_type : _Promise_allocator<_Alloc>, _Gen_promise_base<_Gen_yield_t<_Ref>> {
using yielded = _Gen_yield_t<_Ref>;

friend _Gen_promise_base<yielded>;

struct __declspec(empty_bases) promise_type : _Promise_allocator<_Alloc>, _Gen_promise_base<yielded> {
_NODISCARD generator get_return_object() noexcept {
return generator{_Gen_secret_tag{}, coroutine_handle<promise_type>::from_promise(*this)};
}
};
_STL_INTERNAL_STATIC_ASSERT(is_standard_layout_v<promise_type>);
#ifdef __cpp_lib_is_pointer_interconvertible // TRANSITION, LLVM-48860
_STL_INTERNAL_STATIC_ASSERT(
is_pointer_interconvertible_base_of_v<_Gen_promise_base<_Gen_yield_t<_Ref>>, promise_type>);
_STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Gen_promise_base<yielded>, promise_type>);
#endif // ^^^ no workaround ^^^

generator(generator&& _That) noexcept : _Coro(_STD exchange(_That._Coro, {})) {}
Expand All @@ -475,7 +478,7 @@ public:
_STL_ASSERT(_Coro, "Can't call begin on moved-from generator");
_Coro.resume();
return typename _Gen_iter_provider<_Value, _Ref>::_Iterator{
_Gen_secret_tag{}, coroutine_handle<_Gen_promise_base<_Gen_yield_t<_Ref>>>::from_address(_Coro.address())};
_Gen_secret_tag{}, coroutine_handle<_Gen_promise_base<yielded>>::from_address(_Coro.address())};
}

_NODISCARD default_sentinel_t end() const noexcept {
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ tests\P2474R2_views_repeat
tests\P2474R2_views_repeat_death
tests\P2494R2_move_only_range_adaptors
tests\P2502R2_generator
tests\P2502R2_generator_promise
tests\P2505R5_monadic_functions_for_std_expected
tests\P2510R3_text_formatting_pointers
tests\P2517R1_apply_conditional_noexcept
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P2502R2_generator_promise/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_latest_matrix.lst
Loading

0 comments on commit 7f04044

Please sign in to comment.