From dcb3f60464a031e7548ad4eaa910f3ab62fcb1fc Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Sun, 7 Mar 2021 01:37:54 -0500 Subject: [PATCH 01/13] Base ranges support --- strings/base_collections.h | 11 +++++++++++ test/test/fast_iterator.cpp | 2 ++ 2 files changed, 13 insertions(+) diff --git a/strings/base_collections.h b/strings/base_collections.h index afb70494b..1f810a482 100644 --- a/strings/base_collections.h +++ b/strings/base_collections.h @@ -6,6 +6,7 @@ namespace winrt::impl template struct fast_iterator { + using iterator_concept = std::random_access_iterator_tag; using iterator_category = std::input_iterator_tag; using value_type = decltype(std::declval().GetAt(0)); using difference_type = ptrdiff_t; @@ -113,6 +114,16 @@ namespace winrt::impl return !(*this < other); } + friend fast_iterator operator+(difference_type n, fast_iterator it) noexcept + { + return it + n; + } + + friend fast_iterator operator-(difference_type n, fast_iterator it) noexcept + { + return it - n; + } + private: T const* m_collection{}; diff --git a/test/test/fast_iterator.cpp b/test/test/fast_iterator.cpp index 169b427c1..26f7d73e9 100644 --- a/test/test/fast_iterator.cpp +++ b/test/test/fast_iterator.cpp @@ -44,6 +44,8 @@ TEST_CASE("fast_iterator") REQUIRE(value == 9); REQUIRE(vbegin[2] == 4); REQUIRE(vbegin + 2 > vbegin); + REQUIRE(2 + vbegin > vbegin); + REQUIRE(2 - (vbegin + 4) > vbegin); REQUIRE(vbegin < vbegin + 2); REQUIRE(vbegin + 2 - 2 == vbegin); REQUIRE(end(v) - begin(v) == v.Size()); From 24503c7ded2c093d98bea9cc717a14800bb05df7 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Sun, 7 Mar 2021 11:10:26 -0500 Subject: [PATCH 02/13] Remove pointer typedef since operator-> isn't defined --- cppwinrt/code_writers.h | 4 ++-- strings/base_collections.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 422be0541..0c2f789d2 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -1426,11 +1426,11 @@ namespace cppwinrt if (type_name == "Windows.Foundation.Collections.IIterator`1") { w.write(R"( + using iterator_concept = std::input_iterator_tag; using iterator_category = std::input_iterator_tag; using value_type = T; using difference_type = ptrdiff_t; - using pointer = T*; - using reference = T&; + using reference = T; )"); } else if (type_name == "Windows.Foundation.IReference`1") diff --git a/strings/base_collections.h b/strings/base_collections.h index 1f810a482..44b236ce9 100644 --- a/strings/base_collections.h +++ b/strings/base_collections.h @@ -10,7 +10,6 @@ namespace winrt::impl using iterator_category = std::input_iterator_tag; using value_type = decltype(std::declval().GetAt(0)); using difference_type = ptrdiff_t; - using pointer = value_type*; using reference = value_type; fast_iterator() noexcept : m_collection(nullptr), m_index(0) {} From 5a8ed0775ad70b20b5a0607d203c5570c48927ba Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Sun, 7 Mar 2021 19:19:22 -0500 Subject: [PATCH 03/13] Enable full C++ ranges for collections using fast_iterator --- cppwinrt/code_writers.h | 24 ++++ cppwinrt/cppwinrt.vcxproj | 1 + cppwinrt/cppwinrt.vcxproj.filters | 3 + cppwinrt/file_writers.h | 1 + strings/base_collections.h | 181 +---------------------------- strings/base_iterator.h | 183 ++++++++++++++++++++++++++++++ strings/base_xaml_typename.h | 11 ++ 7 files changed, 229 insertions(+), 175 deletions(-) create mode 100644 strings/base_iterator.h diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 0c2f789d2..877e33a49 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -1415,6 +1415,20 @@ namespace cppwinrt { w.write(R"( auto get() const; auto wait_for(Windows::Foundation::TimeSpan const& timeout) const; +)"); + } + else if (type_name == "Windows.Foundation.Collections.IIterable`1") + { + w.write(R"( + auto begin() const; + auto end() const; +)"); + } + else if (type_name == "Windows.UI.Xaml.Interop.IBindableIterable") + { + w.write(R"( + auto begin() const; + auto end() const; )"); } } @@ -1431,6 +1445,16 @@ namespace cppwinrt using value_type = T; using difference_type = ptrdiff_t; using reference = T; +)"); + } + else if (type_name == "Windows.UI.Xaml.Interop.IBindableIterator") + { + w.write(R"( + using iterator_concept = std::input_iterator_tag; + using iterator_category = std::input_iterator_tag; + using value_type = IInspectable; + using difference_type = ptrdiff_t; + using reference = IInspectable; )"); } else if (type_name == "Windows.Foundation.IReference`1") diff --git a/cppwinrt/cppwinrt.vcxproj b/cppwinrt/cppwinrt.vcxproj index d63b2ce54..665b4f806 100644 --- a/cppwinrt/cppwinrt.vcxproj +++ b/cppwinrt/cppwinrt.vcxproj @@ -68,6 +68,7 @@ + diff --git a/cppwinrt/cppwinrt.vcxproj.filters b/cppwinrt/cppwinrt.vcxproj.filters index 21fabf0f2..e55fcffda 100644 --- a/cppwinrt/cppwinrt.vcxproj.filters +++ b/cppwinrt/cppwinrt.vcxproj.filters @@ -163,6 +163,9 @@ strings + + strings + diff --git a/cppwinrt/file_writers.h b/cppwinrt/file_writers.h index c210b6f47..c91b1de91 100644 --- a/cppwinrt/file_writers.h +++ b/cppwinrt/file_writers.h @@ -38,6 +38,7 @@ namespace cppwinrt w.write(strings::base_chrono); w.write(strings::base_security); w.write(strings::base_std_hash); + w.write(strings::base_iterator); w.write(strings::base_coroutine_threadpool); w.write(strings::base_natvis); w.write(strings::base_version); diff --git a/strings/base_collections.h b/strings/base_collections.h index 44b236ce9..102b853f7 100644 --- a/strings/base_collections.h +++ b/strings/base_collections.h @@ -3,184 +3,15 @@ namespace winrt::impl { namespace wfc = Windows::Foundation::Collections; - template - struct fast_iterator + template + auto consume_Windows_Foundation_Collections_IIterable::begin() const { - using iterator_concept = std::random_access_iterator_tag; - using iterator_category = std::input_iterator_tag; - using value_type = decltype(std::declval().GetAt(0)); - using difference_type = ptrdiff_t; - using reference = value_type; - - fast_iterator() noexcept : m_collection(nullptr), m_index(0) {} - - fast_iterator(T const& collection, uint32_t const index) noexcept : - m_collection(&collection), - m_index(index) - {} - - fast_iterator& operator++() noexcept - { - ++m_index; - return*this; - } - - fast_iterator operator++(int) noexcept - { - auto previous = *this; - ++m_index; - return previous; - } - - fast_iterator& operator--() noexcept - { - --m_index; - return*this; - } - - fast_iterator operator--(int) noexcept - { - auto previous = *this; - --m_index; - return previous; - } - - fast_iterator& operator+=(difference_type n) noexcept - { - m_index += static_cast(n); - return*this; - } - - fast_iterator operator+(difference_type n) const noexcept - { - return fast_iterator(*this) += n; - } - - fast_iterator& operator-=(difference_type n) noexcept - { - return *this += -n; - } - - fast_iterator operator-(difference_type n) const noexcept - { - return *this + -n; - } - - difference_type operator-(fast_iterator const& other) const noexcept - { - return static_cast(m_index) - static_cast(other.m_index); - } - - reference operator*() const - { - return m_collection->GetAt(m_index); - } - - reference operator[](difference_type n) const - { - return m_collection->GetAt(m_index + static_cast(n)); - } - - bool operator==(fast_iterator const& other) const noexcept - { - WINRT_ASSERT(m_collection == other.m_collection); - return m_index == other.m_index; - } - - bool operator<(fast_iterator const& other) const noexcept - { - WINRT_ASSERT(m_collection == other.m_collection); - return m_index < other.m_index; - } - - bool operator!=(fast_iterator const& other) const noexcept - { - return !(*this == other); - } - - bool operator>(fast_iterator const& other) const noexcept - { - return !(*this < other); - } - - bool operator<=(fast_iterator const& other) const noexcept - { - return !(*this > other); - } - - bool operator>=(fast_iterator const& other) const noexcept - { - return !(*this < other); - } - - friend fast_iterator operator+(difference_type n, fast_iterator it) noexcept - { - return it + n; - } - - friend fast_iterator operator-(difference_type n, fast_iterator it) noexcept - { - return it - n; - } - - private: - - T const* m_collection{}; - uint32_t m_index{}; - }; - - template - class has_GetAt - { - template ().GetAt(0))> 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 ::value, int> = 0> - auto begin(T const& collection) -> decltype(collection.First()) - { - auto result = collection.First(); - - if (!result.HasCurrent()) - { - return {}; - } - - return result; - } - - template ::value, int> = 0> - auto end([[maybe_unused]] T const& collection) noexcept -> decltype(collection.First()) - { - return {}; - } - - template ::value, int> = 0> - fast_iterator begin(T const& collection) noexcept - { - return { collection, 0 }; + return impl::begin(static_cast(*this)); } - - template ::value, int> = 0> - fast_iterator end(T const& collection) - { - return { collection, collection.Size() }; - } - - template ::value, int> = 0> - auto rbegin(T const& collection) - { - return std::make_reverse_iterator(end(collection)); - } - - template ::value, int> = 0> - auto rend(T const& collection) + template + auto consume_Windows_Foundation_Collections_IIterable::end() const { - return std::make_reverse_iterator(begin(collection)); + return impl::end(static_cast(*this)); } template diff --git a/strings/base_iterator.h b/strings/base_iterator.h new file mode 100644 index 000000000..380cfccd3 --- /dev/null +++ b/strings/base_iterator.h @@ -0,0 +1,183 @@ + +namespace winrt::impl +{ + template + struct fast_iterator + { + using iterator_concept = std::random_access_iterator_tag; + using iterator_category = std::input_iterator_tag; + using value_type = decltype(std::declval().GetAt(0)); + using difference_type = ptrdiff_t; + using reference = value_type; + + fast_iterator() noexcept : m_collection(nullptr), m_index(0) {} + + fast_iterator(T const& collection, uint32_t const index) noexcept : + m_collection(&collection), + m_index(index) + {} + + fast_iterator& operator++() noexcept + { + ++m_index; + return*this; + } + + fast_iterator operator++(int) noexcept + { + auto previous = *this; + ++m_index; + return previous; + } + + fast_iterator& operator--() noexcept + { + --m_index; + return*this; + } + + fast_iterator operator--(int) noexcept + { + auto previous = *this; + --m_index; + return previous; + } + + fast_iterator& operator+=(difference_type n) noexcept + { + m_index += static_cast(n); + return*this; + } + + fast_iterator operator+(difference_type n) const noexcept + { + return fast_iterator(*this) += n; + } + + fast_iterator& operator-=(difference_type n) noexcept + { + return *this += -n; + } + + fast_iterator operator-(difference_type n) const noexcept + { + return *this + -n; + } + + difference_type operator-(fast_iterator const& other) const noexcept + { + return static_cast(m_index) - static_cast(other.m_index); + } + + reference operator*() const + { + return m_collection->GetAt(m_index); + } + + reference operator[](difference_type n) const + { + return m_collection->GetAt(m_index + static_cast(n)); + } + + bool operator==(fast_iterator const& other) const noexcept + { + WINRT_ASSERT(m_collection == other.m_collection); + return m_index == other.m_index; + } + + bool operator<(fast_iterator const& other) const noexcept + { + WINRT_ASSERT(m_collection == other.m_collection); + return m_index < other.m_index; + } + + bool operator!=(fast_iterator const& other) const noexcept + { + return !(*this == other); + } + + bool operator>(fast_iterator const& other) const noexcept + { + return !(*this < other); + } + + bool operator<=(fast_iterator const& other) const noexcept + { + return !(*this > other); + } + + bool operator>=(fast_iterator const& other) const noexcept + { + return !(*this < other); + } + + friend fast_iterator operator+(difference_type n, fast_iterator it) noexcept + { + return it + n; + } + + friend fast_iterator operator-(difference_type n, fast_iterator it) noexcept + { + return it - n; + } + + private: + + T const* m_collection{}; + uint32_t m_index{}; + }; + + template + class has_GetAt + { + template ().GetAt(0))> 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 ::value, int> = 0> + auto begin(T const& collection) -> decltype(collection.First()) + { + auto result = collection.First(); + + if (!result.HasCurrent()) + { + return {}; + } + + return result; + } + + template ::value, int> = 0> + auto end([[maybe_unused]] T const& collection) noexcept -> decltype(collection.First()) + { + return {}; + } + + template ::value, int> = 0> + fast_iterator begin(T const& collection) noexcept + { + return { collection, 0 }; + } + + template ::value, int> = 0> + fast_iterator end(T const& collection) + { + return { collection, collection.Size() }; + } + + template ::value, int> = 0> + auto rbegin(T const& collection) + { + return std::make_reverse_iterator(end(collection)); + } + + template ::value, int> = 0> + auto rend(T const& collection) + { + return std::make_reverse_iterator(begin(collection)); + } +} diff --git a/strings/base_xaml_typename.h b/strings/base_xaml_typename.h index 4912649a2..9b7c23a50 100644 --- a/strings/base_xaml_typename.h +++ b/strings/base_xaml_typename.h @@ -125,6 +125,17 @@ namespace winrt::impl { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; + + template + auto consume_Windows_UI_Xaml_Interop_IBindableIterable::begin() const + { + return impl::begin(static_cast(*this)); + } + template + auto consume_Windows_UI_Xaml_Interop_IBindableIterable::end() const + { + return impl::end(static_cast(*this)); + } } WINRT_EXPORT namespace winrt From 03b7858fcf81a9e43aca9435fbd01e3fbf5a745b Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Sun, 7 Mar 2021 19:23:18 -0500 Subject: [PATCH 04/13] Fix namespace --- cppwinrt/code_writers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 877e33a49..e31f6575a 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -1452,9 +1452,9 @@ namespace cppwinrt w.write(R"( using iterator_concept = std::input_iterator_tag; using iterator_category = std::input_iterator_tag; - using value_type = IInspectable; + using value_type = Windows::Foundation::IInspectable; using difference_type = ptrdiff_t; - using reference = IInspectable; + using reference = Windows::Foundation::IInspectable; )"); } else if (type_name == "Windows.Foundation.IReference`1") From 53ae49e9d0f692dc71095b8d7152d31aa1163afa Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Sun, 7 Mar 2021 19:25:32 -0500 Subject: [PATCH 05/13] Code style fixes --- strings/base_iterator.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/strings/base_iterator.h b/strings/base_iterator.h index 380cfccd3..352178abf 100644 --- a/strings/base_iterator.h +++ b/strings/base_iterator.h @@ -13,14 +13,14 @@ namespace winrt::impl fast_iterator() noexcept : m_collection(nullptr), m_index(0) {} fast_iterator(T const& collection, uint32_t const index) noexcept : - m_collection(&collection), + m_collection(&collection), m_index(index) {} fast_iterator& operator++() noexcept { ++m_index; - return*this; + return *this; } fast_iterator operator++(int) noexcept @@ -33,7 +33,7 @@ namespace winrt::impl fast_iterator& operator--() noexcept { --m_index; - return*this; + return *this; } fast_iterator operator--(int) noexcept @@ -46,7 +46,7 @@ namespace winrt::impl fast_iterator& operator+=(difference_type n) noexcept { m_index += static_cast(n); - return*this; + return *this; } fast_iterator operator+(difference_type n) const noexcept From 94d267b3dc5f87bd1a1ec95f55f2de482b690540 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Mon, 8 Mar 2021 17:57:24 -0500 Subject: [PATCH 06/13] Enable ranges support for every IIterable --- cppwinrt/code_writers.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index e31f6575a..327136c43 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -1283,13 +1283,18 @@ namespace cppwinrt static_cast(*this) = nullptr; } - return *this; + return static_cast(*this); } auto operator*() const { return Current(); } + + void operator++(int) + { + ++(*this); + } )"); } else if (type_name == "Windows.Storage.Streams.IBuffer") @@ -1313,13 +1318,18 @@ namespace cppwinrt static_cast(*this) = nullptr; } - return *this; + return static_cast(*this); } T operator*() const { return Current(); } + + void operator++(int) + { + ++(*this); + } )"); } else if (type_name == "Windows.Foundation.Collections.IKeyValuePair`2") From 0570d55929c39a76e3160081388a38955e0e039d Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Mon, 8 Mar 2021 18:13:09 -0500 Subject: [PATCH 07/13] Address review comments --- strings/base_iterator.h | 16 +++++++++------- test/test/fast_iterator.cpp | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/strings/base_iterator.h b/strings/base_iterator.h index 352178abf..6c203e8ee 100644 --- a/strings/base_iterator.h +++ b/strings/base_iterator.h @@ -10,7 +10,7 @@ namespace winrt::impl using difference_type = ptrdiff_t; using reference = value_type; - fast_iterator() noexcept : m_collection(nullptr), m_index(0) {} + fast_iterator() noexcept = default; fast_iterator(T const& collection, uint32_t const index) noexcept : m_collection(&collection), @@ -66,6 +66,7 @@ namespace winrt::impl difference_type operator-(fast_iterator const& other) const noexcept { + WINRT_ASSERT(m_collection == other.m_collection); return static_cast(m_index) - static_cast(other.m_index); } @@ -91,14 +92,15 @@ namespace winrt::impl return m_index < other.m_index; } - bool operator!=(fast_iterator const& other) const noexcept + bool operator>(fast_iterator const& other) const noexcept { - return !(*this == other); + WINRT_ASSERT(m_collection == other.m_collection); + return m_index > other.m_index; } - bool operator>(fast_iterator const& other) const noexcept + bool operator!=(fast_iterator const& other) const noexcept { - return !(*this < other); + return !(*this == other); } bool operator<=(fast_iterator const& other) const noexcept @@ -123,8 +125,8 @@ namespace winrt::impl private: - T const* m_collection{}; - uint32_t m_index{}; + T const* m_collection = nullptr; + uint32_t m_index = 0; }; template diff --git a/test/test/fast_iterator.cpp b/test/test/fast_iterator.cpp index 26f7d73e9..c7573903b 100644 --- a/test/test/fast_iterator.cpp +++ b/test/test/fast_iterator.cpp @@ -49,5 +49,6 @@ TEST_CASE("fast_iterator") REQUIRE(vbegin < vbegin + 2); REQUIRE(vbegin + 2 - 2 == vbegin); REQUIRE(end(v) - begin(v) == v.Size()); + REQUIRE((begin(v) + 3)[-1] == 4); } } From 8c70a1d0a4dd7355e82235fc8952c051056bc589 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Mon, 22 Mar 2021 20:40:20 -0400 Subject: [PATCH 08/13] Add test_cpp20 project --- build_test_all.cmd | 1 + cppwinrt.sln | 22 +++ run_tests.cmd | 1 + test/test_cpp20/main.cpp | 16 ++ test/test_cpp20/pch.cpp | 1 + test/test_cpp20/pch.h | 12 ++ test/test_cpp20/test_cpp20.vcxproj | 307 +++++++++++++++++++++++++++++ 7 files changed, 360 insertions(+) create mode 100644 test/test_cpp20/main.cpp create mode 100644 test/test_cpp20/pch.cpp create mode 100644 test/test_cpp20/pch.h create mode 100644 test/test_cpp20/test_cpp20.vcxproj diff --git a/build_test_all.cmd b/build_test_all.cmd index 4529372f1..13a68f6c9 100644 --- a/build_test_all.cmd +++ b/build_test_all.cmd @@ -27,6 +27,7 @@ call msbuild /p:Configuration=%target_configuration%,Platform=%target_platform%, call msbuild /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% test\nuget\NugetTest.sln call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test +call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_cpp20 call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_win7 call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_fast call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_slow diff --git a/cppwinrt.sln b/cppwinrt.sln index 3189d1555..d2141707c 100644 --- a/cppwinrt.sln +++ b/cppwinrt.sln @@ -103,6 +103,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_win7", "test\test_win7 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20", "test\test_cpp20\test_cpp20.vcxproj", "{5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}" + ProjectSection(ProjectDependencies) = postProject + {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -435,6 +440,22 @@ Global {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|x64.Build.0 = Release|x64 {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|x86.ActiveCfg = Release|Win32 {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|x86.Build.0 = Release|Win32 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|ARM.ActiveCfg = Debug|ARM + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|ARM.Build.0 = Debug|ARM + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|ARM64.Build.0 = Debug|ARM64 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|x64.ActiveCfg = Debug|x64 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|x64.Build.0 = Debug|x64 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|x86.ActiveCfg = Debug|Win32 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|x86.Build.0 = Debug|Win32 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|ARM.ActiveCfg = Release|ARM + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|ARM.Build.0 = Release|ARM + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|ARM64.ActiveCfg = Release|ARM64 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|ARM64.Build.0 = Release|ARM64 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|x64.ActiveCfg = Release|x64 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|x64.Build.0 = Release|x64 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|x86.ActiveCfg = Release|Win32 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -457,6 +478,7 @@ Global {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} {08C40663-B6A3-481E-8755-AE32BAD99501} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} {2EF696B9-7F4A-410F-AE5C-5301565C0F08} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2783B8FD-EA3B-4D6B-9F81-662D289E02AA} diff --git a/run_tests.cmd b/run_tests.cmd index d63741994..9cdbeb4b3 100644 --- a/run_tests.cmd +++ b/run_tests.cmd @@ -9,6 +9,7 @@ if "%target_platform%"=="" set target_platform=x64 if "%target_configuration%"=="" set target_configuration=Debug call :run_test test +call :run_test test_cpp20 call :run_test test_win7 call :run_test test_fast call :run_test test_slow diff --git a/test/test_cpp20/main.cpp b/test/test_cpp20/main.cpp new file mode 100644 index 000000000..7873e4ee7 --- /dev/null +++ b/test/test_cpp20/main.cpp @@ -0,0 +1,16 @@ +#define CATCH_CONFIG_RUNNER +#include "catch.hpp" +#include "winrt/base.h" + +using namespace winrt; + +int main(int const argc, char** argv) +{ + init_apartment(); + return Catch::Session().run(argc, argv); +} + +CATCH_TRANSLATE_EXCEPTION(hresult_error const& e) +{ + return to_string(e.message()); +} diff --git a/test/test_cpp20/pch.cpp b/test/test_cpp20/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/test_cpp20/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/test_cpp20/pch.h b/test/test_cpp20/pch.h new file mode 100644 index 000000000..ea74230cc --- /dev/null +++ b/test/test_cpp20/pch.h @@ -0,0 +1,12 @@ +#pragma once + +#pragma warning(4: 4458) // ensure we compile clean with this warning enabled + +#define WINRT_LEAN_AND_MEAN +#include +#include "winrt/Windows.Foundation.Collections.h" +#include "winrt/Windows.Foundation.Numerics.h" +#include +#include "catch.hpp" + +using namespace std::literals; diff --git a/test/test_cpp20/test_cpp20.vcxproj b/test/test_cpp20/test_cpp20.vcxproj new file mode 100644 index 000000000..24000a365 --- /dev/null +++ b/test/test_cpp20/test_cpp20.vcxproj @@ -0,0 +1,307 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA} + unittests + test_cpp20 + 10.0 + + + + Application + true + + + Application + true + + + Application + true + + + Application + false + true + + + Application + false + true + + + Application + false + true + + + Application + true + + + Application + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(OutDir)temp\$(ProjectName)\ + + + + + $(OutDir)temp\$(ProjectName)\ + + + $(OutDir)temp\$(ProjectName)\ + + + $(OutDir)temp\$(ProjectName)\ + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + + + + + + + + + + + + + + + + NotUsing + + + Create + + + + + + \ No newline at end of file From bcb80541e72fadf264215ba8603ffe57a15d6d50 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Mon, 22 Mar 2021 20:41:02 -0400 Subject: [PATCH 09/13] Enable C++20 --- test/test_cpp20/test_cpp20.vcxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_cpp20/test_cpp20.vcxproj b/test/test_cpp20/test_cpp20.vcxproj index 24000a365..73ddbc13c 100644 --- a/test/test_cpp20/test_cpp20.vcxproj +++ b/test/test_cpp20/test_cpp20.vcxproj @@ -130,6 +130,7 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + stdcpplatest Console @@ -151,6 +152,7 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + stdcpplatest Console @@ -170,6 +172,7 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + stdcpplatest Console @@ -189,6 +192,7 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + stdcpplatest Console @@ -208,6 +212,7 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + stdcpplatest Console @@ -229,6 +234,7 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + stdcpplatest Console @@ -252,6 +258,7 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + stdcpplatest Console @@ -275,6 +282,7 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + stdcpplatest Console From 95f3a9885f6aa099a6ab58d26e490e6fb8ed236f Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Mon, 22 Mar 2021 21:20:38 -0400 Subject: [PATCH 10/13] Add ranges unit tests --- test/test_cpp20/ranges.cpp | 48 ++++++++++++++++++++++++++++++ test/test_cpp20/test_cpp20.vcxproj | 1 + 2 files changed, 49 insertions(+) create mode 100644 test/test_cpp20/ranges.cpp diff --git a/test/test_cpp20/ranges.cpp b/test/test_cpp20/ranges.cpp new file mode 100644 index 000000000..220ba7c10 --- /dev/null +++ b/test/test_cpp20/ranges.cpp @@ -0,0 +1,48 @@ +#include "pch.h" +#include +#include + +TEST_CASE("ranges") +{ + { + // random-access range algorithms + auto v = winrt::single_threaded_vector({ 9, 8, 9, 6, 5, 8, 9, 3, 5, 3, 5, 3, 4, 7, 2, 1, 2, 3, 1 }); + + const bool result = std::ranges::is_heap(v); + + REQUIRE((result == true)); + } + { + // bidirectional range views + auto v = winrt::single_threaded_vector({ 1, 2, 3 }); + + std::vector result; + for (const int i : v | std::views::reverse) + { + result.push_back(i); + } + + REQUIRE((result == std::vector{ 3, 2, 1 })); + } + { + // input range algorithms + // decay to IIterable is important, we want to test the non-fast iterators. + winrt::Windows::Foundation::Collections::IIterable iterable = winrt::single_threaded_vector({ 2, 3, 1 }); + + const int result = (std::ranges::max)(iterable); + REQUIRE((result == 3)); + } + { + // input range views + // decay to IIterable is important, we want to test the non-fast iterators. + winrt::Windows::Foundation::Collections::IIterable iterable = winrt::single_threaded_vector({ 1, 2, 3 }); + + std::vector result; + for (const int i : iterable | std::views::transform([](int i) { return i * 2; })) + { + result.push_back(i); + } + + REQUIRE((result == std::vector{ 2, 4, 6 })); + } +} diff --git a/test/test_cpp20/test_cpp20.vcxproj b/test/test_cpp20/test_cpp20.vcxproj index 73ddbc13c..485218a0f 100644 --- a/test/test_cpp20/test_cpp20.vcxproj +++ b/test/test_cpp20/test_cpp20.vcxproj @@ -308,6 +308,7 @@ Create + From 6a33db92ddd85a383a3c940a1dd273d889d595f6 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Tue, 23 Mar 2021 19:56:28 -0400 Subject: [PATCH 11/13] Fix C++17 builds --- cppwinrt/code_writers.h | 2 ++ strings/base_iterator.h | 1 + 2 files changed, 3 insertions(+) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 327136c43..148c9bcd0 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -1454,6 +1454,7 @@ namespace cppwinrt using iterator_category = std::input_iterator_tag; using value_type = T; using difference_type = ptrdiff_t; + using pointer = void; using reference = T; )"); } @@ -1464,6 +1465,7 @@ namespace cppwinrt using iterator_category = std::input_iterator_tag; using value_type = Windows::Foundation::IInspectable; using difference_type = ptrdiff_t; + using pointer = void; using reference = Windows::Foundation::IInspectable; )"); } diff --git a/strings/base_iterator.h b/strings/base_iterator.h index 6c203e8ee..b277b402a 100644 --- a/strings/base_iterator.h +++ b/strings/base_iterator.h @@ -8,6 +8,7 @@ namespace winrt::impl using iterator_category = std::input_iterator_tag; using value_type = decltype(std::declval().GetAt(0)); using difference_type = ptrdiff_t; + using pointer = void; using reference = value_type; fast_iterator() noexcept = default; From e72eeb79b62b6d657d5406f0199e755863e72a86 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Tue, 23 Mar 2021 20:44:14 -0400 Subject: [PATCH 12/13] Tabs -> spaces --- test/test_cpp20/ranges.cpp | 82 +++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/test/test_cpp20/ranges.cpp b/test/test_cpp20/ranges.cpp index 220ba7c10..9bf88a579 100644 --- a/test/test_cpp20/ranges.cpp +++ b/test/test_cpp20/ranges.cpp @@ -4,45 +4,45 @@ TEST_CASE("ranges") { - { - // random-access range algorithms - auto v = winrt::single_threaded_vector({ 9, 8, 9, 6, 5, 8, 9, 3, 5, 3, 5, 3, 4, 7, 2, 1, 2, 3, 1 }); - - const bool result = std::ranges::is_heap(v); - - REQUIRE((result == true)); - } - { - // bidirectional range views - auto v = winrt::single_threaded_vector({ 1, 2, 3 }); - - std::vector result; - for (const int i : v | std::views::reverse) - { - result.push_back(i); - } - - REQUIRE((result == std::vector{ 3, 2, 1 })); - } - { - // input range algorithms - // decay to IIterable is important, we want to test the non-fast iterators. - winrt::Windows::Foundation::Collections::IIterable iterable = winrt::single_threaded_vector({ 2, 3, 1 }); - - const int result = (std::ranges::max)(iterable); - REQUIRE((result == 3)); - } - { - // input range views - // decay to IIterable is important, we want to test the non-fast iterators. - winrt::Windows::Foundation::Collections::IIterable iterable = winrt::single_threaded_vector({ 1, 2, 3 }); - - std::vector result; - for (const int i : iterable | std::views::transform([](int i) { return i * 2; })) - { - result.push_back(i); - } - - REQUIRE((result == std::vector{ 2, 4, 6 })); - } + { + // random-access range algorithms + auto v = winrt::single_threaded_vector({ 9, 8, 9, 6, 5, 8, 9, 3, 5, 3, 5, 3, 4, 7, 2, 1, 2, 3, 1 }); + + const bool result = std::ranges::is_heap(v); + + REQUIRE((result == true)); + } + { + // bidirectional range views + auto v = winrt::single_threaded_vector({ 1, 2, 3 }); + + std::vector result; + for (const int i : v | std::views::reverse) + { + result.push_back(i); + } + + REQUIRE((result == std::vector{ 3, 2, 1 })); + } + { + // input range algorithms + // decay to IIterable is important, we want to test the non-fast iterators. + winrt::Windows::Foundation::Collections::IIterable iterable = winrt::single_threaded_vector({ 2, 3, 1 }); + + const int result = (std::ranges::max)(iterable); + REQUIRE((result == 3)); + } + { + // input range views + // decay to IIterable is important, we want to test the non-fast iterators. + winrt::Windows::Foundation::Collections::IIterable iterable = winrt::single_threaded_vector({ 1, 2, 3 }); + + std::vector result; + for (const int i : iterable | std::views::transform([](int i) { return i * 2; })) + { + result.push_back(i); + } + + REQUIRE((result == std::vector{ 2, 4, 6 })); + } } From 4da13dc42512ec624c4c831618ebfc1f0d2c16db Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Sat, 27 Mar 2021 19:57:55 -0400 Subject: [PATCH 13/13] Fix ambiguous overload errors when importing std::{begin,end} --- strings/base_collections.h | 4 ++-- strings/base_iterator.h | 15 +++++++++------ strings/base_xaml_typename.h | 4 ++-- test/test/fast_iterator.cpp | 8 ++++++++ 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/strings/base_collections.h b/strings/base_collections.h index 102b853f7..cba0864b3 100644 --- a/strings/base_collections.h +++ b/strings/base_collections.h @@ -6,12 +6,12 @@ namespace winrt::impl template auto consume_Windows_Foundation_Collections_IIterable::begin() const { - return impl::begin(static_cast(*this)); + return get_begin_iterator(static_cast(*this)); } template auto consume_Windows_Foundation_Collections_IIterable::end() const { - return impl::end(static_cast(*this)); + return get_end_iterator(static_cast(*this)); } template diff --git a/strings/base_iterator.h b/strings/base_iterator.h index b277b402a..b0ad7836d 100644 --- a/strings/base_iterator.h +++ b/strings/base_iterator.h @@ -142,7 +142,7 @@ namespace winrt::impl }; template ::value, int> = 0> - auto begin(T const& collection) -> decltype(collection.First()) + auto get_begin_iterator(T const& collection) -> decltype(collection.First()) { auto result = collection.First(); @@ -155,19 +155,19 @@ namespace winrt::impl } template ::value, int> = 0> - auto end([[maybe_unused]] T const& collection) noexcept -> decltype(collection.First()) + auto get_end_iterator([[maybe_unused]] T const& collection) noexcept -> decltype(collection.First()) { return {}; } template ::value, int> = 0> - fast_iterator begin(T const& collection) noexcept + fast_iterator get_begin_iterator(T const& collection) noexcept { return { collection, 0 }; } template ::value, int> = 0> - fast_iterator end(T const& collection) + fast_iterator get_end_iterator(T const& collection) { return { collection, collection.Size() }; } @@ -175,12 +175,15 @@ namespace winrt::impl template ::value, int> = 0> auto rbegin(T const& collection) { - return std::make_reverse_iterator(end(collection)); + return std::make_reverse_iterator(get_end_iterator(collection)); } template ::value, int> = 0> auto rend(T const& collection) { - return std::make_reverse_iterator(begin(collection)); + return std::make_reverse_iterator(get_begin_iterator(collection)); } + + using std::begin; + using std::end; } diff --git a/strings/base_xaml_typename.h b/strings/base_xaml_typename.h index 9b7c23a50..4a782fc72 100644 --- a/strings/base_xaml_typename.h +++ b/strings/base_xaml_typename.h @@ -129,12 +129,12 @@ namespace winrt::impl template auto consume_Windows_UI_Xaml_Interop_IBindableIterable::begin() const { - return impl::begin(static_cast(*this)); + return get_begin_iterator(static_cast(*this)); } template auto consume_Windows_UI_Xaml_Interop_IBindableIterable::end() const { - return impl::end(static_cast(*this)); + return get_end_iterator(static_cast(*this)); } } diff --git a/test/test/fast_iterator.cpp b/test/test/fast_iterator.cpp index c7573903b..71ed6a918 100644 --- a/test/test/fast_iterator.cpp +++ b/test/test/fast_iterator.cpp @@ -51,4 +51,12 @@ TEST_CASE("fast_iterator") REQUIRE(end(v) - begin(v) == v.Size()); REQUIRE((begin(v) + 3)[-1] == 4); } + { + // ensure that importing std::begin and std::end does not break existing code + using std::begin; + using std::end; + + auto v = winrt::single_threaded_vector({ 9, 5, 4, 1, 1, 3 }); + REQUIRE(std::is_heap(begin(v), end(v))); + } }