From a1cf55c9edab2c50914f9b73edb0f7924e5a443c Mon Sep 17 00:00:00 2001 From: Docs Allowlist Management Date: Tue, 30 Aug 2022 13:03:47 +0000 Subject: [PATCH 01/10] remove ms.prod = community-toolkit and replace with ms.prod = dotnet-communitytoolkit paired with ms.technology = windows-community-toolkit --- docs/docfx.json | 3 ++- dotnet/docfx.json | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/docfx.json b/docs/docfx.json index 004cad89e..2ffa767fa 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -33,6 +33,7 @@ "overwrite": [], "externalReference": [], "globalMetadata": { + "ms.technology": "windows-community-toolkit", "titleSuffix": "Windows Community Toolkit", "searchScope": [ "windows-toolkit" @@ -42,7 +43,7 @@ "feedback_product_url": "https://github.com/windows-toolkit/WindowsCommunityToolkit/issues", "uhfHeaderId": "MSDocsHeader-UWP-Community", "ms.topic": "article", - "ms.prod": "community-toolkit", + "ms.prod": "dotnet-communitytoolkit", "products": ["https://authoring-docs-microsoft.poolparty.biz/devrel/bcbcbad5-4208-4783-8035-8481272c98b8"], "keywords": "windows uwp community toolkit", "author": "michael-hawker", diff --git a/dotnet/docfx.json b/dotnet/docfx.json index c7991b8b3..dc525fd70 100644 --- a/dotnet/docfx.json +++ b/dotnet/docfx.json @@ -49,9 +49,9 @@ "extendBreadcrumb": true, "apiPlatform": "dotnet", "ms.topic": "managed-reference", - "ms.prod": "community-toolkit", + "ms.prod": "dotnet-communitytoolkit", "products": ["https://authoring-docs-microsoft.poolparty.biz/devrel/bcbcbad5-4208-4783-8035-8481272c98b8"], - "ms.technology": "windows-toolkit", + "ms.technology": "windows-community-toolkit", "ms.author": "nikolame", "author": "dotnet-bot" }, From 8f81658c2b03afbc8dfa0e4da3fdfdda3cc51503 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Tue, 31 Jan 2023 12:17:56 -0800 Subject: [PATCH 02/10] Add .NET Community Toolkit redirects (#679) * Add .NET Community Toolkit redirects * Add docs/ root to all source paths * Remove .NET Community Toolkit docs * Delete old MS Graph docs * Remove redirect_document_id properties --- .openpublishing.redirection.json | 113 ++- .../providers/InteractiveProviderBehavior.md | 60 -- .../graph/providers/MockProviderBehavior.md | 43 - docs/developer-tools/Guard.md | 136 --- docs/developer-tools/ThrowHelper.md | 165 ---- docs/diagnostics/Introduction.md | 39 - docs/graph/authentication/custom.md | 50 -- docs/graph/authentication/msal.md | 61 -- docs/graph/authentication/windows.md | 155 ---- docs/high-performance/Introduction.md | 65 -- docs/high-performance/Memory2D.md | 92 -- docs/high-performance/MemoryOwner.md | 106 --- docs/high-performance/ParallelHelper.md | 102 --- docs/high-performance/Ref.md | 91 -- docs/high-performance/Span2D.md | 116 --- docs/high-performance/SpanOwner.md | 69 -- docs/high-performance/StringPool.md | 47 - docs/mvvm/AsyncRelayCommand.md | 83 -- docs/mvvm/Introduction.md | 82 -- docs/mvvm/Ioc.md | 155 ---- docs/mvvm/Messenger.md | 141 --- docs/mvvm/MigratingFromMvvmBasic.md | 170 ---- docs/mvvm/MigratingFromMvvmLight.md | 807 ------------------ docs/mvvm/ObservableObject.md | 107 --- docs/mvvm/ObservableRecipient.md | 63 -- docs/mvvm/ObservableValidator.md | 160 ---- docs/mvvm/PuttingThingsTogether.md | 465 ---------- docs/mvvm/RelayCommand.md | 74 -- 28 files changed, 98 insertions(+), 3719 deletions(-) delete mode 100644 docs/archive/graph/providers/InteractiveProviderBehavior.md delete mode 100644 docs/archive/graph/providers/MockProviderBehavior.md delete mode 100644 docs/developer-tools/Guard.md delete mode 100644 docs/developer-tools/ThrowHelper.md delete mode 100644 docs/diagnostics/Introduction.md delete mode 100644 docs/graph/authentication/custom.md delete mode 100644 docs/graph/authentication/msal.md delete mode 100644 docs/graph/authentication/windows.md delete mode 100644 docs/high-performance/Introduction.md delete mode 100644 docs/high-performance/Memory2D.md delete mode 100644 docs/high-performance/MemoryOwner.md delete mode 100644 docs/high-performance/ParallelHelper.md delete mode 100644 docs/high-performance/Ref.md delete mode 100644 docs/high-performance/Span2D.md delete mode 100644 docs/high-performance/SpanOwner.md delete mode 100644 docs/high-performance/StringPool.md delete mode 100644 docs/mvvm/AsyncRelayCommand.md delete mode 100644 docs/mvvm/Introduction.md delete mode 100644 docs/mvvm/Ioc.md delete mode 100644 docs/mvvm/Messenger.md delete mode 100644 docs/mvvm/MigratingFromMvvmBasic.md delete mode 100644 docs/mvvm/MigratingFromMvvmLight.md delete mode 100644 docs/mvvm/ObservableObject.md delete mode 100644 docs/mvvm/ObservableRecipient.md delete mode 100644 docs/mvvm/ObservableValidator.md delete mode 100644 docs/mvvm/PuttingThingsTogether.md delete mode 100644 docs/mvvm/RelayCommand.md diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 62d981484..fb4cff05f 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1,29 +1,112 @@ { "redirections": [ { - "source_path": "archive/graph/providers/InteractiveProviderBehavior.md", - "redirect_url": "/graph/providers/interactiveproviderbehavior", - "redirect_document_id": true + "source_path": "docs/archive/graph/providers/InteractiveProviderBehavior.md", + "redirect_url": "/graph/providers/interactiveproviderbehavior" }, { - "source_path": "archive/graph/providers/MockProviderBehavior.md", - "redirect_url": "/graph/providers/mockproviderbehavior", - "redirect_document_id": true + "source_path": "docs/archive/graph/providers/MockProviderBehavior.md", + "redirect_url": "/graph/providers/mockproviderbehavior" }, { - "source_path": "graph/authentication/msal.md", - "redirect_url": "/graph/authentication/msalprovider", - "redirect_document_id": true + "source_path": "docs/graph/authentication/msal.md", + "redirect_url": "/graph/authentication/msalprovider" }, { - "source_path": "graph/authentication/windows.md", - "redirect_url": "/graph/authentication/windowsprovider", - "redirect_document_id": true + "source_path": "docs/graph/authentication/windows.md", + "redirect_url": "/graph/authentication/windowsprovider" }, { - "source_path": "graph/authentication/custom.md", - "redirect_url": "/graph/authentication/iprovider", - "redirect_document_id": true + "source_path": "docs/graph/authentication/custom.md", + "redirect_url": "/graph/authentication/iprovider" + }, + { + "source_path": "docs/mvvm/Introduction.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/" + }, + { + "source_path": "docs/mvvm/ObservableObject.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/observableobject" + }, + { + "source_path": "docs/mvvm/ObservableRecipient.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/observablerecipient" + }, + { + "source_path": "docs/mvvm/ObservableValidator.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/observablevalidator" + }, + { + "source_path": "docs/mvvm/RelayCommand.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/relaycommand" + }, + { + "source_path": "docs/mvvm/AsyncRelayCommand.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/asyncrelaycommand" + }, + { + "source_path": "docs/mvvm/Messenger.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/messenger" + }, + { + "source_path": "docs/mvvm/Ioc.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/ioc" + }, + { + "source_path": "docs/mvvm/PuttingThingsTogether.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/puttingthingstogether" + }, + { + "source_path": "docs/mvvm/MigratingFromMvvmLight.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/migratingfrommvvmlight" + }, + { + "source_path": "docs/mvvm/MigratingFromMvvmBasic.md", + "redirect_url": "/dotnet/communitytoolkit/mvvm/migratingfrommvvmbasic" + }, + { + "source_path": "docs/high-performance/Introduction.md", + "redirect_url": "/dotnet/communitytoolkit/high-performance/introduction" + }, + { + "source_path": "docs/high-performance/MemoryOwner.md", + "redirect_url": "/dotnet/communitytoolkit/high-performance/memoryowner" + }, + { + "source_path": "docs/high-performance/SpanOwner.md", + "redirect_url": "/dotnet/communitytoolkit/high-performance/spanowner" + }, + { + "source_path": "docs/high-performance/StringPool.md", + "redirect_url": "/dotnet/communitytoolkit/high-performance/stringpool" + }, + { + "source_path": "docs/high-performance/Memory2D.md", + "redirect_url": "/dotnet/communitytoolkit/high-performance/memory2d" + }, + { + "source_path": "docs/high-performance/Span2D.md", + "redirect_url": "/dotnet/communitytoolkit/high-performance/span2d" + }, + { + "source_path": "docs/high-performance/ParallelHelper.md", + "redirect_url": "/dotnet/communitytoolkit/high-performance/parallelhelper" + }, + { + "source_path": "docs/high-performance/Ref.md", + "redirect_url": "/dotnet/communitytoolkit/high-performance/ref" + }, + { + "source_path": "docs/diagnostics/Introduction.md", + "redirect_url": "/dotnet/communitytoolkit/diagnostics/introduction" + }, + { + "source_path": "docs/developer-tools/Guard.md", + "redirect_url": "/dotnet/communitytoolkit/diagnostics/guard" + }, + { + "source_path": "docs/developer-tools/ThrowHelper.md", + "redirect_url": "/dotnet/communitytoolkit/diagnostics/throwhelper" } ] } \ No newline at end of file diff --git a/docs/archive/graph/providers/InteractiveProviderBehavior.md b/docs/archive/graph/providers/InteractiveProviderBehavior.md deleted file mode 100644 index daf782716..000000000 --- a/docs/archive/graph/providers/InteractiveProviderBehavior.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: InteractiveProviderBehavior XAML Behavior -author: michael-hawker -description: The InteractiveProviderBehavior provides an easy way in XAML to connect to Microsoft Graph. -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, graph, login, authentication, interactive, provider, identity, xaml islands -dev_langs: - - csharp ---- - -# InteractiveProviderBehavior XAML Behavior - -> [!WARNING] -> This API has been removed. For the latest guidance on using the Microsoft Graph in the Toolkit check out the [Windows Community Toolkit - Graph Helpers and Controls](../../../graph/overview.md). - -The [InteractiveProviderBehavior](/dotnet/api/microsoft.toolkit.graph.providers.interactiveproviderbehavior) provides a quick and easy way to connect to the Microsoft Identity platform and Microsoft Graph. It is built on top of the Graph SDK's authentication providers, but allows usage from XAML. - -Add this behavior to your application's main page. It only needs to be added to a single page to bootstrap all the other Graph enabled XAML controls. - -> [!IMPORTANT] -> Be sure to Register Client Id in Azure first following the guidance here: [Quickstart: Register an application with the Microsoft identity platform](/azure/active-directory/develop/quickstart-register-app) -> -> After finishing the initial registration page, you will also need to add an additional redirect URI. Click on "Add a Redirect URI" and check the "https://login.microsoftonline.com/common/oauth2/nativeclient" checkbox on that page. Then click "Save". - -## Syntax - -```xaml - - - -``` - -## WPF - -> [!IMPORTANT] -> This provider must be initialized in your WPF app when using the XAML Graph controls from [XAML Islands](/windows/apps/desktop/modernize/xaml-islands). The same syntax above is used; however, you must include the [Microsoft.Toolkit.Wpf.Graph.Providers](https://www.nuget.org/packages/Microsoft.Toolkit.Wpf.Graph.Providers) NuGet package instead. - -## Properties - -| Property | Type | Description | -| -- | -- | -- | -| ClientId | string | Client Id obtained from Azure registration. | -| RedirectUri | string | Client's authentication uri redirect as configured in Azure. | -| Scopes | ScopeSet | Comma-delimited list of scopes to pre-authorize from user during authentication. | - -## Requirements - -| Device family | Universal, MinVersion or higher | -| -- | -- | -| Namespace | Microsoft.Toolkit.Graph.Providers | -| NuGet package | [Microsoft.Toolkit.Graph.Controls](https://www.nuget.org/packages/Microsoft.Toolkit.Graph.Controls) | - -## API - -* [InteractiveProviderBehavior source code](https://github.com/windows-toolkit/Graph-Controls/blob/rel/7.1.0/Microsoft.Toolkit.Graph.Controls/Providers/InteractiveProviderBehavior.cs) -* [InteractiveProviderBehavior usage in XAML Islands Sample](https://github.com/windows-toolkit/Graph-Controls/blob/rel/7.1.0/Samples/XAML%20Islands/WPF-Core-GraphApp/MainWindow.xaml) - -## Related Topics - -* [Graph SDK Authentication Providers](https://github.com/microsoftgraph/msgraph-sdk-dotnet-auth) -* [App Registration Quick-Start for Client Id](/azure/active-directory/develop/quickstart-register-app) diff --git a/docs/archive/graph/providers/MockProviderBehavior.md b/docs/archive/graph/providers/MockProviderBehavior.md deleted file mode 100644 index dfe0c3b4a..000000000 --- a/docs/archive/graph/providers/MockProviderBehavior.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: MockProviderBehavior XAML Behavior -author: michael-hawker -description: The MockProviderBehavior provides sample data from Microsoft Graph. -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, graph, login, authentication, interactive, provider, identity, mock, sample -dev_langs: - - csharp ---- - -# MockProviderBehavior XAML Behavior - -> [!WARNING] -> This API has been removed. For the latest guidance on using the Microsoft Graph in the Toolkit check out the [Windows Community Toolkit - Graph Helpers and Controls](../../../graph/overview.md). - - -The [MockProviderBehavior](/dotnet/api/microsoft.toolkit.graph.providers.mockproviderbehavior) provides sample data from the Microsoft Graph for demonstration and learning purposes only. - -Add this behavior to your application's main page. It only needs to be added to a single page to bootstrap all the other Graph enabled XAML controls. - -## Syntax - -```xaml - - - -``` - -## Properties - -| Property | Type | Description | -| -- | -- | -- | -| SignedIn | bool | Value to indicate if the provider should be in the signed-in state at initialization. | - -## Requirements - -| Device family | Universal, MinVersion or higher | -| -- | -- | -| Namespace | Microsoft.Toolkit.Graph.Providers | -| NuGet package | [Microsoft.Toolkit.Graph.Controls](https://www.nuget.org/packages/Microsoft.Toolkit.Graph.Controls) | - -## API - -* [MockProviderBehavior source code](https://github.com/windows-toolkit/Graph-Controls/blob/rel/7.1.0/Microsoft.Toolkit.Graph.Controls/Providers/MockProviderBehavior.cs) diff --git a/docs/developer-tools/Guard.md b/docs/developer-tools/Guard.md deleted file mode 100644 index 01cfb7a05..000000000 --- a/docs/developer-tools/Guard.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: Guard -author: Sergio0694 -description: Helper methods to verify conditions when running code -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, debug, net core, net standard -dev_langs: - - csharp ---- - -# Guard - -The [Guard](/dotnet/api/microsoft.toolkit.diagnostics.guard) can be used to validate method arguments in a streamlined manner, which is also faster, less verbose, more expressive and less error prone than manually writing checks and throwing exceptions. - -## How it works - -These `Guard` APIs are built with three core principles in mind: - -- Being **fast**. To achieve that, all the APIs have been designed to produce as little code as possible in the caller, and each single Guard API will (almost always) be inlined. Furthermore, specialized methods are generated with T4 templates to achieve the most efficient assembly code possible when working with common types (eg. primitive numeric types). -- Being **helpful**. Each `Guard` API produces a detailed exception message that clearly specifies what went wrong, along with additional info (eg. current variable values), when applicable. -- Being **intuitive**. To achieve this, all the `Guard` APIs have expressive and self-explanatory names that make it immediately clear what each API is supposed to do. This shifts the burden of writing checks away from the developers, letting them express conditions using natural language. - -## Syntax - -Here is a sample method, with some checks being done with explicitly and with manual throw statements: - -```csharp -public static void SampleMethod(int[] array, int index, Span span, string text) -{ - if (array is null) - { - throw new ArgumentNullException(nameof(array), "The array must not be null"); - } - - if (array.Length >= 10) - { - throw new ArgumentException($"The array must have less than 10 items, had a size of {array.Length}", nameof(array)); - } - - if (index < 0 || index >= array.Length) - { - throw new ArgumentOutOfRangeException(nameof(index), $"The index must be in the [0, {array.Length}) range, was {index}"); - } - - if (span.Length < array.Length) - { - throw new ArgumentException($"The target span is shorter than the input array, had a length of {span.Length}", nameof(span)); - } - - if (string.IsNullOrEmpty(text)) - { - throw new ArgumentException("The input text can't be null or empty", nameof(text)); - } -} -``` - -And here is the same method, but using the new `Guard.APIs` to validate the input arguments: - -```csharp -public static void SampleMethod(int[] array, int index, Span span, string text) -{ - Guard.IsNotNull(array, nameof(array)); - Guard.HasSizeGreaterThanOrEqualTo(array, 10, nameof(array)); - Guard.IsInRangeFor(index, array, nameof(index)); - Guard.HasSizeLessThanOrEqualTo(array, span, nameof(span)); - Guard.IsNotNullOrEmpty(text, nameof(text)); -} -``` - -The `Guard` APIs will perform the required checks in the fastest way possible, and will throw the appropriate exception with a well formated message if they fail. - -## Methods - -There are dozens of different APIs and overloads in the `Guard` class, here are a few of them: - -### General - -| Methods | Return Type | Description | -| -- | -- | -- | -| IsNotNull<T>(T, string) | void | Asserts that the input value is not null | -| IsOfType<T>(object, string) | void | Asserts that the input value is of a specific type | -| IsAssignableToType<T>(object, string) | void | Asserts that the input value can be assigned to a specified type | -| IsReferenceEqualTo<T>(T, T, string) | void | Asserts that the input value must be the same instance as the target value | -| IsTrue(bool, string) | void | Asserts that the input value must be true | - -### Comparisons - -| Methods | Return Type | Description | -| -- | -- | -- | -| IsEqualTo<T>(T, T, string) | void | Asserts that the input value must be equal to a specified value | -| IsBitwiseEqualTo<T>(T, T, string) | void | Asserts that the input value must be a bitwise match with a specified value | -| IsLessThan<T>(T, T, string) | void | Asserts that the input value must be less than a specified value | -| IsLessThanOrEqualTo<T>(T, T, string) | void | Asserts that the input value must be less than or equal to a specified value | -| IsInRange<T>(T, T, T, string) | void | Asserts that the input value must be in the [minimum, maximum) range | -| IsBetween<T>(T, T, T, string name) | void | Asserts that the input value must be in the (minimum, maximum) interval | -| IsBetweenOrEqualTo<T>(T, T, T, string name) | void | Asserts that the input value must be in the [minimum, maximum] interval | - -### Strings - -| Methods | Return Type | Description | -| -- | -- | -- | -| IsNotNullOrEmpty(string, string) | void | Asserts that the input string instance must not be null or empty | -| IsNotNullOrWhitespace(string, string) | void | Asserts that the input string instance must not be null or whitespace | - -### Collections - -| Methods | Return Type | Description | -| -- | -- | -- | -| IsNotEmpty<T>(T[], string) | void | Asserts that the input array instance must not be empty | -| HasSizeEqualTo<T>(T[], int, string) | void | Asserts that the input array instance must have a size of a specified value | -| HasSizeAtLeast<T>(T[], int, string) | void | Asserts that the input array must have a size of at least or equal to a specified value | -| IsInRangeFor<T>(int, T[], string) | void | Asserts that the input index is valid for a given array | -| HasSizeLessThanOrEqualTo<T>(T[], T[], string) | void | Asserts that the source array must have a size of less than or equal to that of the destination array | - -### Tasks - -| Methods | Return Type | Description | -| -- | -- | -- | -| IsCompleted(Task, string) | void | Asserts that the input task is in a completed state | -| IsNotCanceled(Task, string) | void | Asserts that the input task is not canceled | - -## Sample Code - -You can find more examples in our [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/UnitTests/UnitTests.Shared/Diagnostics/Test_Guard.cs) - -## Requirements - -| Implementation | .NET Standard 2.0 | -| --- | --- | -| Namespace | Microsoft.Toolkit.Diagnostics | -| NuGet package | [Microsoft.Toolkit](https://www.nuget.org/packages/Microsoft.Toolkit/) | - -The Guard class supports .NET Standard - -## API - -- [Guard source code](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/Microsoft.Toolkit.Diagnostics) diff --git a/docs/developer-tools/ThrowHelper.md b/docs/developer-tools/ThrowHelper.md deleted file mode 100644 index 60d7c1a5b..000000000 --- a/docs/developer-tools/ThrowHelper.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -title: ThrowHelper -author: Sergio0694 -description: Helper methods to efficiently throw exceptions -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, debug, net core, net standard -dev_langs: - - csharp ---- - -# ThrowHelper - -The [ThrowHelper](/dotnet/api/microsoft.toolkit.diagnostics.ThrowHelper) class is a helper type that can be used to efficiently throw exceptions. It is meant to support the [Guard](Guard.md) APIs, and it should primarily be used in situations where developers need fine-grained controls over the exception types being thrown, or over the exact exception message to include. - -## Syntax - -The `ThrowHelper` class exposes a series of `ThrowException` APIs that offer a 1:1 mapping to the constructors of all the available exception types. These methods are meant to be used in place of the classic `throw new Exception(...)` statement in code, as it will result in smaller and more efficient code. Put simply: - -```csharp -// Replace this... -throw new InvalidOperationException("Some custom message from my library"); - -// ...with this -ThrowHelper.ThrowInvalidOperationException("Some custom message from my library"); -``` - -> [!NOTE] -> This will also result in a slightly different stack trace, as the exception will be thrown by this helper method instead of directly by the original caller. The practical result is still the same as throwing an exception directly. - -The `Guard` APIs provide an easy to use abstraction over many common checks that might need to be performed, so it is recommended to first try to see if there is a `Guard` API that can be used, and only fallback on using `ThrowHelper` if that's not the case. As mentioned before, this might be if your library needs to throw a specific exception type not present in the `Guard` APIs, or if you need full control on the exact arguments being included in the exception being thrown. - -There are also generic overloads for all the available APIs, which can be used within expressions that require a return type of a specific type (eg. a switch expression). These overloads never return any value, but the return type is declared to allow the C# compiler to accept the usage of these APIs within expressions that wouldn't work with a method returning `void`. Consider the following example: - -```csharp -int result = text switch -{ - "cat" => 0, - "dog" => 1, - _ => ThrowHelper.ThrowArgumentException(nameof(text)) -}; -``` - -Here we're using `ThrowHelper` within an expression that requires a return type of type `int`, so we can use the generic overload of `ThrowArgumentException` to make this possible. This also works with patterns such as ternary operators (`x ? a : b`), null-coalescing operators (`x = a ?? b`) null-coalescing assignment operators (`x ??= y`), and more. - -## Methods - -There are lots of different methods and overloads in the `ThrowHelper` class, providing access to the following exceptions (and mapping all their public constructors): - -- [ArrayTypeMismatchException](/dotnet/api/system.ArrayTypeMismatchException) -- [ArgumentException](/dotnet/api/system.ArgumentException) -- [ArgumentNullException](/dotnet/api/system.ArgumentNullException) -- [ArgumentOutOfRangeException](/dotnet/api/system.ArgumentOutOfRangeException) -- [COMException](/dotnet/api/system.runtime.interopservices.COMException) -- [ExternalException](/dotnet/api/system.runtime.interopservices.ExternalException) -- [FormatException](/dotnet/api/system.FormatException) -- [InsufficientMemoryException](/dotnet/api/system.InsufficientMemoryException) -- [InvalidDataException](/dotnet/api/system.io.InvalidDataException) -- [InvalidOperationException](/dotnet/api/system.InvalidOperationException) -- [LockRecursionException](/dotnet/api/system.threading.LockRecursionException) -- [MissingFieldException](/dotnet/api/system.MissingFieldException) -- [MissingMemberException](/dotnet/api/system.MissingMemberException) -- [MissingMethodException](/dotnet/api/system.MissingMethodException) -- [NotSupportedException](/dotnet/api/system.NotSupportedException) -- [ObjectDisposedException](/dotnet/api/system.ObjectDisposedException) -- [OperationCanceledException](/dotnet/api/system.OperationCanceledException) -- [PlatformNotSupportedException](/dotnet/api/system.PlatformNotSupportedException) -- [SynchronizationLockException](/dotnet/api/system.threading.SynchronizationLockException) -- [TimeoutException](/dotnet/api/system.TimeoutException) -- [UnauthorizedAccessException](/dotnet/api/system.UnauthorizedAccessException) -- [Win32Exception](/dotnet/api/system.componentmodel.Win32Exception) - -You can see the available constructors for each of these exception types from the linked docs - the respective `ThrowHelper` APIs will simply offer a series of overloads corresponding to the existing constructors for that specified type. Each API is simply named "Throw" + the exception type. - -## Technical Details - -The following section describes the impact of switching to `ThrowHelper` APIs over the standard `throw new Expression` statements with respect to the codegen. As mentioned above, knowing these details is not necessary in order to use these APIs, but for developers familiar with how the runtime works or with how the JIT processes code during execution, this will provide a clearer explanation of why using the `ThrowHelper` pattern results in more compact and faster code. In order to do so, we will need to have a peek at the code that the JIT compiler is actually producing in these situations. We will use the code generated on .NET Core 3.1 x64 as a reference, but the same concept applies to other runtimes and architectures as well. - -Let's consider this simple type: - -```csharp -public struct ExceptionTest -{ - private int number; - - public int GetValueIfNotZeroOrThrow() - { - if (number == 0) - { - throw new InvalidOperationException("The value must be != 0"); - } - - return number; - } -} -``` - -This type is only meant to showcase the use of `ThrowHelper` APIs. Here we're simply checking the value of the `number` field, and throwing if it's 0. Let's check the generated asm code: - -```x86asm -ExceptionTest.GetValueIfNotZeroOrThrow() - mov eax, [rcx] ; read number - test eax, eax ; if (number != 0) - je short L0011 ; jump to faulting path (if == 0) - ret ; return (number is already in eax) - mov rcx, 0x7ff95cbaca80 ; exception setup... - call 0x00007ff9bc6178f0 - mov rsi, rax - mov ecx, 1 - mov rdx, 0x7ff96590c080 - call 0x00007ff9bc7403e0 - mov rdx, rax - mov rcx, rsi - call System.InvalidOperationException..ctor(System.String) - mov rcx, rsi - call 0x00007ff9bc5db3a0 - int3 ; finally throw the exception -``` - -We can see the code contains a lot of lines just dedicated to creating the exception being thrown. This can cause a large increase in the code size whenever we have many of these checks because it will reduce the efficiency of the instruction cache, etc. In general, we'd like the size of our methods to be as small as possible. - -The above snippet, rewritten using the `ThrowHelper` APIs, would like like this: - -```csharp -public int GetValueIfNotZeroOrThrow() -{ - if (number == 0) - { - ThrowHelper.ThrowInvalidOperationException("The value must be != 0"); - } - - return number; -} -``` - -Which results in the following assembly: - -```x86asm -ExceptionTest.GetValueIfNotZeroOrThrow2() - mov eax, [rcx] ; load number - test eax, eax ; if (number != 0) - je short L000f ; faulting path (if == 0) - ret ; return number (already in eax) - mov rcx, 0x23435d85b98 ; load the exception message - mov rcx, [rcx] - call ThrowHelper.ThrowInvalidOperationException(System.String) ; ThrowHelper call! - int3 ; return with fault -``` - -We can see that the resulting assembly is much smaller than before. We basically moved all the code to create the exception out of the method, which also means we can just always reuse the same code from the `ThrowHelper` APIs, with different arguments, instead of inlining the exception throw in every single one of our methods. Here we only have those two `mov` instructions to load the `string` with our exception type, and then we jump to the `ThrowHelper.ThrowInvalidOperationException` method. The JIT compiler is able to see that that method will always throw, so it will never inline that call, and it will make sure to rewrite our conditional branches in the best way possible (specifically, knowing what is the branch that is supposed to be executed, without faulting). - -## Requirements - -| Implementation | .NET Standard 2.0 | -| --- | --- | -| Namespace | Microsoft.Toolkit.Diagnostics | -| NuGet package | [Microsoft.Toolkit](https://www.nuget.org/packages/Microsoft.Toolkit/) | - -The ThrowHelper class supports .NET Standard - -## API - -- [ThrowHelper source code](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/Microsoft.Toolkit.Diagnostics/ThrowHelper.cs) - -## Related Topics - -- [Guard](/dotnet/api/microsoft.toolkit.diagnostics.guard) diff --git a/docs/diagnostics/Introduction.md b/docs/diagnostics/Introduction.md deleted file mode 100644 index d79412d2d..000000000 --- a/docs/diagnostics/Introduction.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Introduction to the Diagnostics package -author: Sergio0694 -description: An overview of how to get started with the Diagnostics package and to the APIs it contains -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, get started, visual studio, diagnostics, exceptions, contract, net core, net standard ---- - -# Introduction to the Diagnostics package - -The Diagnostics package contains APIs to efficiently validate method parameters and to throw exceptions in faulting code paths. It is meant to be used to help simplify all argument checks and to make them more expressive and easier to read, while at the same time improving codegen quality and performance. - -This package can be installed through NuGet, and it has the following multi-targets: - -- .NET Standard 1.4 -- .NET Standard 2.0 -- .NET Standard 2.1 -- .NET 5 - -This means the package can be used on any available runtime (including .NET Framework, .NET Core, UWP, Unity, Xamarin, Uno, Blazor, etc.). The API surface is almost identical in all cases, while the internal implementation can be optimized when newer APIs are available. The Diagnostics package as a whole is meant to be self-contained and extremely small in scope and binary size. - -Follow these steps to install the Diagnostics package: - -1. Open an existing project in Visual studio, targeting any of the following: - - UWP (>= 10.0) - - .NET Standard (>= 1.4) - - .NET Core (>= 1.0) - - Any other framework supporting .NET Standard 1.4 and up - -2. In Solution Explorer panel, right click on your project name and select **Manage NuGet Packages**. Search for **Microsoft.Toolkit.Diagnostics** and install it. - - ![NuGet Packages](../resources/images/ManageNugetPackages.png "Manage NuGet Packages Image") - -3. Add a using directive in your C# files to use the new APIs: - - ```csharp - using Microsoft.Toolkit.Diagnostics; - ``` - -4. If you want so see some code samples, you can either read through the other docs pages for the Diagnostics package, or have a look at the various [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/rel/7.1.0/UnitTests/UnitTests.Shared/Diagnostics) for the project. diff --git a/docs/graph/authentication/custom.md b/docs/graph/authentication/custom.md deleted file mode 100644 index 6273027b1..000000000 --- a/docs/graph/authentication/custom.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Custom authentication providers -author: shweaver-MSFT -description: IProvider interface defines the basic functions of an authentication provider in the Graph toolkit. -keywords: uwp, wpf, netstandard, windows, community, toolkit, graph, login, authentication, provider, providers, identity -dev_langs: - - csharp ---- - -# Custom authentication providers - -If you have existing authentication code in your application, you can create a custom provider to enable authentication and access to Microsoft Graph for the toolkit's Graph based controls and helpers. To bring your own authentication provider logic, start by extending `IProvider`. - -## IProvider - -`IProvider` is the base interface for creating authentication providers that work with the various controls and helpers in the toolkit. Handle authentication with one of our premade `IProvider` implementations or create your own. - -Available in the `CommunityToolkit.Authentication` package. - -```csharp -using CommunityToolkit.Authentication; - -// Create an instance of your custom IProvider implementation. -IProvider customProvider = new CustomProvider(); - -// Set the global provider using the custom instance. -ProviderManager.Instance.GlobalProvider = customProvider; -``` - -### Properties - -| Property | Type | Description | -| -- | -- | -- | -| State | ProviderState | Gets the current authentication state of the provider. | - -### Events - -| Event | Type | Description | -| -- | -- | -- | -| StateChanged | EventHandler<ProviderStateChangedEventArgs> | An event that is called whenever the login state changes. - -### Methods - -| Method | Arguments | Returns | Description | -| -- | -- | -- | -- | -| AuthenticateRequestAsync | HttpRequestMessage | Task | Authenticate an outgoing request. | -| GetTokenAsync | bool silentOnly = false | Task<string> | Retrieve a token for the authenticated user. | -| SignInAsync | | Task | Sign in a user. | -| SignOutAsync | | Task | Sign out the current user. | -| TrySilentSignInAsync | | Task<bool> | Try signing in silently, without prompts. | diff --git a/docs/graph/authentication/msal.md b/docs/graph/authentication/msal.md deleted file mode 100644 index 59dcf7609..000000000 --- a/docs/graph/authentication/msal.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: MsalProvider -author: shweaver-MSFT -description: Authentication provider based on the official Microsoft Authentication Library (MSAL). -keywords: uwp, wpf, netstandard, windows, community, toolkit, graph, login, authentication, provider, providers, identity, msal -dev_langs: - - csharp ---- - -# MsalProvider - -The MsalProvider is an [IProvider](./custom.md) implementation built on the official Microsoft Authentication Library (MSAL). It is NetStandard 2.0 so it works in both UWP and WPF apps. - -Available in the `CommunityToolkit.Authentication.Msal` package. - -```csharp -using CommunityToolkit.Authentication; - -string clientId = "YOUR-CLIENT-ID-HERE"; -string[] scopes = new string[] { "User.Read" }; - -ProviderManager.Instance.GlobalProvider = new MsalProvider(clientId, scopes); -``` - -## Prerequisite Configure Client Id in Partner Center - -> [!IMPORTANT] -> To obtain a Client Id, first register your app in Azure following the guidance here: [Quickstart: Register an application with the Microsoft identity platform](/azure/active-directory/develop/quickstart-register-app) -> -> After finishing the initial registration, you will also need to add an additional redirect URI. Click on "Authentication -> Add a Platform", select "Mobile and desktop applications", and check the "https://login.microsoftonline.com/common/oauth2/nativeclient" checkbox on that page. Then click "Configure". - -## Constructor - -| Parameter | Type | Default | Description | -| -- | -- | -- | -- | -| clientId | string | | Registered client id. | -| scopes | string[] | null | Listof scopes to initially request. | -| redirectUri | string | `https://login.microsoftonline.com/common/oauth2/nativeclient` | Redirect URI for authentication response. | -| autoSignIn | bool | true | Determines whether the provider attempts to silently log in upon instantiation. | - -## Properties - -| Property | Type | Description | -| -- | -- | -- | -| State | ProviderState | Gets the current authentication state of the provider. | - -## Events - -| Event | Type | Description | -| -- | -- | -- | -| StateChanged | EventHandler<ProviderStateChangedEventArgs> | Event called when the provider state changes. | - -## Methods - -| Method | Arguments | Returns | Description | -| -- | -- | -- | -- | -| GetTokenAsync | bool silentOnly = false, string[] scopes = null | Task<string> | Retrieve a token for the authenticated user. | -| AuthenticateRequestAsync | HttpRequestMessage | Task | Authenticate an outgoing request. | -| SignInAsync | | Task | Sign in a user. | -| SignOutAsync | | Task | Sign out the current user. | -| TrySilentSignInAsync | | Task<bool> | Try signing in silently, without prompts. | diff --git a/docs/graph/authentication/windows.md b/docs/graph/authentication/windows.md deleted file mode 100644 index a706ecf5e..000000000 --- a/docs/graph/authentication/windows.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: WindowsProvider -author: shweaver-MSFT -description: Lightweight IProvider implementation that enables authentication using native Windows Account Manager APIs (WAM). -keywords: uwp, netstandard, windows, community, toolkit, graph, login, authentication, provider, providers, identity, wam, msa -dev_langs: - - csharp ---- - -# WindowsProvider - -The WindowsProvider is an authentication provider for accessing locally configured accounts on Windows. -It extends [IProvider](./custom.md) and uses the native Windows AccountManager (WAM) APIs and AccountsSettingsPane for sign in. - -Available in the `CommunityToolkit.Authentication.Uwp` package. - -## Prerequisite Windows Store Association in Visual Studio - -To get valid tokens and complete sign in, the app will need to be associated with the Microsoft Store. This will enable your app to authenticate consumer MSA accounts without any additional configuration. - -1. In Visual Studio Solution Explorer, right-click the UWP project, then select **Store -> Associate App with the Store...** - -2. In the wizard, click **Next**, sign in with your Windows developer account, type a name for your app in **Reserve a new app name**, then click **Reserve**. - -3. After completing the app registration, select the new app name, click **Next**, and then click **Associate**. This adds the required Windows Store registration information to the application manifest. - -> [!NOTE] -> You must have a Windows Developer account to use the WindowsProvider in your UWP app. You can [register a Microsoft developer account](https://developer.microsoft.com/store/register) if you don't already have one. - -## Prerequisite Configure Client Id in Partner Center - -If your product integrates with Azure AD and calls APIs that request either application permissions or delegated permissions that require administrator consent, you will also need to enter your Azure AD Client ID in Partner Center: - -`https://partner.microsoft.com/dashboard/products/<YOUR-APP-ID>/administrator-consent` - -This lets administrators who acquire the app for their organization grant consent for your product to act on behalf of all users in the tenant. - -> [!NOTE] -> You only need to specify the client id if you need admin consent for delegated permissions from your AAD app registration, or need to support more advanced authentication scenarios like SSO. Simple authentication for consumer MSA accounts does not require a client id or any additional configuration in Azure for basic access. - -> [!IMPORTANT] -> Make sure to Register Client Id in Azure first following the guidance here: [Quickstart: Register an application with the Microsoft identity platform](/azure/active-directory/develop/quickstart-register-app) -> -> After finishing the initial registration page, you will also need to add an additional redirect URI. Click on "Add a Redirect URI" and add the value retrieved from running `WindowsProvider.RedirectUri` at runtime. -> -> You'll also want to set the toggle to **true** for "Allow public client flows". -> -> Then click "Save". - -## Syntax - -The WindowsProvider can be used in just one line of code: - -```csharp -using CommunityToolkit.Authentication; - -// Easily create a new WindowsProvider instance and set the GlobalProvider. -// Don't forget to associate your app with the Microsoft Store before attempting sign in. -ProviderManager.Instance.GlobalProvider = new WindowsProvider(new string[] { "User.Read", "Tasks.ReadWrite" }); -``` - -The WindowsProvider can also be configured to disable auto-login or show custom content in the `AccountsSettingsPane`. -Configuration for specifying supported account types (such as AAD) is available via the `WebAccountProviderConfig` object. - -```CSharp -using CommunityToolkit.Authentication; - -// Provider config -string[] scopes = { "User.Read", "People.Read", "Calendars.Read", "Mail.Read" }; - -// Additional parameters are also available, -// such as custom settings commands for the AccountsSettingsPane. -Guid settingsCommandId = Guid.NewGuid(); -void OnSettingsCommandInvoked(IUICommand command) -{ - System.Diagnostics.Debug.WriteLine("AccountsSettingsPane command invoked: " + command.Id); -} - -// Configure which types of accounts should be available to choose from. The default is MSA, but AAD is also supported. -var webAccountProviderConfig = new WebAccountProviderConfig(WebAccountProviderType.Msa); - -// ClientId is only required for approving admin level consent in AAD tenants or for supporting advanced authentication scenarios like SSO. -//var webAccountProviderConfig = new WebAccountProviderConfig(WebAccountProviderType.Aad, "YOUR_CLIENT_ID_HERE"); - -// Configure details to present in the AccountsSettingsPane, such as custom header text and links. -var accountsSettingsPaneConfig = new AccountsSettingsPaneConfig( - headerText: "Custom header text", - commands: new List() - { - new SettingsCommand(settingsCommandId: settingsCommandId, label: "Click me!", handler: OnSettingsCommandInvoked) - }); - -// Determine it the provider should automatically sign in or not. Default is true. -// Set to false to delay silent sign in until SignInAsync or TrySilentSignInAsync is called. -bool autoSignIn = false; - -// Set the GlobalProvider with the extra configuration -ProviderManager.Instance.GlobalProvider = new WindowsProvider(scopes, accountsSettingsPaneConfig, webAccountProviderConfig, autoSignIn); -``` - -## Constructor - -| Parameter | Type | Default | Description | -| -- | -- | -- | -- | -| scopes | string[] | null | List of scopes to initially request. | -| webAccountProviderConfig | WebAccountProviderConfig? | null | Configuration value for determining the available web account providers. | -| accountsSettingsPaneConfig | AccountsSettingsPaneConfig? | null | Configuration values for the AccountsSettingsPane. | -| autoSignIn | bool | true | Determines whether the provider attempts to silently log in upon instantiation. | - -## Properties - -| Property | Type | Description | -| -- | -- | -- | -| State | ProviderState | Gets the current authentication state of the provider. | -| Scopes | string[] | List of scopes to pre-authorize on the user during authentication. | -| WebAccountsProviderConfig | WebAccountProviderConfig | configuration values for determining the available web account providers. | -| AccountsSettingsPaneConfig | AccountsSettingsPaneConfig | Configuration values for the AccountsSettingsPane, shown during authentication. | -| RedirectUri | string | Static getter for retrieving a customized redirect uri to put in the Azure app registration. | - -## Events - -| Event | Type | Description | -| -- | -- | -- | -| StateChanged | EventHandler<ProviderStateChangedEventArgs> | Event called when the provider state changes. | - -## Methods - -| Method | Arguments | Returns | Description | -| -- | -- | -- | -- | -| AuthenticateRequestAsync | HttpRequestMessage | Task | Authenticate an outgoing request. | -| GetTokenAsync | bool silentOnly = true, string[] scopes = null | Task<string> | Retrieve a token for the authenticated user. | -| SignInAsync | | Task | Sign in a user. | -| SignOutAsync | | Task | Sign out the current user. | -| TrySilentSignInAsync | | Task<bool> | Try signing in silently, without prompts. | - -## AccountsSettingsPaneConfig Object - -| Property | Type | Description | -| -- | -- | -- | -| HeaderText | string | Gets or sets the header text for the accounts settings pane. | -| Commands | IList<SettingsCommand> | Gets or sets the SettingsCommand collection for the account settings pane. | - -## WebAccountProviderConfig Object - -| Property | Type | Description | -| -- | -- | -- | -| ClientId | string | Client Id obtained from Azure registration. | -| WebAccountProviderType | WebAccountProviderType | The types of accounts providers that should be available to the user. | - -### WebAccountProviderType Enum - -| Name | Description | -| -- | -- | -| All | Enable authentication of all available account types. | -| MSA | Enable authentication of public/consumer MSA accounts. | diff --git a/docs/high-performance/Introduction.md b/docs/high-performance/Introduction.md deleted file mode 100644 index ba611dc19..000000000 --- a/docs/high-performance/Introduction.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Introduction to the High Performance package -author: Sergio0694 -description: An overview of how to get started with the High Performance package and to the APIs it contains -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, get started, visual studio, high performance, net core, net standard ---- - -# Introduction to the High Performance package - -This package can be installed through NuGet, and it has the following multi-targets: - -- .NET Standard 1.4 -- .NET Standard 2.0 -- .NET Standard 2.1 -- .NET Core 2.1 -- .NET Core 3.1 -- .NET 5 - -This means that you can use it from anything from UWP or legacy .NET Framework applications, games written in Unity, cross-platform mobile applications using Xamarin, to .NET Standard libraries and modern .NET Core 2.1 or .NET Core 3.1 applications. The API surface is almost identical in all cases, and lots of work has been put into backporting as many features as possible to older targets like .NET Standard 1.4 and .NET Standard 2.0. Except for some minor differences, you can expect the same APIs to be available on all target frameworks. - -The reason why multi-targeting has been used is to allow the package to leverage all the latest APIs on modern runtimes (like .NET 5) whenever possible, while still offering most of its functionalities to all target platforms. It also makes it possible for .NET Core 2.1 to use all the APIs that it has in common with .NET Standard 2.1, even though the runtime itself doesn't fully implement .NET Standard 2.1. All of this would not have been possible without multi-targeting to both .NET Standard as well as individual runtimes. - -Follow these steps to install the High Performance package: - -1. Open an existing project in Visual studio, targeting any of the following: - - UWP (>= 10.0) - - .NET Standard (>= 1.4) - - .NET Core (>= 1.0) - - Any other framework supporting .NET Standard 1.4 and up - -2. In Solution Explorer panel, right click on your project name and select **Manage NuGet Packages**. Search for **Microsoft.Toolkit.HighPerformance** and install it. - - ![NuGet Packages](../resources/images/ManageNugetPackages.png "Manage NuGet Packages Image") - -3. Add a using directive in your C# files to use the new APIs: - - ```csharp - using Microsoft.Toolkit.HighPerformance; - ``` - -4. If you want so see some code samples, you can either read through the other docs pages for the High Performance package, or have a look at the various [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/rel/7.1.0/UnitTests/UnitTests.HighPerformance.Shared) for the project. - -## When should I use this package? - -As the name suggests, the High Performance package contains a set of APIs that are heavily focused on optimization. All the new APIs have been carefully crafted to achieve the best possible performance when using them, either through reduced memory allocation, micro-optimizations at the assembly level, or by structuring the APIs in a way that facilitates writing performance oriented code in general. - -This package makes heavy use of APIs such as: - -- [`System.Span`](/dotnet/api/system.span-1) -- [`System.Memory`](/dotnet/api/system.memory-1) -- [`System.Buffers.ArrayPool`](/dotnet/api/system.buffers.arraypool-1) -- [`System.Runtime.CompilerServices.Unsafe`](/dotnet/api/system.runtime.compilerservices.unsafe) -- [`System.Runtime.InteropServices.MemoryMarshal`](/dotnet/api/system.runtime.interopservices.memorymarshal) -- [`System.Threading.Tasks.Parallel`](/dotnet/api/system.threading.tasks.parallel) - -If you are already familiar with these APIs or even if you're just getting started with writing high performance code in C# and want a set of well tested helpers to use in your own projects, have a look at what's included in this package to see how you can use it in your own projects! - -## Where to start? - -Here are some APIs you could look at first, if you were already using one of those types mentioned above: - -- [`Span2D`](Span2D.md) and [`Memory2D`](Memory2D.md), for a `Span` and `Memory`-like abstraction over 2D memory -- [`MemoryOwner`](MemoryOwner.md) and [`SpanOwner`](SpanOwner.md), if you were using `System.Buffers.ArrayPool`. -- [`StringPool`](StringPool.md), for an `ArrayPool`-like type to cache `string` instances -- [`ParallelHelper`](ParallelHelper.md), if you were using `System.Threading.Tasks.Parallel`. diff --git a/docs/high-performance/Memory2D.md b/docs/high-performance/Memory2D.md deleted file mode 100644 index d56ff0ca9..000000000 --- a/docs/high-performance/Memory2D.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Memory2D<T> and ReadOnlyMemory2D<T> -author: Sergio0694 -description: A value type that mirrors the behavior of Memory<T> and ReadOnlyMemory<T> with the addition of supporting arbitrary 2D memory locations -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, parallel, high performance, net core, net standard -dev_langs: - - csharp ---- - -# Memory2D<T> - -The [`Memory2D`](/dotnet/api/microsoft.toolkit.highperformance.memory2d-1) is a type that mirrors the functionality of the [`Memory`](/dotnet/api/system.memory-1) type, with the difference being that it can be used to represent 2D memory locations. It is extremely flexible and is capable of wrapping a number of different types, including ND arrays (with explicit support for 1D, 2D, and 3D arrays) or `Memory` instances. This type is meant to be used together with the [`Span2D`](/dotnet/api/communitytoolkit.highperformance.span2d-1?view=win-comm-toolkit-dotnet-7.0) type, in the same way that `Memory` is used along with [`Span`](/dotnet/api/system.span-1). For more info on the key differences and use case scenarios of these two types, you can read [this docs page](/dotnet/standard/memory-and-spans/memory-t-usage-guidelines). - -> **Platform APIs:** [`Memory2D`](/dotnet/api/microsoft.toolkit.highperformance.memory2d-1), [`Span2D`](/dotnet/api/microsoft.toolkit.highperformance.span2d-1), [`ReadOnlyMemory2D`](/dotnet/api/microsoft.toolkit.highperformance.readonlymemory2d-1) - -## How it works - -The `Memory2D` type internally tracks the mapped 2D memory area through a reference to the wrapped object, the height and width parameters, and a special pitch parameter. The height and width indicate the length of the rows and columns in the 2D memory area, while the pitch indicates the offset between the end of each row and the start of the following one. - -Here's a simple diagram that illustrates this configuration (the "XX" cells in the grid represent items belonging to the target 2D memory area): - -```csharp -// _____________________stride_____... -// reference__ /________width_________ ________... -// \/ \/ -// | -- | -- | |- | -- | -- | -- | -- | -- | -- | -- |_ -// | -- | -- | XX | XX | XX | XX | XX | XX | -- | -- | | -// | -- | -- | XX | XX | XX | XX | XX | XX | -- | -- | | -// | -- | -- | XX | XX | XX | XX | XX | XX | -- | -- | |_height -// | -- | -- | XX | XX | XX | XX | XX | XX | -- | -- |_| -// | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -// | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -// ...__pitch__/ -// ...________/ -``` - -This configuration allows `Memory2D` to be extremely flexible in the way it maps existing buffers to 2D memory areas, as it makes it possible to also represent discontiguous buffers as a "virtual" 2D memory location. For instance, here's a few examples of buffer types that a `Memory2D` instance can map to: - -- A 1D `T[]` array which is mapped as a 2D memory area in row-major order. -- A 2D `T[,]` array, mapped directly to a `Memory2D` instance. -- A 3D `T[,,]` array, with a `Memory2D` instance representing a given depth slice (a layer). - -The `Memory` type also exposes a number of utility methods, including most of the same API surface that the standard `Memory` implements. For instance, it includes a `Slice(int, int)` method that makes it easy to do 2D slicing operations directly on the virtual 2D memory location, with the `Memory2D` instance automatically adjusting the necessary parameters internally to shift its mapping on the right memory area(s) corresponding to the requested result. - -## Syntax - -Here's how you can create a `Memory2D` instance from a 2D array: - -```csharp -int[,] array = -{ - { 1, 2, 3 }, - { 4, 5, 6 }, - { 7, 8, 9 } -}; - -Memory2D memory = array; - -// The memory directly maps the 2*3 array here - -Memory2D slice = memory.Slice(0, 1, 2, 2); - -// We create a slice from row 0 and column 1, of size 2*2 - -int[,] copy = slice.ToArray(); - -// { 2, 3 } -// { 5, 6 } - -// If on a supported runtime, we can also slice using a range - -Memory2D test = memory[.., ..2]; - -// { 1, 2 } -// { 4, 5 } -// { 7, 8 } - -Span2D span = memory.Span; - -// We can use the span to perform operations on the underlying -// data for the memory instance. All the available APIs are -// documented in the docs about the Span2D type. - -``` - -## ReadOnlyMemory2D<T> - -The [`ReadOnlyMemory2D`](/dotnet/api/microsoft.toolkit.highperformance.readonlymemory2d-1) is to the `Memory2D` type what `ReadOnlyMemory` is to `Memory`. It exposes the same exact functionalities (minus the APIs that involve modifying the contents of the wrapped memory area) and provides a read-only view to arbitrary 2D memory locations. For more info on how this type works, you can refer to the paragraph on the `Memory2D` type above. - -## Examples - -You can find more examples in the [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/UnitTests/UnitTests.HighPerformance.Shared). diff --git a/docs/high-performance/MemoryOwner.md b/docs/high-performance/MemoryOwner.md deleted file mode 100644 index 02e803ad1..000000000 --- a/docs/high-performance/MemoryOwner.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: MemoryOwner<T> -author: Sergio0694 -description: A buffer type implementing `IMemoryOwner` that rents memory from a shared pool -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, parallel, high performance, net core, net standard -dev_langs: - - csharp ---- - -# MemoryOwner<T> - -The [`MemoryOwner`](/dotnet/api/microsoft.toolkit.highperformance.buffers.memoryowner-1) is a buffer type implementing [`IMemoryOwner`](/dotnet/api/system.buffers.imemoryowner-1), an embedded length property and a series of performance oriented APIs. It is essentially a lightweight wrapper around the [`ArrayPool`](/dotnet/api/system.buffers.arraypool-1) type, with some additional helper utilities. - -> **Platform APIs:** [`MemoryOwner`](/dotnet/api/microsoft.toolkit.highperformance.buffers.memoryowner-1), [`AllocationMode`](/dotnet/api/microsoft.toolkit.highperformance.buffers.allocationmode) - -## How it works - -`MemoryOwner` has the following main features: - -- One of the main issues of arrays returned by the `ArrayPool` APIs and of the `IMemoryOwner` instances returned by the [`MemoryPool`](/dotnet/api/system.buffers.memorypool-1) APIs is that the size specified by the user is only being used as a _minimum_ size: the actual size of the returned buffers might actually be greater. `MemoryOwner` solves this by also storing the original requested size, so that [`Memory`](/dotnet/api/system.memory-1) and [`Span`](/dotnet/api/system.span-1) instances retrieved from it will never need to be manually sliced. -- When using `IMemoryOwner`, getting a `Span` for the underlying buffer requires first to get a `Memory` instance, and then a `Span`. This is fairly expensive, and often unnecessary, as the intermediate `Memory` might actually not be needed at all. `MemoryOwner` instead has an additional `Span` property which is extremely lightweight, as it directly wraps the internal `T[]` array being rented from the pool. -- Buffers rented from the pool are not cleared by default, which means that if they were not cleared when being previous returned to the pool, they might contain garbage data. Normally, users are required to clear these rented buffers manually, which can be verbose especially when done frequently. `MemoryOwner` has a more flexible approach to this, through the `Allocate(int, AllocationMode)` API. This method not only allocates a new instance of exactly the requested size, but can also be used to specify which allocation mode to use: either the same one as `ArrayPool`, or one that automatically clears the rented buffer. -- There are cases where a buffer might be rented with a greater size than what is actually needed, and then resized afterwards. This would normally require users to rent a new buffer and copy the region of interest from the old buffer. Instead, `MemoryOwner` exposes a `Slice(int, int)` API that simply return a new instance wrapping the specified area of interest. This allows to skip renting a new buffer and copying the items entirely. - -## Syntax - -Here is an example of how to rent a buffer and retrieve a `Memory` instance: - -```csharp -// Be sure to include this using at the top of the file: -using Microsoft.Toolkit.HighPerformance.Buffers; - -using (MemoryOwner buffer = MemoryOwner.Allocate(42)) -{ - // Both memory and span have exactly 42 items - Memory memory = buffer.Memory; - Span span = buffer.Span; - - // Writing to the span modifies the underlying buffer - span[0] = 42; -} -``` - -In this example, we used a `using` block to declare the `MemoryOwner` buffer: this is particularly useful as the underlying array will automatically be returned to the pool at the end of the block. If instead we don't have direct control over the lifetime of a `MemoryOwner` instance, the buffer will simply be returned to the pool when the object is finalized by the garbage collector. In both cases, rented buffers will always be correctly returned to the shared pool. - -## When should this be used? - -`MemoryOwner` can be used as a general purpose buffer type, which has the advantage of minimizing the number of allocations done over time, as it internally reuses the same arrays from a shared pool. A common use case is to replace `new T[]` array allocations, especially when doing repeated operations that either require a temporary buffer to work on, or that produce a buffer as a result. - -Suppose we have a dataset consisting of a series of binary files, and that we need to read all these files and process them in some way. To properly separate our code, we might end up writing a method that simply reads one binary file, which might look like this: - -```csharp -public static byte[] GetBytesFromFile(string path) -{ - using Stream stream = File.OpenRead(path); - - byte[] buffer = new byte[(int)stream.Length]; - - stream.Read(buffer, 0, buffer.Length); - - return buffer; -} -``` - -Note that `new byte[]` expression. If we read a large number of files, we'll end up allocating a lot of new arrays, which will put a lot of pressure over the garbage collector. We might want to refactor this code using buffers rented from a pool, like so: - -```csharp -public static (byte[] Buffer, int Length) GetBytesFromFile(string path) -{ - using Stream stream = File.OpenRead(path); - - byte[] buffer = ArrayPool.Shared.Rent((int)stream.Length); - - stream.Read(buffer, 0, (int)stream.Length); - - return (buffer, (int)stream.Length); -} -``` - -Using this approach, buffers are now rented from a pool, which means that in most cases we're able to skip an allocation. Additionally, since rented buffers are not cleared by default, we can also save the time needed to fill them with zeros, which gives us another small performance improvement. In the example above, loading 1000 files would bring the total allocation size from around 1MB down to just 1024 bytes - just a single buffer would effectively be allocated, and then reused automatically. - -There are two main issues with the code above: - -- `ArrayPool` might return buffers that have a size greater than the requested one. To work around this issue, we need to return a tuple which also indicates the actual used size into our rented buffer. -- By simply returning an array, we need to be extra careful to properly track its lifetime and to return it to the appropriate pool. We might work around this issue by using `MemoryPool` instead and by returning an `IMemoryOwner` instance, but we still have the problem of rented buffers having a greater size than what we need. Additionally, `IMemoryOwner` has some overhead when retrieving a `Span` to work on, due to it being an interface, and the fact that we always need to get a `Memory` instance first, and then a `Span`. - -To solve both these issues, we can refactor this code again by using `MemoryOwner`: - -```csharp -public static MemoryOwner GetBytesFromFile(string path) -{ - using Stream stream = File.OpenRead(path); - - MemoryOwner buffer = MemoryOwner.Allocate((int)stream.Length); - - stream.Read(buffer.Span); - - return buffer; -} -``` - -The returned `IMemoryOwner` instance will take care of disposing the underlying buffer and returning it to the pool when its [`IDisposable.Dispose`](/dotnet/api/system.idisposable.dispose) method is invoked. We can use it to get a `Memory` or `Span` instance to interact with the loaded data, and then dispose the instance when we no longer need it. Additionally, all the `MemoryOwner` properties (like `MemoryOwner.Span`) respect the initial requested size we used, so we no longer need to manually keep track of the effective size within the rented buffer. - -## Examples - -You can find more examples in the [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/UnitTests/UnitTests.HighPerformance.Shared/Buffers). diff --git a/docs/high-performance/ParallelHelper.md b/docs/high-performance/ParallelHelper.md deleted file mode 100644 index 82557ee28..000000000 --- a/docs/high-performance/ParallelHelper.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: ParallelHelper -author: Sergio0694 -description: Helpers to work with parallel code in a highly optimized manner -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, parallel, high performance, net core, net standard -dev_langs: - - csharp ---- - -# ParallelHelper - -The [`ParallelHelper`](/dotnet/api/microsoft.toolkit.highperformance.helpers.parallelhelper) contains high performance APIs to work with parallel code. It contains performance oriented methods that can be used to quickly setup and execute parallel operations over a given data set or iteration range or area. - -> **Platform APIs:** [`ParallelHelper`](/dotnet/api/microsoft.toolkit.highperformance.helpers.parallelhelper), [`IAction`](/dotnet/api/microsoft.toolkit.highperformance.helpers.IAction), [`IAction2D`](/dotnet/api/microsoft.toolkit.highperformance.helpers.IAction2D), [`IRefAction`](/dotnet/api/microsoft.toolkit.highperformance.helpers.IRefAction-1), [`IInAction`](/dotnet/api/microsoft.toolkit.highperformance.helpers.IInAction-1) - -## How it works - -`ParallelHelper` type is built around three main concepts: - -- It performs automatic batching over the target iteration range. This means that it automatically schedules the right number of working units based on the number of available CPU cores. This is done to reduce the overhead of invoking the parallel callback once for every single parallel iteration. -- It heavily leverages the way generic types are implemented in C#, and uses `struct` types implementing specific interfaces instead of delegates like [`Action`](/dotnet/api/system.action-1). This is done so that the JIT compiler will be able to "see" each individual callback type being used, which allows it to inline the callback entirely, when possible. This can greatly reduce the overhead of each parallel iteration, especially when using very small callbacks, which would have a trivial cost with respect to the delegate invocation alone. Additionally, using a `struct` type as callback requires developers to manually handle variables that are being captured in the closure, which prevents accidental captures of the `this` pointer from instance methods and other values that could considerably slowdown each callback invocation. This is the same approach that is used in other performance-oriented libraries such as [`ImageSharp`](https://github.com/SixLabors/ImageSharp). -- It exposes 4 types of APIs that represent 4 different types of iterations: 1D and 2D loops, items iteration with side effect and items iteration without side effect. Each type of action has a corresponding `interface` type that needs to be applied to the `struct` callbacks being passed to the `ParallelHelper` APIs: these are [`IAction`](/dotnet/api/microsoft.toolkit.highperformance.helpers.IAction), [`IAction2D`](/dotnet/api/microsoft.toolkit.highperformance.helpers.IAction2D), [`IRefAction`](/dotnet/api/microsoft.toolkit.highperformance.helpers.IRefAction-1) and [`IInAction`](/dotnet/api/microsoft.toolkit.highperformance.helpers.IInAction-1). This helps developers to write code that is clearer regarding its intent, and allows the APIs to perform further optimizations internally. - -## Syntax - -Let's say we're interested in processing all the items in some `float[]` array, and to multiply each of them by `2`. In this case we don't need to capture any variables: we can just use the `IRefAction` `interface` and `ParallelHelper` will load each item to feed to our callback automatically. All that's needed is to define our callback, that will receive a `ref float` argument and perform the necessary operation: - -```csharp -// Be sure to include this using at the top of the file: -using Microsoft.Toolkit.HighPerformance.Helpers; - -// First declare the struct callback -public readonly struct ByTwoMultiplier : IRefAction -{ - public void Invoke(ref float x) => x *= 2; -} - -// Create an array and run the callback -float[] array = new float[10000]; - -ParallelHelper.ForEach(array); -``` - -With the `ForEach` API, we don't need to specify the iteration ranges: `ParallelHelper` will batch the collection and process each input item automatically. Furthermore, in this specific example we didn't even have to pass our `struct` as an argument: since it didn't contain any fields we needed to initialize, we could just specify its type as a type argument when invoking `ParallelHelper.ForEach`: that API will then create a new instance of that `struct` on its own, and use that to process the various items. - -To introduce the concept of closures, suppose we want to multiply the array elements by a value that is specified at runtime. To do so, we need to "capture" that value in our callback `struct` type. We can do that like so: - -```csharp -public readonly struct ItemsMultiplier : IRefAction -{ - private readonly float factor; - - public ItemsMultiplier(float factor) - { - this.factor = factor; - } - - public void Invoke(ref float x) => x *= this.factor; -} - -// ... - -ParallelHelper.ForEach(array, new ItemsMultiplier(3.14f)); -``` - -We can see that the `struct` now contains a field that represents the factor we want to use to multiply elements, instead of using a constant. And when invoking `ForEach`, we're explicitly creating an instance of our callback type, with the factor we're interested in. Furthermore, in this case the C# compiler is also able to automatically recognize the type arguments we're using, so we can omit them together from the method invocation. - -This approach of creating fields for values we need to access from a callback lets us explicitly declare what values we want to capture, which helps makes the code more expressive. This is exactly the same thing that the C# compiler does behind the scenes when we declare a lambda function or local function that accesses some local variable as well. - -Here is another example, this time using the `For` API to initialize all the items of an array in parallel. Note how this time we're capturing the target array directly, and we're using the `IAction` `interface` for our callback, which gives our method the current parallel iteration index as argument: - -```csharp -public readonly struct ArrayInitializer : IAction -{ - private readonly int[] array; - - public ArrayInitializer(int[] array) - { - this.array = array; - } - - public void Invoke(int i) - { - this.array[i] = i; - } -} - -// ... - -ParallelHelper.For(0, array.Length, new ArrayInitializer(array)); -``` - -> [!NOTE] -> Since the callback types are `struct`-s, they're passed _by copy_ to each thread running parallel, not by reference. This means that value types being stored as fields in a callback types will be copied as well. A good practice to remember that detail and avoid errors is to mark the callback `struct` as `readonly`, so that the C# compiler will not let us modify the values of its fields. This only applies to _instance_ fields of a value type: if a callback `struct` has a `static` field of any type, or a reference field, then that value will correctly be shared between parallel threads. - -## Methods - -These are the 4 main APIs exposed by `ParallelHelper`, corresponding to the `IAction`, `IAction2D`, `IRefAction` and `IInAction` interfaces. The `ParallelHelper` type also exposes a number of overloads for these methods, that offer a number of ways to specify the iteration range(s), or the type of input callback. `For` and `For2D` work on `IAction` and `IAction2D` instances, and they are meant to be used when some parallel work needs to be done that doesn't necessary map to an underlying collection that can be directly accessed with the indices of each parallel iteration. The `ForEach` overloads instead wotk on `IRefAction` and `IInAction` instances, and they can be used when the parallel iterations directly map to items in a collection that can be indexed directly. In this case they also abstract away the indexing logic, so that each parallel invocation only has to worry on the input item to work on, and not on how to retrieve that item as well. - -## Examples - -You can find more examples in the [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/UnitTests/UnitTests.HighPerformance.Shared/Helpers). diff --git a/docs/high-performance/Ref.md b/docs/high-performance/Ref.md deleted file mode 100644 index 2504c879d..000000000 --- a/docs/high-performance/Ref.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: Ref<T> and ReadOnlyRef<T> -author: Sergio0694 -description: Two stack-only types that can store a reference to a value of a specified type -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, parallel, high performance, net core, net standard -dev_langs: - - csharp ---- -# Ref<T> and ReadOnlyRef<T> - -## Ref<T> - -The [`Ref&`](/dotnet/api/microsoft.toolkit.highperformance.ref-1) is a stack-only type that can store a reference to a value of a specified type. It is semantically equivalent to a `ref T` value, with the difference that it can also be used as a type of field in another stack-only `struct` type. It can be used in place of proper `ref T` fields, which are currently not supported in C#. - -> **Platform APIs:** [`Ref&`](/dotnet/api/microsoft.toolkit.highperformance.ref-1), [`ReadOnlyRef`](/dotnet/api/microsoft.toolkit.highperformance.readonlyref-1) - -### How it works - -> [!NOTE] -> Due to how it's implemented on different .NET Standard contracts, the `Ref` has some minor differences on .NET Standard 1.4 and .NET Standard 2.1 (and equivalent .NET Core runtimes). In particular, on .NET Standard 1.4 it can only be used to reference fields _within an object_, instead of arbitrary values pointed by a managed reference. This is because the underlying APIs being used on .NET Standard 1.4 don't have built-in support for the `Span` type. - -#### `Ref` on .NET Standard 1.4 - -As mentioned before, on .NET Standard 1.4, `Ref` can only point to locations within a given `object`. Consider the following code: - -```csharp -// Be sure to include this using at the top of the file: -using Microsoft.Toolkit.HighPerformance; - -// Define a sample model -class MyModel -{ - public int Number = 42; -} - -var model = new MyModel(); - -// Create a Ref pointing to the MyModel.Number field -Ref byRef = new Ref(model, ref model.Number); - -// Modify the field indirectly -byRef.Value++; - -Console.WriteLine(model.Number); // Prints 43! -``` - -> [!WARNING] -> The `Ref` constructor doesn't validate the input arguments, meaning that it is your responsibility to pass a valid `object` and a reference to a field within that object. Failing to do so might cause the `Ref.Value` property to return an invalid reference. - -#### `Ref` on .NET Standard 2.1 - -On .NET Standard 2.1, `Ref` can point to any `ref T` value: - -```csharp -int number = 42; - -// Create a Ref pointing to 'number' -Ref byRef1 = new Ref(ref number); - -// Modify 'number' -byRef1.Value++; - -Console.WriteLine(number); // Prints 43! -``` - -> [!WARNING] -> This type comes with a few caveats and should be used carefully, as it can lead to runtime crashes if a `Ref` instance is created with an invalid reference. In particular, you should only create a `Ref` instance pointing to values that have a lifetime that is greater than that of the `Ref` in use. Consider the following snippet: - -```csharp -public static ref int GetDummyReference() -{ - int number = 42; - - Ref byRef = new Ref(ref number); - - return ref byRef.Value; -} -``` - -This will compile and run fine, but the returned `ref int` will be invalid (as in, it will not point to a valid location) and could cause crashes if it's dereferenced. It is your responsibility to track the lifetime of values being referenced by new `Ref` values. - -> [!NOTE] -> Although it is possible to create a `Ref` value wrapping a `null` reference, by using the `default(Ref)` expression, the `Ref` type is not designed to be used with nullable references and does not include proper features to validate the internal reference. If you need to return a reference that can be set to `null`, use the `NullableRef` and `NullableReadOnlyRef` types. - -## ReadOnlyRef<T> - -The [`ReadOnlyRef`](/dotnet/api/microsoft.toolkit.highperformance.readonlyref-1) is a stack-only type that mirrors `Ref`, with the exception that its constructor takes an `in T` parameter (a readonly reference), instead of a `ref T` one. Similarly, its `Value` property has a `ref readonly T` return type instead of `ref T`. - -### Examples - -You can find more examples in the [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/UnitTests/UnitTests.HighPerformance.Shared). diff --git a/docs/high-performance/Span2D.md b/docs/high-performance/Span2D.md deleted file mode 100644 index 760a5ff4e..000000000 --- a/docs/high-performance/Span2D.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Span2D<T> and ReadOnlySpan2D<T> -author: Sergio0694 -description: A stack-only type that mirrors the behavior of Span<T> and ReadOnlySpan<T>, but supporting arbitrary 2D memory locations -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, parallel, high performance, net core, net standard -dev_langs: - - csharp ---- - -# Span2D<T> - -The [`Span2D`](/dotnet/api/microsoft.toolkit.highperformance.span2d-1) is a type that mirrors the functionality of the [`Span`](/dotnet/api/system.span-1) type, but it supports 2D memory regions. Just like [`Memory2D`](/dotnet/api/microsoft.toolkit.highperformance.memory2d-1), it is extremely flexible and can wrap a number of different objects, as well as native pointers or GC references. - -The internal layout is similar to that used by the [`Memory2D`](/dotnet/api/microsoft.toolkit.highperformance.Memory2D-1) type, including a pitch parameter that is used to enable support for discontiguous memory buffers. You can read more info on this in the `Memory2D` docs. - -> **Platform APIs:** [`Span2D`](/dotnet/api/microsoft.toolkit.highperformance.span2d-1), [`Memory2D`](/dotnet/api/microsoft.toolkit.highperformance.Memory2D-1), [`ReadOnlySpan2D`](/dotnet/api/microsoft.toolkit.highperformance.readonlyspan2d-1) - -## Syntax - -Here's how you can create a `Span2D` instance from a 2D array: - -```csharp -int[,] array = -{ - { 1, 2, 3 }, - { 4, 5, 6 } -}; - -Span2D span = array; - -// The memory directly maps the 2*3 array here - -span[0, 0] = 10; -span[2, 1] = 20; - -// The array is now: -// { 10, 2, 3 }, -// { 4, 20, 6 } - -// We can also use indices, on supported runtimes -int x = span[0, ^1]; - -// We can also get references to items, like with arrays -ref int reference = ref span[1, 1]; - -Span2D slice = span.Slice(0, 1, 2, 2); - -// Or alternatively, on supported runtimes - -slice = span[.., 1..]; - -int[,] copy = slice.ToArray(); - -// The resulting array is: -// { 2, 3 }, -// { 20, 6 } -``` - -We can also directly create a 2D view over native memory: - -```csharp -int* p = stackalloc int[9]; - -Span2D span = new Span2D(p, 3, 3); -``` - -The `Span2D` type also includes custom enumerator types to easily traverse a given row, column or the entire memory area using the standard `foreach` syntax in C#, as well as performing bulk operations in a single call: - -```csharp -int[,] array = -{ - { 1, 2, 3 }, - { 4, 5, 6 }, - { 7, 8, 9 } -}; - -Span2D span = array; - -foreach (int i in span.GetColumn(1)) -{ - // 2, 5, 8 -} - -// We can also iterate by reference -foreach (ref int i in span.GetRow(2)) -{ - // 7, 8, 9 -} - -foreach (int i in span) -{ - // 1, 2, 3, 4, 5... -} - -// Set all items in a column to 0 -span.GetColumn(0).Clear(); - -// Set the value of all items in a row -span.GetRow(1).Fill(42); - -Span copy = stackalloc int[3]; - -// Copy all items from a column -span.GetColumn(2).CopyTo(copy); - -// Get a copy of a row as an array -int[] array = span.GetRow(1).ToArray(); -``` - -## ReadOnlySpan2D<T> - -The [`ReadOnlySpan2D`](/dotnet/api/microsoft.toolkit.highperformance.readonlyspan2d-1) is to the `Span2D` type what `ReadOnlySpan` is to `Span`. It exposes a similar set of APIs but provides no way to directly modify the contents of the underlying memory area. - -## Sample Code - -You can find more examples in the [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/UnitTests/UnitTests.HighPerformance.Shared). diff --git a/docs/high-performance/SpanOwner.md b/docs/high-performance/SpanOwner.md deleted file mode 100644 index 848c7891c..000000000 --- a/docs/high-performance/SpanOwner.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: SpanOwner<T> -author: Sergio0694 -description: A stack-only buffer type renting memory from a shared pool -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, parallel, high performance, net core, net standard -dev_langs: - - csharp ---- - -# SpanOwner<T> - -The [`SpanOwner`](/dotnet/api/microsoft.toolkit.highperformance.buffers.spanowner-1) is a stack-only buffer type that rents buffers from a shared memory pool. It essentially mirrors the functionality of [`MemoryOwner`](/dotnet/api/microsoft.toolkit.highperformance.buffers.memoryowner-1), but as a `ref struct` type. This is particularly useful for short-lived buffers that are only used in synchronous code (that don't require [`Memory`](/dotnet/api/system.memory-1) instances), as well as code running in a tight loop, as creating `SpanOwner` values will not require memory allocations at all. - -> **Platform APIs:** [`SpanOwner`](/dotnet/api/microsoft.toolkit.highperformance.buffers.spanowner-1), [`MemoryOwner`](/dotnet/api/microsoft.toolkit.highperformance.buffers.memoryowner-1) - -## Syntax - -The same core features of `MemoryOwner` apply to this type as well, with the exception of it being a stack-only `struct`, and the fact that it lacks the [`IMemoryOwner`](/dotnet/api/system.buffers.imemoryowner-1) `interface` implementation, as well as the `Memory` property. The syntax is virtually identical to that used with `MemoryOwner` as well, except for the differences mentioned above. - -As an example, suppose we have a method where we need to allocate a temporary buffer of a specified size (let's call this value `length`), and then use it to perform some work. A first, inefficient version might look like this: - -```csharp -byte[] buffer = new byte[length]; - -// Use buffer here -``` - -This is not ideal, as we're allocating a new buffer every time this code is used, and then throwing it away immediately (as mentioned in the `MemoryOwner` docs as well), which puts more pressure on the garbage collector. We can optimize the code above by using [`ArrayPool`](/dotnet/api/system.buffers.arraypool-1): - -```csharp -// Using directive to access the ArrayPool type -using System.Buffers; - -int[] buffer = ArrayPool.Shared.Rent(length); - -try -{ - // Slice the span, as it might be larger than the requested size - Span span = buffer.AsSpan(0, length); - - // Use the span here -} -finally -{ - ArrayPool.Shared.Return(buffer); -} -``` - -The code above rents a buffer from an array pool, but it's more verbose and error-prone: we need to be careful with the `try/finally` block to make sure to always return the rented buffer to the pool. We can rewrite it by using the `SpanOwner` type, like so: - -```csharp -// Be sure to include this using at the top of the file: -using Microsoft.Toolkit.HighPerformance.Buffers; - -using SpanOwner buffer = SpanOwner.Allocate(length); - -Span span = buffer.Span; - -// Use the span here, no slicing necessary -``` - -The `SpanOwner` instance will internally rent an array, and will take care of returning it to the pool when it goes out of scope. We no longer need to use a `try/finally` block either, as the C# compiler will add that automatically when expanding that `using` statement. As such, the `SpanOwner` type can be seen as a lightweight wrapper around the `ArrayPool` APIs, which makes them both more compact and easier to use, reducing the amount of code that needs to be written to properly rent and dispose short lived buffers. You can see how using `SpanOwner` makes the code much shorter and more straightforward. - -> [!NOTE] -> As this is a stack-only type, it relies on the duck-typed `IDisposable` pattern introduced with C# 8. That is shown in the sample above: the `SpanOwner` type is being used within a `using` block despite the fact that the type doesn't implement the `IDisposable` interface at all, and it's also never boxed. The functionality is just the same: as soon as the buffer goes out of scope, it is automatically disposed. The APIs in `SpanOwner{T}` rely on this pattern for extra performance: they assume that the underlying buffer will never be disposed as long as the `SpanOwner` type is in scope, and they don't perform the additional checks that are done in `MemoryOwner` to ensure that the buffer is in fact still available before returning a `Memory` or `Span` instance from it. As such, this type should always be used with a `using` block or expression. Not doing so will cause the underlying buffer not to be returned to the shared pool. Technically the same can also be achieved by manually calling `Dispose` on the `SpanOwner` type (which doesn't require C# 8), but that is error prone and hence not recommended. - -## Examples - -You can find more examples in the [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/UnitTests/UnitTests.HighPerformance.Shared/Buffers). diff --git a/docs/high-performance/StringPool.md b/docs/high-performance/StringPool.md deleted file mode 100644 index dc9bf7f3e..000000000 --- a/docs/high-performance/StringPool.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: StringPool -author: Sergio0694 -description: A type implementing a configurable pool for string instances -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, parallel, high performance, net core, net standard -dev_langs: - - csharp ---- - -# StringPool - -The [StringPool](/dotnet/api/microsoft.toolkit.highperformance.buffers.stringpool) type implements a configurable pool for `string` instances. This can be used to minimize allocations when creating multiple `string` instances from buffers of `char` or `byte` values. It provides a mechanism that is somewhat similar to [`string` interning](/dotnet/api/system.string.intern), with the main differences being that the pool is configurable, can be reset, is implemented with a best-effort policy and doesn't require to pre-instantiate `string` objects, so it can save the initial allocations as well when working on temporary buffers. - -> **Platform APIs:** [StringPool](/dotnet/api/microsoft.toolkit.highperformance.buffers.stringpool) - -## Syntax - -The main entry point for `StringPool` is its `GetOrAdd(ReadOnlySpan)` API, which returns a `string` instance matching the contents of the input [`ReadOnlySpan`](/dotnet/api/system.readonlyspan-1), possibly getting the returned object from the internal pool. - -As an example, imagine we have an input `string` representing the URL of a given web request, and we want to also retrieve a `string` with just the host name. If we get a large number of requests possibly for a small number of hosts, we might want to cache those `string` instances, we can do so by using the `StringPool` type as follows: - -```csharp -public static string GetHost(string url) -{ - // We assume the input might start either with eg. https:// (or other prefix), - // or directly with the host name. Furthermore, we also assume that the input - // URL will always have a '/' character right after the host name. - // For instance: "https://learn.microsoft.com/dotnet/api/system.string.intern". - int - prefixOffset = url.AsSpan().IndexOf(stackalloc char[] { ':', '/', '/' }), - startIndex = prefixOffset == -1 ? 0 : prefixOffset + 3, - endIndex = url.AsSpan(startIndex).IndexOf('/'); - - // In this example, it would be "learn.microsoft.com" - ReadOnlySpan span = url.AsSpan(startIndex, endIndex); - - return StringPool.Shared.GetOrAdd(span); -} -``` - -The method above does no allocations at all if the requested `string` is already present in the cache, as the lookup is done with just a `ReadOnlySpan` as input, representing a view on the input URL `string`. - -The `StringPool` type can also be useful when parsing raw requests using a different encoding, for instance UTF8. There is a `GetOrAdd` overload that takes an input `ReadOnlySpan` and an [`Encoding`](/dotnet/api/system.text.encoding) instance, which uses a temporary buffer rented from the pool to retrieve a `ReadOnlySpan` value to use for the lookup. This again can greatly reduce the number of allocations depending on the specific use case scenario. - -## Examples - -You can find more examples in the [unit tests](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/rel/7.1.0/UnitTests/UnitTests.HighPerformance.Shared/Buffers). diff --git a/docs/mvvm/AsyncRelayCommand.md b/docs/mvvm/AsyncRelayCommand.md deleted file mode 100644 index 365b4352b..000000000 --- a/docs/mvvm/AsyncRelayCommand.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: AsyncRelayCommand -author: Sergio0694 -description: An asynchronous command whose sole purpose is to relay its functionality to other objects by invoking delegates -keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp toolkit, mvvm, componentmodel, property changed, notification, binding, command, delegate, net core, net standard -dev_langs: - - csharp ---- - -# AsyncRelayCommand and AsyncRelayCommand<T> - -The [`AsyncRelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.AsyncRelayCommand) and [`AsyncRelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.AsyncRelayCommand-1) are `ICommand` implementations that extend the functionalities offered by [`RelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.RelayCommand), with support for asynchronous operations. - -> **Platform APIs:** [`AsyncRelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.AsyncRelayCommand), [`AsyncRelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.AsyncRelayCommand-1), [`RelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.RelayCommand), [`IAsyncRelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.IAsyncRelayCommand), [`IAsyncRelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.IAsyncRelayCommand-1) - -## How they work - -`AsyncRelayCommand` and `AsyncRelayCommand` have the following main features: - -- They extend the functionalities of the synchronous commands included in the library, with support for `Task`-returning delegates. -- They can wrap asynchronous functions with an additional `CancellationToken` parameter to support cancelation, and they expose a `CanBeCanceled` and `IsCancellationRequested` properties, as well as a `Cancel` method. -- They expose an `ExecutionTask` property that can be used to monitor the progress of a pending operation, and an `IsRunning` that can be used to check when an operation completes. This is particularly useful to bind a command to UI elements such as loading indicators. -- They implement the [`IAsyncRelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.IAsyncRelayCommand) and [`IAsyncRelayCommand`](/dotnet/api/microsoft.toolkit.mvvm.input.IAsyncRelayCommand-1) interfaces, which means that viewmodel can easily expose commands using these to reduce the tight coupling between types. For instance, this makes it easier to replace a command with a custom implementation exposing the same public API surface, if needed. - -## Working with asynchronous commands - -Let's imagine a scenario similar to the one described in the `RelayCommand` sample, but a command executing an asynchronous operation: - -```csharp -public class MyViewModel : ObservableObject -{ - public MyViewModel() - { - DownloadTextCommand = new AsyncRelayCommand(DownloadText); - } - - public IAsyncRelayCommand DownloadTextCommand { get; } - - private Task DownloadText() - { - return WebService.LoadMyTextAsync(); - } -} -``` - -With the related UI code: - -```xml - - - - - - - - - - - - - - - - -