From 276ebc17abdecf112df221a861c1e8e3a85baa48 Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 10 Oct 2019 08:26:33 -0700 Subject: [PATCH 01/11] notify --- strings/base_coroutine_foundation.h | 126 +++++++++++++++++- strings/base_error.h | 2 - strings/base_extern.h | 4 + test/test/notify_awaiter.cpp | 198 ++++++++++++++++++++++++++++ test/test/test.vcxproj | 1 + 5 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 test/test/notify_awaiter.cpp diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index af3db4a64..c52f09fa5 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -260,6 +260,128 @@ namespace winrt::impl Promise* m_promise; }; + template + class has_awaitable_member + { + template ().await_ready())> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + + public: + + static constexpr bool value = get_value(0); + }; + + template + class has_awaitable_free + { + template ()))> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + + public: + + static constexpr bool value = get_value(0); + }; + + template + struct member_await_adapter_impl + { + T&& awaitable; + + bool ready() noexcept + { + return await_ready(awaitable); + } + + template + auto suspend(std::experimental::coroutine_handle handle) noexcept + { + return await_suspend(awaitable, handle); + } + + auto resume() noexcept + { + return await_resume(awaitable); + } + }; + + template + struct member_await_adapter + { + T&& awaitable; + + bool await_ready() noexcept + { + return member_await_adapter_impl{ static_cast(awaitable) }.ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) noexcept + { + return member_await_adapter_impl{ static_cast(awaitable) }.suspend(handle); + } + + auto await_resume() noexcept + { + return member_await_adapter_impl{ static_cast(awaitable) }.resume(); + } + }; + + template + auto get_awaiter(T&& value) noexcept -> decltype(static_cast(value).operator co_await()) + { + return static_cast(value).operator co_await(); + } + + template + auto get_awaiter(T&& value) noexcept -> decltype(operator co_await(static_cast(value))) + { + return operator co_await(static_cast(value)); + } + + template ::value, int> = 0> + auto get_awaiter(T&& value) noexcept + { + return static_cast(value); + } + + template ::value, int> = 0> + auto get_awaiter(T&& value) noexcept + { + return member_await_adapter{ static_cast(value) }; + } + + template + struct notify_awaiter + { + T&& awaitable; + + bool await_ready() noexcept + { + if (winrt_suspend_handler) + { + winrt_suspend_handler(this); + } + + return get_awaiter(static_cast(awaitable)).await_ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) noexcept + { + return get_awaiter(static_cast(awaitable)).await_suspend(handle); + } + + auto await_resume() noexcept + { + if (winrt_resume_handler) + { + winrt_resume_handler(this); + } + + return get_awaiter(static_cast(awaitable)).await_resume(); + } + }; + template struct promise_base : implements { @@ -467,14 +589,14 @@ namespace winrt::impl } template - Expression&& await_transform(Expression&& expression) + auto await_transform(Expression&& expression) { if (Status() == AsyncStatus::Canceled) { throw winrt::hresult_canceled(); } - return std::forward(expression); + return notify_awaiter{ static_cast(expression) }; } cancellation_token await_transform(get_cancellation_token_t) noexcept diff --git a/strings/base_error.h b/strings/base_error.h index 9332ac797..4c03162a4 100644 --- a/strings/base_error.h +++ b/strings/base_error.h @@ -1,6 +1,4 @@ -__declspec(selectany) int32_t (__stdcall *winrt_to_hresult_handler)(void* address) noexcept{}; - namespace winrt::impl { struct heap_traits diff --git a/strings/base_extern.h b/strings/base_extern.h index 0c5fd116c..a149ebd69 100644 --- a/strings/base_extern.h +++ b/strings/base_extern.h @@ -1,4 +1,8 @@ +__declspec(selectany) int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {}; +__declspec(selectany) void(__stdcall* winrt_suspend_handler)(void const* token) noexcept {}; +__declspec(selectany) void(__stdcall* winrt_resume_handler)(void const* token) noexcept {}; + extern "C" { int32_t __stdcall WINRT_GetRestrictedErrorInfo(void** info) noexcept; diff --git a/test/test/notify_awaiter.cpp b/test/test/notify_awaiter.cpp new file mode 100644 index 000000000..874bb53d0 --- /dev/null +++ b/test/test/notify_awaiter.cpp @@ -0,0 +1,198 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation; + +namespace +{ + struct notification + { + uint32_t suspend{}; + uint32_t resume{}; + }; + + std::map watcher; + slim_mutex lock; + handle start_racing{ CreateEventW(nullptr, true, false, nullptr) }; + + struct free_awaitable + { + }; + bool await_ready(free_awaitable) + { + return true; + } + void await_suspend(free_awaitable, std::experimental::coroutine_handle<>) + { + } + void await_resume(free_awaitable) + { + + } + + struct member_awaitable + { + bool await_ready() + { + return true; + } + void await_suspend(std::experimental::coroutine_handle<>) + { + } + void await_resume() + { + + } + }; + + struct free_operator_awaitable + { + }; + auto operator co_await(free_operator_awaitable) + { + struct awaitable + { + bool await_ready() + { + return true; + } + void await_suspend(std::experimental::coroutine_handle<>) + { + } + void await_resume() + { + } + }; + return awaitable{}; + } + + struct member_operator_awaitable + { + auto operator co_await() + { + struct awaitable + { + bool await_ready() + { + return true; + } + void await_suspend(std::experimental::coroutine_handle<>) + { + } + void await_resume() + { + } + }; + return awaitable{}; + } + }; + + IAsyncAction AsyncAction() + { + co_return; + } + IAsyncActionWithProgress AsyncActionWithProgress() + { + co_return; + } + IAsyncOperation AsyncOperation() + { + co_return 0; + } + IAsyncOperationWithProgress AsyncOperationWithProgress() + { + co_return 0; + } + + IAsyncAction Async() + { + co_await resume_on_signal(start_racing.get()); + co_await resume_background(); + co_await resume_background(); + co_await free_awaitable{}; + co_await member_awaitable{}; + co_await free_operator_awaitable{}; + co_await member_operator_awaitable{}; + co_await AsyncAction(); + co_await AsyncActionWithProgress(); + co_await AsyncOperation(); + co_await AsyncOperationWithProgress(); + } + + constexpr size_t test_coroutines = 10; + constexpr size_t test_suspension_points = 11; +} + +TEST_CASE("notify_awaiter") +{ + // Everything works fine when nobody is watching. + + REQUIRE(!winrt_suspend_handler); + REQUIRE(!winrt_resume_handler); + SetEvent(start_racing.get()); + Async().get(); + ResetEvent(start_racing.get()); + + // Hook up some watchers. + + winrt_suspend_handler = [](void const* token) noexcept + { + slim_lock_guard guard(lock); + watcher[token].suspend += 1; + }; + + winrt_resume_handler = [](void const* token) noexcept + { + slim_lock_guard guard(lock); + watcher[token].resume += 1; + }; + + // Prepare a few coroutines. + + std::vector concurrency; + REQUIRE(watcher.empty()); + + for (size_t i = 0; i != test_coroutines; ++i) + { + concurrency.push_back(Async()); + } + + // Give coroutines a moment to get to the racing line. + + Sleep(500); + + // Each coroutine should have suspended once. + + REQUIRE(watcher.size() == test_coroutines); + + for (auto&& [_, tally] : watcher) + { + REQUIRE(tally.suspend == 1); + REQUIRE(tally.resume == 0); + } + + // And the race is on! + + SetEvent(start_racing.get()); + + for (auto&& async : concurrency) + { + async.get(); + } + + // Each suspension point should have been recorded. + + REQUIRE(watcher.size() == test_coroutines * test_suspension_points); + + for (auto&& [_, tally] : watcher) + { + // And should be be perfectly balanced. + REQUIRE(tally.suspend == 1); + REQUIRE(tally.resume == 1); + } + + // Remove watchers. + + winrt_suspend_handler = nullptr; + winrt_resume_handler = nullptr; +} diff --git a/test/test/test.vcxproj b/test/test/test.vcxproj index 18600b663..398cf4e3c 100644 --- a/test/test/test.vcxproj +++ b/test/test/test.vcxproj @@ -225,6 +225,7 @@ + NotUsing From 04ef142b38529302e3e43a783057a2cb3dad4a03 Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 10 Oct 2019 11:37:01 -0700 Subject: [PATCH 02/11] no_copy_awaitable --- strings/base_coroutine_foundation.h | 64 ++++++++++++++++++++--------- test/test/notify_awaiter.cpp | 21 +++++++++- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index c52f09fa5..35afbdfd0 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -283,46 +283,68 @@ namespace winrt::impl }; template - struct member_await_adapter_impl + struct free_await_adapter_impl { T&& awaitable; - bool ready() noexcept + bool ready() { return await_ready(awaitable); } template - auto suspend(std::experimental::coroutine_handle handle) noexcept + auto suspend(std::experimental::coroutine_handle handle) { return await_suspend(awaitable, handle); } - auto resume() noexcept + auto resume() { return await_resume(awaitable); } }; + template + struct free_await_adapter + { + T&& awaitable; + + bool await_ready() + { + return free_await_adapter_impl{ static_cast(awaitable) }.ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return free_await_adapter_impl{ static_cast(awaitable) }.suspend(handle); + } + + auto await_resume() + { + return free_await_adapter_impl{ static_cast(awaitable) }.resume(); + } + }; + template struct member_await_adapter { T&& awaitable; - bool await_ready() noexcept + bool await_ready() { - return member_await_adapter_impl{ static_cast(awaitable) }.ready(); + return awaitable.await_ready(); } template - auto await_suspend(std::experimental::coroutine_handle handle) noexcept + auto await_suspend(std::experimental::coroutine_handle handle) { - return member_await_adapter_impl{ static_cast(awaitable) }.suspend(handle); + return awaitable.await_suspend(handle); } - auto await_resume() noexcept + auto await_resume() { - return member_await_adapter_impl{ static_cast(awaitable) }.resume(); + return awaitable.await_resume(); } }; @@ -341,44 +363,48 @@ namespace winrt::impl template ::value, int> = 0> auto get_awaiter(T&& value) noexcept { - return static_cast(value); + return member_await_adapter{ static_cast(value) }; } template ::value, int> = 0> auto get_awaiter(T&& value) noexcept { - return member_await_adapter{ static_cast(value) }; + return free_await_adapter{ static_cast(value) }; } template struct notify_awaiter { - T&& awaitable; + decltype(get_awaiter(std::declval())) awaitable; + + notify_awaiter(T&& awaitable) : awaitable(get_awaiter(static_cast(awaitable))) + { + } - bool await_ready() noexcept + bool await_ready() { if (winrt_suspend_handler) { winrt_suspend_handler(this); } - return get_awaiter(static_cast(awaitable)).await_ready(); + return awaitable.await_ready(); } template - auto await_suspend(std::experimental::coroutine_handle handle) noexcept + auto await_suspend(std::experimental::coroutine_handle handle) { - return get_awaiter(static_cast(awaitable)).await_suspend(handle); + return awaitable.await_suspend(handle); } - auto await_resume() noexcept + auto await_resume() { if (winrt_resume_handler) { winrt_resume_handler(this); } - return get_awaiter(static_cast(awaitable)).await_resume(); + return awaitable.await_resume(); } }; diff --git a/test/test/notify_awaiter.cpp b/test/test/notify_awaiter.cpp index 874bb53d0..2d31e7584 100644 --- a/test/test/notify_awaiter.cpp +++ b/test/test/notify_awaiter.cpp @@ -87,6 +87,24 @@ namespace } }; + struct no_copy_awaitable + { + no_copy_awaitable() = default; + no_copy_awaitable(no_copy_awaitable const&) = delete; + + bool await_ready() + { + return true; + } + void await_suspend(std::experimental::coroutine_handle<>) + { + } + void await_resume() + { + + } + }; + IAsyncAction AsyncAction() { co_return; @@ -113,6 +131,7 @@ namespace co_await member_awaitable{}; co_await free_operator_awaitable{}; co_await member_operator_awaitable{}; + co_await no_copy_awaitable{}; co_await AsyncAction(); co_await AsyncActionWithProgress(); co_await AsyncOperation(); @@ -120,7 +139,7 @@ namespace } constexpr size_t test_coroutines = 10; - constexpr size_t test_suspension_points = 11; + constexpr size_t test_suspension_points = 12; } TEST_CASE("notify_awaiter") From 8f39915ebfb0e9966f0f39dbaf278085c59df736 Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 10 Oct 2019 12:41:37 -0700 Subject: [PATCH 03/11] test --- test/test/notify_awaiter.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/test/test/notify_awaiter.cpp b/test/test/notify_awaiter.cpp index 2d31e7584..a6e4773a7 100644 --- a/test/test/notify_awaiter.cpp +++ b/test/test/notify_awaiter.cpp @@ -5,16 +5,6 @@ using namespace Windows::Foundation; namespace { - struct notification - { - uint32_t suspend{}; - uint32_t resume{}; - }; - - std::map watcher; - slim_mutex lock; - handle start_racing{ CreateEventW(nullptr, true, false, nullptr) }; - struct free_awaitable { }; @@ -122,6 +112,18 @@ namespace co_return 0; } + struct notification + { + uint32_t suspend{}; + uint32_t resume{}; + }; + + static std::map watcher; + static slim_mutex lock; + static handle start_racing{ CreateEventW(nullptr, true, false, nullptr) }; + constexpr size_t test_coroutines = 10; + constexpr size_t test_suspension_points = 12; + IAsyncAction Async() { co_await resume_on_signal(start_racing.get()); @@ -137,13 +139,15 @@ namespace co_await AsyncOperation(); co_await AsyncOperationWithProgress(); } - - constexpr size_t test_coroutines = 10; - constexpr size_t test_suspension_points = 12; } TEST_CASE("notify_awaiter") { + // TODO: another test is creating a coroutine that may be running after this test + // starts. This bumps into the notify handlers and breaks this test. + // Find and destroy. + Sleep(2000); + // Everything works fine when nobody is watching. REQUIRE(!winrt_suspend_handler); @@ -178,10 +182,11 @@ TEST_CASE("notify_awaiter") // Give coroutines a moment to get to the racing line. - Sleep(500); + Sleep(1000); // Each coroutine should have suspended once. + REQUIRE(concurrency.size() == test_coroutines); REQUIRE(watcher.size() == test_coroutines); for (auto&& [_, tally] : watcher) From 499f68d1fd8c07eb1e9ac7e2d8ed46f4be66b8ad Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 10 Oct 2019 13:50:10 -0700 Subject: [PATCH 04/11] test --- test/test/notify_awaiter.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/test/notify_awaiter.cpp b/test/test/notify_awaiter.cpp index a6e4773a7..01c245ebe 100644 --- a/test/test/notify_awaiter.cpp +++ b/test/test/notify_awaiter.cpp @@ -143,11 +143,6 @@ namespace TEST_CASE("notify_awaiter") { - // TODO: another test is creating a coroutine that may be running after this test - // starts. This bumps into the notify handlers and breaks this test. - // Find and destroy. - Sleep(2000); - // Everything works fine when nobody is watching. REQUIRE(!winrt_suspend_handler); From c97ebebe774ade484e34d29a4587a819a6c593ca Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 10 Oct 2019 14:06:09 -0700 Subject: [PATCH 05/11] test --- test/test/disconnected.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/test/disconnected.cpp b/test/test/disconnected.cpp index 32f53bf35..583b7df36 100644 --- a/test/test/disconnected.cpp +++ b/test/test/disconnected.cpp @@ -79,16 +79,20 @@ TEST_CASE("disconnected") { auto async = ActionProgress(); + handle signal{ CreateEventW(nullptr, true, false, nullptr) }; async.Progress([](auto&&...) { throw hresult_error(RPC_E_DISCONNECTED); }); - async.Completed([](auto&&...) + async.Completed([&](auto&&...) { + SetEvent(signal.get()); throw hresult_error(RPC_E_DISCONNECTED); }); + + WaitForSingleObject(signal.get(), INFINITE); } { @@ -102,15 +106,19 @@ TEST_CASE("disconnected") { auto async = OperationProgress(); + handle signal{ CreateEventW(nullptr, true, false, nullptr) }; async.Progress([](auto&&...) { throw hresult_error(RPC_E_DISCONNECTED); }); - async.Completed([](auto&&...) + async.Completed([&](auto&&...) { + SetEvent(signal.get()); throw hresult_error(RPC_E_DISCONNECTED); }); + + WaitForSingleObject(signal.get(), INFINITE); } } From db5d4493b81d4b0cd532615f1029ce6a5211f1bb Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 10 Oct 2019 14:08:11 -0700 Subject: [PATCH 06/11] test --- test/test/notify_awaiter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test/notify_awaiter.cpp b/test/test/notify_awaiter.cpp index 01c245ebe..9b074d2e4 100644 --- a/test/test/notify_awaiter.cpp +++ b/test/test/notify_awaiter.cpp @@ -121,7 +121,7 @@ namespace static std::map watcher; static slim_mutex lock; static handle start_racing{ CreateEventW(nullptr, true, false, nullptr) }; - constexpr size_t test_coroutines = 10; + constexpr size_t test_coroutines = 20; constexpr size_t test_suspension_points = 12; IAsyncAction Async() @@ -175,7 +175,7 @@ TEST_CASE("notify_awaiter") concurrency.push_back(Async()); } - // Give coroutines a moment to get to the racing line. + // Give coroutines a moment to get to the starting line. Sleep(1000); From a6badcec70b8082ffaa3b5a8fe08a47672a10f3c Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 10 Oct 2019 16:10:42 -0700 Subject: [PATCH 07/11] conformance --- strings/base_coroutine_foundation.h | 18 +++++++----------- test/test/generic_types.cpp | 4 ++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 35afbdfd0..5456cf981 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -307,22 +307,22 @@ namespace winrt::impl template struct free_await_adapter { - T&& awaitable; + free_await_adapter_impl&& awaitable; bool await_ready() { - return free_await_adapter_impl{ static_cast(awaitable) }.ready(); + return awaitable.ready(); } template auto await_suspend(std::experimental::coroutine_handle handle) { - return free_await_adapter_impl{ static_cast(awaitable) }.suspend(handle); + return awaitable.suspend(handle); } auto await_resume() { - return free_await_adapter_impl{ static_cast(awaitable) }.resume(); + return awaitable.resume(); } }; @@ -369,17 +369,13 @@ namespace winrt::impl template ::value, int> = 0> auto get_awaiter(T&& value) noexcept { - return free_await_adapter{ static_cast(value) }; + return free_await_adapter{ { static_cast(value) }}; } template struct notify_awaiter { - decltype(get_awaiter(std::declval())) awaitable; - - notify_awaiter(T&& awaitable) : awaitable(get_awaiter(static_cast(awaitable))) - { - } + decltype(get_awaiter(std::declval()))&& awaitable; bool await_ready() { @@ -622,7 +618,7 @@ namespace winrt::impl throw winrt::hresult_canceled(); } - return notify_awaiter{ static_cast(expression) }; + return notify_awaiter{ get_awaiter(static_cast(expression)) }; } cancellation_token await_transform(get_cancellation_token_t) noexcept diff --git a/test/test/generic_types.cpp b/test/test/generic_types.cpp index 4c8e68e9b..77c61931e 100644 --- a/test/test/generic_types.cpp +++ b/test/test/generic_types.cpp @@ -8,5 +8,9 @@ TEST_CASE("generic_types") REQUIRE_EQUAL_NAME(L"Windows.Foundation.Uri", Uri); REQUIRE_EQUAL_NAME(L"Windows.Foundation.PropertyType", PropertyType); REQUIRE_EQUAL_NAME(L"Windows.Foundation.Point", Point); + + // Clang 9 doesn't think this is a constant expression. +#ifndef __clang__ REQUIRE_EQUAL_NAME(L"{96369f54-8eb6-48f0-abce-c1b211e627c3}", IStringable); +#endif } From 7c6948c6da6fe7d31583bce194c4eaa09cd6f7ff Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 10 Oct 2019 16:25:11 -0700 Subject: [PATCH 08/11] feedback --- strings/base_coroutine_foundation.h | 144 -------------------------- strings/base_coroutine_threadpool.h | 150 ++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 144 deletions(-) diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 5456cf981..22888d2bf 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -260,150 +260,6 @@ namespace winrt::impl Promise* m_promise; }; - template - class has_awaitable_member - { - template ().await_ready())> static constexpr bool get_value(int) { return true; } - template static constexpr bool get_value(...) { return false; } - - public: - - static constexpr bool value = get_value(0); - }; - - template - class has_awaitable_free - { - template ()))> static constexpr bool get_value(int) { return true; } - template static constexpr bool get_value(...) { return false; } - - public: - - static constexpr bool value = get_value(0); - }; - - template - struct free_await_adapter_impl - { - T&& awaitable; - - bool ready() - { - return await_ready(awaitable); - } - - template - auto suspend(std::experimental::coroutine_handle handle) - { - return await_suspend(awaitable, handle); - } - - auto resume() - { - return await_resume(awaitable); - } - }; - - template - struct free_await_adapter - { - free_await_adapter_impl&& awaitable; - - bool await_ready() - { - return awaitable.ready(); - } - - template - auto await_suspend(std::experimental::coroutine_handle handle) - { - return awaitable.suspend(handle); - } - - auto await_resume() - { - return awaitable.resume(); - } - }; - - template - struct member_await_adapter - { - T&& awaitable; - - bool await_ready() - { - return awaitable.await_ready(); - } - - template - auto await_suspend(std::experimental::coroutine_handle handle) - { - return awaitable.await_suspend(handle); - } - - auto await_resume() - { - return awaitable.await_resume(); - } - }; - - template - auto get_awaiter(T&& value) noexcept -> decltype(static_cast(value).operator co_await()) - { - return static_cast(value).operator co_await(); - } - - template - auto get_awaiter(T&& value) noexcept -> decltype(operator co_await(static_cast(value))) - { - return operator co_await(static_cast(value)); - } - - template ::value, int> = 0> - auto get_awaiter(T&& value) noexcept - { - return member_await_adapter{ static_cast(value) }; - } - - template ::value, int> = 0> - auto get_awaiter(T&& value) noexcept - { - return free_await_adapter{ { static_cast(value) }}; - } - - template - struct notify_awaiter - { - decltype(get_awaiter(std::declval()))&& awaitable; - - bool await_ready() - { - if (winrt_suspend_handler) - { - winrt_suspend_handler(this); - } - - return awaitable.await_ready(); - } - - template - auto await_suspend(std::experimental::coroutine_handle handle) - { - return awaitable.await_suspend(handle); - } - - auto await_resume() - { - if (winrt_resume_handler) - { - winrt_resume_handler(this); - } - - return awaitable.await_resume(); - } - }; - template struct promise_base : implements { diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index b983333f5..f5db5f376 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -53,6 +53,150 @@ namespace winrt::impl } } } + + template + class has_awaitable_member + { + template ().await_ready())> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + + public: + + static constexpr bool value = get_value(0); + }; + + template + class has_awaitable_free + { + template ()))> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + + public: + + static constexpr bool value = get_value(0); + }; + + template + struct free_await_adapter_impl + { + T&& awaitable; + + bool ready() + { + return await_ready(awaitable); + } + + template + auto suspend(std::experimental::coroutine_handle handle) + { + return await_suspend(awaitable, handle); + } + + auto resume() + { + return await_resume(awaitable); + } + }; + + template + struct free_await_adapter + { + free_await_adapter_impl&& awaitable; + + bool await_ready() + { + return awaitable.ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return awaitable.suspend(handle); + } + + auto await_resume() + { + return awaitable.resume(); + } + }; + + template + struct member_await_adapter + { + T&& awaitable; + + bool await_ready() + { + return awaitable.await_ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return awaitable.await_suspend(handle); + } + + auto await_resume() + { + return awaitable.await_resume(); + } + }; + + template + auto get_awaiter(T&& value) noexcept -> decltype(static_cast(value).operator co_await()) + { + return static_cast(value).operator co_await(); + } + + template + auto get_awaiter(T&& value) noexcept -> decltype(operator co_await(static_cast(value))) + { + return operator co_await(static_cast(value)); + } + + template ::value, int> = 0> + auto get_awaiter(T&& value) noexcept + { + return member_await_adapter{ static_cast(value) }; + } + + template ::value, int> = 0> + auto get_awaiter(T&& value) noexcept + { + return free_await_adapter{ { static_cast(value) }}; + } + + template + struct notify_awaiter + { + decltype(get_awaiter(std::declval())) && awaitable; + + bool await_ready() + { + if (winrt_suspend_handler) + { + winrt_suspend_handler(this); + } + + return awaitable.await_ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return awaitable.await_suspend(handle); + } + + auto await_resume() + { + if (winrt_resume_handler) + { + winrt_resume_handler(this); + } + + return awaitable.await_resume(); + } + }; } WINRT_EXPORT namespace winrt @@ -378,6 +522,12 @@ namespace std::experimental { winrt::terminate(); } + + template + auto await_transform(Expression&& expression) noexcept + { + return winrt::impl::notify_awaiter{ winrt::impl::get_awaiter(static_cast(expression)) }; + } }; }; } From 936ff274e2b9fa98035a6cc61a345af4c1f17478 Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Tue, 15 Oct 2019 08:13:31 -0700 Subject: [PATCH 09/11] stabilize1 --- strings/base_coroutine_foundation.h | 144 ++++++++++++++++++++++++++ strings/base_coroutine_threadpool.h | 150 ---------------------------- 2 files changed, 144 insertions(+), 150 deletions(-) diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 22888d2bf..5456cf981 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -260,6 +260,150 @@ namespace winrt::impl Promise* m_promise; }; + template + class has_awaitable_member + { + template ().await_ready())> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + + public: + + static constexpr bool value = get_value(0); + }; + + template + class has_awaitable_free + { + template ()))> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + + public: + + static constexpr bool value = get_value(0); + }; + + template + struct free_await_adapter_impl + { + T&& awaitable; + + bool ready() + { + return await_ready(awaitable); + } + + template + auto suspend(std::experimental::coroutine_handle handle) + { + return await_suspend(awaitable, handle); + } + + auto resume() + { + return await_resume(awaitable); + } + }; + + template + struct free_await_adapter + { + free_await_adapter_impl&& awaitable; + + bool await_ready() + { + return awaitable.ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return awaitable.suspend(handle); + } + + auto await_resume() + { + return awaitable.resume(); + } + }; + + template + struct member_await_adapter + { + T&& awaitable; + + bool await_ready() + { + return awaitable.await_ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return awaitable.await_suspend(handle); + } + + auto await_resume() + { + return awaitable.await_resume(); + } + }; + + template + auto get_awaiter(T&& value) noexcept -> decltype(static_cast(value).operator co_await()) + { + return static_cast(value).operator co_await(); + } + + template + auto get_awaiter(T&& value) noexcept -> decltype(operator co_await(static_cast(value))) + { + return operator co_await(static_cast(value)); + } + + template ::value, int> = 0> + auto get_awaiter(T&& value) noexcept + { + return member_await_adapter{ static_cast(value) }; + } + + template ::value, int> = 0> + auto get_awaiter(T&& value) noexcept + { + return free_await_adapter{ { static_cast(value) }}; + } + + template + struct notify_awaiter + { + decltype(get_awaiter(std::declval()))&& awaitable; + + bool await_ready() + { + if (winrt_suspend_handler) + { + winrt_suspend_handler(this); + } + + return awaitable.await_ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return awaitable.await_suspend(handle); + } + + auto await_resume() + { + if (winrt_resume_handler) + { + winrt_resume_handler(this); + } + + return awaitable.await_resume(); + } + }; + template struct promise_base : implements { diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index f5db5f376..b983333f5 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -53,150 +53,6 @@ namespace winrt::impl } } } - - template - class has_awaitable_member - { - template ().await_ready())> static constexpr bool get_value(int) { return true; } - template static constexpr bool get_value(...) { return false; } - - public: - - static constexpr bool value = get_value(0); - }; - - template - class has_awaitable_free - { - template ()))> static constexpr bool get_value(int) { return true; } - template static constexpr bool get_value(...) { return false; } - - public: - - static constexpr bool value = get_value(0); - }; - - template - struct free_await_adapter_impl - { - T&& awaitable; - - bool ready() - { - return await_ready(awaitable); - } - - template - auto suspend(std::experimental::coroutine_handle handle) - { - return await_suspend(awaitable, handle); - } - - auto resume() - { - return await_resume(awaitable); - } - }; - - template - struct free_await_adapter - { - free_await_adapter_impl&& awaitable; - - bool await_ready() - { - return awaitable.ready(); - } - - template - auto await_suspend(std::experimental::coroutine_handle handle) - { - return awaitable.suspend(handle); - } - - auto await_resume() - { - return awaitable.resume(); - } - }; - - template - struct member_await_adapter - { - T&& awaitable; - - bool await_ready() - { - return awaitable.await_ready(); - } - - template - auto await_suspend(std::experimental::coroutine_handle handle) - { - return awaitable.await_suspend(handle); - } - - auto await_resume() - { - return awaitable.await_resume(); - } - }; - - template - auto get_awaiter(T&& value) noexcept -> decltype(static_cast(value).operator co_await()) - { - return static_cast(value).operator co_await(); - } - - template - auto get_awaiter(T&& value) noexcept -> decltype(operator co_await(static_cast(value))) - { - return operator co_await(static_cast(value)); - } - - template ::value, int> = 0> - auto get_awaiter(T&& value) noexcept - { - return member_await_adapter{ static_cast(value) }; - } - - template ::value, int> = 0> - auto get_awaiter(T&& value) noexcept - { - return free_await_adapter{ { static_cast(value) }}; - } - - template - struct notify_awaiter - { - decltype(get_awaiter(std::declval())) && awaitable; - - bool await_ready() - { - if (winrt_suspend_handler) - { - winrt_suspend_handler(this); - } - - return awaitable.await_ready(); - } - - template - auto await_suspend(std::experimental::coroutine_handle handle) - { - return awaitable.await_suspend(handle); - } - - auto await_resume() - { - if (winrt_resume_handler) - { - winrt_resume_handler(this); - } - - return awaitable.await_resume(); - } - }; } WINRT_EXPORT namespace winrt @@ -522,12 +378,6 @@ namespace std::experimental { winrt::terminate(); } - - template - auto await_transform(Expression&& expression) noexcept - { - return winrt::impl::notify_awaiter{ winrt::impl::get_awaiter(static_cast(expression)) }; - } }; }; } From e161f5945c6e2c0d00d85220318393501ee2f75b Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Tue, 15 Oct 2019 08:18:13 -0700 Subject: [PATCH 10/11] stable --- strings/base_coroutine_foundation.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 5456cf981..35afbdfd0 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -307,22 +307,22 @@ namespace winrt::impl template struct free_await_adapter { - free_await_adapter_impl&& awaitable; + T&& awaitable; bool await_ready() { - return awaitable.ready(); + return free_await_adapter_impl{ static_cast(awaitable) }.ready(); } template auto await_suspend(std::experimental::coroutine_handle handle) { - return awaitable.suspend(handle); + return free_await_adapter_impl{ static_cast(awaitable) }.suspend(handle); } auto await_resume() { - return awaitable.resume(); + return free_await_adapter_impl{ static_cast(awaitable) }.resume(); } }; @@ -369,13 +369,17 @@ namespace winrt::impl template ::value, int> = 0> auto get_awaiter(T&& value) noexcept { - return free_await_adapter{ { static_cast(value) }}; + return free_await_adapter{ static_cast(value) }; } template struct notify_awaiter { - decltype(get_awaiter(std::declval()))&& awaitable; + decltype(get_awaiter(std::declval())) awaitable; + + notify_awaiter(T&& awaitable) : awaitable(get_awaiter(static_cast(awaitable))) + { + } bool await_ready() { @@ -618,7 +622,7 @@ namespace winrt::impl throw winrt::hresult_canceled(); } - return notify_awaiter{ get_awaiter(static_cast(expression)) }; + return notify_awaiter{ static_cast(expression) }; } cancellation_token await_transform(get_cancellation_token_t) noexcept From 92e336f6ab200cf33e90c038de2c28052de746ea Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Tue, 15 Oct 2019 08:24:05 -0700 Subject: [PATCH 11/11] stable --- strings/base_coroutine_foundation.h | 148 -------------------------- strings/base_coroutine_threadpool.h | 154 ++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 148 deletions(-) diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 35afbdfd0..c95234e8e 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -260,154 +260,6 @@ namespace winrt::impl Promise* m_promise; }; - template - class has_awaitable_member - { - template ().await_ready())> static constexpr bool get_value(int) { return true; } - template static constexpr bool get_value(...) { return false; } - - public: - - static constexpr bool value = get_value(0); - }; - - template - class has_awaitable_free - { - template ()))> static constexpr bool get_value(int) { return true; } - template static constexpr bool get_value(...) { return false; } - - public: - - static constexpr bool value = get_value(0); - }; - - template - struct free_await_adapter_impl - { - T&& awaitable; - - bool ready() - { - return await_ready(awaitable); - } - - template - auto suspend(std::experimental::coroutine_handle handle) - { - return await_suspend(awaitable, handle); - } - - auto resume() - { - return await_resume(awaitable); - } - }; - - template - struct free_await_adapter - { - T&& awaitable; - - bool await_ready() - { - return free_await_adapter_impl{ static_cast(awaitable) }.ready(); - } - - template - auto await_suspend(std::experimental::coroutine_handle handle) - { - return free_await_adapter_impl{ static_cast(awaitable) }.suspend(handle); - } - - auto await_resume() - { - return free_await_adapter_impl{ static_cast(awaitable) }.resume(); - } - }; - - template - struct member_await_adapter - { - T&& awaitable; - - bool await_ready() - { - return awaitable.await_ready(); - } - - template - auto await_suspend(std::experimental::coroutine_handle handle) - { - return awaitable.await_suspend(handle); - } - - auto await_resume() - { - return awaitable.await_resume(); - } - }; - - template - auto get_awaiter(T&& value) noexcept -> decltype(static_cast(value).operator co_await()) - { - return static_cast(value).operator co_await(); - } - - template - auto get_awaiter(T&& value) noexcept -> decltype(operator co_await(static_cast(value))) - { - return operator co_await(static_cast(value)); - } - - template ::value, int> = 0> - auto get_awaiter(T&& value) noexcept - { - return member_await_adapter{ static_cast(value) }; - } - - template ::value, int> = 0> - auto get_awaiter(T&& value) noexcept - { - return free_await_adapter{ static_cast(value) }; - } - - template - struct notify_awaiter - { - decltype(get_awaiter(std::declval())) awaitable; - - notify_awaiter(T&& awaitable) : awaitable(get_awaiter(static_cast(awaitable))) - { - } - - bool await_ready() - { - if (winrt_suspend_handler) - { - winrt_suspend_handler(this); - } - - return awaitable.await_ready(); - } - - template - auto await_suspend(std::experimental::coroutine_handle handle) - { - return awaitable.await_suspend(handle); - } - - auto await_resume() - { - if (winrt_resume_handler) - { - winrt_resume_handler(this); - } - - return awaitable.await_resume(); - } - }; - template struct promise_base : implements { diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index b983333f5..9f9e75a3c 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -53,6 +53,154 @@ namespace winrt::impl } } } + + template + class has_awaitable_member + { + template ().await_ready())> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + + public: + + static constexpr bool value = get_value(0); + }; + + template + class has_awaitable_free + { + template ()))> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + + public: + + static constexpr bool value = get_value(0); + }; + + template + struct free_await_adapter_impl + { + T&& awaitable; + + bool ready() + { + return await_ready(awaitable); + } + + template + auto suspend(std::experimental::coroutine_handle handle) + { + return await_suspend(awaitable, handle); + } + + auto resume() + { + return await_resume(awaitable); + } + }; + + template + struct free_await_adapter + { + T&& awaitable; + + bool await_ready() + { + return free_await_adapter_impl{ static_cast(awaitable) }.ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return free_await_adapter_impl{ static_cast(awaitable) }.suspend(handle); + } + + auto await_resume() + { + return free_await_adapter_impl{ static_cast(awaitable) }.resume(); + } + }; + + template + struct member_await_adapter + { + T&& awaitable; + + bool await_ready() + { + return awaitable.await_ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return awaitable.await_suspend(handle); + } + + auto await_resume() + { + return awaitable.await_resume(); + } + }; + + template + auto get_awaiter(T&& value) noexcept -> decltype(static_cast(value).operator co_await()) + { + return static_cast(value).operator co_await(); + } + + template + auto get_awaiter(T&& value) noexcept -> decltype(operator co_await(static_cast(value))) + { + return operator co_await(static_cast(value)); + } + + template ::value, int> = 0> + auto get_awaiter(T&& value) noexcept + { + return member_await_adapter{ static_cast(value) }; + } + + template ::value, int> = 0> + auto get_awaiter(T&& value) noexcept + { + return free_await_adapter{ static_cast(value) }; + } + + template + struct notify_awaiter + { + decltype(get_awaiter(std::declval())) awaitable; + + notify_awaiter(T&& awaitable) : awaitable(get_awaiter(static_cast(awaitable))) + { + } + + bool await_ready() + { + if (winrt_suspend_handler) + { + winrt_suspend_handler(this); + } + + return awaitable.await_ready(); + } + + template + auto await_suspend(std::experimental::coroutine_handle handle) + { + return awaitable.await_suspend(handle); + } + + auto await_resume() + { + if (winrt_resume_handler) + { + winrt_resume_handler(this); + } + + return awaitable.await_resume(); + } + }; } WINRT_EXPORT namespace winrt @@ -378,6 +526,12 @@ namespace std::experimental { winrt::terminate(); } + + template + auto await_transform(Expression&& expression) + { + return winrt::impl::notify_awaiter{ static_cast(expression) }; + } }; }; }