Skip to content

Commit ae0e4c1

Browse files
authored
Merge branch 'master' into feature/ibuffer-writer-stream2
2 parents ba19b76 + 15edbed commit ae0e4c1

File tree

411 files changed

+33319
-6497
lines changed

Some content is hidden

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

411 files changed

+33319
-6497
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

GazeInputTest/GazeInputTest.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@
157157
</PackageReference>
158158
</ItemGroup>
159159
<ItemGroup>
160-
<ProjectReference Include="..\Microsoft.Toolkit.UWP.Input.GazeInteraction\Microsoft.Toolkit.Uwp.Input.GazeInteraction.vcxproj">
161-
<Project>{a5e98964-45b1-442d-a07a-298a3221d81e}</Project>
160+
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.Input.GazeInteraction\Microsoft.Toolkit.Uwp.Input.GazeInteraction.csproj">
161+
<Project>{5bf75694-798a-43a0-8150-415de195359c}</Project>
162162
<Name>Microsoft.Toolkit.Uwp.Input.GazeInteraction</Name>
163163
</ProjectReference>
164164
</ItemGroup>

GazeInputTest/Properties/AssemblyInfo.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Reflection;
66
using System.Runtime.InteropServices;
77

8-
// General Information about an assembly is controlled through the following
8+
// General Information about an assembly is controlled through the following
99
// set of attributes. Change these attribute values to modify the information
1010
// associated with an assembly.
1111
[assembly: AssemblyTitle("GazeInputTest")]
@@ -20,13 +20,13 @@
2020
// Version information for an assembly consists of the following four values:
2121
//
2222
// Major Version
23-
// Minor Version
23+
// Minor Version
2424
// Build Number
2525
// Revision
2626
//
27-
// You can specify all the values or you can default the Build and Revision Numbers
27+
// You can specify all the values or you can default the Build and Revision Numbers
2828
// by using the '*' as shown below:
2929
// [assembly: AssemblyVersion("1.0.*")]
30-
//[assembly: AssemblyVersion("1.0.0.0")]
31-
//[assembly: AssemblyFileVersion("1.0.0.0")]
30+
// [assembly: AssemblyVersion("1.0.0.0")]
31+
// [assembly: AssemblyFileVersion("1.0.0.0")]
3232
[assembly: ComVisible(false)]

Microsoft.Toolkit.HighPerformance/Box{T}.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public static Box<T> GetFrom(object obj)
7878
ThrowInvalidCastExceptionForGetFrom();
7979
}
8080

81-
return Unsafe.As<Box<T>>(obj);
81+
return Unsafe.As<Box<T>>(obj)!;
8282
}
8383

8484
/// <summary>
@@ -94,7 +94,7 @@ public static Box<T> GetFrom(object obj)
9494
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9595
public static Box<T> DangerousGetFrom(object obj)
9696
{
97-
return Unsafe.As<Box<T>>(obj);
97+
return Unsafe.As<Box<T>>(obj)!;
9898
}
9999

100100
/// <summary>
@@ -108,7 +108,7 @@ public static bool TryGetFrom(object obj, [NotNullWhen(true)] out Box<T>? box)
108108
{
109109
if (obj.GetType() == typeof(T))
110110
{
111-
box = Unsafe.As<Box<T>>(obj);
111+
box = Unsafe.As<Box<T>>(obj)!;
112112

113113
return true;
114114
}
@@ -145,7 +145,7 @@ public static implicit operator Box<T>(T value)
145145
// manually be implemented in the Box<T> type. For instance, boxing a float
146146
// and calling ToString() on it directly, on its boxed object or on a Box<T>
147147
// reference retrieved from it will produce the same result in all cases.
148-
return Unsafe.As<Box<T>>(value);
148+
return Unsafe.As<Box<T>>(value)!;
149149
}
150150

151151
/// <inheritdoc/>

Microsoft.Toolkit.HighPerformance/Buffers/ArrayPoolBufferWriter{T}.cs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Runtime.InteropServices;
1111
using Microsoft.Toolkit.HighPerformance.Buffers.Views;
1212
using Microsoft.Toolkit.HighPerformance.Extensions;
13+
using Microsoft.Toolkit.HighPerformance.Helpers.Internals;
1314

1415
namespace Microsoft.Toolkit.HighPerformance.Buffers
1516
{
@@ -24,7 +25,7 @@ namespace Microsoft.Toolkit.HighPerformance.Buffers
2425
/// the arrays in use are rented from the shared <see cref="ArrayPool{T}"/> instance,
2526
/// and that <see cref="ArrayPoolBufferWriter{T}"/> is also available on .NET Standard 2.0.
2627
/// </remarks>
27-
[DebuggerTypeProxy(typeof(ArrayPoolBufferWriterDebugView<>))]
28+
[DebuggerTypeProxy(typeof(MemoryDebugView<>))]
2829
[DebuggerDisplay("{ToString(),raw}")]
2930
public sealed class ArrayPoolBufferWriter<T> : IBuffer<T>, IMemoryOwner<T>
3031
{
@@ -233,15 +234,15 @@ public void Advance(int count)
233234
/// <inheritdoc/>
234235
public Memory<T> GetMemory(int sizeHint = 0)
235236
{
236-
CheckAndResizeBuffer(sizeHint);
237+
CheckBufferAndEnsureCapacity(sizeHint);
237238

238239
return this.array.AsMemory(this.index);
239240
}
240241

241242
/// <inheritdoc/>
242243
public Span<T> GetSpan(int sizeHint = 0)
243244
{
244-
CheckAndResizeBuffer(sizeHint);
245+
CheckBufferAndEnsureCapacity(sizeHint);
245246

246247
return this.array.AsSpan(this.index);
247248
}
@@ -251,9 +252,11 @@ public Span<T> GetSpan(int sizeHint = 0)
251252
/// </summary>
252253
/// <param name="sizeHint">The minimum number of items to ensure space for in <see cref="array"/>.</param>
253254
[MethodImpl(MethodImplOptions.AggressiveInlining)]
254-
private void CheckAndResizeBuffer(int sizeHint)
255+
private void CheckBufferAndEnsureCapacity(int sizeHint)
255256
{
256-
if (this.array is null)
257+
T[]? array = this.array;
258+
259+
if (array is null)
257260
{
258261
ThrowObjectDisposedException();
259262
}
@@ -268,12 +271,32 @@ private void CheckAndResizeBuffer(int sizeHint)
268271
sizeHint = 1;
269272
}
270273

271-
if (sizeHint > FreeCapacity)
274+
if (sizeHint > array!.Length - this.index)
272275
{
273-
int minimumSize = this.index + sizeHint;
276+
ResizeBuffer(sizeHint);
277+
}
278+
}
274279

275-
this.pool.Resize(ref this.array, minimumSize);
280+
/// <summary>
281+
/// Resizes <see cref="array"/> to ensure it can fit the specified number of new items.
282+
/// </summary>
283+
/// <param name="sizeHint">The minimum number of items to ensure space for in <see cref="array"/>.</param>
284+
[MethodImpl(MethodImplOptions.NoInlining)]
285+
private void ResizeBuffer(int sizeHint)
286+
{
287+
int minimumSize = this.index + sizeHint;
288+
289+
// The ArrayPool<T> class has a maximum threshold of 1024 * 1024 for the maximum length of
290+
// pooled arrays, and once this is exceeded it will just allocate a new array every time
291+
// of exactly the requested size. In that case, we manually round up the requested size to
292+
// the nearest power of two, to ensure that repeated consecutive writes when the array in
293+
// use is bigger than that threshold don't end up causing a resize every single time.
294+
if (minimumSize > 1024 * 1024)
295+
{
296+
minimumSize = BitOperations.RoundUpPowerOfTwo(minimumSize);
276297
}
298+
299+
this.pool.Resize(ref this.array, minimumSize);
277300
}
278301

279302
/// <inheritdoc/>
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Buffers;
7+
using System.Runtime.CompilerServices;
8+
using System.Runtime.InteropServices;
9+
using Microsoft.Toolkit.HighPerformance.Buffers.Internals.Interfaces;
10+
using Microsoft.Toolkit.HighPerformance.Extensions;
11+
using RuntimeHelpers = Microsoft.Toolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
12+
13+
namespace Microsoft.Toolkit.HighPerformance.Buffers.Internals
14+
{
15+
/// <summary>
16+
/// A custom <see cref="MemoryManager{T}"/> that casts data from a <typeparamref name="TFrom"/> array, to <typeparamref name="TTo"/> values.
17+
/// </summary>
18+
/// <typeparam name="TFrom">The source type of items to read.</typeparam>
19+
/// <typeparam name="TTo">The target type to cast the source items to.</typeparam>
20+
internal sealed class ArrayMemoryManager<TFrom, TTo> : MemoryManager<TTo>, IMemoryManager
21+
where TFrom : unmanaged
22+
where TTo : unmanaged
23+
{
24+
/// <summary>
25+
/// The source <typeparamref name="TFrom"/> array to read data from.
26+
/// </summary>
27+
private readonly TFrom[] array;
28+
29+
/// <summary>
30+
/// The starting offset within <see name="array"/>.
31+
/// </summary>
32+
private readonly int offset;
33+
34+
/// <summary>
35+
/// The original used length for <see name="array"/>.
36+
/// </summary>
37+
private readonly int length;
38+
39+
/// <summary>
40+
/// Initializes a new instance of the <see cref="ArrayMemoryManager{TFrom, TTo}"/> class.
41+
/// </summary>
42+
/// <param name="array">The source <typeparamref name="TFrom"/> array to read data from.</param>
43+
/// <param name="offset">The starting offset within <paramref name="array"/>.</param>
44+
/// <param name="length">The original used length for <paramref name="array"/>.</param>
45+
public ArrayMemoryManager(TFrom[] array, int offset, int length)
46+
{
47+
this.array = array;
48+
this.offset = offset;
49+
this.length = length;
50+
}
51+
52+
/// <inheritdoc/>
53+
public override Span<TTo> GetSpan()
54+
{
55+
#if SPAN_RUNTIME_SUPPORT
56+
ref TFrom r0 = ref this.array.DangerousGetReferenceAt(this.offset);
57+
ref TTo r1 = ref Unsafe.As<TFrom, TTo>(ref r0);
58+
int length = RuntimeHelpers.ConvertLength<TFrom, TTo>(this.length);
59+
60+
return MemoryMarshal.CreateSpan(ref r1, length);
61+
#else
62+
Span<TFrom> span = this.array.AsSpan(this.offset, this.length);
63+
64+
// We rely on MemoryMarshal.Cast here to deal with calculating the effective
65+
// size of the new span to return. This will also make the behavior consistent
66+
// for users that are both using this type as well as casting spans directly.
67+
return MemoryMarshal.Cast<TFrom, TTo>(span);
68+
#endif
69+
}
70+
71+
/// <inheritdoc/>
72+
public override unsafe MemoryHandle Pin(int elementIndex = 0)
73+
{
74+
if ((uint)elementIndex >= (uint)(this.length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>()))
75+
{
76+
ThrowArgumentOutOfRangeExceptionForInvalidIndex();
77+
}
78+
79+
int
80+
bytePrefix = this.offset * Unsafe.SizeOf<TFrom>(),
81+
byteSuffix = elementIndex * Unsafe.SizeOf<TTo>(),
82+
byteOffset = bytePrefix + byteSuffix;
83+
84+
GCHandle handle = GCHandle.Alloc(this.array, GCHandleType.Pinned);
85+
86+
ref TFrom r0 = ref this.array.DangerousGetReference();
87+
ref byte r1 = ref Unsafe.As<TFrom, byte>(ref r0);
88+
ref byte r2 = ref Unsafe.Add(ref r1, byteOffset);
89+
void* pi = Unsafe.AsPointer(ref r2);
90+
91+
return new MemoryHandle(pi, handle);
92+
}
93+
94+
/// <inheritdoc/>
95+
public override void Unpin()
96+
{
97+
}
98+
99+
/// <inheritdoc/>
100+
protected override void Dispose(bool disposing)
101+
{
102+
}
103+
104+
/// <inheritdoc/>
105+
public Memory<T> GetMemory<T>(int offset, int length)
106+
where T : unmanaged
107+
{
108+
// We need to calculate the right offset and length of the new Memory<T>. The local offset
109+
// is the original offset into the wrapped TFrom[] array, while the input offset is the one
110+
// with respect to TTo items in the Memory<TTo> instance that is currently being cast.
111+
int
112+
absoluteOffset = this.offset + RuntimeHelpers.ConvertLength<TTo, TFrom>(offset),
113+
absoluteLength = RuntimeHelpers.ConvertLength<TTo, TFrom>(length);
114+
115+
// We have a special handling in cases where the user is circling back to the original type
116+
// of the wrapped array. In this case we can just return a memory wrapping that array directly,
117+
// with offset and length being adjusted, without the memory manager indirection.
118+
if (typeof(T) == typeof(TFrom))
119+
{
120+
return (Memory<T>)(object)this.array.AsMemory(absoluteOffset, absoluteLength);
121+
}
122+
123+
return new ArrayMemoryManager<TFrom, T>(this.array, absoluteOffset, absoluteLength).Memory;
124+
}
125+
126+
/// <summary>
127+
/// Throws an <see cref="ArgumentOutOfRangeException"/> when the target index for <see cref="Pin"/> is invalid.
128+
/// </summary>
129+
private static void ThrowArgumentOutOfRangeExceptionForInvalidIndex()
130+
{
131+
throw new ArgumentOutOfRangeException("elementIndex", "The input index is not in the valid range");
132+
}
133+
}
134+
}

0 commit comments

Comments
 (0)