From 6dc6c1813e723256bca7320d5c614dc62c6d319c Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Tue, 19 Sep 2023 00:10:21 +0200 Subject: [PATCH 1/7] Allow methods returning IIterable to be used as synchronous generators --- include/wil/cppwinrt_helpers.h | 195 +++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/include/wil/cppwinrt_helpers.h b/include/wil/cppwinrt_helpers.h index c46a73e0d..493f07d82 100644 --- a/include/wil/cppwinrt_helpers.h +++ b/include/wil/cppwinrt_helpers.h @@ -41,12 +41,16 @@ namespace wil::details namespace wil::details { template using coroutine_handle = std::experimental::coroutine_handle; + using suspend_always = std::experimental::suspend_always; + using suspend_never = std::experimental::suspend_never; } #elif defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L) #include namespace wil::details { template using coroutine_handle = std::coroutine_handle; + using suspend_always = std::suspend_always; + using suspend_never = std::suspend_never; } #endif /// @endcond @@ -312,6 +316,197 @@ namespace wil } } } + +#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) || (defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L)) +namespace wil::details +{ + template + struct iterable_promise : winrt::implements< + iterable_promise, + winrt::Windows::Foundation::Collections::IIterable, + winrt::Windows::Foundation::Collections::IIterator + > + { + private: + enum class IterationStatus + { + Initial, + Producing, + Value, + Done + }; + + public: + unsigned long __stdcall Release() noexcept + { + uint32_t const remaining = this->subtract_reference(); + + if (remaining == 0) + { + std::atomic_thread_fence(std::memory_order_acquire); + coroutine_handle::from_promise(*this).destroy(); + } + + return remaining; + } + + winrt::Windows::Foundation::Collections::IIterable get_return_object() noexcept + { + return { winrt::get_abi(static_cast const&>(*this)), winrt::take_ownership_from_abi }; + } + + suspend_always initial_suspend() const noexcept + { + return {}; + } + + suspend_always final_suspend() const noexcept + { + return {}; + } + + void unhandled_exception() const + { + throw; + } + + constexpr void await_transform() = delete; + + constexpr void return_void() noexcept + { + m_status = IterationStatus::Done; + } + + template + auto yield_value(U &&value) + { + struct YieldAwaiter + { + bool m_ready; + + constexpr bool await_ready() const noexcept + { + return m_ready; + } + + constexpr void await_suspend(coroutine_handle<>) const noexcept {} + constexpr void await_resume() const noexcept {} + }; + + *m_current = std::forward(value); + + if (m_current == m_values.end() - 1) + { + if (m_current != &m_last_value) + { + m_last_value = *m_current; + } + + m_status = IterationStatus::Value; + ++m_current; + return YieldAwaiter{ false }; + } + else + { + ++m_current; + return YieldAwaiter{ true }; + } + } + +#if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION) + void use_make_function_to_create_this_object() final + { + } +#endif + + uint32_t produce_values(winrt::array_view const& view) + { + if (m_status != IterationStatus::Initial && m_status != IterationStatus::Value) + { + return 0; + } + + m_values = view; + m_current = m_values.begin(); + m_status = IterationStatus::Producing; + + coroutine_handle::from_promise(*this).resume(); + + return static_cast(m_current - m_values.begin()); + } + + winrt::Windows::Foundation::Collections::IIterator First() + { + if (m_status != IterationStatus::Initial) + { + throw winrt::hresult_changed_state(); + } + + MoveNext(); + + return *this; + } + + bool HasCurrent() const noexcept + { + return m_status == IterationStatus::Value; + } + + TResult Current() const noexcept + { + return m_last_value; + } + + uint32_t GetMany(winrt::array_view values) + { + if (!HasCurrent() || values.empty()) + { + return 0; + } + + values.front() = Current(); + + uint32_t result; + + if (values.size() == 1) + { + result = 1; + } + else + { + result = produce_values({ values.data() + 1, values.size() - 1 }) + 1; + } + + MoveNext(); + return result; + } + + bool MoveNext() + { + return produce_values({ &m_last_value, 1 }); + } + + private: + IterationStatus m_status{ IterationStatus::Initial }; + winrt::array_view m_values; + TResult* m_current{ nullptr }; + TResult m_last_value{ empty() }; + }; +} + +#ifdef __cpp_lib_coroutine +namespace std +#else +namespace std::experimental +#endif +{ + template + struct coroutine_traits, Args...> + { + using promise_type = wil::details::iterable_promise; + }; +} +#endif #endif #if defined(WINRT_Windows_UI_H) && defined(_WINDOWS_UI_INTEROP_H_) && !defined(__WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS) From d4f4f48f181dd6b2b91b48a00d8a5b3b8e9d2768 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Tue, 19 Sep 2023 00:12:36 +0200 Subject: [PATCH 2/7] Add test cases --- tests/CppWinRTTests.cpp | 177 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/tests/CppWinRTTests.cpp b/tests/CppWinRTTests.cpp index 210ad8586..a163ba12c 100644 --- a/tests/CppWinRTTests.cpp +++ b/tests/CppWinRTTests.cpp @@ -647,6 +647,183 @@ TEST_CASE("CppWinRTTests::ResumeForegroundTests", "[cppwinrt]") co_await wil::resume_foreground(dispatcher, test::TestDispatcherPriority::Weird); }().get(); } + +namespace test +{ + winrt::Windows::Foundation::Collections::IIterable hello_world_generator() + { + co_yield L"Hello"; + co_yield L"World!"; + } + + class set_true_on_destruction + { + public: + set_true_on_destruction(bool& value) noexcept : m_value{ &value } + { + } + + set_true_on_destruction(set_true_on_destruction const&) = delete; + set_true_on_destruction& operator=(set_true_on_destruction const&) = delete; + + set_true_on_destruction(set_true_on_destruction&& other) noexcept : m_value{ std::exchange(other.m_value, nullptr) } + { + } + + set_true_on_destruction& operator=(set_true_on_destruction&& other) noexcept + { + m_value = std::exchange(other.m_value, nullptr); + return *this; + } + + ~set_true_on_destruction() + { + if (m_value) + { + *m_value = true; + } + } + + private: + bool* m_value{nullptr}; + }; +} + + +TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") +{ + SECTION("Hello World") + { + auto generator = test::hello_world_generator(); + auto iterator = generator.First(); + REQUIRE(iterator.HasCurrent()); + REQUIRE(iterator.Current() == L"Hello"); + + REQUIRE(iterator.MoveNext()); + REQUIRE(iterator.HasCurrent()); + REQUIRE(iterator.Current() == L"World!"); + + REQUIRE(!iterator.MoveNext()); + REQUIRE(!iterator.HasCurrent()); + } + + SECTION("Value types") + { + auto generator = []() -> winrt::Windows::Foundation::Collections::IIterable + { + for (int i = 0; i < 10; ++i) + { + co_yield i; + } + }(); + + auto iterator = generator.First(); + REQUIRE(iterator.HasCurrent()); + REQUIRE(iterator.MoveNext()); + REQUIRE(iterator.Current() == 1); + + for (int i = 2; i < 10; ++i) + { + REQUIRE(iterator.MoveNext()); + REQUIRE(iterator.Current() == i); + } + + REQUIRE(!iterator.MoveNext()); + REQUIRE(!iterator.HasCurrent()); + } + + SECTION("First can only be called once") + { + auto generator = test::hello_world_generator(); + auto iterator = generator.First(); + REQUIRE_THROWS_AS(generator.First(), winrt::hresult_changed_state); + } + + SECTION("GetMany") + { + { + auto iterator = test::hello_world_generator().First(); + + std::array values; + REQUIRE(iterator.GetMany(values) == 2); + REQUIRE(values[0] == L"Hello"); + REQUIRE(values[1] == L"World!"); + REQUIRE(iterator.GetMany(values) == 0); + } + + { + auto iterator = test::hello_world_generator().First(); + std::array values; + REQUIRE(iterator.GetMany(values) == 1); + REQUIRE(values[0] == L"Hello"); + REQUIRE(iterator.HasCurrent()); + REQUIRE(iterator.Current() == L"World!"); + + REQUIRE(iterator.GetMany(values) == 1); + REQUIRE(values[0] == L"World!"); + REQUIRE(iterator.GetMany(values) == 0); + } + } + + SECTION("Coroutine destruction") + { + auto set_true_on_destruction_generator = [](test::set_true_on_destruction) -> winrt::Windows::Foundation::Collections::IIterable + { + co_yield L"Hello"; + co_yield L"World!"; + }; + + bool destroyed = false; + { + auto _generator = set_true_on_destruction_generator(destroyed); + } + + REQUIRE(destroyed); + + destroyed = false; + { + winrt::Windows::Foundation::Collections::IIterator iterator; + { + auto generator = set_true_on_destruction_generator(destroyed); + iterator = generator.First(); + } + + REQUIRE(!destroyed); + REQUIRE(iterator.HasCurrent()); + REQUIRE(iterator.Current() == L"Hello"); + } + + REQUIRE(destroyed); + } + + SECTION("Coroutine destruction with exception") + { + auto set_true_on_destruction_generator = [](test::set_true_on_destruction) -> winrt::Windows::Foundation::Collections::IIterable + { + co_yield L"Hello"; + + throw winrt::hresult_invalid_argument(); + + co_yield L"World!"; + }; + + bool destroyed = false; + auto iterator = set_true_on_destruction_generator(destroyed).First(); + REQUIRE_THROWS_AS(iterator.MoveNext(), winrt::hresult_invalid_argument); + } + + SECTION("Range-based for loop") + { + std::wstring result; + for (const auto &i : test::hello_world_generator()) + { + result += i; + } + + REQUIRE(result == L"HelloWorld!"); + } +} + #endif // coroutines TEST_CASE("CppWinRTTests::ThrownExceptionWithMessage", "[cppwinrt]") From a2e9ae3086f4ad56f4fbe2d998403e91623acdca Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Wed, 20 Sep 2023 19:08:21 +0200 Subject: [PATCH 3/7] Constrain the generator implementation to `IIterator` and add `wil::make_iterable_from_iterator` to create an `IIterable` helper object C++ coroutines can only be evaluated once, which doesn't fulfill `IIterable`'s requirement that it can return multiple independent iterators. Thus the generator implementation is constrained to `IIterator`, which may only be evaluated once, and a helper method is added that returns an `IIterable` which creates a new generator instance every time an iterator is requested. --- include/wil/cppwinrt_helpers.h | 80 ++++++++++++++++++++++------------ tests/CppWinRTTests.cpp | 72 ++++++++++++++++-------------- 2 files changed, 92 insertions(+), 60 deletions(-) diff --git a/include/wil/cppwinrt_helpers.h b/include/wil/cppwinrt_helpers.h index 493f07d82..be9ce584f 100644 --- a/include/wil/cppwinrt_helpers.h +++ b/include/wil/cppwinrt_helpers.h @@ -321,16 +321,14 @@ namespace wil namespace wil::details { template - struct iterable_promise : winrt::implements< - iterable_promise, - winrt::Windows::Foundation::Collections::IIterable, + struct iterator_promise : winrt::implements< + iterator_promise, winrt::Windows::Foundation::Collections::IIterator > { private: enum class IterationStatus { - Initial, Producing, Value, Done @@ -344,18 +342,18 @@ namespace wil::details if (remaining == 0) { std::atomic_thread_fence(std::memory_order_acquire); - coroutine_handle::from_promise(*this).destroy(); + coroutine_handle::from_promise(*this).destroy(); } return remaining; } - winrt::Windows::Foundation::Collections::IIterable get_return_object() noexcept + winrt::Windows::Foundation::Collections::IIterator get_return_object() noexcept { - return { winrt::get_abi(static_cast const&>(*this)), winrt::take_ownership_from_abi }; + return { winrt::get_abi(static_cast const&>(*this)), winrt::take_ownership_from_abi }; } - suspend_always initial_suspend() const noexcept + suspend_never initial_suspend() const noexcept { return {}; } @@ -421,7 +419,7 @@ namespace wil::details uint32_t produce_values(winrt::array_view const& view) { - if (m_status != IterationStatus::Initial && m_status != IterationStatus::Value) + if (m_status != IterationStatus::Value) { return 0; } @@ -430,23 +428,11 @@ namespace wil::details m_current = m_values.begin(); m_status = IterationStatus::Producing; - coroutine_handle::from_promise(*this).resume(); + coroutine_handle::from_promise(*this).resume(); return static_cast(m_current - m_values.begin()); } - winrt::Windows::Foundation::Collections::IIterator First() - { - if (m_status != IterationStatus::Initial) - { - throw winrt::hresult_changed_state(); - } - - MoveNext(); - - return *this; - } - bool HasCurrent() const noexcept { return m_status == IterationStatus::Value; @@ -487,11 +473,51 @@ namespace wil::details } private: - IterationStatus m_status{ IterationStatus::Initial }; - winrt::array_view m_values; - TResult* m_current{ nullptr }; + IterationStatus m_status{ IterationStatus::Producing }; + winrt::array_view m_values{ &m_last_value, 1 }; + TResult* m_current{ &m_last_value }; TResult m_last_value{ empty() }; }; + + template + struct iterable_iterator_helper : winrt::implements< + iterable_iterator_helper, + winrt::Windows::Foundation::Collections::IIterable + > + { + iterable_iterator_helper(Func&& func, Args&&... args) : + m_func{ std::forward(func) }, + m_args{ std::forward(args)... } + { + } + + auto First() + { + return std::apply(m_func, m_args); + } + + private: + Func m_func; + std::tuple m_args; + }; + + template + struct iterator_result; + + template + struct iterator_result> + { + using type = TResult; + }; +} + +namespace wil +{ + template>::type> + winrt::Windows::Foundation::Collections::IIterable make_iterable_from_iterator(Func&& func, Args&&... args) + { + return winrt::make>(std::forward(func), std::forward(args)...); + } } #ifdef __cpp_lib_coroutine @@ -501,9 +527,9 @@ namespace std::experimental #endif { template - struct coroutine_traits, Args...> + struct coroutine_traits, Args...> { - using promise_type = wil::details::iterable_promise; + using promise_type = wil::details::iterator_promise; }; } #endif diff --git a/tests/CppWinRTTests.cpp b/tests/CppWinRTTests.cpp index a163ba12c..94debd14c 100644 --- a/tests/CppWinRTTests.cpp +++ b/tests/CppWinRTTests.cpp @@ -650,7 +650,7 @@ TEST_CASE("CppWinRTTests::ResumeForegroundTests", "[cppwinrt]") namespace test { - winrt::Windows::Foundation::Collections::IIterable hello_world_generator() + winrt::Windows::Foundation::Collections::IIterator hello_world_generator() { co_yield L"Hello"; co_yield L"World!"; @@ -694,8 +694,7 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") { SECTION("Hello World") { - auto generator = test::hello_world_generator(); - auto iterator = generator.First(); + auto iterator = test::hello_world_generator(); REQUIRE(iterator.HasCurrent()); REQUIRE(iterator.Current() == L"Hello"); @@ -709,7 +708,7 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") SECTION("Value types") { - auto generator = []() -> winrt::Windows::Foundation::Collections::IIterable + auto iterator = []() -> winrt::Windows::Foundation::Collections::IIterator { for (int i = 0; i < 10; ++i) { @@ -717,7 +716,6 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") } }(); - auto iterator = generator.First(); REQUIRE(iterator.HasCurrent()); REQUIRE(iterator.MoveNext()); REQUIRE(iterator.Current() == 1); @@ -732,17 +730,10 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") REQUIRE(!iterator.HasCurrent()); } - SECTION("First can only be called once") - { - auto generator = test::hello_world_generator(); - auto iterator = generator.First(); - REQUIRE_THROWS_AS(generator.First(), winrt::hresult_changed_state); - } - SECTION("GetMany") { { - auto iterator = test::hello_world_generator().First(); + auto iterator = test::hello_world_generator(); std::array values; REQUIRE(iterator.GetMany(values) == 2); @@ -752,7 +743,7 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") } { - auto iterator = test::hello_world_generator().First(); + auto iterator = test::hello_world_generator(); std::array values; REQUIRE(iterator.GetMany(values) == 1); REQUIRE(values[0] == L"Hello"); @@ -767,7 +758,7 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") SECTION("Coroutine destruction") { - auto set_true_on_destruction_generator = [](test::set_true_on_destruction) -> winrt::Windows::Foundation::Collections::IIterable + auto set_true_on_destruction_generator = [](test::set_true_on_destruction) -> winrt::Windows::Foundation::Collections::IIterator { co_yield L"Hello"; co_yield L"World!"; @@ -779,26 +770,11 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") } REQUIRE(destroyed); - - destroyed = false; - { - winrt::Windows::Foundation::Collections::IIterator iterator; - { - auto generator = set_true_on_destruction_generator(destroyed); - iterator = generator.First(); - } - - REQUIRE(!destroyed); - REQUIRE(iterator.HasCurrent()); - REQUIRE(iterator.Current() == L"Hello"); - } - - REQUIRE(destroyed); } SECTION("Coroutine destruction with exception") { - auto set_true_on_destruction_generator = [](test::set_true_on_destruction) -> winrt::Windows::Foundation::Collections::IIterable + auto set_true_on_destruction_generator = [](test::set_true_on_destruction) -> winrt::Windows::Foundation::Collections::IIterator { co_yield L"Hello"; @@ -808,14 +784,44 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") }; bool destroyed = false; - auto iterator = set_true_on_destruction_generator(destroyed).First(); + auto iterator = set_true_on_destruction_generator(destroyed); REQUIRE_THROWS_AS(iterator.MoveNext(), winrt::hresult_invalid_argument); } + SECTION("make_iterable_from_iterator") + { + auto generator = wil::make_iterable_from_iterator(&test::hello_world_generator); + auto iterator = generator.First(); + + REQUIRE(iterator.Current() == L"Hello"); + REQUIRE(iterator.MoveNext()); + REQUIRE(iterator.Current() == L"World!"); + REQUIRE(!iterator.MoveNext()); + + auto iterator2 = generator.First(); + REQUIRE(iterator2.Current() == L"Hello"); + REQUIRE(iterator2.MoveNext()); + REQUIRE(iterator2.Current() == L"World!"); + REQUIRE(!iterator2.MoveNext()); + } + + SECTION("make_iterable_from_iterator with arguments") + { + auto ptr = std::make_unique(3); + auto const_ref_generator = wil::make_iterable_from_iterator([](const std::unique_ptr &ptr) -> winrt::Windows::Foundation::Collections::IIterator + { + co_yield *ptr; + }, ptr); + + REQUIRE(const_ref_generator.First().Current() == 3); + *ptr = 4; + REQUIRE(const_ref_generator.First().Current() == 4); + } + SECTION("Range-based for loop") { std::wstring result; - for (const auto &i : test::hello_world_generator()) + for (const auto &i : wil::make_iterable_from_iterator(&test::hello_world_generator)) { result += i; } From fc62916b48110cfff2829297b1367741905eeb33 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Wed, 20 Sep 2023 19:17:28 +0200 Subject: [PATCH 4/7] Throw winrt::hresult_out_of_bounds when the iterator is at the end --- include/wil/cppwinrt_helpers.h | 6 +++++- tests/CppWinRTTests.cpp | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/wil/cppwinrt_helpers.h b/include/wil/cppwinrt_helpers.h index be9ce584f..61ed4eea0 100644 --- a/include/wil/cppwinrt_helpers.h +++ b/include/wil/cppwinrt_helpers.h @@ -419,10 +419,14 @@ namespace wil::details uint32_t produce_values(winrt::array_view const& view) { - if (m_status != IterationStatus::Value) + if (m_status == IterationStatus::Producing) { return 0; } + else if (m_status == IterationStatus::Done) + { + throw winrt::hresult_out_of_bounds(); + } m_values = view; m_current = m_values.begin(); diff --git a/tests/CppWinRTTests.cpp b/tests/CppWinRTTests.cpp index 94debd14c..dd25c2073 100644 --- a/tests/CppWinRTTests.cpp +++ b/tests/CppWinRTTests.cpp @@ -756,6 +756,16 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") } } + SECTION("MoveNext") + { + auto iterator = test::hello_world_generator(); + REQUIRE(iterator.HasCurrent()); + REQUIRE(iterator.MoveNext()); + REQUIRE(iterator.HasCurrent()); + REQUIRE(!iterator.MoveNext()); + REQUIRE_THROWS_AS(iterator.MoveNext(), winrt::hresult_out_of_bounds); + } + SECTION("Coroutine destruction") { auto set_true_on_destruction_generator = [](test::set_true_on_destruction) -> winrt::Windows::Foundation::Collections::IIterator From adbe1bd67c5495b31ff3717c28785986b809e91f Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Wed, 20 Sep 2023 19:18:27 +0200 Subject: [PATCH 5/7] Add missing @cond / @endcond for wil::details --- include/wil/cppwinrt_helpers.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/wil/cppwinrt_helpers.h b/include/wil/cppwinrt_helpers.h index 61ed4eea0..b77caf339 100644 --- a/include/wil/cppwinrt_helpers.h +++ b/include/wil/cppwinrt_helpers.h @@ -318,6 +318,7 @@ namespace wil } #if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) || (defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L)) +/// @cond namespace wil::details { template @@ -514,6 +515,7 @@ namespace wil::details using type = TResult; }; } +/// @endcond namespace wil { From f58cdcbd0226274ab5114f0459e622cf2f3bf8a4 Mon Sep 17 00:00:00 2001 From: Fulgen301 Date: Thu, 2 Nov 2023 12:35:58 +0100 Subject: [PATCH 6/7] Rename make_iterable_from_iterator to make_iterable_from_generator Co-authored-by: Duncan Horn <40036384+dunhor@users.noreply.github.com> --- include/wil/cppwinrt_helpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wil/cppwinrt_helpers.h b/include/wil/cppwinrt_helpers.h index b77caf339..f4d5c4e35 100644 --- a/include/wil/cppwinrt_helpers.h +++ b/include/wil/cppwinrt_helpers.h @@ -520,7 +520,7 @@ namespace wil::details namespace wil { template>::type> - winrt::Windows::Foundation::Collections::IIterable make_iterable_from_iterator(Func&& func, Args&&... args) + winrt::Windows::Foundation::Collections::IIterable make_iterable_from_generator(Func&& func, Args&&... args) { return winrt::make>(std::forward(func), std::forward(args)...); } From 7d038a67e859b8d1bb8b05e4c28634f41e7886c3 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Thu, 2 Nov 2023 19:25:30 +0100 Subject: [PATCH 7/7] Rename make_iterable_from_iterator to make_iterable_from_generator in the test cases --- tests/CppWinRTTests.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/CppWinRTTests.cpp b/tests/CppWinRTTests.cpp index dd25c2073..800753614 100644 --- a/tests/CppWinRTTests.cpp +++ b/tests/CppWinRTTests.cpp @@ -798,9 +798,9 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") REQUIRE_THROWS_AS(iterator.MoveNext(), winrt::hresult_invalid_argument); } - SECTION("make_iterable_from_iterator") + SECTION("make_iterable_from_generator") { - auto generator = wil::make_iterable_from_iterator(&test::hello_world_generator); + auto generator = wil::make_iterable_from_generator(&test::hello_world_generator); auto iterator = generator.First(); REQUIRE(iterator.Current() == L"Hello"); @@ -815,10 +815,10 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") REQUIRE(!iterator2.MoveNext()); } - SECTION("make_iterable_from_iterator with arguments") + SECTION("make_iterable_from_generator with arguments") { auto ptr = std::make_unique(3); - auto const_ref_generator = wil::make_iterable_from_iterator([](const std::unique_ptr &ptr) -> winrt::Windows::Foundation::Collections::IIterator + auto const_ref_generator = wil::make_iterable_from_generator([](const std::unique_ptr &ptr) -> winrt::Windows::Foundation::Collections::IIterator { co_yield *ptr; }, ptr); @@ -831,7 +831,7 @@ TEST_CASE("CppWinRTTests::Generator", "[cppwinrt]") SECTION("Range-based for loop") { std::wstring result; - for (const auto &i : wil::make_iterable_from_iterator(&test::hello_world_generator)) + for (const auto &i : wil::make_iterable_from_generator(&test::hello_world_generator)) { result += i; }