-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Microsoft.Toolkit.HighPerformance package #3128
Merged
michael-hawker
merged 319 commits into
CommunityToolkit:master
from
Sergio0694:feature/high-perf-apis
May 5, 2020
Merged
Changes from 250 commits
Commits
Show all changes
319 commits
Select commit
Hold shift + click to select a range
fc9ead5
Code refactoring
Sergio0694 9f9be38
Added StringExtensions tests
Sergio0694 79cb412
Fixed test method names
Sergio0694 bdf712e
Added ArrayExtensions tests
Sergio0694 f47b006
Removed MemoryPool<T>.Resize extension
Sergio0694 445f221
Added ArrayPoolExtensions tests
Sergio0694 6c76b1c
Added SpinLockExtensions tests
Sergio0694 9c877dd
Moved HashCode<T> class to Helpers namespace
Sergio0694 c81104c
Added ByReference<T> tests
Sergio0694 27f8a01
Changed visibility of one constructor
Sergio0694 c7edb06
Improved ByReference<T> tests
Sergio0694 515913b
Added ReadOnlyByReference<T> tests
Sergio0694 6569e50
Merge pull request #2 from Sergio0694/tests/high-perf-apis
Sergio0694 24e74ca
Fixed a small build error
Sergio0694 54e04ef
Added new List<T> extensions
Sergio0694 092057a
Added List<T> extensions tests
Sergio0694 2306037
Merge pull request #3 from Sergio0694/feature/high-perf-list-extensions
Sergio0694 8b01680
Fixed a parameter name
Sergio0694 7b713c3
Fixed incorrect XML docs
Sergio0694 a50d0dd
Added missing List<T> extension APIs
Sergio0694 7337a74
Disabled warning
Sergio0694 1c8b34f
Removed unnecessary type constraint
Sergio0694 41c64bf
Bug fixes to some List<T> extensions
Sergio0694 0318498
Improved some XML docs
Sergio0694 4ded3cf
Added List<T>.DangerousAsSpan extension
Sergio0694 124d081
Added more unit tests
Sergio0694 9af1541
Fixed a bug in the List<T>.DangerousAsSpan extension
Sergio0694 637b772
Minor tweaks to some docs
Sergio0694 d7d33e4
Removed List<T> extensions (too hacky)
Sergio0694 22751f0
Minor code tweaks (just in case)
Sergio0694 b0c364d
Fixed incorrect API visibility
Sergio0694 7337fa2
Added tests for the HashCode<T> type
Sergio0694 59a0b0f
Added .NET Core 3.0 tests for HashCode<T>
Sergio0694 731131c
Added ParallelHelper.For tests
Sergio0694 177ec09
Code refactoring
Sergio0694 768f29b
Added ParallelHelper.For2D tests
Sergio0694 ad6d647
Fixed empty condition check for 2D loops
Sergio0694 0aeb839
Added ParallelHelper.ForEach in tests
Sergio0694 0a15b25
Added ParallelHelper.ForEach ref tests
Sergio0694 78376cf
Fixed ParallelHelper.For2D tests
Sergio0694 2e5dc71
Improved ParallelHelper.For/2D tests
Sergio0694 e52333d
Switched HighPerformance tests to shared project
Sergio0694 25bfeef
Renamed HighPerformance.NetCore project
Sergio0694 0bc4710
Moved HighPerformance tests to subfolder
Sergio0694 198f021
Fixed incorrect namespaces
Sergio0694 0cc1bad
Added empty HighPerformance.UWP test project
Sergio0694 98f22ef
Fixed shared project for UWP test project
Sergio0694 d3d2c6a
Added missing Unsafe NuGet package to UWP project
Sergio0694 a8163ee
Switched compile tile directives in HighPerformance project
Sergio0694 f4fb15a
Merge pull request #4 from Sergio0694/tests/high-perf-on-uwp
Sergio0694 0d0fa11
Added missing file headers
Sergio0694 481989f
Minor code refactoring to HashCode<T>
Sergio0694 1fbb18a
Minor performance improvements
Sergio0694 fac4974
Fixed HashCode<T>.Combine API for > int.MaxValue byte sizes
Sergio0694 b3e1b6c
Improved HashCode<T>.Combine performance on small spans
Sergio0694 e8f667f
Speed improvements in the GetDjb2HashCode<T> API
Sergio0694 fd015c2
Refactored HashCode<T> to facilitate extensions
Sergio0694 b4e0228
Fixed incorrect namespace
Sergio0694 3e9e562
Added HashCodeExtensions class
Sergio0694 fe69083
Added HashCodeExtensions tests
Sergio0694 51d1f03
Merge pull request #5 from Sergio0694/feature/hash-code-extensions
Sergio0694 d9e89a6
Minor code style tweaks
Sergio0694 fd5eab5
Added SpanEnumerable<T> type
Sergio0694 6c13389
Updated T[] and Span<T> Enumerate extensions
Sergio0694 e03c05c
Added SpanExtensions tests
Sergio0694 8160b97
Merge pull request #6 from Sergio0694/feature/span-enumerator
Sergio0694 5825f7c
Fixed an issue in the DJB2 hash method
Sergio0694 d0604e4
Minor code refactoring
Sergio0694 d779651
Added EditorBrowsable attributes to enumerator types
Sergio0694 c6a62e8
Added MemoryOwner<T> type
Sergio0694 dcea9d2
Minor code refactoring
Sergio0694 1d13037
More code refactoring
Sergio0694 a0cac52
Added MemoryOwner<T> Empty and Length properties
Sergio0694 0170a85
Added missing header text
Sergio0694 4d68280
Fixed a refactoring typo
Sergio0694 61a96e1
Added MemoryOwner<T> tests
Sergio0694 49cdcde
Minor code refactoring
Sergio0694 ebc9de1
Fixed MemoryOwner<T> XML docs
Sergio0694 8246a62
Minor optimization to GetDjb2HashCode
Sergio0694 fd0dd18
Minor optimization to HashCode<T>.CombineValues
Sergio0694 bd8e98d
Minor optimization to Count extension with managed types
Sergio0694 a8b7f9e
Added a Count test for the managed path
Sergio0694 a128948
Added BoolExtensions.ToInt API
Sergio0694 9a21816
Removed automatically added rules
Sergio0694 9e9bb1b
Fixed incorrect XML docs
Sergio0694 50ab934
Added MemoryOwner<T>.DangerousGetReference API
Sergio0694 a9b6fe4
Added extensions for some MemoryMarshal APIs
Sergio0694 3151b83
Merge branch 'master' into feature/high-perf-apis
Sergio0694 4ac25b8
Minor code tweaks
Sergio0694 c68c000
Added MemoryOwner<T> method
Sergio0694 1361e6a
Added more XML comments
Sergio0694 f8b2d47
Fixed an incorrect method prototype
Sergio0694 89a2433
Code refactoring, added AllocationMode enum
Sergio0694 adf1cf7
Added SpanOwner<T> type
Sergio0694 0ce5444
Added SpanOwner<T> tests
Sergio0694 53ac1ef
Removed unnecessary check
Sergio0694 de1e761
Removed unnecessary package reference on .NET Standard 2.1
Sergio0694 19db944
Improved tests for ReadOnlySpan<T>.Count
Sergio0694 aa15f3c
Fixed a bug in ReadOnlySpan<T>.Count with managed types
Sergio0694 2d0b7dd
Updated two type constraints
Sergio0694 3a8aeb8
Minor optimizations to ParallelHelper
Sergio0694 ec5cbd0
Minor code tweaks
Sergio0694 4246fcd
Removed unnecessary APIs
Sergio0694 5a8d245
Added UInt32Extensions class
Sergio0694 2496665
Added unit tests for the UInt32Extensions class
Sergio0694 9a87296
Fixed some comments
Sergio0694 66d430c
Added some remarks to the new uint APIs
Sergio0694 e161a94
Minor optimization
Sergio0694 9c1a1b3
Added UInt64Extensions class
Sergio0694 c7ef640
Added unit tests for UInt64Extensions type
Sergio0694 6e9a2a1
Fixed some typos and comments
Sergio0694 2952daf
Fixed a unit test
Sergio0694 2a6335b
Minor performance improvements
Sergio0694 28d10c7
Added ToString() override and debug display to MemoryOwner<T>
Sergio0694 bc8094c
Added ToString() override and debug display to SpanOwner<T>
Sergio0694 e7e066d
Added MemoryOwner<T> debug proxy type
Sergio0694 0e40898
Added SpanOwner<T> debug proxy type
Sergio0694 321864e
Added missing using directive
Sergio0694 096ac2c
Added info to the .csproj file
Sergio0694 bdaa7ee
Removed two APIs, for additional safety
Sergio0694 7846747
Merge branch 'master' into feature/high-perf-apis
Sergio0694 dc1a502
Refactored bit helpers into a separate class, added by ref overloads
Sergio0694 2df5324
Minor code tweaks
Sergio0694 3d224a5
Merge branch 'master' into feature/high-perf-apis
Sergio0694 a477fd1
Merge branch 'master' into feature/high-perf-apis
Sergio0694 90d993c
Added Box<T> type
Sergio0694 9a0e77f
Added tests for the Box<T> type
Sergio0694 cc8f52e
Merge pull request #11 from Sergio0694/feature/box-T
Sergio0694 dd6eb33
Added Box<T> object schema
Sergio0694 fd5b7da
Added Box<T>.GetFrom(object) API
Sergio0694 ce87e47
Added more Box<T> tests, added more comments
Sergio0694 ae09fbd
Fixed a copy paste fail
Sergio0694 69494f2
Added ValueTypeExtensions type
Sergio0694 b406e94
Added ValueTypeExtensions tests
Sergio0694 e7c767e
Merge branch 'master' into feature/high-perf-apis
Sergio0694 6035a0f
Added missing GC.SuppressFinalize call in MemoryOwner<T>
Sergio0694 6a486b8
Initial implementation of MemoryStream
Sergio0694 345d375
Implemented MemoryStream.Seek method
Sergio0694 b0c4f97
Implemented ReadByte and WriteByte methods
Sergio0694 f8102ef
Added Memory<T> extension to create a Stream
Sergio0694 c3a0c2c
Implemented MemoryStream.Dispose method
Sergio0694 935572c
Fixed typos in a test class
Sergio0694 2c48a16
Added ReadAsync overrides
Sergio0694 8b8e3c7
Added WriteAsync overrides
Sergio0694 faa6f77
Code refactoring
Sergio0694 8f99d1e
Added more .NET Standard 2.1 overrides
Sergio0694 fc9fea7
Moved CopyToAsync method to .NET Standard 2.0
Sergio0694 50f4cdc
Moved FlushAsync, reordered methods
Sergio0694 627efc6
Added [ReadOnly]Memory<T> extension tests
Sergio0694 56752f0
Added initial stream tests
Sergio0694 ddc2479
Fixed a bug in MemoryStream.Read
Sergio0694 5edaebb
Added unit tests for the MemoryStream type
Sergio0694 e37961c
Added MemoryStream.[Read|Write]Byte tests, minor tweaks
Sergio0694 cca83a0
Merge pull request #12 from Sergio0694/feature/memory-streams
Sergio0694 66ae978
Updated .sln file
Sergio0694 059f0c8
Added IMemoryOwnerStream type
Sergio0694 7e3d812
Added IMemoryOwnerExtensions.AsStream type
Sergio0694 b6082e2
Minor tweaks to some XML comments
Sergio0694 30d8b16
Added IMemoryOwner extensions and stream tests
Sergio0694 f8e29d8
Fixed an incorrect namespace
Sergio0694 9327fcd
Aadded ArrayPoolBufferWriter<T> type
Sergio0694 93b9081
Minor code refactoring
Sergio0694 7cb64b3
Added debug view and ToString override for ArrayPoolBufferWriter<T>
Sergio0694 f134100
Minor code refactoring
Sergio0694 9acf1c9
Added destructor to ArrayPoolBufferWriter<T> type
Sergio0694 c51ff5a
Added tests for ArrayPoolBufferWriter<T>
Sergio0694 ef4c0de
Merge pull request #13 from Sergio0694/feature/pool-buffer-writer
Sergio0694 9dd5a43
Fixed some copy-paste fails
Sergio0694 14c025a
Added IMemoryOwner<T> interface to ArrayPoolBufferWriter<T>
Sergio0694 96845ba
Merge branch 'master' into feature/high-perf-apis
Sergio0694 0d38b2b
Updated .csproj description
Sergio0694 be2a3f6
Merge branch 'master' into feature/high-perf-apis
Sergio0694 648a373
Fixed some comments
Sergio0694 773bfe3
Merge branch 'master' into feature/high-perf-apis
michael-hawker 2b6ff44
Updated sln
azchohfi a51f3b2
Minor code style tweak
Sergio0694 989d621
Minor optimization, code style tweaks
Sergio0694 cb67314
Fixed some tests not running on .NET Core 3.0
Sergio0694 d1b84e1
Added initial Array2DExtensions type
Sergio0694 10d3d1d
Added T[,].AsSpan extension
Sergio0694 81298f9
Added Count<T> and Djb2 hashcode extensions for T[,] arrays
Sergio0694 54bde92
Added tests for the 2D array extensions
Sergio0694 cff0954
Code refactoring
Sergio0694 32ea59b
Added NullableByReference<T> type
Sergio0694 be57346
Minor code refactoring
Sergio0694 d538383
Added NullableReadOnlyByReference<T> type
Sergio0694 e3855f2
Added unit tests for new Nullable[ReadOnly]ByReference<T> types
Sergio0694 750df08
Merge pull request #16 from Sergio0694/feature/nullable-by-ref
Sergio0694 d4d4e39
Fixed an XML comment
Sergio0694 a076be0
Added T[,] array GetRow and GetColumn extensions
Sergio0694 95edf1d
Added Array2DColumnEnumerable<T>.ToArray() helper method
Sergio0694 79494f4
Code refactoring
Sergio0694 27f3cea
Added T[,].GetRow support on .NET Standard 2.0
Sergio0694 160b753
Added and optimized T[,].Fill extension
Sergio0694 eca873c
Added T[,].Fill tests
Sergio0694 41b2ea8
Added tests for T[,].GetRow extension
Sergio0694 acbb53e
Bug fixes in the 2D array enumerators
Sergio0694 536ceec
Added tests for T[,].GetColumn extension
Sergio0694 ad58d1d
Merge pull request #17 from Sergio0694/feature/toolkit-api-port
Sergio0694 c02a3ab
Merge branch 'master' into feature/high-perf-apis
Sergio0694 0abbe26
Fixed a typo
Sergio0694 b26ef88
Fixed duplicate using directives
Sergio0694 b918082
Fixed an XML comment
Sergio0694 4b053aa
Inverted precompiler conditional directive for clarity
Sergio0694 d61d6bd
Fixed error in an XML comment
Sergio0694 fd6043b
Removed unnecessary using directive
Sergio0694 760fcd2
Fixed publisher name in UWP test project
Sergio0694 e3ee8a8
Added StyleCop.Analyzers package to UWP test project
Sergio0694 dcd9bba
Resolved StyleCop warnings in unit tests
Sergio0694 2fd6342
Added StyleCop.Analyzers package to .NET Core test project
Sergio0694 e747688
Resolved .NET Core specific StyleCop warnings
Sergio0694 570b083
Updated Test SDK and packages in .NET Core unit test project
Sergio0694 31c27e6
Fixed object name in MemoryStream.ThrowObjectDisposedException()
Sergio0694 f1cf183
Minor code style tweak and optimization
Sergio0694 2ff55e1
Added test for the argument name in ParallelHelper exceptions
Sergio0694 af44306
Fixed visibility modifiers
Sergio0694 487808a
Fixed Box<T> type on ARM devices
Sergio0694 8774bc7
Added MemoryStream tests for argument names in exceptions
Sergio0694 939e6ee
Minor improvements to some unit tests
Sergio0694 6ab2a4f
Merge branch 'master' into feature/high-perf-apis
Sergio0694 692d0cf
Removed duplicate System.Runtime.CompilerServices.Unsafe reference
Sergio0694 abf4beb
Removed unnecessary StyleCop reference and .ruleset file
Sergio0694 f2b4977
Resolved StyleCop warnings in unit tests
Sergio0694 5ccbc13
Minor performance improvements in ByReference<T> types on x64
Sergio0694 a18b783
Minor style tweaks
Sergio0694 7b0ec84
Fixed missed refactoring
Sergio0694 f86d948
Code refactoring
Sergio0694 3ac3338
Added missing readonly struct modifiers
Sergio0694 fd22cc1
Merge branch 'master' into feature/high-perf-apis
azchohfi f3826c3
Merge branch 'master' into feature/high-perf-apis
Sergio0694 1a34ded
Merge branch 'master' into feature/high-perf-apis
Sergio0694 b59948c
Enabgled running HighPerformance tests on build.
azchohfi 9382830
Bug fixes in the Box<T> type on some runtimes
Sergio0694 a9e6b15
Added missing "Pack" target in UWP test project
Sergio0694 f63eb02
Code refactoring, moved Box<T> extensions to same file for clarity
Sergio0694 fe40cfb
Merge branch 'master' into feature/high-perf-apis
azchohfi cfd67b4
Merge branch 'master' into feature/high-perf-apis
azchohfi debdac5
Bumped System.Runtime.CompilerServices.Unsafe to 5.0.0-preview.2.20160.6
Sergio0694 77ad2fb
Fixed Box<T>.ToString/GetHashCode issues on .NET Core 2.1 Release
Sergio0694 b8654de
Updated comments on the Box<T>.GetReference() method
Sergio0694 6b9ab8e
Fixed package downgrade in UWP test project
Sergio0694 41af423
Merge branch 'master' into feature/high-perf-apis
Sergio0694 c1d01e1
Aligned ref returns for ReadOnlySpan<T>/string to MemoryMarsha.GetRef…
Sergio0694 14d09bb
Merge branch 'master' into feature/high-perf-apis
Sergio0694 da2d1db
Merge branch 'master' into feature/high-perf-apis
Sergio0694 d31f63d
Merge branch 'master' into feature/high-perf-apis
Sergio0694 893d0e8
Merge branch 'master' into feature/high-perf-apis
Sergio0694 b996bb3
Merge branch 'master' into feature/high-perf-apis
Sergio0694 d4344f4
Renamed ByReference<T> APIs
Sergio0694 80d71ac
Removed unnecessary preview package
Sergio0694 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Diagnostics.Contracts; | ||
using System.Runtime.CompilerServices; | ||
|
||
#nullable enable | ||
|
||
namespace Microsoft.Toolkit.HighPerformance | ||
{ | ||
/// <summary> | ||
/// A <see langword="class"/> that represents a boxed <typeparamref name="T"/> value on the managed heap. | ||
/// </summary> | ||
/// <typeparam name="T">The type of value being boxed.</typeparam> | ||
[DebuggerDisplay("{ToString(),raw}")] | ||
public sealed class Box<T> | ||
where T : struct | ||
{ | ||
// Boxed value types in the CLR are represented in memory as simple objects that store the method table of | ||
// the corresponding T value type being boxed, and then the data of the value being boxed: | ||
// [ sync block || pMethodTable || boxed T value ] | ||
// ^ ^ | ||
// | \-- Unsafe.Unbox<T>(Box<T>) | ||
// \-- Box<T> reference | ||
// For more info, see: https://mattwarren.org/2017/08/02/A-look-at-the-internals-of-boxing-in-the-CLR/. | ||
// Note that there might be some padding before the actual data representing the boxed value, | ||
// which might depend on both the runtime and the exact CPU architecture. | ||
// This is automatically handled by the unbox !!T instruction in IL, which | ||
// unboxes a given value type T and returns a reference to its boxed data. | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="Box{T}"/> class. | ||
/// </summary> | ||
/// <remarks> | ||
/// This constructor is never used, it is only declared in order to mark it with | ||
/// the <see langword="private"/> visibility modifier and prevent direct use. | ||
/// </remarks> | ||
private Box() | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Returns a <see cref="Box{T}"/> reference from the input <see cref="object"/> instance. | ||
/// </summary> | ||
/// <param name="obj">The input <see cref="object"/> instance, representing a boxed <typeparamref name="T"/> value.</param> | ||
/// <returns>A <see cref="Box{T}"/> reference pointing to <paramref name="obj"/>.</returns> | ||
[Pure] | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static Box<T> GetFrom(object obj) | ||
{ | ||
if (obj.GetType() != typeof(T)) | ||
{ | ||
ThrowInvalidCastExceptionForGetFrom(); | ||
} | ||
|
||
return Unsafe.As<Box<T>>(obj); | ||
} | ||
|
||
/// <summary> | ||
/// Returns a <see cref="Box{T}"/> reference from the input <see cref="object"/> instance. | ||
/// </summary> | ||
/// <param name="obj">The input <see cref="object"/> instance, representing a boxed <typeparamref name="T"/> value.</param> | ||
/// <returns>A <see cref="Box{T}"/> reference pointing to <paramref name="obj"/>.</returns> | ||
/// <remarks> | ||
/// This method doesn't check the actual type of <paramref name="obj"/>, so it is responsability of the caller | ||
/// to ensure it actually represents a boxed <typeparamref name="T"/> value and not some other instance. | ||
/// </remarks> | ||
[Pure] | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static Box<T> DangerousGetFrom(object obj) | ||
{ | ||
return Unsafe.As<Box<T>>(obj); | ||
} | ||
|
||
/// <summary> | ||
/// Tries to get a <see cref="Box{T}"/> reference from an input <see cref="object"/> representing a boxed <typeparamref name="T"/> value. | ||
/// </summary> | ||
/// <param name="obj">The input <see cref="object"/> instance to check.</param> | ||
/// <param name="box">The resulting <see cref="Box{T}"/> reference, if <paramref name="obj"/> was a boxed <typeparamref name="T"/> value.</param> | ||
/// <returns><see langword="true"/> if a <see cref="Box{T}"/> instance was retrieved correctly, <see langword="false"/> otherwise.</returns> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
[SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1115", Justification = "Comment for [NotNullWhen] attribute")] | ||
public static bool TryGetFrom( | ||
object obj, | ||
#if NETSTANDARD2_1 | ||
/* On .NET Standard 2.1, we can add the [NotNullWhen] attribute | ||
* to let the code analysis engine know that whenever this method | ||
* returns true, box will always be assigned to a non-null value. | ||
* This will eliminate the null warnings when in a branch that | ||
* is only taken when this method returns true. */ | ||
[NotNullWhen(true)] | ||
#endif | ||
out Box<T>? box) | ||
{ | ||
if (obj.GetType() == typeof(T)) | ||
{ | ||
box = Unsafe.As<Box<T>>(obj); | ||
|
||
return true; | ||
} | ||
|
||
box = null; | ||
|
||
return false; | ||
} | ||
|
||
/// <summary> | ||
/// Implicitly gets the <typeparamref name="T"/> value from a given <see cref="Box{T}"/> instance. | ||
/// </summary> | ||
/// <param name="box">The input <see cref="Box{T}"/> instance.</param> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static implicit operator T(Box<T> box) | ||
{ | ||
return Unsafe.Unbox<T>(box); | ||
} | ||
|
||
/// <summary> | ||
/// Implicitly creates a new <see cref="Box{T}"/> instance from a given <typeparamref name="T"/> value. | ||
/// </summary> | ||
/// <param name="value">The input <typeparamref name="T"/> value to wrap.</param> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static implicit operator Box<T>(T value) | ||
{ | ||
/* The Box<T> type is never actually instantiated. | ||
* Here we are just boxing the input T value, and then reinterpreting | ||
* that object reference as a Box<T> reference. As such, the Box<T> | ||
* type is really only used as an interface to access the contents | ||
* of a boxed value type. This also makes it so that additional methods | ||
* like ToString() or GetHashCode() will automatically be referenced from | ||
* the method table of the boxed object, meaning that they don't need to | ||
* manually be implemented in the Box<T> type. For instance, boxing a float | ||
* and calling ToString() on it directly, on its boxed object or on a Box<T> | ||
* reference retrieved from it will produce the same result in all cases. */ | ||
return Unsafe.As<Box<T>>(value); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override string ToString() | ||
{ | ||
/* Here we're overriding the base object virtual methods to ensure | ||
* calls to those methods have a correct results on all runtimes. | ||
* For instance, not doing so is causing issue on .NET Core 2.1 Release | ||
* due to how the runtime handles the Box<T> reference to an actual | ||
* boxed T value (not a concrete Box<T> instance as it would expect). | ||
* To fix that, the overrides will simply call the expected methods | ||
* directly on the boxed T values. These methods will be directly | ||
* invoked by the JIT compiler when using a Box<T> reference. When | ||
* an object reference is used instead, the call would be forwarded | ||
* to those same methods anyway, since the method table for an object | ||
* representing a T instance is the one of type T anyway. */ | ||
return this.GetReference().ToString(); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override bool Equals(object obj) | ||
{ | ||
return Equals(this, obj); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override int GetHashCode() | ||
{ | ||
return this.GetReference().GetHashCode(); | ||
} | ||
|
||
/// <summary> | ||
/// Throws an <see cref="InvalidCastException"/> when a cast from an invalid <see cref="object"/> is attempted. | ||
/// </summary> | ||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private static void ThrowInvalidCastExceptionForGetFrom() | ||
{ | ||
throw new InvalidCastException($"Can't cast the input object to the type Box<{typeof(T)}>"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Helpers for working with the <see cref="Box{T}"/> type. | ||
/// </summary> | ||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402", Justification = "Extension class to replace instance methods for Box<T>")] | ||
[SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204", Justification = "Extensions being declared after the type they apply to")] | ||
public static class BoxExtensions | ||
{ | ||
/// <summary> | ||
/// Gets a <typeparamref name="T"/> reference from a <see cref="Box{T}"/> instance. | ||
/// </summary> | ||
/// <typeparam name="T">The type of reference to retrieve.</typeparam> | ||
/// <param name="box">The input <see cref="Box{T}"/> instance.</param> | ||
/// <returns>A <typeparamref name="T"/> reference to the boxed value within <paramref name="box"/>.</returns> | ||
[Pure] | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static ref T GetReference<T>(this Box<T> box) | ||
where T : struct | ||
{ | ||
/* The reason why this method is an extension and is not part of | ||
* the Box<T> type itself is that Box<T> is really just a mask | ||
* used over object references, but it is never actually instantiated. | ||
* Because of this, the method table of the objects in the heap will | ||
* be the one of type T created by the runtime, and not the one of | ||
* the Box<T> type. To avoid potential issues when invoking this method | ||
* on different runtimes, which might handle that scenario differently, | ||
* we use an extension method, which is just syntactic sugar for a static | ||
* method belonging to another class. This isn't technically necessary, | ||
* but it's just an extra precaution since the syntax for users remains | ||
* exactly the same anyway. Here we just call the Unsafe.Unbox<T>(object) | ||
* API, which is hidden away for users of the type for simplicity. | ||
* Note that this API will always actually involve a conditional | ||
* branch, which is introduced by the JIT compiler to validate the | ||
* object instance being unboxed. But since the alternative of | ||
* manually tracking the offset to the boxed data would be both | ||
* more error prone, and it would still introduce some overhead, | ||
* this doesn't really matter in this case anyway. */ | ||
return ref Unsafe.Unbox<T>(box); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have some examples/docs at least inline here if not called out about why/where this could be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 018f4a7.