Skip to content

Commit 971cf01

Browse files
committed
Merge branch 'master' into dev/7.0.0
2 parents ac4bf26 + c65d648 commit 971cf01

File tree

125 files changed

+12366
-75
lines changed

Some content is hidden

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

125 files changed

+12366
-75
lines changed

CODE_OF_CONDUCT.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
In the interest of fostering an open and welcoming environment, we as
6+
contributors and maintainers pledge to making participation in our project and
7+
our community a harassment-free experience for everyone, regardless of age, body
8+
size, disability, ethnicity, sex characteristics, gender identity and expression,
9+
level of experience, education, socio-economic status, nationality, personal
10+
appearance, race, religion, or sexual identity and orientation.
11+
12+
## Our Standards
13+
14+
Examples of behavior that contributes to creating a positive environment
15+
include:
16+
17+
* Using welcoming and inclusive language
18+
* Being respectful of differing viewpoints and experiences
19+
* Gracefully accepting constructive criticism
20+
* Focusing on what is best for the community
21+
* Showing empathy towards other community members
22+
23+
Examples of unacceptable behavior by participants include:
24+
25+
* The use of sexualized language or imagery and unwelcome sexual attention or
26+
advances
27+
* Trolling, insulting/derogatory comments, and personal or political attacks
28+
* Public or private harassment
29+
* Publishing others' private information, such as a physical or electronic
30+
address, without explicit permission
31+
* Other conduct which could reasonably be considered inappropriate in a
32+
professional setting
33+
34+
## Our Responsibilities
35+
36+
Project maintainers are responsible for clarifying the standards of acceptable
37+
behavior and are expected to take appropriate and fair corrective action in
38+
response to any instances of unacceptable behavior.
39+
40+
Project maintainers have the right and responsibility to remove, edit, or
41+
reject comments, commits, code, wiki edits, issues, and other contributions
42+
that are not aligned to this Code of Conduct, or to ban temporarily or
43+
permanently any contributor for other behaviors that they deem inappropriate,
44+
threatening, offensive, or harmful.
45+
46+
## Scope
47+
48+
This Code of Conduct applies both within project spaces and in public spaces
49+
when an individual is representing the project or its community. Examples of
50+
representing a project or community include using an official project e-mail
51+
address, posting via an official social media account, or acting as an appointed
52+
representative at an online or offline event. Representation of a project may be
53+
further defined and clarified by project maintainers.
54+
55+
## Enforcement
56+
57+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
58+
reported by contacting the project team at [email protected]. All
59+
complaints will be reviewed and investigated and will result in a response that
60+
is deemed necessary and appropriate to the circumstances. The project team is
61+
obligated to maintain confidentiality with regard to the reporter of an incident.
62+
Further details of specific enforcement policies may be posted separately.
63+
64+
Project maintainers who do not follow or enforce the Code of Conduct in good
65+
faith may face temporary or permanent repercussions as determined by other
66+
members of the project's leadership.
67+
68+
## Attribution
69+
70+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71+
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72+
73+
[homepage]: https://www.contributor-covenant.org
74+
75+
For answers to common questions about this code of conduct, see
76+
https://www.contributor-covenant.org/faq
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Diagnostics;
7+
using System.Diagnostics.CodeAnalysis;
8+
using System.Diagnostics.Contracts;
9+
using System.Runtime.CompilerServices;
10+
11+
#nullable enable
12+
13+
namespace Microsoft.Toolkit.HighPerformance
14+
{
15+
/// <summary>
16+
/// A <see langword="class"/> that represents a boxed <typeparamref name="T"/> value on the managed heap.
17+
/// </summary>
18+
/// <typeparam name="T">The type of value being boxed.</typeparam>
19+
[DebuggerDisplay("{ToString(),raw}")]
20+
public sealed class Box<T>
21+
where T : struct
22+
{
23+
// Boxed value types in the CLR are represented in memory as simple objects that store the method table of
24+
// the corresponding T value type being boxed, and then the data of the value being boxed:
25+
// [ sync block || pMethodTable || boxed T value ]
26+
// ^ ^
27+
// | \-- Unsafe.Unbox<T>(Box<T>)
28+
// \-- Box<T> reference
29+
// For more info, see: https://mattwarren.org/2017/08/02/A-look-at-the-internals-of-boxing-in-the-CLR/.
30+
// Note that there might be some padding before the actual data representing the boxed value,
31+
// which might depend on both the runtime and the exact CPU architecture.
32+
// This is automatically handled by the unbox !!T instruction in IL, which
33+
// unboxes a given value type T and returns a reference to its boxed data.
34+
35+
/// <summary>
36+
/// Initializes a new instance of the <see cref="Box{T}"/> class.
37+
/// </summary>
38+
/// <remarks>
39+
/// This constructor is never used, it is only declared in order to mark it with
40+
/// the <see langword="private"/> visibility modifier and prevent direct use.
41+
/// </remarks>
42+
private Box()
43+
{
44+
}
45+
46+
/// <summary>
47+
/// Returns a <see cref="Box{T}"/> reference from the input <see cref="object"/> instance.
48+
/// </summary>
49+
/// <param name="obj">The input <see cref="object"/> instance, representing a boxed <typeparamref name="T"/> value.</param>
50+
/// <returns>A <see cref="Box{T}"/> reference pointing to <paramref name="obj"/>.</returns>
51+
[Pure]
52+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
53+
public static Box<T> GetFrom(object obj)
54+
{
55+
if (obj.GetType() != typeof(T))
56+
{
57+
ThrowInvalidCastExceptionForGetFrom();
58+
}
59+
60+
return Unsafe.As<Box<T>>(obj);
61+
}
62+
63+
/// <summary>
64+
/// Returns a <see cref="Box{T}"/> reference from the input <see cref="object"/> instance.
65+
/// </summary>
66+
/// <param name="obj">The input <see cref="object"/> instance, representing a boxed <typeparamref name="T"/> value.</param>
67+
/// <returns>A <see cref="Box{T}"/> reference pointing to <paramref name="obj"/>.</returns>
68+
/// <remarks>
69+
/// This method doesn't check the actual type of <paramref name="obj"/>, so it is responsability of the caller
70+
/// to ensure it actually represents a boxed <typeparamref name="T"/> value and not some other instance.
71+
/// </remarks>
72+
[Pure]
73+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
74+
public static Box<T> DangerousGetFrom(object obj)
75+
{
76+
return Unsafe.As<Box<T>>(obj);
77+
}
78+
79+
/// <summary>
80+
/// Tries to get a <see cref="Box{T}"/> reference from an input <see cref="object"/> representing a boxed <typeparamref name="T"/> value.
81+
/// </summary>
82+
/// <param name="obj">The input <see cref="object"/> instance to check.</param>
83+
/// <param name="box">The resulting <see cref="Box{T}"/> reference, if <paramref name="obj"/> was a boxed <typeparamref name="T"/> value.</param>
84+
/// <returns><see langword="true"/> if a <see cref="Box{T}"/> instance was retrieved correctly, <see langword="false"/> otherwise.</returns>
85+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
86+
[SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1115", Justification = "Comment for [NotNullWhen] attribute")]
87+
public static bool TryGetFrom(
88+
object obj,
89+
#if NETSTANDARD2_1
90+
/* On .NET Standard 2.1, we can add the [NotNullWhen] attribute
91+
* to let the code analysis engine know that whenever this method
92+
* returns true, box will always be assigned to a non-null value.
93+
* This will eliminate the null warnings when in a branch that
94+
* is only taken when this method returns true. */
95+
[NotNullWhen(true)]
96+
#endif
97+
out Box<T>? box)
98+
{
99+
if (obj.GetType() == typeof(T))
100+
{
101+
box = Unsafe.As<Box<T>>(obj);
102+
103+
return true;
104+
}
105+
106+
box = null;
107+
108+
return false;
109+
}
110+
111+
/// <summary>
112+
/// Implicitly gets the <typeparamref name="T"/> value from a given <see cref="Box{T}"/> instance.
113+
/// </summary>
114+
/// <param name="box">The input <see cref="Box{T}"/> instance.</param>
115+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
116+
public static implicit operator T(Box<T> box)
117+
{
118+
return Unsafe.Unbox<T>(box);
119+
}
120+
121+
/// <summary>
122+
/// Implicitly creates a new <see cref="Box{T}"/> instance from a given <typeparamref name="T"/> value.
123+
/// </summary>
124+
/// <param name="value">The input <typeparamref name="T"/> value to wrap.</param>
125+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
126+
public static implicit operator Box<T>(T value)
127+
{
128+
/* The Box<T> type is never actually instantiated.
129+
* Here we are just boxing the input T value, and then reinterpreting
130+
* that object reference as a Box<T> reference. As such, the Box<T>
131+
* type is really only used as an interface to access the contents
132+
* of a boxed value type. This also makes it so that additional methods
133+
* like ToString() or GetHashCode() will automatically be referenced from
134+
* the method table of the boxed object, meaning that they don't need to
135+
* manually be implemented in the Box<T> type. For instance, boxing a float
136+
* and calling ToString() on it directly, on its boxed object or on a Box<T>
137+
* reference retrieved from it will produce the same result in all cases. */
138+
return Unsafe.As<Box<T>>(value);
139+
}
140+
141+
/// <inheritdoc/>
142+
public override string ToString()
143+
{
144+
/* Here we're overriding the base object virtual methods to ensure
145+
* calls to those methods have a correct results on all runtimes.
146+
* For instance, not doing so is causing issue on .NET Core 2.1 Release
147+
* due to how the runtime handles the Box<T> reference to an actual
148+
* boxed T value (not a concrete Box<T> instance as it would expect).
149+
* To fix that, the overrides will simply call the expected methods
150+
* directly on the boxed T values. These methods will be directly
151+
* invoked by the JIT compiler when using a Box<T> reference. When
152+
* an object reference is used instead, the call would be forwarded
153+
* to those same methods anyway, since the method table for an object
154+
* representing a T instance is the one of type T anyway. */
155+
return this.GetReference().ToString();
156+
}
157+
158+
/// <inheritdoc/>
159+
public override bool Equals(object obj)
160+
{
161+
return Equals(this, obj);
162+
}
163+
164+
/// <inheritdoc/>
165+
public override int GetHashCode()
166+
{
167+
return this.GetReference().GetHashCode();
168+
}
169+
170+
/// <summary>
171+
/// Throws an <see cref="InvalidCastException"/> when a cast from an invalid <see cref="object"/> is attempted.
172+
/// </summary>
173+
[MethodImpl(MethodImplOptions.NoInlining)]
174+
private static void ThrowInvalidCastExceptionForGetFrom()
175+
{
176+
throw new InvalidCastException($"Can't cast the input object to the type Box<{typeof(T)}>");
177+
}
178+
}
179+
180+
/// <summary>
181+
/// Helpers for working with the <see cref="Box{T}"/> type.
182+
/// </summary>
183+
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402", Justification = "Extension class to replace instance methods for Box<T>")]
184+
[SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204", Justification = "Extensions being declared after the type they apply to")]
185+
public static class BoxExtensions
186+
{
187+
/// <summary>
188+
/// Gets a <typeparamref name="T"/> reference from a <see cref="Box{T}"/> instance.
189+
/// </summary>
190+
/// <typeparam name="T">The type of reference to retrieve.</typeparam>
191+
/// <param name="box">The input <see cref="Box{T}"/> instance.</param>
192+
/// <returns>A <typeparamref name="T"/> reference to the boxed value within <paramref name="box"/>.</returns>
193+
[Pure]
194+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
195+
public static ref T GetReference<T>(this Box<T> box)
196+
where T : struct
197+
{
198+
/* The reason why this method is an extension and is not part of
199+
* the Box<T> type itself is that Box<T> is really just a mask
200+
* used over object references, but it is never actually instantiated.
201+
* Because of this, the method table of the objects in the heap will
202+
* be the one of type T created by the runtime, and not the one of
203+
* the Box<T> type. To avoid potential issues when invoking this method
204+
* on different runtimes, which might handle that scenario differently,
205+
* we use an extension method, which is just syntactic sugar for a static
206+
* method belonging to another class. This isn't technically necessary,
207+
* but it's just an extra precaution since the syntax for users remains
208+
* exactly the same anyway. Here we just call the Unsafe.Unbox<T>(object)
209+
* API, which is hidden away for users of the type for simplicity.
210+
* Note that this API will always actually involve a conditional
211+
* branch, which is introduced by the JIT compiler to validate the
212+
* object instance being unboxed. But since the alternative of
213+
* manually tracking the offset to the boxed data would be both
214+
* more error prone, and it would still introduce some overhead,
215+
* this doesn't really matter in this case anyway. */
216+
return ref Unsafe.Unbox<T>(box);
217+
}
218+
}
219+
}

0 commit comments

Comments
 (0)