Skip to content

Commit 691f6f8

Browse files
jonwisjaigakJon Wiswallkennykerr
authored
Support for std::span for winrt::array_view and winrt::com_array (#1343)
* Implicit conversion between std::span and winrt::array_view * Add testing and additional ctad for spans * PR FB - yes, yes it does! * PR FB --------- Co-authored-by: Jaiganésh Kumaran <[email protected]> Co-authored-by: Jon Wiswall <[email protected]> Co-authored-by: Kenny Kerr <[email protected]>
1 parent de6ca88 commit 691f6f8

File tree

5 files changed

+228
-0
lines changed

5 files changed

+228
-0
lines changed

strings/base_array.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ WINRT_EXPORT namespace winrt
3131
array_view(value.begin(), static_cast<size_type>(value.size()))
3232
{}
3333

34+
#ifdef __cpp_lib_span
35+
template <typename C, size_t extent>
36+
array_view(std::span<C, extent> span) noexcept :
37+
array_view(span.data(), static_cast<size_type>(span.size()))
38+
{
39+
WINRT_ASSERT(span.size() <= UINT_MAX);
40+
}
41+
42+
operator std::span<T>() const noexcept
43+
{
44+
return { m_data, m_size };
45+
}
46+
#endif
47+
3448
template <typename C, size_type N>
3549
array_view(C(&value)[N]) noexcept :
3650
array_view(value, N)
@@ -223,6 +237,11 @@ WINRT_EXPORT namespace winrt
223237
template <typename C, size_t N> array_view(std::array<C, N>& value) -> array_view<C>;
224238
template <typename C, size_t N> array_view(std::array<C, N> const& value) -> array_view<C const>;
225239

240+
#ifdef __cpp_lib_span
241+
template <typename C, size_t extent> array_view(std::span<C, extent>& value) -> array_view<C>;
242+
template <typename C, size_t extent> array_view(std::span<C, extent> const& value) -> array_view<C const>;
243+
#endif
244+
226245
template <typename T>
227246
struct com_array : array_view<T>
228247
{
@@ -274,6 +293,15 @@ WINRT_EXPORT namespace winrt
274293
com_array(value.begin(), value.end())
275294
{}
276295

296+
#ifdef __cpp_lib_span
297+
template <typename U, size_t extent>
298+
explicit com_array(std::span<U, extent> span) noexcept :
299+
com_array(span.data(), span.data() + span.size())
300+
{
301+
WINRT_ASSERT(span.size() <= UINT_MAX);
302+
}
303+
#endif
304+
277305
template <typename U, size_t N>
278306
explicit com_array(U const(&value)[N]) :
279307
com_array(value, value + N)
@@ -375,6 +403,11 @@ WINRT_EXPORT namespace winrt
375403
template <size_t N, typename C> com_array(C const(&)[N]) -> com_array<std::decay_t<C>>;
376404
template <typename C> com_array(std::initializer_list<C>) -> com_array<std::decay_t<C>>;
377405

406+
#ifdef __cpp_lib_span
407+
template <typename C, size_t extent> com_array(std::span<C, extent> const& value) -> com_array<std::decay_t<C>>;
408+
#endif
409+
410+
378411
namespace impl
379412
{
380413
template <typename T, typename U>

strings/base_includes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
#include <ostream>
3535
#endif
3636

37+
#ifdef __cpp_lib_span
38+
#include <span>
39+
#endif
40+
3741
#ifdef __cpp_lib_format
3842
#include <format>
3943
#endif

test/test_cpp20/array_span.cpp

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#include "pch.h"
2+
#include "catch.hpp"
3+
#include <array>
4+
5+
using namespace winrt;
6+
using namespace Windows::Foundation;
7+
using namespace Windows::Storage::Streams;
8+
using namespace Windows::Data::Json;
9+
10+
//
11+
// This is a helper to create a data reader for use in testing arrays.
12+
//
13+
static IAsyncOperation<IDataReader> CreateDataReader(std::initializer_list<byte> values)
14+
{
15+
InMemoryRandomAccessStream stream;
16+
DataWriter writer(stream);
17+
writer.WriteByte(1);
18+
writer.WriteByte(2);
19+
writer.WriteByte(3);
20+
co_await writer.StoreAsync();
21+
22+
stream.Seek(0);
23+
DataReader reader(stream);
24+
co_await reader.LoadAsync(3);
25+
co_return reader;
26+
}
27+
28+
//
29+
// This test illustrates an array_view<T> (non-const) bound to a std::span<T> on a std::array
30+
//
31+
TEST_CASE("array,DataReader,std::span")
32+
{
33+
auto reader = CreateDataReader({ 1, 2, 3 }).get();
34+
35+
std::array<byte, 3> a{};
36+
std::span<byte> sp(a);
37+
reader.ReadBytes(sp); // FillArray pattern
38+
39+
REQUIRE(a.size() == 3);
40+
REQUIRE(a[0] == 1);
41+
REQUIRE(a[1] == 2);
42+
REQUIRE(a[2] == 3);
43+
}
44+
45+
//
46+
// This test illustrates passing a std::array to a method that takes array_view<T>
47+
//
48+
TEST_CASE("array,DataReader,std::span,direct")
49+
{
50+
auto reader = CreateDataReader({ 1, 2, 3 }).get();
51+
52+
std::array<byte, 3> a{};
53+
reader.ReadBytes(a); // FillArray pattern
54+
55+
REQUIRE(a.size() == 3);
56+
REQUIRE(a[0] == 1);
57+
REQUIRE(a[1] == 2);
58+
REQUIRE(a[2] == 3);
59+
}
60+
61+
62+
TEST_CASE("array_view,span")
63+
{
64+
{
65+
int v[] = { 1, 2, 3 };
66+
std::span<int> s(v);
67+
array_view<int> a = s;
68+
REQUIRE(a.data() == v);
69+
REQUIRE(a.size() == 3);
70+
}
71+
72+
{
73+
int v[] = { 1, 2, 3 };
74+
std::span<int const> s(v);
75+
array_view<int const> a = s;
76+
REQUIRE(a.data() == v);
77+
REQUIRE(a.size() == 3);
78+
}
79+
80+
{
81+
int const v[] = { 1, 2, 3 };
82+
std::span<int const> s(v);
83+
array_view<int const> a = s;
84+
REQUIRE(a.data() == v);
85+
REQUIRE(a.size() == 3);
86+
}
87+
}
88+
89+
//
90+
// Tests com_array support for span construction.
91+
//
92+
TEST_CASE("com_array,span")
93+
{
94+
{
95+
int v[] = { 1, 2, 3 };
96+
std::span<int> s(v);
97+
com_array<int> a(s);
98+
REQUIRE(a.size() == 3);
99+
REQUIRE(a[0] == 1);
100+
REQUIRE(a[1] == 2);
101+
REQUIRE(a[2] == 3);
102+
}
103+
}
104+
105+
//
106+
// Tests array_view support for conversion to span
107+
//
108+
TEST_CASE("array_view,span,as")
109+
{
110+
{
111+
int v[] = { 1, 2, 3 };
112+
array_view<int> a = v;
113+
std::span<int> s(a);
114+
REQUIRE(s.data() == v);
115+
REQUIRE(s.size() == 3);
116+
}
117+
118+
{
119+
int v[] = { 1, 2, 3 };
120+
array_view<int const> a = v;
121+
std::span<int const> s(a);
122+
REQUIRE(s.data() == v);
123+
REQUIRE(s.size() == 3);
124+
}
125+
126+
{
127+
int const v[] = { 1, 2, 3 };
128+
array_view<int const> a = v;
129+
std::span<int const> s(a);
130+
REQUIRE(s.data() == v);
131+
REQUIRE(s.size() == 3);
132+
}
133+
}
134+
135+
//
136+
// Tests com_array support for conversion to span
137+
//
138+
TEST_CASE("com_array,span,as")
139+
{
140+
{
141+
int v[] = { 1, 2, 3 };
142+
com_array<int> a(v);
143+
std::span<int> s(a);
144+
REQUIRE(s.size() == 3);
145+
REQUIRE(s[0] == 1);
146+
REQUIRE(s[1] == 2);
147+
REQUIRE(s[2] == 3);
148+
}
149+
}
150+
151+
// Verify that class template argument deduction works for array_view.
152+
TEST_CASE("array_view,span,ctad")
153+
{
154+
#define REQUIRE_DEDUCED_AS(T, ...) \
155+
static_assert(std::is_same_v<array_view<T>, decltype(array_view(__VA_ARGS__))>)
156+
157+
uint8_t a[] = {1, 2, 3};
158+
std::span<uint8_t, 3> sp{ a };
159+
160+
REQUIRE_DEDUCED_AS(uint8_t, sp);
161+
162+
std::span<uint8_t const, 3> csp{ a };
163+
REQUIRE_DEDUCED_AS(uint8_t const, csp);
164+
165+
std::span<uint8_t, 3> const cs{ a };
166+
REQUIRE_DEDUCED_AS(uint8_t const, cs);
167+
168+
#undef REQUIRE_DEDUCED_AS
169+
}
170+
171+
// Verify that class template argument deduction works for com_array.
172+
TEST_CASE("com_array,span,ctad")
173+
{
174+
#define REQUIRE_DEDUCED_AS(T, ...) \
175+
static_assert(std::is_same_v<com_array<T>, decltype(com_array(__VA_ARGS__))>)
176+
177+
uint8_t a[] = { 1, 2, 3 };
178+
179+
std::span<uint8_t, 3> sp{ a };
180+
REQUIRE_DEDUCED_AS(uint8_t, sp);
181+
182+
std::span<uint8_t const, 3> csp{ a };
183+
REQUIRE_DEDUCED_AS(uint8_t, csp);
184+
185+
std::span<uint8_t, 3> const cs{ a };
186+
REQUIRE_DEDUCED_AS(uint8_t, cs);
187+
188+
#undef REQUIRE_DEDUCED_AS
189+
}

test/test_cpp20/pch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "winrt/Windows.Foundation.h"
99
#include "winrt/Windows.Foundation.Collections.h"
1010
#include "winrt/Windows.Foundation.Numerics.h"
11+
#include "winrt/Windows.Storage.Streams.h"
1112
#include <winstring.h>
1213
#include "catch.hpp"
1314

test/test_cpp20/test_cpp20.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@
280280
<ClInclude Include="pch.h" />
281281
</ItemGroup>
282282
<ItemGroup>
283+
<ClCompile Include="array_span.cpp" />
283284
<ClCompile Include="await_completed.cpp" />
284285
<ClCompile Include="custom_error.cpp" />
285286
<ClCompile Include="format.cpp" />

0 commit comments

Comments
 (0)