From 7a9c6c4a66530d62f22aaff87c1d83b7035db738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaigan=C3=A9sh=20Kumaran?= Date: Wed, 12 Jul 2023 21:10:00 +0530 Subject: [PATCH 1/4] Implicit conversion between std::span and winrt::array_view --- strings/base_array.h | 10 ++++++++++ strings/base_includes.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/strings/base_array.h b/strings/base_array.h index 9f20cf34e..e74104074 100644 --- a/strings/base_array.h +++ b/strings/base_array.h @@ -31,6 +31,16 @@ WINRT_EXPORT namespace winrt array_view(value.begin(), static_cast(value.size())) {} +#ifdef __cpp_lib_span + template + array_view(std::span span) : array_view(span.data(), static_cast(span.size())) {} + + operator std::span() const noexcept + { + return { m_data, m_size }; + } +#endif + template array_view(C(&value)[N]) noexcept : array_view(value, N) diff --git a/strings/base_includes.h b/strings/base_includes.h index 54edca841..ee22bc0aa 100644 --- a/strings/base_includes.h +++ b/strings/base_includes.h @@ -34,6 +34,10 @@ #include #endif +#ifdef __cpp_lib_span +#include +#endif + #ifdef __cpp_lib_format #include #endif From 761106435b90acce3130ae8348cb858ee07e92be Mon Sep 17 00:00:00 2001 From: Jon Wiswall Date: Fri, 18 Aug 2023 20:58:14 -0700 Subject: [PATCH 2/4] Add testing and additional ctad for spans --- strings/base_array.h | 27 ++++- test/test_cpp20/array_span.cpp | 172 +++++++++++++++++++++++++++++ test/test_cpp20/pch.h | 1 + test/test_cpp20/test_cpp20.vcxproj | 1 + 4 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 test/test_cpp20/array_span.cpp diff --git a/strings/base_array.h b/strings/base_array.h index e74104074..2c3c3cc78 100644 --- a/strings/base_array.h +++ b/strings/base_array.h @@ -32,8 +32,12 @@ WINRT_EXPORT namespace winrt {} #ifdef __cpp_lib_span - template - array_view(std::span span) : array_view(span.data(), static_cast(span.size())) {} + template + array_view(std::span span) noexcept : + array_view(span.data(), static_cast(span.size())) + { + WINRT_ASSERT(span.size() <= UINT_MAX); + } operator std::span() const noexcept { @@ -233,6 +237,11 @@ WINRT_EXPORT namespace winrt template array_view(std::array& value) -> array_view; template array_view(std::array const& value) -> array_view; +#ifdef __cpp_lib_span + template array_view(std::span& value) -> array_view; + template array_view(std::span const& value) -> array_view; +#endif + template struct com_array : array_view { @@ -284,6 +293,15 @@ WINRT_EXPORT namespace winrt com_array(value.begin(), value.end()) {} +#ifdef __cpp_lib_span + template + explicit com_array(std::span span) noexcept : + com_array(span.data(), span.data() + span.size()) + { + WINRT_ASSERT(span.size() <= UINT_MAX); + } +#endif + template explicit com_array(U const(&value)[N]) : com_array(value, value + N) @@ -385,6 +403,11 @@ WINRT_EXPORT namespace winrt template com_array(C const(&)[N]) -> com_array>; template com_array(std::initializer_list) -> com_array>; +#ifdef __cpp_lib_span + template com_array(std::span const& value) -> com_array>; +#endif + + namespace impl { template diff --git a/test/test_cpp20/array_span.cpp b/test/test_cpp20/array_span.cpp new file mode 100644 index 000000000..82693a3f5 --- /dev/null +++ b/test/test_cpp20/array_span.cpp @@ -0,0 +1,172 @@ +#include "pch.h" +#include "catch.hpp" +#include + +using namespace winrt; +using namespace Windows::Foundation; +using namespace Windows::Storage::Streams; +using namespace Windows::Data::Json; + +// +// This is a helper to create a data reader for use in testing arrays. +// +static IAsyncOperation CreateDataReader(std::initializer_list values) +{ + InMemoryRandomAccessStream stream; + DataWriter writer(stream); + writer.WriteByte(1); + writer.WriteByte(2); + writer.WriteByte(3); + co_await writer.StoreAsync(); + + stream.Seek(0); + DataReader reader(stream); + co_await reader.LoadAsync(3); + co_return reader; +} + +// +// This test illustrates an array_view (non-const) bound to a std::span on a std::array +// +TEST_CASE("array,DataReader,std::span") +{ + auto reader = CreateDataReader({ 1, 2, 3 }).get(); + + std::array a{}; + std::span sp(a); + reader.ReadBytes(sp); // FillArray pattern + + REQUIRE(a.size() == 3); + REQUIRE(a[0] == 1); + REQUIRE(a[1] == 2); + REQUIRE(a[2] == 3); +} + +TEST_CASE("array_view,span") +{ + { + int v[] = { 1, 2, 3 }; + std::span s(v); + array_view a = s; + REQUIRE(a.data() == v); + REQUIRE(a.size() == 3); + } + + { + int v[] = { 1, 2, 3 }; + std::span s(v); + array_view a = s; + REQUIRE(a.data() == v); + REQUIRE(a.size() == 3); + } + + { + int const v[] = { 1, 2, 3 }; + std::span s(v); + array_view a = s; + REQUIRE(a.data() == v); + REQUIRE(a.size() == 3); + } +} + +// +// Tests com_array support for span construction. +// +TEST_CASE("com_array,span") +{ + { + int v[] = { 1, 2, 3 }; + std::span s(v); + com_array a(s); + REQUIRE(a.size() == 3); + REQUIRE(a[0] == 1); + REQUIRE(a[1] == 2); + REQUIRE(a[2] == 3); + } +} + +// +// Tests array_view support for conversion to span +// +TEST_CASE("array_view,span,as") +{ + { + int v[] = { 1, 2, 3 }; + array_view a = v; + std::span s(a); + REQUIRE(s.data() == v); + REQUIRE(s.size() == 3); + } + + { + int v[] = { 1, 2, 3 }; + array_view a = v; + std::span s(a); + REQUIRE(s.data() == v); + REQUIRE(s.size() == 3); + } + + { + int const v[] = { 1, 2, 3 }; + array_view a = v; + std::span s(a); + REQUIRE(s.data() == v); + REQUIRE(s.size() == 3); + } +} + +// +// Tests com_array support for conversion to span +// +TEST_CASE("com_array,span,as") +{ + { + int v[] = { 1, 2, 3 }; + com_array a(v); + std::span s(a); + REQUIRE(s.size() == 3); + REQUIRE(s[0] == 1); + REQUIRE(s[1] == 2); + REQUIRE(s[2] == 3); + } +} + +// Verify that class template argument deduction works for array_view. +TEST_CASE("array_view,span,ctad") +{ +#define REQUIRE_DEDUCED_AS(T, ...) \ + static_assert(std::is_same_v, decltype(array_view(__VA_ARGS__))>) + + uint8_t a[] = {1, 2, 3}; + std::span sp{ a }; + + REQUIRE_DEDUCED_AS(uint8_t, sp); + + std::span csp{ a }; + REQUIRE_DEDUCED_AS(uint8_t const, csp); + + std::span const cs{ a }; + REQUIRE_DEDUCED_AS(uint8_t const, cs); + +#undef REQUIRE_DEDUCED_AS +} + +// Verify that class template argument deduction works for com_array. +TEST_CASE("com_array,span,ctad") +{ +#define REQUIRE_DEDUCED_AS(T, ...) \ + static_assert(std::is_same_v, decltype(com_array(__VA_ARGS__))>) + + uint8_t a[] = { 1, 2, 3 }; + + std::span sp{ a }; + REQUIRE_DEDUCED_AS(uint8_t, sp); + + std::span csp{ a }; + REQUIRE_DEDUCED_AS(uint8_t, csp); + + std::span const cs{ a }; + REQUIRE_DEDUCED_AS(uint8_t, cs); + +#undef REQUIRE_DEDUCED_AS +} diff --git a/test/test_cpp20/pch.h b/test/test_cpp20/pch.h index 6565bea1b..c1a8f5ff3 100644 --- a/test/test_cpp20/pch.h +++ b/test/test_cpp20/pch.h @@ -8,6 +8,7 @@ #include "winrt/Windows.Foundation.h" #include "winrt/Windows.Foundation.Collections.h" #include "winrt/Windows.Foundation.Numerics.h" +#include "winrt/Windows.Storage.Streams.h" #include #include "catch.hpp" diff --git a/test/test_cpp20/test_cpp20.vcxproj b/test/test_cpp20/test_cpp20.vcxproj index 1717d6bf8..72d203a37 100644 --- a/test/test_cpp20/test_cpp20.vcxproj +++ b/test/test_cpp20/test_cpp20.vcxproj @@ -280,6 +280,7 @@ + From 971f28076a8497752d17929ad0508a289c70d449 Mon Sep 17 00:00:00 2001 From: Jon Wiswall Date: Sat, 19 Aug 2023 20:56:55 -0700 Subject: [PATCH 3/4] PR FB - yes, yes it does! --- test/test_cpp20/array_span.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test_cpp20/array_span.cpp b/test/test_cpp20/array_span.cpp index 82693a3f5..dff5a2ec5 100644 --- a/test/test_cpp20/array_span.cpp +++ b/test/test_cpp20/array_span.cpp @@ -42,6 +42,23 @@ TEST_CASE("array,DataReader,std::span") REQUIRE(a[2] == 3); } +// +// This test illustrates passing a std::array to a method that takes array_view +// +TEST_CASE("array,DataReader,std::span,direct") +{ + auto reader = CreateDataReader({ 1, 2, 3 }).get(); + + std::array a{}; + reader.ReadBytes(a); // FillArray pattern + + REQUIRE(a.size() == 3); + REQUIRE(a[0] == 1); + REQUIRE(a[1] == 2); + REQUIRE(a[2] == 3); +} + + TEST_CASE("array_view,span") { { From edccd3ce009c5c9640306d734f761e1bd176c50d Mon Sep 17 00:00:00 2001 From: Jon Wiswall Date: Thu, 24 Aug 2023 14:22:02 -0700 Subject: [PATCH 4/4] PR FB --- strings/base_array.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/strings/base_array.h b/strings/base_array.h index 2c3c3cc78..a4f570614 100644 --- a/strings/base_array.h +++ b/strings/base_array.h @@ -32,7 +32,7 @@ WINRT_EXPORT namespace winrt {} #ifdef __cpp_lib_span - template + template array_view(std::span span) noexcept : array_view(span.data(), static_cast(span.size())) { @@ -238,8 +238,8 @@ WINRT_EXPORT namespace winrt template array_view(std::array const& value) -> array_view; #ifdef __cpp_lib_span - template array_view(std::span& value) -> array_view; - template array_view(std::span const& value) -> array_view; + template array_view(std::span& value) -> array_view; + template array_view(std::span const& value) -> array_view; #endif template @@ -294,7 +294,7 @@ WINRT_EXPORT namespace winrt {} #ifdef __cpp_lib_span - template + template explicit com_array(std::span span) noexcept : com_array(span.data(), span.data() + span.size()) { @@ -404,7 +404,7 @@ WINRT_EXPORT namespace winrt template com_array(std::initializer_list) -> com_array>; #ifdef __cpp_lib_span - template com_array(std::span const& value) -> com_array>; + template com_array(std::span const& value) -> com_array>; #endif