diff --git a/strings/base_array.h b/strings/base_array.h index 9f20cf34e..a4f570614 100644 --- a/strings/base_array.h +++ b/strings/base_array.h @@ -31,6 +31,20 @@ WINRT_EXPORT namespace winrt array_view(value.begin(), static_cast(value.size())) {} +#ifdef __cpp_lib_span + 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 + { + return { m_data, m_size }; + } +#endif + template array_view(C(&value)[N]) noexcept : array_view(value, N) @@ -223,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 { @@ -274,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) @@ -375,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/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 diff --git a/test/test_cpp20/array_span.cpp b/test/test_cpp20/array_span.cpp new file mode 100644 index 000000000..dff5a2ec5 --- /dev/null +++ b/test/test_cpp20/array_span.cpp @@ -0,0 +1,189 @@ +#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); +} + +// +// 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") +{ + { + 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 @@ +