Skip to content

Commit 7e0ac4b

Browse files
Merge branch 'master' into feature/mvvm-toolkit-preview4
2 parents 727e828 + 6d567c5 commit 7e0ac4b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1344
-160
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,25 @@ assignees: ''
77

88
---
99

10-
<!--
11-
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
12-
ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
13-
-->
10+
<!-- 🚨 Please Do Not skip any instructions and information mentioned below as they are all required and essential to investigate the issue. Issues with missing information may be closed without investigation 🚨 -->
1411

1512
## Describe the bug
1613
A clear and concise description of what the bug is.
1714

1815
- [ ] Is this bug a regression in the toolkit? If so, what toolkit version did you last see it work:
1916

2017
## Steps to Reproduce
18+
19+
- [ ] Can this be reproduced in the Sample App? (Either in a sample as-is or with new XAML pasted in the editor.) If so, please provide custom XAML or steps to reproduce. If not, let us know why it can't be reproduced (e.g. more complex setup, environment, dependencies, etc...) <!-- Being able to reproduce the problem in the sample app, really stream-lines the whole process in being able to discover, resolve, and validate bug fixes. -->
20+
2121
Steps to reproduce the behavior:
22-
1. Go to '...'
23-
2. Click on '....'
24-
3. Scroll down to '....'
25-
4. See error
22+
1. Given the following environment (Sample App w/ XAML, Project with Isolated setup, etc...)
23+
2. Go to '...'
24+
3. Click on '....'
25+
4. Scroll down to '....'
26+
5. See error
27+
28+
<!-- Provide as many code-snippets or XAML snippets where appropriate. -->
2629

2730
## Expected behavior
2831
A clear and concise description of what you expected to happen.

.github/ISSUE_TEMPLATE/feature_request.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ assignees: ''
77

88
---
99

10+
<!-- 🚨 Please provide detailed information and Do Not skip any instructions as they are all required and essential to help us understand the feature 🚨 -->
11+
1012
## Describe the problem this feature would solve
1113
<!-- Please describe or link to any existing issues or discussions.
1214
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->

.github/ISSUE_TEMPLATE/question.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Hi!
1313
We try and keep our GitHub issue list for bugs and features.
1414
1515
Ideally, it'd be great to post your question on Stack Overflow using the 'windows-community-toolkit' tag here: https://stackoverflow.com/questions/tagged/windows-community-toolkit
16+
🚨 Please provide detailed information that includes examples, screenshots, and relevant issues if possible 🚨
1617
1718
If this is more about a scenario that you think is missing documentation, please file an issue instead at https://github.com/MicrosoftDocs/WindowsCommunityToolkitDocs/issues/new
1819

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
<!-- 🚨 Please Do Not skip any instructions and information mentioned below as they are all required and essential to evaluate and test the PR. By fulfilling all the required information you will be able to reduce the volume of questions and most likely help merge the PR faster 🚨 -->
2+
13
## Fixes #
24
<!-- Add the relevant issue number after the "#" mentioned above (for ex: Fixes #1234) which will automatically close the issue once the PR is merged. -->
35

@@ -38,7 +40,7 @@ Please check if your PR fulfills the following requirements:
3840
- [ ] Contains **NO** breaking changes
3941

4042
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below.
41-
Please note that breaking changes are likely to be rejected. -->
43+
Please note that breaking changes are likely to be rejected within minor release cycles or held until major versions. -->
4244

4345

4446
## Other information

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,8 @@ msbuild.binlog
227227
!/build/tools/packages.config
228228

229229
# Generated file from .ttinclude
230-
**/Generated/TypeInfo.g.cs
230+
**/Generated/TypeInfo.g.cs
231+
232+
# TAEF Log output
233+
WexLogFileOutput
234+
*.wtl

Microsoft.Toolkit.HighPerformance/Extensions/ArrayExtensions.2D.cs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ public static ref T DangerousGetReference<T>(this T[,] array)
6666
/// </remarks>
6767
[Pure]
6868
[MethodImpl(MethodImplOptions.AggressiveInlining)]
69-
public static ref T DangerousGetReferenceAt<T>(this T[,] array, int i, int j)
69+
public static unsafe ref T DangerousGetReferenceAt<T>(this T[,] array, int i, int j)
7070
{
7171
#if NETCORE_RUNTIME
7272
var arrayData = Unsafe.As<RawArray2DData>(array);
7373
int offset = (i * arrayData.Width) + j;
7474
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
75-
ref T ri = ref Unsafe.Add(ref r0, offset);
75+
ref T ri = ref Unsafe.Add(ref r0, (IntPtr)(void*)(uint)offset);
7676

7777
return ref ri;
7878
#else
@@ -82,10 +82,7 @@ public static ref T DangerousGetReferenceAt<T>(this T[,] array, int i, int j)
8282
return ref array[i, j];
8383
}
8484

85-
unsafe
86-
{
87-
return ref Unsafe.AsRef<T>(null);
88-
}
85+
return ref Unsafe.AsRef<T>(null);
8986
#endif
9087
}
9188

@@ -274,11 +271,11 @@ public static Span<T> AsSpan<T>(this T[,] array)
274271
/// <returns>The number of occurrences of <paramref name="value"/> in <paramref name="array"/>.</returns>
275272
[Pure]
276273
[MethodImpl(MethodImplOptions.AggressiveInlining)]
277-
public static int Count<T>(this T[,] array, T value)
274+
public static unsafe int Count<T>(this T[,] array, T value)
278275
where T : IEquatable<T>
279276
{
280277
ref T r0 = ref array.DangerousGetReference();
281-
IntPtr length = (IntPtr)array.Length;
278+
IntPtr length = (IntPtr)(void*)(uint)array.Length;
282279

283280
return SpanHelper.Count(ref r0, length, value);
284281
}
@@ -293,11 +290,11 @@ public static int Count<T>(this T[,] array, T value)
293290
/// <remarks>The Djb2 hash is fully deterministic and with no random components.</remarks>
294291
[Pure]
295292
[MethodImpl(MethodImplOptions.AggressiveInlining)]
296-
public static int GetDjb2HashCode<T>(this T[,] array)
293+
public static unsafe int GetDjb2HashCode<T>(this T[,] array)
297294
where T : notnull
298295
{
299296
ref T r0 = ref array.DangerousGetReference();
300-
IntPtr length = (IntPtr)array.Length;
297+
IntPtr length = (IntPtr)(void*)(uint)array.Length;
301298

302299
return SpanHelper.GetDjb2HashCode(ref r0, length);
303300
}

Microsoft.Toolkit.HighPerformance/Extensions/ArrayExtensions.cs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ public static ref T DangerousGetReference<T>(this T[] array)
6262
/// <remarks>This method doesn't do any bounds checks, therefore it is responsibility of the caller to ensure the <paramref name="i"/> parameter is valid.</remarks>
6363
[Pure]
6464
[MethodImpl(MethodImplOptions.AggressiveInlining)]
65-
public static ref T DangerousGetReferenceAt<T>(this T[] array, int i)
65+
public static unsafe ref T DangerousGetReferenceAt<T>(this T[] array, int i)
6666
{
6767
#if NETCORE_RUNTIME
6868
var arrayData = Unsafe.As<RawArrayData>(array);
6969
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
70-
ref T ri = ref Unsafe.Add(ref r0, i);
70+
ref T ri = ref Unsafe.Add(ref r0, (IntPtr)(void*)(uint)i);
7171

7272
return ref ri;
7373
#else
@@ -76,10 +76,7 @@ public static ref T DangerousGetReferenceAt<T>(this T[] array, int i)
7676
return ref array[i];
7777
}
7878

79-
unsafe
80-
{
81-
return ref Unsafe.AsRef<T>(null);
82-
}
79+
return ref Unsafe.AsRef<T>(null);
8380
#endif
8481
}
8582

@@ -114,11 +111,11 @@ private sealed class RawArrayData
114111
/// <returns>The number of occurrences of <paramref name="value"/> in <paramref name="array"/>.</returns>
115112
[Pure]
116113
[MethodImpl(MethodImplOptions.AggressiveInlining)]
117-
public static int Count<T>(this T[] array, T value)
114+
public static unsafe int Count<T>(this T[] array, T value)
118115
where T : IEquatable<T>
119116
{
120117
ref T r0 = ref array.DangerousGetReference();
121-
IntPtr length = (IntPtr)array.Length;
118+
IntPtr length = (IntPtr)(void*)(uint)array.Length;
122119

123120
return SpanHelper.Count(ref r0, length, value);
124121
}
@@ -185,11 +182,11 @@ public static SpanTokenizer<T> Tokenize<T>(this T[] array, T separator)
185182
/// <remarks>The Djb2 hash is fully deterministic and with no random components.</remarks>
186183
[Pure]
187184
[MethodImpl(MethodImplOptions.AggressiveInlining)]
188-
public static int GetDjb2HashCode<T>(this T[] array)
185+
public static unsafe int GetDjb2HashCode<T>(this T[] array)
189186
where T : notnull
190187
{
191188
ref T r0 = ref array.DangerousGetReference();
192-
IntPtr length = (IntPtr)array.Length;
189+
IntPtr length = (IntPtr)(void*)(uint)array.Length;
193190

194191
return SpanHelper.GetDjb2HashCode(ref r0, length);
195192
}

Microsoft.Toolkit.HighPerformance/Extensions/ReadOnlySpanExtensions.cs

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,40 @@ public static ref T DangerousGetReference<T>(this ReadOnlySpan<T> span)
4040
/// <remarks>This method doesn't do any bounds checks, therefore it is responsibility of the caller to ensure the <paramref name="i"/> parameter is valid.</remarks>
4141
[Pure]
4242
[MethodImpl(MethodImplOptions.AggressiveInlining)]
43-
public static ref T DangerousGetReferenceAt<T>(this ReadOnlySpan<T> span, int i)
43+
public static unsafe ref T DangerousGetReferenceAt<T>(this ReadOnlySpan<T> span, int i)
4444
{
45+
// Here we assume the input index will never be negative, so we do an unsafe cast to
46+
// force the JIT to skip the sign extension when going from int to native int.
47+
// On .NET Core 3.1, if we only use Unsafe.Add(ref r0, i), we get the following:
48+
// =============================
49+
// L0000: mov rax, [rcx]
50+
// L0003: movsxd rdx, edx
51+
// L0006: lea rax, [rax+rdx*4]
52+
// L000a: ret
53+
// =============================
54+
// Note the movsxd (move with sign extension) to expand the index passed in edx to
55+
// the whole rdx register. This is unnecessary and more expensive than just a mov,
56+
// which when done to a large register size automatically zeroes the upper bits.
57+
// With the (IntPtr)(void*)(uint) cast, we get the following codegen instead:
58+
// =============================
59+
// L0000: mov rax, [rcx]
60+
// L0003: mov edx, edx
61+
// L0005: lea rax, [rax+rdx*4]
62+
// L0009: ret
63+
// =============================
64+
// Here we can see how the index is extended to a native integer with just a mov,
65+
// which effectively only zeroes the upper bits of the same register used as source.
66+
// These three casts are a bit verbose, but they do the trick on both 32 bit and 64
67+
// bit architectures, producing optimal code in both cases (they are either completely
68+
// elided on 32 bit systems, or result in the correct register expansion when on 64 bit).
69+
// We first do an unchecked conversion to uint (which is just a reinterpret-cast). We
70+
// then cast to void*, which lets the following IntPtr cast avoid the range check on 32 bit
71+
// (since uint could be out of range there if the original index was negative). The final
72+
// result is a clean mov as shown above. This will eventually be natively supported by the
73+
// JIT compiler (see https://github.com/dotnet/runtime/issues/38794), but doing this here
74+
// still ensures the optimal codegen even on existing runtimes (eg. .NET Core 2.1 and 3.1).
4575
ref T r0 = ref MemoryMarshal.GetReference(span);
46-
ref T ri = ref Unsafe.Add(ref r0, i);
76+
ref T ri = ref Unsafe.Add(ref r0, (IntPtr)(void*)(uint)i);
4777

4878
return ref ri;
4979
}
@@ -87,7 +117,7 @@ public static ref T DangerousGetReferenceAt<T>(this ReadOnlySpan<T> span, int i)
87117
/// </returns>
88118
[Pure]
89119
[MethodImpl(MethodImplOptions.AggressiveInlining)]
90-
public static ref readonly T DangerousGetLookupReferenceAt<T>(this ReadOnlySpan<T> span, int i)
120+
public static unsafe ref readonly T DangerousGetLookupReferenceAt<T>(this ReadOnlySpan<T> span, int i)
91121
{
92122
// Check whether the input is in range by first casting both
93123
// operands to uint and then comparing them, as this allows
@@ -106,12 +136,12 @@ public static ref readonly T DangerousGetLookupReferenceAt<T>(this ReadOnlySpan<
106136
// lookup table can just be assumed to always be false.
107137
bool isInRange = (uint)i < (uint)span.Length;
108138
byte rangeFlag = Unsafe.As<bool, byte>(ref isInRange);
109-
int
110-
negativeFlag = rangeFlag - 1,
139+
uint
140+
negativeFlag = unchecked(rangeFlag - 1u),
111141
mask = ~negativeFlag,
112-
offset = i & mask;
142+
offset = (uint)i & mask;
113143
ref T r0 = ref MemoryMarshal.GetReference(span);
114-
ref T r1 = ref Unsafe.Add(ref r0, offset);
144+
ref T r1 = ref Unsafe.Add(ref r0, (IntPtr)(void*)offset);
115145

116146
return ref r1;
117147
}
@@ -165,11 +195,11 @@ public static unsafe int IndexOf<T>(this ReadOnlySpan<T> span, in T value)
165195
/// <returns>The number of occurrences of <paramref name="value"/> in <paramref name="span"/>.</returns>
166196
[Pure]
167197
[MethodImpl(MethodImplOptions.AggressiveInlining)]
168-
public static int Count<T>(this ReadOnlySpan<T> span, T value)
198+
public static unsafe int Count<T>(this ReadOnlySpan<T> span, T value)
169199
where T : IEquatable<T>
170200
{
171201
ref T r0 = ref MemoryMarshal.GetReference(span);
172-
IntPtr length = (IntPtr)span.Length;
202+
IntPtr length = (IntPtr)(void*)(uint)span.Length;
173203

174204
return SpanHelper.Count(ref r0, length, value);
175205
}
@@ -291,11 +321,11 @@ public static ReadOnlySpanTokenizer<T> Tokenize<T>(this ReadOnlySpan<T> span, T
291321
/// <remarks>The Djb2 hash is fully deterministic and with no random components.</remarks>
292322
[Pure]
293323
[MethodImpl(MethodImplOptions.AggressiveInlining)]
294-
public static int GetDjb2HashCode<T>(this ReadOnlySpan<T> span)
324+
public static unsafe int GetDjb2HashCode<T>(this ReadOnlySpan<T> span)
295325
where T : notnull
296326
{
297327
ref T r0 = ref MemoryMarshal.GetReference(span);
298-
IntPtr length = (IntPtr)span.Length;
328+
IntPtr length = (IntPtr)(void*)(uint)span.Length;
299329

300330
return SpanHelper.GetDjb2HashCode(ref r0, length);
301331
}

Microsoft.Toolkit.HighPerformance/Extensions/SpanExtensions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ public static ref T DangerousGetReference<T>(this Span<T> span)
4040
/// <remarks>This method doesn't do any bounds checks, therefore it is responsibility of the caller to ensure the <paramref name="i"/> parameter is valid.</remarks>
4141
[Pure]
4242
[MethodImpl(MethodImplOptions.AggressiveInlining)]
43-
public static ref T DangerousGetReferenceAt<T>(this Span<T> span, int i)
43+
public static unsafe ref T DangerousGetReferenceAt<T>(this Span<T> span, int i)
4444
{
4545
ref T r0 = ref MemoryMarshal.GetReference(span);
46-
ref T ri = ref Unsafe.Add(ref r0, i);
46+
ref T ri = ref Unsafe.Add(ref r0, (IntPtr)(void*)(uint)i);
4747

4848
return ref ri;
4949
}
@@ -140,11 +140,11 @@ public static unsafe int IndexOf<T>(this Span<T> span, ref T value)
140140
/// <returns>The number of occurrences of <paramref name="value"/> in <paramref name="span"/>.</returns>
141141
[Pure]
142142
[MethodImpl(MethodImplOptions.AggressiveInlining)]
143-
public static int Count<T>(this Span<T> span, T value)
143+
public static unsafe int Count<T>(this Span<T> span, T value)
144144
where T : IEquatable<T>
145145
{
146146
ref T r0 = ref MemoryMarshal.GetReference(span);
147-
IntPtr length = (IntPtr)span.Length;
147+
IntPtr length = (IntPtr)(void*)(uint)span.Length;
148148

149149
return SpanHelper.Count(ref r0, length, value);
150150
}
@@ -211,11 +211,11 @@ public static SpanTokenizer<T> Tokenize<T>(this Span<T> span, T separator)
211211
/// <remarks>The Djb2 hash is fully deterministic and with no random components.</remarks>
212212
[Pure]
213213
[MethodImpl(MethodImplOptions.AggressiveInlining)]
214-
public static int GetDjb2HashCode<T>(this Span<T> span)
214+
public static unsafe int GetDjb2HashCode<T>(this Span<T> span)
215215
where T : notnull
216216
{
217217
ref T r0 = ref MemoryMarshal.GetReference(span);
218-
IntPtr length = (IntPtr)span.Length;
218+
IntPtr length = (IntPtr)(void*)(uint)span.Length;
219219

220220
return SpanHelper.GetDjb2HashCode(ref r0, length);
221221
}

Microsoft.Toolkit.HighPerformance/Extensions/StringExtensions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public static ref char DangerousGetReference(this string text)
4848
/// <remarks>This method doesn't do any bounds checks, therefore it is responsibility of the caller to ensure the <paramref name="i"/> parameter is valid.</remarks>
4949
[Pure]
5050
[MethodImpl(MethodImplOptions.AggressiveInlining)]
51-
public static ref char DangerousGetReferenceAt(this string text, int i)
51+
public static unsafe ref char DangerousGetReferenceAt(this string text, int i)
5252
{
5353
#if NETCOREAPP3_1
5454
ref char r0 = ref Unsafe.AsRef(text.GetPinnableReference());
@@ -57,7 +57,7 @@ public static ref char DangerousGetReferenceAt(this string text, int i)
5757
#else
5858
ref char r0 = ref MemoryMarshal.GetReference(text.AsSpan());
5959
#endif
60-
ref char ri = ref Unsafe.Add(ref r0, i);
60+
ref char ri = ref Unsafe.Add(ref r0, (IntPtr)(void*)(uint)i);
6161

6262
return ref ri;
6363
}
@@ -91,10 +91,10 @@ private sealed class RawStringData
9191
/// <returns>The number of occurrences of <paramref name="c"/> in <paramref name="text"/>.</returns>
9292
[Pure]
9393
[MethodImpl(MethodImplOptions.AggressiveInlining)]
94-
public static int Count(this string text, char c)
94+
public static unsafe int Count(this string text, char c)
9595
{
9696
ref char r0 = ref text.DangerousGetReference();
97-
IntPtr length = (IntPtr)text.Length;
97+
IntPtr length = (IntPtr)(void*)(uint)text.Length;
9898

9999
return SpanHelper.Count(ref r0, length, c);
100100
}
@@ -157,10 +157,10 @@ public static ReadOnlySpanTokenizer<char> Tokenize(this string text, char separa
157157
/// <remarks>The Djb2 hash is fully deterministic and with no random components.</remarks>
158158
[Pure]
159159
[MethodImpl(MethodImplOptions.AggressiveInlining)]
160-
public static int GetDjb2HashCode(this string text)
160+
public static unsafe int GetDjb2HashCode(this string text)
161161
{
162162
ref char r0 = ref text.DangerousGetReference();
163-
IntPtr length = (IntPtr)text.Length;
163+
IntPtr length = (IntPtr)(void*)(uint)text.Length;
164164

165165
return SpanHelper.GetDjb2HashCode(ref r0, length);
166166
}

0 commit comments

Comments
 (0)