Skip to content

Commit 4da4b24

Browse files
authored
Merge branch 'master' into feature/mvvm-toolkit-part2
2 parents 1360f91 + e4da174 commit 4da4b24

File tree

12 files changed

+224
-85
lines changed

12 files changed

+224
-85
lines changed

Microsoft.Toolkit.HighPerformance/Microsoft.Toolkit.HighPerformance.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@
7878

7979
<!-- NETCORE_RUNTIME: to avoid issues with APIs that assume a specific memory layout, we define a
8080
.NET Core runtime constant to indicate the either .NET Core 2.1 or .NET Core 3.1. These are
81-
runtimes with the same overall memory layout for objects (in particular: strings, SZ arrays
81+
runtimes with the same overall memory layout for objects (in particular: strings, SZ arrays,
8282
and 2D arrays). We can use this constant to make sure that APIs that are exclusively available
83-
for .NET Standard targets do not make any assumtpion of any internals of the runtime being
83+
for .NET Standard targets do not make any assumption of any internals of the runtime being
8484
actually used by the consumers. -->
8585
<DefineConstants>NETSTANDARD2_1_OR_GREATER;SPAN_RUNTIME_SUPPORT;NETCORE_RUNTIME</DefineConstants>
8686
</PropertyGroup>

Microsoft.Toolkit.Uwp.SampleApp/readme.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This document describes how to add a new sample page for a new control you want
66

77

88
## 1. Add Sample page and .bind template
9-
First you need to create a Xaml page in the folder /SamplePages/YourControl. This will be the logical page used to by the app to navigate to the sample and containe code.
9+
First you need to create a Xaml page in the folder /SamplePages/YourControl. This will be the logical page used to by the app to navigate to the sample and contain code.
1010

1111
If providing 'live' XAML, a .bind file is loaded and dynamically fed to the XamlReader.Load method to convert into actual controls. This changes a few things about how samples need to be written (detailed below), but allows developers to actually change the sample and see the results live.
1212

@@ -39,11 +39,11 @@ You can define "interactive" values in this file. The value types can be:
3939
* String: You want the user to provide a text. The string is built like this @[Name:**String**:Default value]
4040
* Slider: You want the user to provide a double value. The string is built like this @[Name:**Slider**:Default value:min-max]
4141
* DoubleSlider: Same as slider but with double values (0.01 precision)
42-
* TimeSpan: You want the user to provide a duration. The string is built like this (all values in miliseconds) @[Name:**TimeSpan**:DefaultValue:min-max]
42+
* TimeSpan: You want the user to provide a duration. The string is built like this (all values in milliseconds) @[Name:**TimeSpan**:DefaultValue:min-max]
4343
* Enum: You want the user to provide a enum value. The string is built like this @[Name:**Enum**:EnumType.DefaultValue]
4444
* Brush: You want the user to select a color from a list. The string is built like this @[Name:**Brush**:Black]
4545
* Bool: You want the user to enable or disable a property. The string is built like this @[Name:**Bool**:True]
46-
* Thickness: You want the user to provide a Thicknes. The string is built like this @[Name:**Thickness**:0,20,10,0]
46+
* Thickness: You want the user to provide a Thickness. The string is built like this @[Name:**Thickness**:0,20,10,0]
4747

4848
The `Property Name` can also contain spaces, but these will be removed from the property name used for accessing the value in the property bag for any binding/access, see below.
4949

@@ -86,7 +86,7 @@ Value="@[Value:Slider:0:0-180]@"
8686
## 3. Have a *'Shallow Copy'* of your example in the sample page
8787
Even though the sample page content is ignored and the dynamic template injected, for the XamlReader to access some classes, a reference to the item is sometimes needed in the hosting app for it to be accessible. (I assume it's an optimization thing.)
8888

89-
Therefore, for any new control/extension, you should still have a simplified snippet of it contained in the sample page compiled/loaded by the app. You should remove names, events, and properties (unless extensions) from these so the namespace isn't accidently polluted. If you re-use the same control, you don't have to include it twice.
89+
Therefore, for any new control/extension, you should still have a simplified snippet of it contained in the sample page compiled/loaded by the app. You should remove names, events, and properties (unless extensions) from these so the namespace isn't accidentally polluted. If you re-use the same control, you don't have to include it twice.
9090

9191

9292
## 4. For Events/Resource Templates: Have your sample page implement the **IXamlRendererListener** interface
@@ -163,7 +163,7 @@ Select the category where you want your page to be listed and add the following
163163

164164
Some features used by samples aren't available on all the OS versions that the Sample App runs on. In order to make sure a sample is valid for the host OS, add the `ApiCheck` key/value in your JSON definition.
165165

166-
The value is a string which is the fully-qualified typename to check for the presense of. You can also accompany this with the `BadgeUpdateVersionRequred` which uses the string provided to show a short message on the sample information so uplevel implementors know the minimum version required.
166+
The value is a string which is the fully-qualified typename to check for the presence of. You can also accompany this with the `BadgeUpdateVersionRequred` which uses the string provided to show a short message on the sample information so uplevel implementors know the minimum version required.
167167

168168
```json
169169
{
@@ -190,7 +190,7 @@ Use the DocumentationUrl property to add a link to the raw documentation in *sam
190190

191191
> NOTE: The documentation is also packaged with the sample app. If there is no network connection, or the documentation is not yet on github, the sample app will use the packaged version
192192

193-
> NOTE: To test your documentation in the sample app while running in debug mode, the docs repository will need to be cloned in the same folder as this repository and named **WindowsCommunityToolkitDocs**. For exaple, this folder structure works best:
193+
> NOTE: To test your documentation in the sample app while running in debug mode, the docs repository will need to be cloned in the same folder as this repository and named **WindowsCommunityToolkitDocs**. For example, this folder structure works best:
194194
> ```
195195
> repositories
196196
> ├── WindowsCommunityToolkit
@@ -199,4 +199,4 @@ Use the DocumentationUrl property to add a link to the raw documentation in *sam
199199

200200
### CodeUrl
201201

202-
The value of CodeUrl is modified when the app is built in release mode. The branch is automaticaly changed to **master**. This allows you to test the link in debug while pointing to dev.
202+
The value of CodeUrl is modified when the app is built in release mode. The branch is automatically changed to **master**. This allows you to test the link in debug while pointing to dev.

Microsoft.Toolkit.Uwp.UI.Controls/Microsoft.Toolkit.Uwp.UI.Controls.csproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77
This library provides XAML templated controls. It is part of the Windows Community Toolkit.
88

99
Controls:
10-
- AdaptiveGridView: Presents items in a evenly-spaced set of columns to fill the total available space.
10+
- AdaptiveGridView: Presents items in an evenly-spaced set of columns to fill the total available space.
1111
- BladeView: Provides a horizontal collection of blades for master-detail scenarios.
1212
- CameraPreview: Easily preview video from camera sources and get realtime frames from the selected source.
1313
- Carousel: Presents items in a carousel control.
1414
- DockPanel: Define areas where you can arrange child elements either horizontally or vertically, relative to each other.
15-
- DropShadowPanel: DropShadowPanel contol allows the creation of a DropShadow for any Xaml FrameworkElement in markup.
15+
- DropShadowPanel: DropShadowPanel control allows the creation of a DropShadow for any Xaml FrameworkElement in markup.
1616
- Expander: Expander allows user to show/hide content based on a boolean state.
1717
- GridSplitter: A the control that redistributes space between columns or rows of a Grid control.
1818
- HeaderedContentControl: Provides a header to content.
1919
- HeaderedItemsControl: Provides a header to items.
20-
- HeaderedTextBlock: Provide a header for read only text.
20+
- HeaderedTextBlock: Provide a header for read-only text.
2121
- ImageCropper: ImageCropper control allows user to crop image freely.
2222
- ImageEx: Images are downloaded asynchronously showing a load indicator and can be stored in a local cache.
2323
- InAppNotification: Show local notifications in your application.
@@ -32,12 +32,12 @@
3232
- RangeSelector: "Double slider" control for range values.
3333
- RemoteDevicePicker: Remote Device Picker Control for Project Rome.
3434
- RotatorTile: Rotates through a set of items one-by-one like a live-tile.
35-
- ScrollHeader: A UI control that works as a ListView or GridView header control with quick return, sticky and fade behavior.
35+
- ScrollHeader: A UI control that works as a ListView or GridView header control with quick return, sticky, and fade behavior.
3636
- StaggeredPanel: Layout of items in a column approach where an item will be added to whichever column has used the least amount of space.
3737
- TextToolbar: A Toolbar for Editing Text attached to a RichEditBox. It can format RTF, Markdown, or use a Custom Formatter.
3838
- TileControl: A ContentControl that show an image repeated many times.
3939
- TokenizingTextBox: An AutoSuggestBox like control which places entered input into easily removed containers for contacts or tags.
40-
- UniformGrid: Presents items in a evenly-spaced set of rows or columns to fill the total available display space.
40+
- UniformGrid: Presents items in an evenly-spaced set of rows or columns to fill the total available display space.
4141
- WrapPanel: Positions child elements in sequential position from left to right and breaks content to the next line.
4242
</Description>
4343
<PackageTags>UWP Toolkit Windows Controls XAML Range WrapPanel Adaptive Markdown BladeView Blade CameraPreview Camera Carousel DockPanel DropShadow Expander GridSplitter HeaderedContent ImageEx InAppNotification InfiniteCanvas Master Details MasterDetails Orbit Radial Gauge RadiaGauge RadialProgressBar Scroll ScrollHeader StaggeredPanel Staggered Tile Tokenizing TextBox UniformGrid Uniform Grid</PackageTags>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
10+
namespace UnitTests.HighPerformance.Shared.Buffers.Internals
11+
{
12+
/// <summary>
13+
/// An owner for a buffer of an unmanaged type, recycling <see cref="byte"/> arrays to save memory.
14+
/// </summary>
15+
/// <typeparam name="T">The type of items to store in the rented buffers.</typeparam>
16+
internal sealed unsafe class UnmanagedSpanOwner<T> : MemoryManager<T>
17+
where T : unmanaged
18+
{
19+
/// <summary>
20+
/// The size of the current instance
21+
/// </summary>
22+
private readonly int length;
23+
24+
/// <summary>
25+
/// The pointer to the underlying <see cref="byte"/> array.
26+
/// </summary>
27+
private IntPtr ptr;
28+
29+
/// <summary>
30+
/// Initializes a new instance of the <see cref="UnmanagedSpanOwner{T}"/> class.
31+
/// </summary>
32+
/// <param name="size">The size of the buffer to rent.</param>
33+
public UnmanagedSpanOwner(int size)
34+
{
35+
this.ptr = Marshal.AllocHGlobal(size * Unsafe.SizeOf<T>());
36+
this.length = size;
37+
}
38+
39+
/// <summary>
40+
/// Gets the length of the buffer in use.
41+
/// </summary>
42+
public int Length => this.length;
43+
44+
/// <summary>
45+
/// Gets a pointer to the start of the buffer in use.
46+
/// </summary>
47+
public T* Ptr => (T*)this.ptr;
48+
49+
/// <inheritdoc/>
50+
protected override void Dispose(bool disposing)
51+
{
52+
IntPtr ptr = this.ptr;
53+
54+
if (ptr == IntPtr.Zero)
55+
{
56+
return;
57+
}
58+
59+
this.ptr = IntPtr.Zero;
60+
61+
Marshal.FreeHGlobal(ptr);
62+
}
63+
64+
/// <inheritdoc/>
65+
public override Span<T> GetSpan()
66+
{
67+
return new Span<T>((void*)this.ptr, this.length);
68+
}
69+
70+
/// <inheritdoc/>
71+
public override MemoryHandle Pin(int elementIndex = 0)
72+
{
73+
throw new NotImplementedException();
74+
}
75+
76+
/// <inheritdoc/>
77+
public override void Unpin()
78+
{
79+
throw new NotImplementedException();
80+
}
81+
}
82+
}

UnitTests/UnitTests.HighPerformance.Shared/Extensions/Test_ReadOnlySpanExtensions.Count.cs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
using System.Runtime.InteropServices;
99
using Microsoft.Toolkit.HighPerformance.Extensions;
1010
using Microsoft.VisualStudio.TestTools.UnitTesting;
11+
using UnitTests.HighPerformance.Shared.Buffers.Internals;
12+
13+
#nullable enable
1114

1215
namespace UnitTests.HighPerformance.Extensions
1316
{
@@ -168,15 +171,15 @@ public void Test_ReadOnlySpanExtensions_FilledCount64()
168171
/// <typeparam name="T">The type to test.</typeparam>
169172
/// <param name="value">The target value to look for.</param>
170173
/// <param name="provider">The function to use to create random data.</param>
171-
private static void TestForType<T>(T value, Func<int, T, T[]> provider)
174+
private static void TestForType<T>(T value, Func<int, T, UnmanagedSpanOwner<T>> provider)
172175
where T : unmanaged, IEquatable<T>
173176
{
174177
foreach (var count in TestCounts)
175178
{
176-
T[] data = provider(count, value);
179+
using UnmanagedSpanOwner<T> data = provider(count, value);
177180

178-
int result = data.Count(value);
179-
int expected = CountWithForeach(data, value);
181+
int result = data.GetSpan().Count(value);
182+
int expected = CountWithForeach(data.GetSpan(), value);
180183

181184
Assert.AreEqual(result, expected, $"Failed {typeof(T)} test with count {count}: got {result} instead of {expected}");
182185
}
@@ -214,24 +217,26 @@ private static int CountWithForeach<T>(ReadOnlySpan<T> span, T value)
214217
/// <param name="value">The value to look for.</param>
215218
/// <returns>An array of random <typeparamref name="T"/> elements.</returns>
216219
[Pure]
217-
private static T[] CreateRandomData<T>(int count, T value)
220+
private static UnmanagedSpanOwner<T> CreateRandomData<T>(int count, T value)
218221
where T : unmanaged
219222
{
220223
var random = new Random(count);
221224

222-
T[] data = new T[count];
225+
UnmanagedSpanOwner<T> data = new UnmanagedSpanOwner<T>(count);
223226

224-
foreach (ref byte n in MemoryMarshal.AsBytes(data.AsSpan()))
227+
foreach (ref byte n in MemoryMarshal.AsBytes(data.GetSpan()))
225228
{
226229
n = (byte)random.Next(0, byte.MaxValue);
227230
}
228231

229232
// Fill at least 20% of the items with a matching value
230233
int minimum = count / 20;
231234

235+
Span<T> span = data.GetSpan();
236+
232237
for (int i = 0; i < minimum; i++)
233238
{
234-
data[random.Next(0, count)] = value;
239+
span[random.Next(0, count)] = value;
235240
}
236241

237242
return data;
@@ -245,12 +250,12 @@ private static T[] CreateRandomData<T>(int count, T value)
245250
/// <param name="value">The value to use to populate the array.</param>
246251
/// <returns>An array of <typeparamref name="T"/> elements.</returns>
247252
[Pure]
248-
private static T[] CreateFilledData<T>(int count, T value)
253+
private static UnmanagedSpanOwner<T> CreateFilledData<T>(int count, T value)
249254
where T : unmanaged
250255
{
251-
T[] data = new T[count];
256+
UnmanagedSpanOwner<T> data = new UnmanagedSpanOwner<T>(count);
252257

253-
data.AsSpan().Fill(value);
258+
data.GetSpan().Fill(value);
254259

255260
return data;
256261
}

UnitTests/UnitTests.HighPerformance.Shared/Extensions/Test_ReadOnlySpanExtensions.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ public partial class Test_ReadOnlySpanExtensions
1818
[TestMethod]
1919
public void Test_ReadOnlySpanExtensions_DangerousGetReference()
2020
{
21-
ReadOnlySpan<int> data = CreateRandomData<int>(12, default).AsSpan();
21+
using var owner = CreateRandomData<int>(12, default);
22+
23+
ReadOnlySpan<int> data = owner.GetSpan();
2224

2325
ref int r0 = ref data.DangerousGetReference();
2426
ref int r1 = ref Unsafe.AsRef(data[0]);
@@ -30,7 +32,9 @@ public void Test_ReadOnlySpanExtensions_DangerousGetReference()
3032
[TestMethod]
3133
public void Test_ReadOnlySpanExtensions_DangerousGetReferenceAt_Zero()
3234
{
33-
ReadOnlySpan<int> data = CreateRandomData<int>(12, default).AsSpan();
35+
using var owner = CreateRandomData<int>(12, default);
36+
37+
ReadOnlySpan<int> data = owner.GetSpan();
3438

3539
ref int r0 = ref data.DangerousGetReference();
3640
ref int r1 = ref data.DangerousGetReferenceAt(0);
@@ -42,7 +46,9 @@ public void Test_ReadOnlySpanExtensions_DangerousGetReferenceAt_Zero()
4246
[TestMethod]
4347
public void Test_ReadOnlySpanExtensions_DangerousGetReferenceAt_Index()
4448
{
45-
ReadOnlySpan<int> data = CreateRandomData<int>(12, default).AsSpan();
49+
using var owner = CreateRandomData<int>(12, default);
50+
51+
ReadOnlySpan<int> data = owner.GetSpan();
4652

4753
ref int r0 = ref data.DangerousGetReferenceAt(5);
4854
ref int r1 = ref Unsafe.AsRef(data[5]);

0 commit comments

Comments
 (0)