Fix incorrect whitespaces, minor code style tweaks

This commit is contained in:
Sergio Pedri 2021-11-02 00:01:05 +01:00
Родитель 6afdd81742
Коммит 93cb82a0d0
59 изменённых файлов: 2728 добавлений и 2742 удалений

Просмотреть файл

@ -31,9 +31,9 @@ public static class TaskExtensions
// Check if the instance is a completed Task
if (
#if NETSTANDARD2_1
task.IsCompletedSuccessfully
task.IsCompletedSuccessfully
#else
task.Status == TaskStatus.RanToCompletion
task.Status == TaskStatus.RanToCompletion
#endif
)
{
@ -51,9 +51,9 @@ public static class TaskExtensions
// runtime-specific type that inherits from Task<T>.
PropertyInfo? propertyInfo =
#if NETSTANDARD1_4
task.GetType().GetRuntimeProperty(nameof(Task<object>.Result));
task.GetType().GetRuntimeProperty(nameof(Task<object>.Result));
#else
task.GetType().GetProperty(nameof(Task<object>.Result));
task.GetType().GetProperty(nameof(Task<object>.Result));
#endif
// Return the result, if possible
@ -76,7 +76,7 @@ public static class TaskExtensions
public static T? GetResultOrDefault<T>(this Task<T?> task)
{
#if NETSTANDARD2_1
return task.IsCompletedSuccessfully ? task.Result : default;
return task.IsCompletedSuccessfully ? task.Result : default;
#else
return task.Status == TaskStatus.RanToCompletion ? task.Result : default;
#endif

Просмотреть файл

@ -193,7 +193,7 @@ public static class TypeExtensions
#if NETSTANDARD1_4
return type.GetTypeInfo().IsGenericType;
#else
return type.IsGenericType;
return type.IsGenericType;
#endif
}

Просмотреть файл

@ -247,111 +247,111 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <exception cref="COMException">Thrown with no parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowCOMException<T>()
{
throw new COMException();
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <exception cref="COMException">Thrown with no parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowCOMException<T>()
{
throw new COMException();
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="COMException">Thrown with the specified parameter.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowCOMException<T>(string? message)
{
throw new COMException(message);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="COMException">Thrown with the specified parameter.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowCOMException<T>(string? message)
{
throw new COMException(message);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The argument name.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowCOMException<T>(string? message, Exception? innerException)
{
throw new COMException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The argument name.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowCOMException<T>(string? message, Exception? innerException)
{
throw new COMException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The argument name.</param>
/// <param name="error">The HRESULT of the errror to include.</param>
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowCOMException<T>(string? message, int error)
{
throw new COMException(message, error);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The argument name.</param>
/// <param name="error">The HRESULT of the errror to include.</param>
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowCOMException<T>(string? message, int error)
{
throw new COMException(message, error);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <exception cref="ExternalException">Thrown with no parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowExternalException<T>()
{
throw new ExternalException();
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <exception cref="ExternalException">Thrown with no parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowExternalException<T>()
{
throw new ExternalException();
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="ExternalException">Thrown with the specified parameter.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowExternalException<T>(string? message)
{
throw new ExternalException(message);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="ExternalException">Thrown with the specified parameter.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowExternalException<T>(string? message)
{
throw new ExternalException(message);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The argument name.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowExternalException<T>(string? message, Exception? innerException)
{
throw new ExternalException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The argument name.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowExternalException<T>(string? message, Exception? innerException)
{
throw new ExternalException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The argument name.</param>
/// <param name="error">The HRESULT of the errror to include.</param>
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowExternalException<T>(string? message, int error)
{
throw new ExternalException(message, error);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The argument name.</param>
/// <param name="error">The HRESULT of the errror to include.</param>
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowExternalException<T>(string? message, int error)
{
throw new ExternalException(message, error);
}
#endif
/// <summary>
@ -394,44 +394,44 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <exception cref="InsufficientMemoryException">Thrown with no parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowInsufficientMemoryException<T>()
{
throw new InsufficientMemoryException();
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <exception cref="InsufficientMemoryException">Thrown with no parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowInsufficientMemoryException<T>()
{
throw new InsufficientMemoryException();
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowInsufficientMemoryException<T>(string? message)
{
throw new InsufficientMemoryException(message);
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowInsufficientMemoryException<T>(string? message)
{
throw new InsufficientMemoryException(message);
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The message to include in the exception.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowInsufficientMemoryException<T>(string? message, Exception? innerException)
{
throw new InsufficientMemoryException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="message">The message to include in the exception.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowInsufficientMemoryException<T>(string? message, Exception? innerException)
{
throw new InsufficientMemoryException(message, innerException);
}
#endif
/// <summary>
@ -591,19 +591,19 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="MissingFieldException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="className">The target class being inspected.</param>
/// <param name="fieldName">The target field being retrieved.</param>
/// <exception cref="MissingFieldException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowMissingFieldException<T>(string? className, string? fieldName)
{
throw new MissingFieldException(className, fieldName);
}
/// <summary>
/// Throws a new <see cref="MissingFieldException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="className">The target class being inspected.</param>
/// <param name="fieldName">The target field being retrieved.</param>
/// <exception cref="MissingFieldException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowMissingFieldException<T>(string? className, string? fieldName)
{
throw new MissingFieldException(className, fieldName);
}
#endif
/// <summary>
@ -646,19 +646,19 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="MissingMemberException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="className">The target class being inspected.</param>
/// <param name="memberName">The target member being retrieved.</param>
/// <exception cref="MissingMemberException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowMissingMemberException<T>(string? className, string? memberName)
{
throw new MissingMemberException(className, memberName);
}
/// <summary>
/// Throws a new <see cref="MissingMemberException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="className">The target class being inspected.</param>
/// <param name="memberName">The target member being retrieved.</param>
/// <exception cref="MissingMemberException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowMissingMemberException<T>(string? className, string? memberName)
{
throw new MissingMemberException(className, memberName);
}
#endif
/// <summary>
@ -701,19 +701,19 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="MissingMethodException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="className">The target class being inspected.</param>
/// <param name="methodName">The target method being retrieved.</param>
/// <exception cref="MissingMethodException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowMissingMethodException<T>(string? className, string? methodName)
{
throw new MissingMethodException(className, methodName);
}
/// <summary>
/// Throws a new <see cref="MissingMethodException"/>.
/// </summary>
/// <typeparam name="T">The type of expected result.</typeparam>
/// <param name="className">The target class being inspected.</param>
/// <param name="methodName">The target method being retrieved.</param>
/// <exception cref="MissingMethodException">Thrown with the specified parameters.</exception>
/// <returns>This method always throws, so it actually never returns a value.</returns>
[DoesNotReturn]
public static T ThrowMissingMethodException<T>(string? className, string? methodName)
{
throw new MissingMethodException(className, methodName);
}
#endif
/// <summary>

Просмотреть файл

@ -213,95 +213,95 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <exception cref="COMException">Thrown with no paarameters.</exception>
[DoesNotReturn]
public static void ThrowCOMException()
{
throw new COMException();
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <exception cref="COMException">Thrown with no paarameters.</exception>
[DoesNotReturn]
public static void ThrowCOMException()
{
throw new COMException();
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="COMException">Thrown with the specified parameter.</exception>
[DoesNotReturn]
public static void ThrowCOMException(string? message)
{
throw new COMException(message);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="COMException">Thrown with the specified parameter.</exception>
[DoesNotReturn]
public static void ThrowCOMException(string? message)
{
throw new COMException(message);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <param name="message">The argument name.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowCOMException(string? message, Exception? innerException)
{
throw new COMException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <param name="message">The argument name.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowCOMException(string? message, Exception? innerException)
{
throw new COMException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <param name="message">The argument name.</param>
/// <param name="error">The HRESULT of the errror to include.</param>
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowCOMException(string? message, int error)
{
throw new COMException(message, error);
}
/// <summary>
/// Throws a new <see cref="COMException"/>.
/// </summary>
/// <param name="message">The argument name.</param>
/// <param name="error">The HRESULT of the errror to include.</param>
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowCOMException(string? message, int error)
{
throw new COMException(message, error);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <exception cref="ExternalException">Thrown with no parameters.</exception>
[DoesNotReturn]
public static void ThrowExternalException()
{
throw new ExternalException();
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <exception cref="ExternalException">Thrown with no parameters.</exception>
[DoesNotReturn]
public static void ThrowExternalException()
{
throw new ExternalException();
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="ExternalException">Thrown with the specified parameter.</exception>
[DoesNotReturn]
public static void ThrowExternalException(string? message)
{
throw new ExternalException(message);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="ExternalException">Thrown with the specified parameter.</exception>
[DoesNotReturn]
public static void ThrowExternalException(string? message)
{
throw new ExternalException(message);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <param name="message">The argument name.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowExternalException(string? message, Exception? innerException)
{
throw new ExternalException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <param name="message">The argument name.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowExternalException(string? message, Exception? innerException)
{
throw new ExternalException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <param name="message">The argument name.</param>
/// <param name="error">The HRESULT of the errror to include.</param>
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowExternalException(string? message, int error)
{
throw new ExternalException(message, error);
}
/// <summary>
/// Throws a new <see cref="ExternalException"/>.
/// </summary>
/// <param name="message">The argument name.</param>
/// <param name="error">The HRESULT of the errror to include.</param>
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowExternalException(string? message, int error)
{
throw new ExternalException(message, error);
}
#endif
/// <summary>
@ -338,38 +338,38 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <exception cref="InsufficientMemoryException">Thrown with no parameters.</exception>
[DoesNotReturn]
public static void ThrowInsufficientMemoryException()
{
throw new InsufficientMemoryException();
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <exception cref="InsufficientMemoryException">Thrown with no parameters.</exception>
[DoesNotReturn]
public static void ThrowInsufficientMemoryException()
{
throw new InsufficientMemoryException();
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
[DoesNotReturn]
public static void ThrowInsufficientMemoryException(string? message)
{
throw new InsufficientMemoryException(message);
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <param name="message">The message to include in the exception.</param>
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
[DoesNotReturn]
public static void ThrowInsufficientMemoryException(string? message)
{
throw new InsufficientMemoryException(message);
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <param name="message">The message to include in the exception.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
[DoesNotReturn]
public static void ThrowInsufficientMemoryException(string? message, Exception? innerException)
{
throw new InsufficientMemoryException(message, innerException);
}
/// <summary>
/// Throws a new <see cref="InsufficientMemoryException"/>.
/// </summary>
/// <param name="message">The message to include in the exception.</param>
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
[DoesNotReturn]
public static void ThrowInsufficientMemoryException(string? message, Exception? innerException)
{
throw new InsufficientMemoryException(message, innerException);
}
#endif
/// <summary>
@ -505,17 +505,17 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="MissingFieldException"/>.
/// </summary>
/// <param name="className">The target class being inspected.</param>
/// <param name="fieldName">The target field being retrieved.</param>
/// <exception cref="MissingFieldException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowMissingFieldException(string? className, string? fieldName)
{
throw new MissingFieldException(className, fieldName);
}
/// <summary>
/// Throws a new <see cref="MissingFieldException"/>.
/// </summary>
/// <param name="className">The target class being inspected.</param>
/// <param name="fieldName">The target field being retrieved.</param>
/// <exception cref="MissingFieldException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowMissingFieldException(string? className, string? fieldName)
{
throw new MissingFieldException(className, fieldName);
}
#endif
/// <summary>
@ -552,17 +552,17 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="MissingMemberException"/>.
/// </summary>
/// <param name="className">The target class being inspected.</param>
/// <param name="memberName">The target member being retrieved.</param>
/// <exception cref="MissingMemberException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowMissingMemberException(string? className, string? memberName)
{
throw new MissingMemberException(className, memberName);
}
/// <summary>
/// Throws a new <see cref="MissingMemberException"/>.
/// </summary>
/// <param name="className">The target class being inspected.</param>
/// <param name="memberName">The target member being retrieved.</param>
/// <exception cref="MissingMemberException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowMissingMemberException(string? className, string? memberName)
{
throw new MissingMemberException(className, memberName);
}
#endif
/// <summary>
@ -599,17 +599,17 @@ public static partial class ThrowHelper
}
#if !NETSTANDARD1_4
/// <summary>
/// Throws a new <see cref="MissingMethodException"/>.
/// </summary>
/// <param name="className">The target class being inspected.</param>
/// <param name="methodName">The target method being retrieved.</param>
/// <exception cref="MissingMethodException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowMissingMethodException(string? className, string? methodName)
{
throw new MissingMethodException(className, methodName);
}
/// <summary>
/// Throws a new <see cref="MissingMethodException"/>.
/// </summary>
/// <param name="className">The target class being inspected.</param>
/// <param name="methodName">The target method being retrieved.</param>
/// <exception cref="MissingMethodException">Thrown with the specified parameters.</exception>
[DoesNotReturn]
public static void ThrowMissingMethodException(string? className, string? methodName)
{
throw new MissingMethodException(className, methodName);
}
#endif
/// <summary>

Просмотреть файл

@ -52,11 +52,11 @@ internal sealed class ArrayMemoryManager<TFrom, TTo> : MemoryManager<TTo>, IMemo
public override Span<TTo> GetSpan()
{
#if NETSTANDARD2_1_OR_GREATER
ref TFrom r0 = ref this.array.DangerousGetReferenceAt(this.offset);
ref TTo r1 = ref Unsafe.As<TFrom, TTo>(ref r0);
int length = RuntimeHelpers.ConvertLength<TFrom, TTo>(this.length);
ref TFrom r0 = ref this.array.DangerousGetReferenceAt(this.offset);
ref TTo r1 = ref Unsafe.As<TFrom, TTo>(ref r0);
int length = RuntimeHelpers.ConvertLength<TFrom, TTo>(this.length);
return MemoryMarshal.CreateSpan(ref r1, length);
return MemoryMarshal.CreateSpan(ref r1, length);
#else
Span<TFrom> span = this.array.AsSpan(this.offset, this.length);

Просмотреть файл

@ -72,7 +72,7 @@ internal sealed class ProxyMemoryManager<TFrom, TTo> : MemoryManager<TTo>, IMemo
int shiftedOffset = byteOffset / Unsafe.SizeOf<TFrom>();
int remainder = byteOffset - (shiftedOffset * Unsafe.SizeOf<TFrom>());
#else
int shiftedOffset = Math.DivRem(byteOffset, Unsafe.SizeOf<TFrom>(), out int remainder);
int shiftedOffset = Math.DivRem(byteOffset, Unsafe.SizeOf<TFrom>(), out int remainder);
#endif
if (remainder != 0)

Просмотреть файл

@ -10,88 +10,87 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using CommunityToolkit.HighPerformance.Helpers;
namespace CommunityToolkit.HighPerformance.Buffers.Internals
namespace CommunityToolkit.HighPerformance.Buffers.Internals;
/// <summary>
/// A custom <see cref="MemoryManager{T}"/> that can wrap arbitrary <see cref="object"/> instances.
/// </summary>
/// <typeparam name="T">The type of elements in the target memory area.</typeparam>
internal sealed class RawObjectMemoryManager<T> : MemoryManager<T>
{
/// <summary>
/// A custom <see cref="MemoryManager{T}"/> that can wrap arbitrary <see cref="object"/> instances.
/// The target <see cref="object"/> instance.
/// </summary>
/// <typeparam name="T">The type of elements in the target memory area.</typeparam>
internal sealed class RawObjectMemoryManager<T> : MemoryManager<T>
private readonly object instance;
/// <summary>
/// The initial offset within <see cref="instance"/>.
/// </summary>
private readonly IntPtr offset;
/// <summary>
/// The length of the target memory area.
/// </summary>
private readonly int length;
/// <summary>
/// Initializes a new instance of the <see cref="RawObjectMemoryManager{T}"/> class.
/// </summary>
/// <param name="instance">The target <see cref="object"/> instance.</param>
/// <param name="offset">The starting offset within <paramref name="instance"/>.</param>
/// <param name="length">The usable length within <paramref name="instance"/>.</param>
public RawObjectMemoryManager(object instance, IntPtr offset, int length)
{
/// <summary>
/// The target <see cref="object"/> instance.
/// </summary>
private readonly object instance;
this.instance = instance;
this.offset = offset;
this.length = length;
}
/// <summary>
/// The initial offset within <see cref="instance"/>.
/// </summary>
private readonly IntPtr offset;
/// <inheritdoc/>
public override Span<T> GetSpan()
{
ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(this.instance, this.offset);
/// <summary>
/// The length of the target memory area.
/// </summary>
private readonly int length;
return MemoryMarshal.CreateSpan(ref r0, this.length);
}
/// <summary>
/// Initializes a new instance of the <see cref="RawObjectMemoryManager{T}"/> class.
/// </summary>
/// <param name="instance">The target <see cref="object"/> instance.</param>
/// <param name="offset">The starting offset within <paramref name="instance"/>.</param>
/// <param name="length">The usable length within <paramref name="instance"/>.</param>
public RawObjectMemoryManager(object instance, IntPtr offset, int length)
/// <inheritdoc/>
public override unsafe MemoryHandle Pin(int elementIndex = 0)
{
if ((uint)elementIndex >= (uint)this.length)
{
this.instance = instance;
this.offset = offset;
this.length = length;
ThrowArgumentOutOfRangeExceptionForInvalidElementIndex();
}
/// <inheritdoc/>
public override Span<T> GetSpan()
{
ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(this.instance, this.offset);
// Allocating a pinned handle for the array with fail and throw an exception
// if the array contains non blittable data. This is the expected behavior and
// the same happens when trying to pin a Memory<T> instance obtained through
// traditional means (eg. via the implicit T[] array conversion), if T is a
// reference type or a type containing some references.
GCHandle handle = GCHandle.Alloc(this.instance, GCHandleType.Pinned);
ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(this.instance, this.offset);
ref T r1 = ref Unsafe.Add(ref r0, (nint)(uint)elementIndex);
void* p = Unsafe.AsPointer(ref r1);
return MemoryMarshal.CreateSpan(ref r0, this.length);
}
return new MemoryHandle(p, handle);
}
/// <inheritdoc/>
public override unsafe MemoryHandle Pin(int elementIndex = 0)
{
if ((uint)elementIndex >= (uint)this.length)
{
ThrowArgumentOutOfRangeExceptionForInvalidElementIndex();
}
/// <inheritdoc/>
public override void Unpin()
{
}
// Allocating a pinned handle for the array with fail and throw an exception
// if the array contains non blittable data. This is the expected behavior and
// the same happens when trying to pin a Memory<T> instance obtained through
// traditional means (eg. via the implicit T[] array conversion), if T is a
// reference type or a type containing some references.
GCHandle handle = GCHandle.Alloc(this.instance, GCHandleType.Pinned);
ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(this.instance, this.offset);
ref T r1 = ref Unsafe.Add(ref r0, (nint)(uint)elementIndex);
void* p = Unsafe.AsPointer(ref r1);
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
}
return new MemoryHandle(p, handle);
}
/// <inheritdoc/>
public override void Unpin()
{
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when the input index for <see cref="Pin"/> is not valid.
/// </summary>
private static void ThrowArgumentOutOfRangeExceptionForInvalidElementIndex()
{
throw new ArgumentOutOfRangeException("elementIndex", "The input element index was not in the valid range");
}
/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> when the input index for <see cref="Pin"/> is not valid.
/// </summary>
private static void ThrowArgumentOutOfRangeExceptionForInvalidElementIndex()
{
throw new ArgumentOutOfRangeException("elementIndex", "The input element index was not in the valid range");
}
}

Просмотреть файл

@ -50,11 +50,11 @@ internal sealed class StringMemoryManager<TTo> : MemoryManager<TTo>, IMemoryMana
public override Span<TTo> GetSpan()
{
#if NETSTANDARD2_1_OR_GREATER
ref char r0 = ref this.text.DangerousGetReferenceAt(this.offset);
ref TTo r1 = ref Unsafe.As<char, TTo>(ref r0);
int length = RuntimeHelpers.ConvertLength<char, TTo>(this.length);
ref char r0 = ref this.text.DangerousGetReferenceAt(this.offset);
ref TTo r1 = ref Unsafe.As<char, TTo>(ref r0);
int length = RuntimeHelpers.ConvertLength<char, TTo>(this.length);
return MemoryMarshal.CreateSpan(ref r1, length);
return MemoryMarshal.CreateSpan(ref r1, length);
#else
ReadOnlyMemory<char> memory = this.text.AsMemory(this.offset, this.length);
Span<char> span = MemoryMarshal.AsMemory(memory).Span;

Просмотреть файл

@ -183,18 +183,18 @@ public sealed class MemoryOwner<T> : IMemoryOwner<T>
}
#if NETCOREAPP3_1_OR_GREATER
ref T r0 = ref array!.DangerousGetReferenceAt(this.start);
ref T r0 = ref array!.DangerousGetReferenceAt(this.start);
// On .NET Core runtimes, we can manually create a span from the starting reference to
// skip the argument validations, which include an explicit null check, covariance check
// for the array and the actual validation for the starting offset and target length. We
// only do this on .NET Core as we can leverage the runtime-specific array layout to get
// a fast access to the initial element, which makes this trick worth it. Otherwise, on
// runtimes where we would need to at least access a static field to retrieve the base
// byte offset within an SZ array object, we can get better performance by just using the
// default Span<T> constructor and paying the cost of the extra conditional branches,
// especially if T is a value type, in which case the covariance check is JIT removed.
return MemoryMarshal.CreateSpan(ref r0, this.length);
// On .NET Core runtimes, we can manually create a span from the starting reference to
// skip the argument validations, which include an explicit null check, covariance check
// for the array and the actual validation for the starting offset and target length. We
// only do this on .NET Core as we can leverage the runtime-specific array layout to get
// a fast access to the initial element, which makes this trick worth it. Otherwise, on
// runtimes where we would need to at least access a static field to retrieve the base
// byte offset within an SZ array object, we can get better performance by just using the
// default Span<T> constructor and paying the cost of the extra conditional branches,
// especially if T is a value type, in which case the covariance check is JIT removed.
return MemoryMarshal.CreateSpan(ref r0, this.length);
#else
return new Span<T>(array!, this.start, this.length);
#endif

Просмотреть файл

@ -148,9 +148,9 @@ public readonly ref struct SpanOwner<T>
get
{
#if NETCOREAPP3_1_OR_GREATER
ref T r0 = ref array!.DangerousGetReference();
ref T r0 = ref array!.DangerousGetReference();
return MemoryMarshal.CreateSpan(ref r0, this.length);
return MemoryMarshal.CreateSpan(ref r0, this.length);
#else
return new Span<T>(this.array, 0, this.length);
#endif

Просмотреть файл

@ -772,7 +772,7 @@ public sealed class StringPool
#if NETSTANDARD1_4
return span.GetDjb2HashCode();
#else
return HashCode<char>.Combine(span);
return HashCode<char>.Combine(span);
#endif
}

Просмотреть файл

@ -23,11 +23,11 @@ namespace CommunityToolkit.HighPerformance.Enumerables;
public readonly ref struct ReadOnlyRefEnumerable<T>
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>The <see cref="ReadOnlySpan{T}.Length"/> field maps to the total available length.</remarks>
private readonly ReadOnlySpan<T> span;
/// <summary>
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>The <see cref="ReadOnlySpan{T}.Length"/> field maps to the total available length.</remarks>
private readonly ReadOnlySpan<T> span;
#else
/// <summary>
/// The target <see cref="object"/> instance, if present.
@ -52,56 +52,56 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
private readonly int step;
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
/// </summary>
/// <param name="span">The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ReadOnlyRefEnumerable(ReadOnlySpan<T> span, int step)
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
/// </summary>
/// <param name="span">The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ReadOnlyRefEnumerable(ReadOnlySpan<T> span, int step)
{
this.span = span;
this.step = step;
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
/// </summary>
/// <param name="reference">A reference to the first item of the sequence.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ReadOnlyRefEnumerable(in T reference, int length, int step)
{
this.span = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(reference), length);
this.step = step;
}
/// <summary>
/// Creates a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
/// <returns>A <see cref="ReadOnlyRefEnumerable{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static ReadOnlyRefEnumerable<T> DangerousCreate(in T value, int length, int step)
{
if (length < 0)
{
this.span = span;
this.step = step;
ThrowArgumentOutOfRangeExceptionForLength();
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
/// </summary>
/// <param name="reference">A reference to the first item of the sequence.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ReadOnlyRefEnumerable(in T reference, int length, int step)
if (step < 0)
{
this.span = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(reference), length);
this.step = step;
ThrowArgumentOutOfRangeExceptionForStep();
}
/// <summary>
/// Creates a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
/// <returns>A <see cref="ReadOnlyRefEnumerable{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static ReadOnlyRefEnumerable<T> DangerousCreate(in T value, int length, int step)
{
if (length < 0)
{
ThrowArgumentOutOfRangeExceptionForLength();
}
OverflowHelper.EnsureIsInNativeIntRange(length, 1, step);
if (step < 0)
{
ThrowArgumentOutOfRangeExceptionForStep();
}
OverflowHelper.EnsureIsInNativeIntRange(length, 1, step);
return new ReadOnlyRefEnumerable<T>(in value, length, step);
}
return new ReadOnlyRefEnumerable<T>(in value, length, step);
}
#else
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
@ -127,7 +127,7 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#if NETSTANDARD2_1_OR_GREATER
get => this.span.Length;
get => this.span.Length;
#else
get => this.length;
#endif
@ -152,7 +152,7 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
}
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T r0 = ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
#endif
@ -164,19 +164,19 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Gets the element at the specified zero-based index.
/// </summary>
/// <param name="index">The zero-based index of the element.</param>
/// <returns>A reference to the element at the specified index.</returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when <paramref name="index"/> is invalid.
/// </exception>
public ref readonly T this[Index index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref this[index.GetOffset(Length)];
}
/// <summary>
/// Gets the element at the specified zero-based index.
/// </summary>
/// <param name="index">The zero-based index of the element.</param>
/// <returns>A reference to the element at the specified index.</returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when <paramref name="index"/> is invalid.
/// </exception>
public ref readonly T this[Index index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref this[index.GetOffset(Length)];
}
#endif
/// <inheritdoc cref="System.Collections.IEnumerable.GetEnumerator"/>
@ -185,7 +185,7 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
public Enumerator GetEnumerator()
{
#if NETSTANDARD2_1_OR_GREATER
return new Enumerator(this.span, this.step);
return new Enumerator(this.span, this.step);
#else
return new Enumerator(this.instance, this.offset, this.length, this.step);
#endif
@ -201,25 +201,24 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
public void CopyTo(RefEnumerable<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
if (this.step == 1)
{
destination.CopyFrom(this.span);
if (this.step == 1)
{
destination.CopyFrom(this.span);
return;
}
return;
}
if (destination.Step == 1)
{
CopyTo(destination.Span);
if (destination.Step == 1)
{
CopyTo(destination.Span);
return;
}
return;
}
ref T sourceRef = ref this.span.DangerousGetReference();
ref T destinationRef = ref destination.Span.DangerousGetReference();
int
sourceLength = this.span.Length,
destinationLength = destination.Span.Length;
ref T sourceRef = ref this.span.DangerousGetReference();
ref T destinationRef = ref destination.Span.DangerousGetReference();
int sourceLength = this.span.Length;
int destinationLength = destination.Span.Length;
#else
ref T sourceRef = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
ref T destinationRef = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(destination.Instance, destination.Offset);
@ -243,9 +242,8 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
public bool TryCopyTo(RefEnumerable<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
int
sourceLength = this.span.Length,
destinationLength = destination.Span.Length;
int sourceLength = this.span.Length;
int destinationLength = destination.Span.Length;
#else
int sourceLength = this.length;
int destinationLength = destination.Length;
@ -271,15 +269,15 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
public void CopyTo(Span<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
if (this.step == 1)
{
this.span.CopyTo(destination);
if (this.step == 1)
{
this.span.CopyTo(destination);
return;
}
return;
}
ref T sourceRef = ref this.span.DangerousGetReference();
int length = this.span.Length;
ref T sourceRef = ref this.span.DangerousGetReference();
int length = this.span.Length;
#else
ref T sourceRef = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
int length = this.length;
@ -302,7 +300,7 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
public bool TryCopyTo(Span<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
int length = this.span.Length;
int length = this.span.Length;
#else
int length = this.length;
#endif
@ -322,7 +320,7 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
public T[] ToArray()
{
#if NETSTANDARD2_1_OR_GREATER
int length = this.span.Length;
int length = this.span.Length;
#else
int length = this.length;
#endif
@ -348,7 +346,7 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
public static implicit operator ReadOnlyRefEnumerable<T>(RefEnumerable<T> enumerable)
{
#if NETSTANDARD2_1_OR_GREATER
return new ReadOnlyRefEnumerable<T>(enumerable.Span, enumerable.Step);
return new ReadOnlyRefEnumerable<T>(enumerable.Span, enumerable.Step);
#else
return new ReadOnlyRefEnumerable<T>(enumerable.Instance, enumerable.Offset, enumerable.Length, enumerable.Step);
#endif
@ -360,8 +358,8 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
public ref struct Enumerator
{
#if NETSTANDARD2_1_OR_GREATER
/// <inheritdoc cref="ReadOnlyRefEnumerable{T}.span"/>
private readonly ReadOnlySpan<T> span;
/// <inheritdoc cref="ReadOnlyRefEnumerable{T}.span"/>
private readonly ReadOnlySpan<T> span;
#else
/// <inheritdoc cref="ReadOnlyRefEnumerable{T}.instance"/>
private readonly object? instance;
@ -382,18 +380,18 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
private int position;
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
/// </summary>
/// <param name="span">The <see cref="ReadOnlySpan{T}"/> instance with the info on the items to traverse.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(ReadOnlySpan<T> span, int step)
{
this.span = span;
this.step = step;
this.position = -1;
}
/// <summary>
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
/// </summary>
/// <param name="span">The <see cref="ReadOnlySpan{T}"/> instance with the info on the items to traverse.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(ReadOnlySpan<T> span, int step)
{
this.span = span;
this.step = step;
this.position = -1;
}
#else
/// <summary>
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
@ -418,7 +416,7 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
public bool MoveNext()
{
#if NETSTANDARD2_1_OR_GREATER
return ++this.position < this.span.Length;
return ++this.position < this.span.Length;
#else
return ++this.position < this.length;
#endif
@ -431,7 +429,7 @@ public readonly ref struct ReadOnlyRefEnumerable<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref this.span.DangerousGetReference();
ref T r0 = ref this.span.DangerousGetReference();
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
#endif

Просмотреть файл

@ -66,11 +66,11 @@ public ref struct ReadOnlySpanEnumerable<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)this.index);
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)this.index);
// See comment in SpanEnumerable<T> about this
return new Item(ref ri, this.index);
// See comment in SpanEnumerable<T> about this
return new Item(ref ri, this.index);
#else
return new Item(this.span, this.index);
#endif
@ -89,16 +89,16 @@ public ref struct ReadOnlySpanEnumerable<T>
private readonly ReadOnlySpan<T> span;
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Item"/> struct.
/// </summary>
/// <param name="value">A reference to the target value.</param>
/// <param name="index">The index of the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Item(ref T value, int index)
{
this.span = MemoryMarshal.CreateReadOnlySpan(ref value, index);
}
/// <summary>
/// Initializes a new instance of the <see cref="Item"/> struct.
/// </summary>
/// <param name="value">A reference to the target value.</param>
/// <param name="index">The index of the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Item(ref T value, int index)
{
this.span = MemoryMarshal.CreateReadOnlySpan(ref value, index);
}
#else
/// <summary>
/// The current index within <see cref="span"/>.
@ -127,7 +127,7 @@ public ref struct ReadOnlySpanEnumerable<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
return ref MemoryMarshal.GetReference(this.span);
return ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)this.index);
@ -146,7 +146,7 @@ public ref struct ReadOnlySpanEnumerable<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
return this.span.Length;
return this.span.Length;
#else
return this.index;
#endif

Просмотреть файл

@ -23,11 +23,11 @@ namespace CommunityToolkit.HighPerformance.Enumerables;
public readonly ref struct RefEnumerable<T>
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// The <see cref="Span{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>The <see cref="Span{T}.Length"/> field maps to the total available length.</remarks>
internal readonly Span<T> Span;
/// <summary>
/// The <see cref="Span{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>The <see cref="Span{T}.Length"/> field maps to the total available length.</remarks>
internal readonly Span<T> Span;
#else
/// <summary>
/// The target <see cref="object"/> instance, if present.
@ -47,44 +47,44 @@ public readonly ref struct RefEnumerable<T>
internal readonly int Step;
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="RefEnumerable{T}"/> struct.
/// </summary>
/// <param name="reference">A reference to the first item of the sequence.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal RefEnumerable(ref T reference, int length, int step)
/// <summary>
/// Initializes a new instance of the <see cref="RefEnumerable{T}"/> struct.
/// </summary>
/// <param name="reference">A reference to the first item of the sequence.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal RefEnumerable(ref T reference, int length, int step)
{
Span = MemoryMarshal.CreateSpan(ref reference, length);
Step = step;
}
/// <summary>
/// Creates a new instance of the <see cref="RefEnumerable{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
/// <returns>A <see cref="RefEnumerable{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static RefEnumerable<T> DangerousCreate(ref T value, int length, int step)
{
if (length < 0)
{
Span = MemoryMarshal.CreateSpan(ref reference, length);
Step = step;
ThrowArgumentOutOfRangeExceptionForLength();
}
/// <summary>
/// Creates a new instance of the <see cref="RefEnumerable{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="length">The number of items in the sequence.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
/// <returns>A <see cref="RefEnumerable{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static RefEnumerable<T> DangerousCreate(ref T value, int length, int step)
if (step < 0)
{
if (length < 0)
{
ThrowArgumentOutOfRangeExceptionForLength();
}
if (step < 0)
{
ThrowArgumentOutOfRangeExceptionForStep();
}
OverflowHelper.EnsureIsInNativeIntRange(length, 1, step);
return new RefEnumerable<T>(ref value, length, step);
ThrowArgumentOutOfRangeExceptionForStep();
}
OverflowHelper.EnsureIsInNativeIntRange(length, 1, step);
return new RefEnumerable<T>(ref value, length, step);
}
#else
/// <summary>
/// Initializes a new instance of the <see cref="RefEnumerable{T}"/> struct.
@ -110,7 +110,7 @@ public readonly ref struct RefEnumerable<T>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#if NETSTANDARD2_1_OR_GREATER
get => this.Span.Length;
get => this.Span.Length;
#else
get;
#endif
@ -135,7 +135,7 @@ public readonly ref struct RefEnumerable<T>
}
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.Span);
ref T r0 = ref MemoryMarshal.GetReference(this.Span);
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
#endif
@ -147,19 +147,19 @@ public readonly ref struct RefEnumerable<T>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Gets the element at the specified zero-based index.
/// </summary>
/// <param name="index">The zero-based index of the element.</param>
/// <returns>A reference to the element at the specified index.</returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when <paramref name="index"/> is invalid.
/// </exception>
public ref T this[Index index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref this[index.GetOffset(Length)];
}
/// <summary>
/// Gets the element at the specified zero-based index.
/// </summary>
/// <param name="index">The zero-based index of the element.</param>
/// <returns>A reference to the element at the specified index.</returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when <paramref name="index"/> is invalid.
/// </exception>
public ref T this[Index index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref this[index.GetOffset(Length)];
}
#endif
/// <inheritdoc cref="System.Collections.IEnumerable.GetEnumerator"/>
@ -168,7 +168,7 @@ public readonly ref struct RefEnumerable<T>
public Enumerator GetEnumerator()
{
#if NETSTANDARD2_1_OR_GREATER
return new Enumerator(this.Span, this.Step);
return new Enumerator(this.Span, this.Step);
#else
return new Enumerator(this.Instance, this.Offset, this.Length, this.Step);
#endif
@ -180,16 +180,16 @@ public readonly ref struct RefEnumerable<T>
public void Clear()
{
#if NETSTANDARD2_1_OR_GREATER
// Fast path for contiguous items
if (this.Step == 1)
{
this.Span.Clear();
// Fast path for contiguous items
if (this.Step == 1)
{
this.Span.Clear();
return;
}
return;
}
ref T r0 = ref this.Span.DangerousGetReference();
int length = this.Span.Length;
ref T r0 = ref this.Span.DangerousGetReference();
int length = this.Span.Length;
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
int length = this.Length;
@ -208,25 +208,24 @@ public readonly ref struct RefEnumerable<T>
public void CopyTo(RefEnumerable<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
if (this.Step == 1)
{
destination.CopyFrom(this.Span);
if (this.Step == 1)
{
destination.CopyFrom(this.Span);
return;
}
return;
}
if (destination.Step == 1)
{
CopyTo(destination.Span);
if (destination.Step == 1)
{
CopyTo(destination.Span);
return;
}
return;
}
ref T sourceRef = ref this.Span.DangerousGetReference();
ref T destinationRef = ref destination.Span.DangerousGetReference();
int
sourceLength = this.Span.Length,
destinationLength = destination.Span.Length;
ref T sourceRef = ref this.Span.DangerousGetReference();
ref T destinationRef = ref destination.Span.DangerousGetReference();
int sourceLength = this.Span.Length;
int destinationLength = destination.Span.Length;
#else
ref T sourceRef = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
ref T destinationRef = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(destination.Instance, destination.Offset);
@ -250,9 +249,8 @@ public readonly ref struct RefEnumerable<T>
public bool TryCopyTo(RefEnumerable<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
int
sourceLength = this.Span.Length,
destinationLength = destination.Span.Length;
int sourceLength = this.Span.Length;
int destinationLength = destination.Span.Length;
#else
int sourceLength = this.Length;
int destinationLength = destination.Length;
@ -278,15 +276,15 @@ public readonly ref struct RefEnumerable<T>
public void CopyTo(Span<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
if (this.Step == 1)
{
this.Span.CopyTo(destination);
if (this.Step == 1)
{
this.Span.CopyTo(destination);
return;
}
return;
}
ref T sourceRef = ref this.Span.DangerousGetReference();
int length = this.Span.Length;
ref T sourceRef = ref this.Span.DangerousGetReference();
int length = this.Span.Length;
#else
ref T sourceRef = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
int length = this.Length;
@ -309,7 +307,7 @@ public readonly ref struct RefEnumerable<T>
public bool TryCopyTo(Span<T> destination)
{
#if NETSTANDARD2_1_OR_GREATER
int length = this.Span.Length;
int length = this.Span.Length;
#else
int length = this.Length;
#endif
@ -334,15 +332,15 @@ public readonly ref struct RefEnumerable<T>
internal void CopyFrom(ReadOnlySpan<T> source)
{
#if NETSTANDARD2_1_OR_GREATER
if (this.Step == 1)
{
source.CopyTo(this.Span);
if (this.Step == 1)
{
source.CopyTo(this.Span);
return;
}
return;
}
ref T destinationRef = ref this.Span.DangerousGetReference();
int destinationLength = this.Span.Length;
ref T destinationRef = ref this.Span.DangerousGetReference();
int destinationLength = this.Span.Length;
#else
ref T destinationRef = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
int destinationLength = this.Length;
@ -366,7 +364,7 @@ public readonly ref struct RefEnumerable<T>
public bool TryCopyFrom(ReadOnlySpan<T> source)
{
#if NETSTANDARD2_1_OR_GREATER
int length = this.Span.Length;
int length = this.Span.Length;
#else
int length = this.Length;
#endif
@ -388,15 +386,15 @@ public readonly ref struct RefEnumerable<T>
public void Fill(T value)
{
#if NETSTANDARD2_1_OR_GREATER
if (this.Step == 1)
{
this.Span.Fill(value);
if (this.Step == 1)
{
this.Span.Fill(value);
return;
}
return;
}
ref T r0 = ref this.Span.DangerousGetReference();
int length = this.Span.Length;
ref T r0 = ref this.Span.DangerousGetReference();
int length = this.Span.Length;
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
int length = this.Length;
@ -417,7 +415,7 @@ public readonly ref struct RefEnumerable<T>
public T[] ToArray()
{
#if NETSTANDARD2_1_OR_GREATER
int length = this.Span.Length;
int length = this.Span.Length;
#else
int length = this.Length;
#endif
@ -441,8 +439,8 @@ public readonly ref struct RefEnumerable<T>
public ref struct Enumerator
{
#if NETSTANDARD2_1_OR_GREATER
/// <inheritdoc cref="RefEnumerable{T}.Span"/>
private readonly Span<T> span;
/// <inheritdoc cref="RefEnumerable{T}.Span"/>
private readonly Span<T> span;
#else
/// <inheritdoc cref="RefEnumerable{T}.Instance"/>
private readonly object? instance;
@ -463,18 +461,18 @@ public readonly ref struct RefEnumerable<T>
private int position;
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
/// </summary>
/// <param name="span">The <see cref="Span{T}"/> instance with the info on the items to traverse.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(Span<T> span, int step)
{
this.span = span;
this.step = step;
this.position = -1;
}
/// <summary>
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
/// </summary>
/// <param name="span">The <see cref="Span{T}"/> instance with the info on the items to traverse.</param>
/// <param name="step">The distance between items in the sequence to enumerate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(Span<T> span, int step)
{
this.span = span;
this.step = step;
this.position = -1;
}
#else
/// <summary>
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
@ -499,7 +497,7 @@ public readonly ref struct RefEnumerable<T>
public bool MoveNext()
{
#if NETSTANDARD2_1_OR_GREATER
return ++this.position < this.span.Length;
return ++this.position < this.span.Length;
#else
return ++this.position < this.length;
#endif
@ -512,7 +510,7 @@ public readonly ref struct RefEnumerable<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref this.span.DangerousGetReference();
ref T r0 = ref this.span.DangerousGetReference();
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
#endif

Просмотреть файл

@ -66,16 +66,16 @@ public ref struct SpanEnumerable<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)this.index);
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)this.index);
// On .NET Standard 2.1 and .NET Core (or on any target that offers runtime
// support for the Span<T> types), we can save 4 bytes by piggybacking the
// current index in the length of the wrapped span. We're going to use the
// first item as the target reference, and the length as a host for the
// current original offset. This is not possible on eg. .NET Standard 2.0,
// as we lack the API to create Span<T>-s from arbitrary references.
return new Item(ref ri, this.index);
// On .NET Standard 2.1 and .NET Core (or on any target that offers runtime
// support for the Span<T> types), we can save 4 bytes by piggybacking the
// current index in the length of the wrapped span. We're going to use the
// first item as the target reference, and the length as a host for the
// current original offset. This is not possible on eg. .NET Standard 2.0,
// as we lack the API to create Span<T>-s from arbitrary references.
return new Item(ref ri, this.index);
#else
return new Item(this.span, this.index);
#endif
@ -94,16 +94,16 @@ public ref struct SpanEnumerable<T>
private readonly Span<T> span;
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Item"/> struct.
/// </summary>
/// <param name="value">A reference to the target value.</param>
/// <param name="index">The index of the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Item(ref T value, int index)
{
this.span = MemoryMarshal.CreateSpan(ref value, index);
}
/// <summary>
/// Initializes a new instance of the <see cref="Item"/> struct.
/// </summary>
/// <param name="value">A reference to the target value.</param>
/// <param name="index">The index of the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Item(ref T value, int index)
{
this.span = MemoryMarshal.CreateSpan(ref value, index);
}
#else
/// <summary>
/// The current index within <see cref="span"/>.
@ -132,7 +132,7 @@ public ref struct SpanEnumerable<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
return ref MemoryMarshal.GetReference(this.span);
return ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)this.index);
@ -151,7 +151,7 @@ public ref struct SpanEnumerable<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
return this.span.Length;
return this.span.Length;
#else
return this.index;
#endif

Просмотреть файл

@ -34,12 +34,12 @@ public static partial class ArrayExtensions
public static ref T DangerousGetReference<T>(this T[] array)
{
#if NET5_0
return ref MemoryMarshal.GetArrayDataReference(array);
return ref MemoryMarshal.GetArrayDataReference(array);
#elif NETCOREAPP3_1
RawArrayData? arrayData = Unsafe.As<RawArrayData>(array)!;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
RawArrayData? arrayData = Unsafe.As<RawArrayData>(array)!;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
return ref r0;
return ref r0;
#else
IntPtr offset = RuntimeHelpers.GetArrayDataByteOffset<T>();
@ -60,16 +60,16 @@ public static partial class ArrayExtensions
public static ref T DangerousGetReferenceAt<T>(this T[] array, int i)
{
#if NET5_0
ref T r0 = ref MemoryMarshal.GetArrayDataReference(array);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)i);
ref T r0 = ref MemoryMarshal.GetArrayDataReference(array);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)i);
return ref ri;
return ref ri;
#elif NETCOREAPP3_1
RawArrayData? arrayData = Unsafe.As<RawArrayData>(array)!;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)i);
RawArrayData? arrayData = Unsafe.As<RawArrayData>(array)!;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
ref T ri = ref Unsafe.Add(ref r0, (nint)(uint)i);
return ref ri;
return ref ri;
#else
IntPtr offset = RuntimeHelpers.GetArrayDataByteOffset<T>();
ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(array, offset);
@ -80,23 +80,23 @@ public static partial class ArrayExtensions
}
#if NETCOREAPP3_1
// Description taken from CoreCLR: see https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs,285.
// CLR arrays are laid out in memory as follows (multidimensional array bounds are optional):
// [ sync block || pMethodTable || num components || MD array bounds || array data .. ]
// ^ ^ ^ returned reference
// | \-- ref Unsafe.As<RawArrayData>(array).Data
// \-- array
// The base size of an array includes all the fields before the array data,
// including the sync block and method table. The reference to RawData.Data
// points at the number of components, skipping over these two pointer-sized fields.
[StructLayout(LayoutKind.Sequential)]
private sealed class RawArrayData
{
// Description taken from CoreCLR: see https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs,285.
// CLR arrays are laid out in memory as follows (multidimensional array bounds are optional):
// [ sync block || pMethodTable || num components || MD array bounds || array data .. ]
// ^ ^ ^ returned reference
// | \-- ref Unsafe.As<RawArrayData>(array).Data
// \-- array
// The base size of an array includes all the fields before the array data,
// including the sync block and method table. The reference to RawData.Data
// points at the number of components, skipping over these two pointer-sized fields.
[StructLayout(LayoutKind.Sequential)]
private sealed class RawArrayData
{
#pragma warning disable CS0649 // Unassigned fields
public IntPtr Length;
public byte Data;
public IntPtr Length;
public byte Data;
#pragma warning restore CS0649
}
}
#endif
/// <summary>

Просмотреть файл

@ -33,10 +33,10 @@ public static partial class ArrayExtensions
public static ref T DangerousGetReference<T>(this T[,] array)
{
#if NETCOREAPP3_1
RawArray2DData? arrayData = Unsafe.As<RawArray2DData>(array)!;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
RawArray2DData? arrayData = Unsafe.As<RawArray2DData>(array)!;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
return ref r0;
return ref r0;
#else
IntPtr offset = RuntimeHelpers.GetArray2DDataByteOffset<T>();
@ -63,12 +63,12 @@ public static partial class ArrayExtensions
public static ref T DangerousGetReferenceAt<T>(this T[,] array, int i, int j)
{
#if NETCOREAPP3_1
RawArray2DData? arrayData = Unsafe.As<RawArray2DData>(array)!;
nint offset = ((nint)(uint)i * (nint)(uint)arrayData.Width) + (nint)(uint)j;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
ref T ri = ref Unsafe.Add(ref r0, offset);
RawArray2DData? arrayData = Unsafe.As<RawArray2DData>(array)!;
nint offset = ((nint)(uint)i * (nint)(uint)arrayData.Width) + (nint)(uint)j;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
ref T ri = ref Unsafe.Add(ref r0, offset);
return ref ri;
return ref ri;
#else
int width = array.GetLength(1);
nint index = ((nint)(uint)i * (nint)(uint)width) + (nint)(uint)j;
@ -81,26 +81,26 @@ public static partial class ArrayExtensions
}
#if NETCOREAPP3_1
// Description adapted from CoreCLR: see https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs,285.
// CLR 2D arrays are laid out in memory as follows:
// [ sync block || pMethodTable || Length (padded to IntPtr) || HxW || HxW bounds || array data .. ]
// ^ ^
// | \-- ref Unsafe.As<RawArray2DData>(array).Data
// \-- array
// The length is always padded to IntPtr just like with SZ arrays.
// The total data padding is therefore 20 bytes on x86 (4 + 4 + 4 + 4 + 4), or 24 bytes on x64.
[StructLayout(LayoutKind.Sequential)]
private sealed class RawArray2DData
{
// Description adapted from CoreCLR: see https://source.dot.net/#System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs,285.
// CLR 2D arrays are laid out in memory as follows:
// [ sync block || pMethodTable || Length (padded to IntPtr) || HxW || HxW bounds || array data .. ]
// ^ ^
// | \-- ref Unsafe.As<RawArray2DData>(array).Data
// \-- array
// The length is always padded to IntPtr just like with SZ arrays.
// The total data padding is therefore 20 bytes on x86 (4 + 4 + 4 + 4 + 4), or 24 bytes on x64.
[StructLayout(LayoutKind.Sequential)]
private sealed class RawArray2DData
{
#pragma warning disable CS0649 // Unassigned fields
public IntPtr Length;
public int Height;
public int Width;
public int HeightLowerBound;
public int WidthLowerBound;
public byte Data;
public IntPtr Length;
public int Height;
public int Width;
public int HeightLowerBound;
public int WidthLowerBound;
public byte Data;
#pragma warning restore CS0649
}
}
#endif
/// <summary>
@ -131,9 +131,9 @@ public static partial class ArrayExtensions
int width = array.GetLength(1);
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref array.DangerousGetReferenceAt(row, 0);
ref T r0 = ref array.DangerousGetReferenceAt(row, 0);
return new RefEnumerable<T>(ref r0, width, 1);
return new RefEnumerable<T>(ref r0, width, 1);
#else
ref T r0 = ref array.DangerousGetReferenceAt(row, 0);
IntPtr offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref r0);
@ -185,9 +185,9 @@ public static partial class ArrayExtensions
int height = array.GetLength(0);
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref array.DangerousGetReferenceAt(0, column);
ref T r0 = ref array.DangerousGetReferenceAt(0, column);
return new RefEnumerable<T>(ref r0, height, width);
return new RefEnumerable<T>(ref r0, height, width);
#else
ref T r0 = ref array.DangerousGetReferenceAt(0, column);
IntPtr offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref r0);
@ -271,114 +271,114 @@ public static partial class ArrayExtensions
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Returns a <see cref="Span{T}"/> over a row in a given 2D <typeparamref name="T"/> array instance.
/// </summary>
/// <typeparam name="T">The type of elements in the input 2D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input <typeparamref name="T"/> array instance.</param>
/// <param name="row">The target row to retrieve (0-based index).</param>
/// <returns>A <see cref="Span{T}"/> with the items from the target row within <paramref name="array"/>.</returns>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> doesn't match <typeparamref name="T"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="row"/> is invalid.</exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> GetRowSpan<T>(this T[,] array, int row)
/// <summary>
/// Returns a <see cref="Span{T}"/> over a row in a given 2D <typeparamref name="T"/> array instance.
/// </summary>
/// <typeparam name="T">The type of elements in the input 2D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input <typeparamref name="T"/> array instance.</param>
/// <param name="row">The target row to retrieve (0-based index).</param>
/// <returns>A <see cref="Span{T}"/> with the items from the target row within <paramref name="array"/>.</returns>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> doesn't match <typeparamref name="T"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="row"/> is invalid.</exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> GetRowSpan<T>(this T[,] array, int row)
{
if (array.IsCovariant())
{
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
if ((uint)row >= (uint)array.GetLength(0))
{
ThrowArgumentOutOfRangeExceptionForRow();
}
ref T r0 = ref array.DangerousGetReferenceAt(row, 0);
return MemoryMarshal.CreateSpan(ref r0, array.GetLength(1));
ThrowArrayTypeMismatchException();
}
/// <summary>
/// Returns a <see cref="Memory{T}"/> over a row in a given 2D <typeparamref name="T"/> array instance.
/// </summary>
/// <typeparam name="T">The type of elements in the input 2D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input <typeparamref name="T"/> array instance.</param>
/// <param name="row">The target row to retrieve (0-based index).</param>
/// <returns>A <see cref="Memory{T}"/> with the items from the target row within <paramref name="array"/>.</returns>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> doesn't match <typeparamref name="T"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="row"/> is invalid.</exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> GetRowMemory<T>(this T[,] array, int row)
if ((uint)row >= (uint)array.GetLength(0))
{
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
if ((uint)row >= (uint)array.GetLength(0))
{
ThrowArgumentOutOfRangeExceptionForRow();
}
ref T r0 = ref array.DangerousGetReferenceAt(row, 0);
IntPtr offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref r0);
return new RawObjectMemoryManager<T>(array, offset, array.GetLength(1)).Memory;
ThrowArgumentOutOfRangeExceptionForRow();
}
/// <summary>
/// Creates a new <see cref="Memory{T}"/> over an input 2D <typeparamref name="T"/> array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 2D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input 2D <typeparamref name="T"/> array instance.</param>
/// <returns>A <see cref="Memory{T}"/> instance with the values of <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> AsMemory<T>(this T[,]? array)
ref T r0 = ref array.DangerousGetReferenceAt(row, 0);
return MemoryMarshal.CreateSpan(ref r0, array.GetLength(1));
}
/// <summary>
/// Returns a <see cref="Memory{T}"/> over a row in a given 2D <typeparamref name="T"/> array instance.
/// </summary>
/// <typeparam name="T">The type of elements in the input 2D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input <typeparamref name="T"/> array instance.</param>
/// <param name="row">The target row to retrieve (0-based index).</param>
/// <returns>A <see cref="Memory{T}"/> with the items from the target row within <paramref name="array"/>.</returns>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> doesn't match <typeparamref name="T"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="row"/> is invalid.</exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> GetRowMemory<T>(this T[,] array, int row)
{
if (array.IsCovariant())
{
if (array is null)
{
return default;
}
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
IntPtr offset = RuntimeHelpers.GetArray2DDataByteOffset<T>();
int length = array.Length;
return new RawObjectMemoryManager<T>(array, offset, length).Memory;
ThrowArrayTypeMismatchException();
}
/// <summary>
/// Creates a new <see cref="Span{T}"/> over an input 2D <typeparamref name="T"/> array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 2D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input 2D <typeparamref name="T"/> array instance.</param>
/// <returns>A <see cref="Span{T}"/> instance with the values of <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this T[,]? array)
if ((uint)row >= (uint)array.GetLength(0))
{
if (array is null)
{
return default;
}
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
ref T r0 = ref array.DangerousGetReference();
int length = array.Length;
return MemoryMarshal.CreateSpan(ref r0, length);
ThrowArgumentOutOfRangeExceptionForRow();
}
ref T r0 = ref array.DangerousGetReferenceAt(row, 0);
IntPtr offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref r0);
return new RawObjectMemoryManager<T>(array, offset, array.GetLength(1)).Memory;
}
/// <summary>
/// Creates a new <see cref="Memory{T}"/> over an input 2D <typeparamref name="T"/> array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 2D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input 2D <typeparamref name="T"/> array instance.</param>
/// <returns>A <see cref="Memory{T}"/> instance with the values of <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> AsMemory<T>(this T[,]? array)
{
if (array is null)
{
return default;
}
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
IntPtr offset = RuntimeHelpers.GetArray2DDataByteOffset<T>();
int length = array.Length;
return new RawObjectMemoryManager<T>(array, offset, length).Memory;
}
/// <summary>
/// Creates a new <see cref="Span{T}"/> over an input 2D <typeparamref name="T"/> array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 2D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input 2D <typeparamref name="T"/> array instance.</param>
/// <returns>A <see cref="Span{T}"/> instance with the values of <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this T[,]? array)
{
if (array is null)
{
return default;
}
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
ref T r0 = ref array.DangerousGetReference();
int length = array.Length;
return MemoryMarshal.CreateSpan(ref r0, length);
}
#endif
/// <summary>

Просмотреть файл

@ -32,10 +32,10 @@ public static partial class ArrayExtensions
public static ref T DangerousGetReference<T>(this T[,,] array)
{
#if NETCOREAPP3_1
RawArray3DData? arrayData = Unsafe.As<RawArray3DData>(array)!;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
RawArray3DData? arrayData = Unsafe.As<RawArray3DData>(array)!;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
return ref r0;
return ref r0;
#else
IntPtr offset = RuntimeHelpers.GetArray3DDataByteOffset<T>();
@ -63,12 +63,12 @@ public static partial class ArrayExtensions
public static ref T DangerousGetReferenceAt<T>(this T[,,] array, int i, int j, int k)
{
#if NETCOREAPP3_1
RawArray3DData? arrayData = Unsafe.As<RawArray3DData>(array)!;
nint offset =
((nint)(uint)i * (nint)(uint)arrayData.Height * (nint)(uint)arrayData.Width) +
((nint)(uint)j * (nint)(uint)arrayData.Width) + (nint)(uint)k;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
ref T ri = ref Unsafe.Add(ref r0, offset);
RawArray3DData? arrayData = Unsafe.As<RawArray3DData>(array)!;
nint offset =
((nint)(uint)i * (nint)(uint)arrayData.Height * (nint)(uint)arrayData.Width) +
((nint)(uint)j * (nint)(uint)arrayData.Width) + (nint)(uint)k;
ref T r0 = ref Unsafe.As<byte, T>(ref arrayData.Data);
ref T ri = ref Unsafe.Add(ref r0, offset);
return ref ri;
#else
@ -86,135 +86,135 @@ public static partial class ArrayExtensions
}
#if NETCOREAPP3_1
// See description for this in the 2D partial file.
// Using the CHW naming scheme here (like with RGB images).
[StructLayout(LayoutKind.Sequential)]
private sealed class RawArray3DData
{
// See description for this in the 2D partial file.
// Using the CHW naming scheme here (like with RGB images).
[StructLayout(LayoutKind.Sequential)]
private sealed class RawArray3DData
{
#pragma warning disable CS0649 // Unassigned fields
public IntPtr Length;
public int Channel;
public int Height;
public int Width;
public int ChannelLowerBound;
public int HeightLowerBound;
public int WidthLowerBound;
public byte Data;
public IntPtr Length;
public int Channel;
public int Height;
public int Width;
public int ChannelLowerBound;
public int HeightLowerBound;
public int WidthLowerBound;
public byte Data;
#pragma warning restore CS0649
}
}
#endif
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Creates a new <see cref="Memory{T}"/> over an input 3D <typeparamref name="T"/> array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 3D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input 3D <typeparamref name="T"/> array instance.</param>
/// <returns>A <see cref="Memory{T}"/> instance with the values of <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> AsMemory<T>(this T[,,]? array)
/// <summary>
/// Creates a new <see cref="Memory{T}"/> over an input 3D <typeparamref name="T"/> array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 3D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input 3D <typeparamref name="T"/> array instance.</param>
/// <returns>A <see cref="Memory{T}"/> instance with the values of <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> AsMemory<T>(this T[,,]? array)
{
if (array is null)
{
if (array is null)
{
return default;
}
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
IntPtr offset = RuntimeHelpers.GetArray3DDataByteOffset<T>();
int length = array.Length;
return new RawObjectMemoryManager<T>(array, offset, length).Memory;
return default;
}
/// <summary>
/// Creates a new <see cref="Span{T}"/> over an input 3D <typeparamref name="T"/> array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 3D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input 3D <typeparamref name="T"/> array instance.</param>
/// <returns>A <see cref="Span{T}"/> instance with the values of <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this T[,,]? array)
if (array.IsCovariant())
{
if (array is null)
{
return default;
}
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
ref T r0 = ref array.DangerousGetReference();
int length = array.Length;
return MemoryMarshal.CreateSpan(ref r0, length);
ThrowArrayTypeMismatchException();
}
/// <summary>
/// Creates a new instance of the <see cref="Span{T}"/> struct wrapping a layer in a 3D array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 3D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The given 3D array to wrap.</param>
/// <param name="depth">The target layer to map within <paramref name="array"/>.</param>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> doesn't match <typeparamref name="T"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="depth"/> is invalid.</exception>
/// <returns>A <see cref="Span{T}"/> instance wrapping the target layer within <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this T[,,] array, int depth)
IntPtr offset = RuntimeHelpers.GetArray3DDataByteOffset<T>();
int length = array.Length;
return new RawObjectMemoryManager<T>(array, offset, length).Memory;
}
/// <summary>
/// Creates a new <see cref="Span{T}"/> over an input 3D <typeparamref name="T"/> array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 3D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The input 3D <typeparamref name="T"/> array instance.</param>
/// <returns>A <see cref="Span{T}"/> instance with the values of <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this T[,,]? array)
{
if (array is null)
{
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
if ((uint)depth >= (uint)array.GetLength(0))
{
ThrowArgumentOutOfRangeExceptionForDepth();
}
ref T r0 = ref array.DangerousGetReferenceAt(depth, 0, 0);
int length = checked(array.GetLength(1) * array.GetLength(2));
return MemoryMarshal.CreateSpan(ref r0, length);
return default;
}
/// <summary>
/// Creates a new instance of the <see cref="Memory{T}"/> struct wrapping a layer in a 3D array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 3D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The given 3D array to wrap.</param>
/// <param name="depth">The target layer to map within <paramref name="array"/>.</param>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> doesn't match <typeparamref name="T"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="depth"/> is invalid.</exception>
/// <returns>A <see cref="Memory{T}"/> instance wrapping the target layer within <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> AsMemory<T>(this T[,,] array, int depth)
if (array.IsCovariant())
{
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
if ((uint)depth >= (uint)array.GetLength(0))
{
ThrowArgumentOutOfRangeExceptionForDepth();
}
ref T r0 = ref array.DangerousGetReferenceAt(depth, 0, 0);
IntPtr offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref r0);
int length = checked(array.GetLength(1) * array.GetLength(2));
return new RawObjectMemoryManager<T>(array, offset, length).Memory;
ThrowArrayTypeMismatchException();
}
ref T r0 = ref array.DangerousGetReference();
int length = array.Length;
return MemoryMarshal.CreateSpan(ref r0, length);
}
/// <summary>
/// Creates a new instance of the <see cref="Span{T}"/> struct wrapping a layer in a 3D array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 3D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The given 3D array to wrap.</param>
/// <param name="depth">The target layer to map within <paramref name="array"/>.</param>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> doesn't match <typeparamref name="T"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="depth"/> is invalid.</exception>
/// <returns>A <see cref="Span{T}"/> instance wrapping the target layer within <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this T[,,] array, int depth)
{
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
if ((uint)depth >= (uint)array.GetLength(0))
{
ThrowArgumentOutOfRangeExceptionForDepth();
}
ref T r0 = ref array.DangerousGetReferenceAt(depth, 0, 0);
int length = checked(array.GetLength(1) * array.GetLength(2));
return MemoryMarshal.CreateSpan(ref r0, length);
}
/// <summary>
/// Creates a new instance of the <see cref="Memory{T}"/> struct wrapping a layer in a 3D array.
/// </summary>
/// <typeparam name="T">The type of elements in the input 3D <typeparamref name="T"/> array instance.</typeparam>
/// <param name="array">The given 3D array to wrap.</param>
/// <param name="depth">The target layer to map within <paramref name="array"/>.</param>
/// <exception cref="ArrayTypeMismatchException">Thrown when <paramref name="array"/> doesn't match <typeparamref name="T"/>.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="depth"/> is invalid.</exception>
/// <returns>A <see cref="Memory{T}"/> instance wrapping the target layer within <paramref name="array"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory<T> AsMemory<T>(this T[,,] array, int depth)
{
if (array.IsCovariant())
{
ThrowArrayTypeMismatchException();
}
if ((uint)depth >= (uint)array.GetLength(0))
{
ThrowArgumentOutOfRangeExceptionForDepth();
}
ref T r0 = ref array.DangerousGetReferenceAt(depth, 0, 0);
IntPtr offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref r0);
int length = checked(array.GetLength(1) * array.GetLength(2));
return new RawObjectMemoryManager<T>(array, offset, length).Memory;
}
#endif
/// <summary>

Просмотреть файл

@ -8,27 +8,26 @@ using System;
using System.Runtime.CompilerServices;
using CommunityToolkit.HighPerformance.Helpers;
namespace CommunityToolkit.HighPerformance
namespace CommunityToolkit.HighPerformance;
/// <summary>
/// Helpers for working with the <see cref="HashCode"/> type.
/// </summary>
public static class HashCodeExtensions
{
/// <summary>
/// Helpers for working with the <see cref="HashCode"/> type.
/// Adds a sequence of <typeparamref name="T"/> values to the hash code.
/// </summary>
public static class HashCodeExtensions
/// <typeparam name="T">The type of elements in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
/// <param name="hashCode">The input <see cref="HashCode"/> instance.</param>
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add<T>(ref this HashCode hashCode, ReadOnlySpan<T> span)
where T : notnull
{
/// <summary>
/// Adds a sequence of <typeparamref name="T"/> values to the hash code.
/// </summary>
/// <typeparam name="T">The type of elements in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
/// <param name="hashCode">The input <see cref="HashCode"/> instance.</param>
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add<T>(ref this HashCode hashCode, ReadOnlySpan<T> span)
where T : notnull
{
int hash = HashCode<T>.CombineValues(span);
int hash = HashCode<T>.CombineValues(span);
hashCode.Add(hash);
}
hashCode.Add(hash);
}
}

Просмотреть файл

@ -10,32 +10,31 @@ using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace CommunityToolkit.HighPerformance
namespace CommunityToolkit.HighPerformance;
/// <summary>
/// Helpers for working with the <see cref="List{T}"/> type.
/// </summary>
public static class ListExtensions
{
/// <summary>
/// Helpers for working with the <see cref="List{T}"/> type.
/// Creates a new <see cref="Span{T}"/> over an input <see cref="List{T}"/> instance.
/// </summary>
public static class ListExtensions
/// <typeparam name="T">The type of elements in the input <see cref="List{T}"/> instance.</typeparam>
/// <param name="list">The input <see cref="List{T}"/> instance.</param>
/// <returns>A <see cref="Span{T}"/> instance with the values of <paramref name="list"/>.</returns>
/// <remarks>
/// Note that the returned <see cref="Span{T}"/> is only guaranteed to be valid as long as the items within
/// <paramref name="list"/> are not modified. Doing so might cause the <see cref="List{T}"/> to swap its
/// internal buffer, causing the returned <see cref="Span{T}"/> to become out of date. That means that in this
/// scenario, the <see cref="Span{T}"/> would end up wrapping an array no longer in use. Always make sure to use
/// the returned <see cref="Span{T}"/> while the target <see cref="List{T}"/> is not modified.
/// </remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this List<T>? list)
{
/// <summary>
/// Creates a new <see cref="Span{T}"/> over an input <see cref="List{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of elements in the input <see cref="List{T}"/> instance.</typeparam>
/// <param name="list">The input <see cref="List{T}"/> instance.</param>
/// <returns>A <see cref="Span{T}"/> instance with the values of <paramref name="list"/>.</returns>
/// <remarks>
/// Note that the returned <see cref="Span{T}"/> is only guaranteed to be valid as long as the items within
/// <paramref name="list"/> are not modified. Doing so might cause the <see cref="List{T}"/> to swap its
/// internal buffer, causing the returned <see cref="Span{T}"/> to become out of date. That means that in this
/// scenario, the <see cref="Span{T}"/> would end up wrapping an array no longer in use. Always make sure to use
/// the returned <see cref="Span{T}"/> while the target <see cref="List{T}"/> is not modified.
/// </remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this List<T>? list)
{
return CollectionsMarshal.AsSpan(list);
}
return CollectionsMarshal.AsSpan(list);
}
}

Просмотреть файл

@ -17,49 +17,49 @@ namespace CommunityToolkit.HighPerformance;
public static class MemoryExtensions
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Returns a <see cref="Memory2D{T}"/> instance wrapping the underlying data for the given <see cref="Memory{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="Memory{T}"/> instance.</typeparam>
/// <param name="memory">The input <see cref="Memory{T}"/> instance.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <returns>The resulting <see cref="Memory2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory2D<T> AsMemory2D<T>(this Memory<T> memory, int height, int width)
{
return new(memory, height, width);
}
/// <summary>
/// Returns a <see cref="Memory2D{T}"/> instance wrapping the underlying data for the given <see cref="Memory{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="Memory{T}"/> instance.</typeparam>
/// <param name="memory">The input <see cref="Memory{T}"/> instance.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <returns>The resulting <see cref="Memory2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory2D<T> AsMemory2D<T>(this Memory<T> memory, int height, int width)
{
return new(memory, height, width);
}
/// <summary>
/// Returns a <see cref="Memory2D{T}"/> instance wrapping the underlying data for the given <see cref="Memory{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="Memory{T}"/> instance.</typeparam>
/// <param name="memory">The input <see cref="Memory{T}"/> instance.</param>
/// <param name="offset">The initial offset within <paramref name="memory"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <returns>The resulting <see cref="Memory2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory2D<T> AsMemory2D<T>(this Memory<T> memory, int offset, int height, int width, int pitch)
{
return new(memory, offset, height, width, pitch);
}
/// <summary>
/// Returns a <see cref="Memory2D{T}"/> instance wrapping the underlying data for the given <see cref="Memory{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="Memory{T}"/> instance.</typeparam>
/// <param name="memory">The input <see cref="Memory{T}"/> instance.</param>
/// <param name="offset">The initial offset within <paramref name="memory"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <returns>The resulting <see cref="Memory2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Memory2D<T> AsMemory2D<T>(this Memory<T> memory, int offset, int height, int width, int pitch)
{
return new(memory, offset, height, width, pitch);
}
#endif
/// <summary>

Просмотреть файл

@ -11,44 +11,43 @@
using System;
using System.Runtime.CompilerServices;
namespace CommunityToolkit.HighPerformance.Extensions
namespace CommunityToolkit.HighPerformance.Extensions;
/// <summary>
/// Helpers for working with the <see cref="Nullable{T}"/> type.
/// </summary>
public static class NullableExtensions
{
/// <summary>
/// Helpers for working with the <see cref="Nullable{T}"/> type.
/// Returns a reference to the value of the input <see cref="Nullable{T}"/> instance, regardless of whether
/// the <see cref="Nullable{T}.HasValue"/> property is returning <see langword="true"/> or not. If that is not
/// the case, this method will still return a reference to the underlying <see langword="default"/> value.
/// </summary>
public static class NullableExtensions
/// <typeparam name="T">The type of the underlying value</typeparam>
/// <param name="value">The <see cref="Nullable{T}"/></param>
/// <returns>A reference to the underlying value from the input <see cref="Nullable{T}"/> instance.</returns>
/// <remarks>
/// Note that attempting to mutate the returned reference will not change the value returned by <see cref="Nullable{T}.HasValue"/>.
/// That means that reassigning the value of an empty instance will not make <see cref="Nullable{T}.HasValue"/> return <see langword="true"/>.
/// </remarks>
public static ref T DangerousGetValueOrDefaultReference<T>(this ref T? value)
where T : struct
{
/// <summary>
/// Returns a reference to the value of the input <see cref="Nullable{T}"/> instance, regardless of whether
/// the <see cref="Nullable{T}.HasValue"/> property is returning <see langword="true"/> or not. If that is not
/// the case, this method will still return a reference to the underlying <see langword="default"/> value.
/// </summary>
/// <typeparam name="T">The type of the underlying value</typeparam>
/// <param name="value">The <see cref="Nullable{T}"/></param>
/// <returns>A reference to the underlying value from the input <see cref="Nullable{T}"/> instance.</returns>
/// <remarks>
/// Note that attempting to mutate the returned reference will not change the value returned by <see cref="Nullable{T}.HasValue"/>.
/// That means that reassigning the value of an empty instance will not make <see cref="Nullable{T}.HasValue"/> return <see langword="true"/>.
/// </remarks>
public static ref T DangerousGetValueOrDefaultReference<T>(this ref T? value)
where T : struct
{
return ref Unsafe.As<T?, RawNullableData<T>>(ref value).Value;
}
return ref Unsafe.As<T?, RawNullableData<T>>(ref value).Value;
}
/// <summary>
/// Mapping type that reflects the internal layout of the <see cref="Nullable{T}"/> type.
/// See https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Nullable.cs.
/// </summary>
/// <typeparam name="T">The value type wrapped by the current instance.</typeparam>
private struct RawNullableData<T>
where T : struct
{
/// <summary>
/// Mapping type that reflects the internal layout of the <see cref="Nullable{T}"/> type.
/// See https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Nullable.cs.
/// </summary>
/// <typeparam name="T">The value type wrapped by the current instance.</typeparam>
private struct RawNullableData<T>
where T : struct
{
#pragma warning disable CS0649 // Unassigned fields
public bool HasValue;
public T Value;
public bool HasValue;
public T Value;
#pragma warning restore CS0649
}
}
}

Просмотреть файл

@ -20,49 +20,49 @@ namespace CommunityToolkit.HighPerformance;
public static class ReadOnlyMemoryExtensions
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Returns a <see cref="ReadOnlyMemory2D{T}"/> instance wrapping the underlying data for the given <see cref="ReadOnlyMemory{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlyMemory{T}"/> instance.</typeparam>
/// <param name="memory">The input <see cref="ReadOnlyMemory{T}"/> instance.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <returns>The resulting <see cref="ReadOnlyMemory2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlyMemory2D<T> AsMemory2D<T>(this ReadOnlyMemory<T> memory, int height, int width)
{
return new(memory, height, width);
}
/// <summary>
/// Returns a <see cref="ReadOnlyMemory2D{T}"/> instance wrapping the underlying data for the given <see cref="ReadOnlyMemory{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlyMemory{T}"/> instance.</typeparam>
/// <param name="memory">The input <see cref="ReadOnlyMemory{T}"/> instance.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <returns>The resulting <see cref="ReadOnlyMemory2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlyMemory2D<T> AsMemory2D<T>(this ReadOnlyMemory<T> memory, int height, int width)
{
return new(memory, height, width);
}
/// <summary>
/// Returns a <see cref="ReadOnlyMemory2D{T}"/> instance wrapping the underlying data for the given <see cref="ReadOnlyMemory{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlyMemory{T}"/> instance.</typeparam>
/// <param name="memory">The input <see cref="ReadOnlyMemory{T}"/> instance.</param>
/// <param name="offset">The initial offset within <paramref name="memory"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <returns>The resulting <see cref="ReadOnlyMemory2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlyMemory2D<T> AsMemory2D<T>(this ReadOnlyMemory<T> memory, int offset, int height, int width, int pitch)
{
return new(memory, offset, height, width, pitch);
}
/// <summary>
/// Returns a <see cref="ReadOnlyMemory2D{T}"/> instance wrapping the underlying data for the given <see cref="ReadOnlyMemory{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlyMemory{T}"/> instance.</typeparam>
/// <param name="memory">The input <see cref="ReadOnlyMemory{T}"/> instance.</param>
/// <param name="offset">The initial offset within <paramref name="memory"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <returns>The resulting <see cref="ReadOnlyMemory2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlyMemory2D<T> AsMemory2D<T>(this ReadOnlyMemory<T> memory, int offset, int height, int width, int pitch)
{
return new(memory, offset, height, width, pitch);
}
#endif
/// <summary>

Просмотреть файл

@ -164,49 +164,49 @@ public static class ReadOnlySpanExtensions
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Returns a <see cref="ReadOnlySpan2D{T}"/> instance wrapping the underlying data for the given <see cref="ReadOnlySpan{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <returns>The resulting <see cref="ReadOnlySpan2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan2D<T> AsSpan2D<T>(this ReadOnlySpan<T> span, int height, int width)
{
return new(span, height, width);
}
/// <summary>
/// Returns a <see cref="ReadOnlySpan2D{T}"/> instance wrapping the underlying data for the given <see cref="ReadOnlySpan{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <returns>The resulting <see cref="ReadOnlySpan2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan2D<T> AsSpan2D<T>(this ReadOnlySpan<T> span, int height, int width)
{
return new(span, height, width);
}
/// <summary>
/// Returns a <see cref="ReadOnlySpan2D{T}"/> instance wrapping the underlying data for the given <see cref="ReadOnlySpan{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance.</param>
/// <param name="offset">The initial offset within <paramref name="span"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <returns>The resulting <see cref="ReadOnlySpan2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan2D<T> AsSpan2D<T>(this ReadOnlySpan<T> span, int offset, int height, int width, int pitch)
{
return new(span, offset, height, width, pitch);
}
/// <summary>
/// Returns a <see cref="ReadOnlySpan2D{T}"/> instance wrapping the underlying data for the given <see cref="ReadOnlySpan{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance.</param>
/// <param name="offset">The initial offset within <paramref name="span"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <returns>The resulting <see cref="ReadOnlySpan2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan2D<T> AsSpan2D<T>(this ReadOnlySpan<T> span, int offset, int height, int width, int pitch)
{
return new(span, offset, height, width, pitch);
}
#endif
/// <summary>

Просмотреть файл

@ -67,49 +67,49 @@ public static class SpanExtensions
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Returns a <see cref="Span2D{T}"/> instance wrapping the underlying data for the given <see cref="Span{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="Span{T}"/> instance.</typeparam>
/// <param name="span">The input <see cref="Span{T}"/> instance.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <returns>The resulting <see cref="Span2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span2D<T> AsSpan2D<T>(this Span<T> span, int height, int width)
{
return new(span, height, width);
}
/// <summary>
/// Returns a <see cref="Span2D{T}"/> instance wrapping the underlying data for the given <see cref="Span{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="Span{T}"/> instance.</typeparam>
/// <param name="span">The input <see cref="Span{T}"/> instance.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <returns>The resulting <see cref="Span2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span2D<T> AsSpan2D<T>(this Span<T> span, int height, int width)
{
return new(span, height, width);
}
/// <summary>
/// Returns a <see cref="Span2D{T}"/> instance wrapping the underlying data for the given <see cref="Span{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="Span{T}"/> instance.</typeparam>
/// <param name="span">The input <see cref="Span{T}"/> instance.</param>
/// <param name="offset">The initial offset within <paramref name="span"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <returns>The resulting <see cref="Span2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span2D<T> AsSpan2D<T>(this Span<T> span, int offset, int height, int width, int pitch)
{
return new(span, offset, height, width, pitch);
}
/// <summary>
/// Returns a <see cref="Span2D{T}"/> instance wrapping the underlying data for the given <see cref="Span{T}"/> instance.
/// </summary>
/// <typeparam name="T">The type of items in the input <see cref="Span{T}"/> instance.</typeparam>
/// <param name="span">The input <see cref="Span{T}"/> instance.</param>
/// <param name="offset">The initial offset within <paramref name="span"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <returns>The resulting <see cref="Span2D{T}"/> instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span2D<T> AsSpan2D<T>(this Span<T> span, int offset, int height, int width, int pitch)
{
return new(span, offset, height, width, pitch);
}
#endif
/// <summary>

Просмотреть файл

@ -78,27 +78,27 @@ public static class SpinLockExtensions
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Enters a specified <see cref="SpinLock"/> instance and returns a wrapper to use to release the lock.
/// This extension should be used though a <see langword="using"/> block or statement:
/// <code>
/// SpinLock spinLock = new SpinLock();
///
/// using (spinLock.Enter())
/// {
/// // Thread-safe code here...
/// }
/// </code>
/// The compiler will take care of releasing the SpinLock when the code goes out of that <see langword="using"/> scope.
/// </summary>
/// <param name="spinLock">The target <see cref="SpinLock"/> to use</param>
/// <returns>A wrapper type that will release <paramref name="spinLock"/> when its <see cref="System.IDisposable.Dispose"/> method is called.</returns>
/// <remarks>The returned <see cref="Lock"/> value shouldn't be used directly: use this extension in a <see langword="using"/> block or statement.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Lock Enter(ref this SpinLock spinLock)
{
return new(ref spinLock);
}
/// <summary>
/// Enters a specified <see cref="SpinLock"/> instance and returns a wrapper to use to release the lock.
/// This extension should be used though a <see langword="using"/> block or statement:
/// <code>
/// SpinLock spinLock = new SpinLock();
///
/// using (spinLock.Enter())
/// {
/// // Thread-safe code here...
/// }
/// </code>
/// The compiler will take care of releasing the SpinLock when the code goes out of that <see langword="using"/> scope.
/// </summary>
/// <param name="spinLock">The target <see cref="SpinLock"/> to use</param>
/// <returns>A wrapper type that will release <paramref name="spinLock"/> when its <see cref="System.IDisposable.Dispose"/> method is called.</returns>
/// <remarks>The returned <see cref="Lock"/> value shouldn't be used directly: use this extension in a <see langword="using"/> block or statement.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Lock Enter(ref this SpinLock spinLock)
{
return new(ref spinLock);
}
#else
/// <summary>
/// Enters a specified <see cref="SpinLock"/> instance and returns a wrapper to use to release the lock.
@ -144,18 +144,18 @@ public static class SpinLockExtensions
private readonly bool lockTaken;
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Lock"/> struct.
/// </summary>
/// <param name="spinLock">The target <see cref="SpinLock"/> to use.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Lock(ref SpinLock spinLock)
{
this.spinLock = new Ref<SpinLock>(ref spinLock);
this.lockTaken = false;
/// <summary>
/// Initializes a new instance of the <see cref="Lock"/> struct.
/// </summary>
/// <param name="spinLock">The target <see cref="SpinLock"/> to use.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Lock(ref SpinLock spinLock)
{
this.spinLock = new Ref<SpinLock>(ref spinLock);
this.lockTaken = false;
spinLock.Enter(ref this.lockTaken);
}
spinLock.Enter(ref this.lockTaken);
}
#else
/// <summary>
/// Initializes a new instance of the <see cref="Lock"/> struct.

Просмотреть файл

@ -167,24 +167,24 @@ public static class StreamExtensions
/// <returns>The <typeparamref name="T"/> value read from <paramref name="stream"/>.</returns>
/// <exception cref="InvalidOperationException">Thrown if <paramref name="stream"/> reaches the end.</exception>
#if NETSTANDARD2_1_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static T Read<T>(this Stream stream)
where T : unmanaged
{
#if NETSTANDARD2_1_OR_GREATER
T result = default;
int length = Unsafe.SizeOf<T>();
T result = default;
int length = Unsafe.SizeOf<T>();
unsafe
unsafe
{
if (stream.Read(new Span<byte>(&result, length)) != length)
{
if (stream.Read(new Span<byte>(&result, length)) != length)
{
ThrowInvalidOperationExceptionForEndOfStream();
}
ThrowInvalidOperationExceptionForEndOfStream();
}
}
return result;
return result;
#else
int length = Unsafe.SizeOf<T>();
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);
@ -212,19 +212,19 @@ public static class StreamExtensions
/// <param name="stream">The target <see cref="Stream"/> instance to write to.</param>
/// <param name="value">The input value to write to <paramref name="stream"/>.</param>
#if NETSTANDARD2_1_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static void Write<T>(this Stream stream, in T value)
where T : unmanaged
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref Unsafe.AsRef(value);
ref byte r1 = ref Unsafe.As<T, byte>(ref r0);
int length = Unsafe.SizeOf<T>();
ref T r0 = ref Unsafe.AsRef(value);
ref byte r1 = ref Unsafe.As<T, byte>(ref r0);
int length = Unsafe.SizeOf<T>();
ReadOnlySpan<byte> span = MemoryMarshal.CreateReadOnlySpan(ref r1, length);
ReadOnlySpan<byte> span = MemoryMarshal.CreateReadOnlySpan(ref r1, length);
stream.Write(span);
stream.Write(span);
#else
int length = Unsafe.SizeOf<T>();
byte[] buffer = ArrayPool<byte>.Shared.Rent(length);

Просмотреть файл

@ -29,7 +29,7 @@ public static class StringExtensions
public static ref char DangerousGetReference(this string text)
{
#if NETCOREAPP3_1 || NET5_0
return ref Unsafe.AsRef(text.GetPinnableReference());
return ref Unsafe.AsRef(text.GetPinnableReference());
#else
return ref MemoryMarshal.GetReference(text.AsSpan());
#endif
@ -47,7 +47,7 @@ public static class StringExtensions
public static ref char DangerousGetReferenceAt(this string text, int i)
{
#if NETCOREAPP3_1 || NET5_0
ref char r0 = ref Unsafe.AsRef(text.GetPinnableReference());
ref char r0 = ref Unsafe.AsRef(text.GetPinnableReference());
#else
ref char r0 = ref MemoryMarshal.GetReference(text.AsSpan());
#endif

Просмотреть файл

@ -234,10 +234,10 @@ public static class BitHelper
public static uint ExtractRange(uint value, byte start, byte length)
{
#if NETCOREAPP3_1 || NET5_0
if (Bmi1.IsSupported)
{
return Bmi1.BitFieldExtract(value, start, length);
}
if (Bmi1.IsSupported)
{
return Bmi1.BitFieldExtract(value, start, length);
}
#endif
return (value >> start) & ((1u << length) - 1u);
@ -281,10 +281,10 @@ public static class BitHelper
uint storeMask = (flags & highBits) << start;
#if NETCOREAPP3_1 || NET5_0
if (Bmi1.IsSupported)
{
return Bmi1.AndNot(loadMask, value) | storeMask;
}
if (Bmi1.IsSupported)
{
return Bmi1.AndNot(loadMask, value) | storeMask;
}
#endif
return (~loadMask & value) | storeMask;
@ -401,10 +401,10 @@ public static class BitHelper
public static ulong ExtractRange(ulong value, byte start, byte length)
{
#if NETCOREAPP3_1 || NET5_0
if (Bmi1.X64.IsSupported)
{
return Bmi1.X64.BitFieldExtract(value, start, length);
}
if (Bmi1.X64.IsSupported)
{
return Bmi1.X64.BitFieldExtract(value, start, length);
}
#endif
return (value >> start) & ((1ul << length) - 1ul);
@ -448,10 +448,10 @@ public static class BitHelper
ulong storeMask = (flags & highBits) << start;
#if NETCOREAPP3_1 || NET5_0
if (Bmi1.X64.IsSupported)
{
return Bmi1.X64.AndNot(loadMask, value) | storeMask;
}
if (Bmi1.X64.IsSupported)
{
return Bmi1.X64.AndNot(loadMask, value) | storeMask;
}
#endif
return (~loadMask & value) | storeMask;

Просмотреть файл

@ -15,70 +15,69 @@ using RuntimeHelpers = System.Runtime.CompilerServices.RuntimeHelpers;
using RuntimeHelpers = CommunityToolkit.HighPerformance.Helpers.Internals.RuntimeHelpers;
#endif
namespace CommunityToolkit.HighPerformance.Helpers
namespace CommunityToolkit.HighPerformance.Helpers;
/// <summary>
/// Combines the hash code of sequences of <typeparamref name="T"/> values into a single hash code.
/// </summary>
/// <typeparam name="T">The type of values to hash.</typeparam>
/// <remarks>
/// The hash codes returned by the <see cref="Combine"/> method are only guaranteed to be repeatable for
/// the current execution session, just like with the available <see cref="HashCode"/> APIs.In other words,
/// hashing the same <see cref="ReadOnlySpan{T}"/> collection multiple times in the same process will always
/// result in the same hash code, while the same collection being hashed again from another process
/// (or another instance of the same process) is not guaranteed to result in the same final value.
/// For more info, see <see href="https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode#remarks"/>.
/// </remarks>
public struct HashCode<T>
where T : notnull
{
/// <summary>
/// Combines the hash code of sequences of <typeparamref name="T"/> values into a single hash code.
/// Gets a content hash from the input <see cref="ReadOnlySpan{T}"/> instance using the xxHash32 algorithm.
/// </summary>
/// <typeparam name="T">The type of values to hash.</typeparam>
/// <remarks>
/// The hash codes returned by the <see cref="Combine"/> method are only guaranteed to be repeatable for
/// the current execution session, just like with the available <see cref="HashCode"/> APIs.In other words,
/// hashing the same <see cref="ReadOnlySpan{T}"/> collection multiple times in the same process will always
/// result in the same hash code, while the same collection being hashed again from another process
/// (or another instance of the same process) is not guaranteed to result in the same final value.
/// For more info, see <see href="https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode#remarks"/>.
/// </remarks>
public struct HashCode<T>
where T : notnull
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance</param>
/// <returns>The xxHash32 value for the input <see cref="ReadOnlySpan{T}"/> instance</returns>
/// <remarks>The xxHash32 is only guaranteed to be deterministic within the scope of a single app execution</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Combine(ReadOnlySpan<T> span)
{
/// <summary>
/// Gets a content hash from the input <see cref="ReadOnlySpan{T}"/> instance using the xxHash32 algorithm.
/// </summary>
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance</param>
/// <returns>The xxHash32 value for the input <see cref="ReadOnlySpan{T}"/> instance</returns>
/// <remarks>The xxHash32 is only guaranteed to be deterministic within the scope of a single app execution</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Combine(ReadOnlySpan<T> span)
{
int hash = CombineValues(span);
int hash = CombineValues(span);
return HashCode.Combine(hash);
return HashCode.Combine(hash);
}
/// <summary>
/// Gets a content hash from the input <see cref="ReadOnlySpan{T}"/> instance.
/// </summary>
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance</param>
/// <returns>The hash code for the input <see cref="ReadOnlySpan{T}"/> instance</returns>
/// <remarks>The returned hash code is not processed through <see cref="HashCode"/> APIs.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int CombineValues(ReadOnlySpan<T> span)
{
ref T r0 = ref MemoryMarshal.GetReference(span);
// If typeof(T) is not unmanaged, iterate over all the items one by one.
// This check is always known in advance either by the JITter or by the AOT
// compiler, so this branch will never actually be executed by the code.
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
return SpanHelper.GetDjb2HashCode(ref r0, (nint)(uint)span.Length);
}
/// <summary>
/// Gets a content hash from the input <see cref="ReadOnlySpan{T}"/> instance.
/// </summary>
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance</param>
/// <returns>The hash code for the input <see cref="ReadOnlySpan{T}"/> instance</returns>
/// <remarks>The returned hash code is not processed through <see cref="HashCode"/> APIs.</remarks>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int CombineValues(ReadOnlySpan<T> span)
{
ref T r0 = ref MemoryMarshal.GetReference(span);
// Get the info for the target memory area to process.
// The line below is computing the total byte size for the span,
// and we cast both input factors to uint first to avoid sign extensions
// (they're both guaranteed to always be positive values), and to let the
// JIT avoid the 64 bit computation entirely when running in a 32 bit
// process. In that case it will just compute the byte size as a 32 bit
// multiplication with overflow, which is guaranteed never to happen anyway.
ref byte rb = ref Unsafe.As<T, byte>(ref r0);
nint length = (nint)((uint)span.Length * (uint)Unsafe.SizeOf<T>());
// If typeof(T) is not unmanaged, iterate over all the items one by one.
// This check is always known in advance either by the JITter or by the AOT
// compiler, so this branch will never actually be executed by the code.
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
return SpanHelper.GetDjb2HashCode(ref r0, (nint)(uint)span.Length);
}
// Get the info for the target memory area to process.
// The line below is computing the total byte size for the span,
// and we cast both input factors to uint first to avoid sign extensions
// (they're both guaranteed to always be positive values), and to let the
// JIT avoid the 64 bit computation entirely when running in a 32 bit
// process. In that case it will just compute the byte size as a 32 bit
// multiplication with overflow, which is guaranteed never to happen anyway.
ref byte rb = ref Unsafe.As<T, byte>(ref r0);
nint length = (nint)((uint)span.Length * (uint)Unsafe.SizeOf<T>());
return SpanHelper.GetDjb2LikeByteHash(ref rb, length);
}
return SpanHelper.GetDjb2LikeByteHash(ref rb, length);
}
}

Просмотреть файл

@ -26,7 +26,7 @@ internal static class BitOperations
public static int RoundUpPowerOfTwo(int x)
{
#if NETCOREAPP3_1 || NET5_0
return 1 << (32 - LeadingZeroCount((uint)(x - 1)));
return 1 << (32 - LeadingZeroCount((uint)(x - 1)));
#else
x--;
x |= x >> 1;

Просмотреть файл

@ -70,7 +70,7 @@ internal static class RuntimeHelpers
// int.MaxValue. There's not much we can do in this specific case.
return (nint)(uint)array.Length;
#else
return (nint)array.LongLength;
return (nint)array.LongLength;
#endif
}
@ -86,7 +86,7 @@ internal static class RuntimeHelpers
#if NETSTANDARD1_4
return (nint)(uint)array.Length;
#else
return (nint)array.LongLength;
return (nint)array.LongLength;
#endif
}

Просмотреть файл

@ -14,77 +14,77 @@ namespace CommunityToolkit.HighPerformance.Helpers;
public static partial class ParallelHelper
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction"/>) to invoke for each iteration index.</typeparam>
/// <param name="range">The iteration range.</param>
/// <remarks>None of the bounds of <paramref name="range"/> can start from an end.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For<TAction>(Range range)
where TAction : struct, IAction
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction"/>) to invoke for each iteration index.</typeparam>
/// <param name="range">The iteration range.</param>
/// <remarks>None of the bounds of <paramref name="range"/> can start from an end.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For<TAction>(Range range)
where TAction : struct, IAction
{
For(range, default(TAction), 1);
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction"/>) to invoke for each iteration index.</typeparam>
/// <param name="range">The iteration range.</param>
/// <param name="minimumActionsPerThread">
/// The minimum number of actions to run per individual thread. Set to 1 if all invocations
/// should be parallelized, or to a greater number if each individual invocation is fast
/// enough that it is more efficient to set a lower bound per each running thread.
/// </param>
/// <remarks>None of the bounds of <paramref name="range"/> can start from an end.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For<TAction>(Range range, int minimumActionsPerThread)
where TAction : struct, IAction
{
For(range, default(TAction), minimumActionsPerThread);
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction"/>) to invoke for each iteration index.</typeparam>
/// <param name="range">The iteration range.</param>
/// <param name="action">The <typeparamref name="TAction"/> instance representing the action to invoke.</param>
/// <remarks>None of the bounds of <paramref name="range"/> can start from an end.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For<TAction>(Range range, in TAction action)
where TAction : struct, IAction
{
For(range, action, 1);
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction"/>) to invoke for each iteration index.</typeparam>
/// <param name="range">The iteration range.</param>
/// <param name="action">The <typeparamref name="TAction"/> instance representing the action to invoke.</param>
/// <param name="minimumActionsPerThread">
/// The minimum number of actions to run per individual thread. Set to 1 if all invocations
/// should be parallelized, or to a greater number if each individual invocation is fast
/// enough that it is more efficient to set a lower bound per each running thread.
/// </param>
/// <remarks>None of the bounds of <paramref name="range"/> can start from an end.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For<TAction>(Range range, in TAction action, int minimumActionsPerThread)
where TAction : struct, IAction
{
if (range.Start.IsFromEnd || range.End.IsFromEnd)
{
For(range, default(TAction), 1);
ThrowArgumentExceptionForRangeIndexFromEnd(nameof(range));
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction"/>) to invoke for each iteration index.</typeparam>
/// <param name="range">The iteration range.</param>
/// <param name="minimumActionsPerThread">
/// The minimum number of actions to run per individual thread. Set to 1 if all invocations
/// should be parallelized, or to a greater number if each individual invocation is fast
/// enough that it is more efficient to set a lower bound per each running thread.
/// </param>
/// <remarks>None of the bounds of <paramref name="range"/> can start from an end.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For<TAction>(Range range, int minimumActionsPerThread)
where TAction : struct, IAction
{
For(range, default(TAction), minimumActionsPerThread);
}
int start = range.Start.Value;
int end = range.End.Value;
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction"/>) to invoke for each iteration index.</typeparam>
/// <param name="range">The iteration range.</param>
/// <param name="action">The <typeparamref name="TAction"/> instance representing the action to invoke.</param>
/// <remarks>None of the bounds of <paramref name="range"/> can start from an end.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For<TAction>(Range range, in TAction action)
where TAction : struct, IAction
{
For(range, action, 1);
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction"/>) to invoke for each iteration index.</typeparam>
/// <param name="range">The iteration range.</param>
/// <param name="action">The <typeparamref name="TAction"/> instance representing the action to invoke.</param>
/// <param name="minimumActionsPerThread">
/// The minimum number of actions to run per individual thread. Set to 1 if all invocations
/// should be parallelized, or to a greater number if each individual invocation is fast
/// enough that it is more efficient to set a lower bound per each running thread.
/// </param>
/// <remarks>None of the bounds of <paramref name="range"/> can start from an end.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For<TAction>(Range range, in TAction action, int minimumActionsPerThread)
where TAction : struct, IAction
{
if (range.Start.IsFromEnd || range.End.IsFromEnd)
{
ThrowArgumentExceptionForRangeIndexFromEnd(nameof(range));
}
int start = range.Start.Value;
int end = range.End.Value;
For(start, end, action, minimumActionsPerThread);
}
For(start, end, action, minimumActionsPerThread);
}
#endif
/// <summary>

Просмотреть файл

@ -15,84 +15,84 @@ namespace CommunityToolkit.HighPerformance.Helpers;
public static partial class ParallelHelper
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction2D"/>) to invoke for each pair of iteration indices.</typeparam>
/// <param name="i">The <see cref="Range"/> value indicating the iteration range for the outer loop.</param>
/// <param name="j">The <see cref="Range"/> value indicating the iteration range for the inner loop.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For2D<TAction>(Range i, Range j)
where TAction : struct, IAction2D
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction2D"/>) to invoke for each pair of iteration indices.</typeparam>
/// <param name="i">The <see cref="Range"/> value indicating the iteration range for the outer loop.</param>
/// <param name="j">The <see cref="Range"/> value indicating the iteration range for the inner loop.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For2D<TAction>(Range i, Range j)
where TAction : struct, IAction2D
{
For2D(i, j, default(TAction), 1);
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction2D"/>) to invoke for each pair of iteration indices.</typeparam>
/// <param name="i">The <see cref="Range"/> value indicating the iteration range for the outer loop.</param>
/// <param name="j">The <see cref="Range"/> value indicating the iteration range for the inner loop.</param>
/// <param name="minimumActionsPerThread">
/// The minimum number of actions to run per individual thread. Set to 1 if all invocations
/// should be parallelized, or to a greater number if each individual invocation is fast
/// enough that it is more efficient to set a lower bound per each running thread.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For2D<TAction>(Range i, Range j, int minimumActionsPerThread)
where TAction : struct, IAction2D
{
For2D(i, j, default(TAction), minimumActionsPerThread);
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction2D"/>) to invoke for each pair of iteration indices.</typeparam>
/// <param name="i">The <see cref="Range"/> value indicating the iteration range for the outer loop.</param>
/// <param name="j">The <see cref="Range"/> value indicating the iteration range for the inner loop.</param>
/// <param name="action">The <typeparamref name="TAction"/> instance representing the action to invoke.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For2D<TAction>(Range i, Range j, in TAction action)
where TAction : struct, IAction2D
{
For2D(i, j, action, 1);
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction2D"/>) to invoke for each pair of iteration indices.</typeparam>
/// <param name="i">The <see cref="Range"/> value indicating the iteration range for the outer loop.</param>
/// <param name="j">The <see cref="Range"/> value indicating the iteration range for the inner loop.</param>
/// <param name="action">The <typeparamref name="TAction"/> instance representing the action to invoke.</param>
/// <param name="minimumActionsPerThread">
/// The minimum number of actions to run per individual thread. Set to 1 if all invocations
/// should be parallelized, or to a greater number if each individual invocation is fast
/// enough that it is more efficient to set a lower bound per each running thread.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For2D<TAction>(Range i, Range j, in TAction action, int minimumActionsPerThread)
where TAction : struct, IAction2D
{
if (i.Start.IsFromEnd || i.End.IsFromEnd)
{
For2D(i, j, default(TAction), 1);
ThrowArgumentExceptionForRangeIndexFromEnd(nameof(i));
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction2D"/>) to invoke for each pair of iteration indices.</typeparam>
/// <param name="i">The <see cref="Range"/> value indicating the iteration range for the outer loop.</param>
/// <param name="j">The <see cref="Range"/> value indicating the iteration range for the inner loop.</param>
/// <param name="minimumActionsPerThread">
/// The minimum number of actions to run per individual thread. Set to 1 if all invocations
/// should be parallelized, or to a greater number if each individual invocation is fast
/// enough that it is more efficient to set a lower bound per each running thread.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For2D<TAction>(Range i, Range j, int minimumActionsPerThread)
where TAction : struct, IAction2D
if (j.Start.IsFromEnd || j.End.IsFromEnd)
{
For2D(i, j, default(TAction), minimumActionsPerThread);
ThrowArgumentExceptionForRangeIndexFromEnd(nameof(j));
}
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction2D"/>) to invoke for each pair of iteration indices.</typeparam>
/// <param name="i">The <see cref="Range"/> value indicating the iteration range for the outer loop.</param>
/// <param name="j">The <see cref="Range"/> value indicating the iteration range for the inner loop.</param>
/// <param name="action">The <typeparamref name="TAction"/> instance representing the action to invoke.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For2D<TAction>(Range i, Range j, in TAction action)
where TAction : struct, IAction2D
{
For2D(i, j, action, 1);
}
int top = i.Start.Value;
int bottom = i.End.Value;
int left = j.Start.Value;
int right = j.End.Value;
/// <summary>
/// Executes a specified action in an optimized parallel loop.
/// </summary>
/// <typeparam name="TAction">The type of action (implementing <see cref="IAction2D"/>) to invoke for each pair of iteration indices.</typeparam>
/// <param name="i">The <see cref="Range"/> value indicating the iteration range for the outer loop.</param>
/// <param name="j">The <see cref="Range"/> value indicating the iteration range for the inner loop.</param>
/// <param name="action">The <typeparamref name="TAction"/> instance representing the action to invoke.</param>
/// <param name="minimumActionsPerThread">
/// The minimum number of actions to run per individual thread. Set to 1 if all invocations
/// should be parallelized, or to a greater number if each individual invocation is fast
/// enough that it is more efficient to set a lower bound per each running thread.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void For2D<TAction>(Range i, Range j, in TAction action, int minimumActionsPerThread)
where TAction : struct, IAction2D
{
if (i.Start.IsFromEnd || i.End.IsFromEnd)
{
ThrowArgumentExceptionForRangeIndexFromEnd(nameof(i));
}
if (j.Start.IsFromEnd || j.End.IsFromEnd)
{
ThrowArgumentExceptionForRangeIndexFromEnd(nameof(j));
}
int top = i.Start.Value;
int bottom = i.End.Value;
int left = j.Start.Value;
int right = j.End.Value;
For2D(top, bottom, left, right, action, minimumActionsPerThread);
}
For2D(top, bottom, left, right, action, minimumActionsPerThread);
}
#endif
/// <summary>

Просмотреть файл

@ -310,188 +310,188 @@ public readonly struct Memory2D<T> : IEquatable<Memory2D<T>>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Memory2D{T}"/> struct.
/// </summary>
/// <param name="memoryManager">The target <see cref="MemoryManager{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="memoryManager"/>.</remarks>
public Memory2D(MemoryManager<T> memoryManager, int height, int width)
: this(memoryManager, 0, height, width, 0)
/// <summary>
/// Initializes a new instance of the <see cref="Memory2D{T}"/> struct.
/// </summary>
/// <param name="memoryManager">The target <see cref="MemoryManager{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="memoryManager"/>.</remarks>
public Memory2D(MemoryManager<T> memoryManager, int height, int width)
: this(memoryManager, 0, height, width, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Memory2D{T}"/> struct.
/// </summary>
/// <param name="memoryManager">The target <see cref="MemoryManager{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="memoryManager"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memoryManager"/>.
/// </exception>
public Memory2D(MemoryManager<T> memoryManager, int offset, int height, int width, int pitch)
{
int length = memoryManager.GetSpan().Length;
if ((uint)offset > (uint)length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
/// <summary>
/// Initializes a new instance of the <see cref="Memory2D{T}"/> struct.
/// </summary>
/// <param name="memoryManager">The target <see cref="MemoryManager{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="memoryManager"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memoryManager"/>.
/// </exception>
public Memory2D(MemoryManager<T> memoryManager, int offset, int height, int width, int pitch)
if (height < 0)
{
int length = memoryManager.GetSpan().Length;
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if ((uint)offset > (uint)length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (width == 0 || height == 0)
{
this = default;
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
return;
}
if (width == 0 || height == 0)
{
this = default;
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
int remaining = length - offset;
return;
}
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
int remaining = length - offset;
this.instance = memoryManager;
this.offset = (nint)(uint)offset;
this.height = height;
this.width = width;
this.pitch = pitch;
}
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
/// <summary>
/// Initializes a new instance of the <see cref="Memory2D{T}"/> struct.
/// </summary>
/// <param name="memory">The target <see cref="Memory{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="memory"/>.</remarks>
internal Memory2D(Memory<T> memory, int height, int width)
: this(memory, 0, height, width, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Memory2D{T}"/> struct.
/// </summary>
/// <param name="memory">The target <see cref="Memory{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="memory"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
internal Memory2D(Memory<T> memory, int offset, int height, int width, int pitch)
{
if ((uint)offset > (uint)memory.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width == 0 || height == 0)
{
this = default;
return;
}
int
area = OverflowHelper.ComputeInt32Area(height, width, pitch),
remaining = memory.Length - offset;
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
// Check if the Memory<T> instance wraps a string. This is possible in case
// consumers do an unsafe cast for the entire Memory<T> object, and while not
// really safe it is still supported in CoreCLR too, so we're following suit here.
if (typeof(T) == typeof(char) &&
MemoryMarshal.TryGetString(Unsafe.As<Memory<T>, Memory<char>>(ref memory), out string? text, out int textStart, out _))
{
ref char r0 = ref text.DangerousGetReferenceAt(textStart + offset);
this.instance = text;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(text, ref r0);
}
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
{
// Check if the input Memory<T> instance wraps an array we can access.
// This is fine, since Memory<T> on its own doesn't control the lifetime
// of the underlying array anyway, and this Memory2D<T> type would do the same.
// Using the array directly makes retrieving a Span2D<T> faster down the line,
// as we no longer have to jump through the boxed Memory<T> first anymore.
T[] array = segment.Array!;
this.instance = array;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(segment.Offset + offset));
}
else if (MemoryMarshal.TryGetMemoryManager<T, MemoryManager<T>>(memory, out MemoryManager<T>? memoryManager, out int memoryManagerStart, out _))
{
this.instance = memoryManager;
this.offset = (nint)(uint)offset;
this.height = height;
this.width = width;
this.pitch = pitch;
this.offset = (nint)(uint)(memoryManagerStart + offset);
}
/// <summary>
/// Initializes a new instance of the <see cref="Memory2D{T}"/> struct.
/// </summary>
/// <param name="memory">The target <see cref="Memory{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="memory"/>.</remarks>
internal Memory2D(Memory<T> memory, int height, int width)
: this(memory, 0, height, width, 0)
else
{
ThrowHelper.ThrowArgumentExceptionForUnsupportedType();
this.instance = null;
this.offset = default;
}
/// <summary>
/// Initializes a new instance of the <see cref="Memory2D{T}"/> struct.
/// </summary>
/// <param name="memory">The target <see cref="Memory{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="memory"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
internal Memory2D(Memory<T> memory, int offset, int height, int width, int pitch)
{
if ((uint)offset > (uint)memory.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width == 0 || height == 0)
{
this = default;
return;
}
int
area = OverflowHelper.ComputeInt32Area(height, width, pitch),
remaining = memory.Length - offset;
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
// Check if the Memory<T> instance wraps a string. This is possible in case
// consumers do an unsafe cast for the entire Memory<T> object, and while not
// really safe it is still supported in CoreCLR too, so we're following suit here.
if (typeof(T) == typeof(char) &&
MemoryMarshal.TryGetString(Unsafe.As<Memory<T>, Memory<char>>(ref memory), out string? text, out int textStart, out _))
{
ref char r0 = ref text.DangerousGetReferenceAt(textStart + offset);
this.instance = text;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(text, ref r0);
}
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
{
// Check if the input Memory<T> instance wraps an array we can access.
// This is fine, since Memory<T> on its own doesn't control the lifetime
// of the underlying array anyway, and this Memory2D<T> type would do the same.
// Using the array directly makes retrieving a Span2D<T> faster down the line,
// as we no longer have to jump through the boxed Memory<T> first anymore.
T[] array = segment.Array!;
this.instance = array;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(segment.Offset + offset));
}
else if (MemoryMarshal.TryGetMemoryManager<T, MemoryManager<T>>(memory, out MemoryManager<T>? memoryManager, out int memoryManagerStart, out _))
{
this.instance = memoryManager;
this.offset = (nint)(uint)(memoryManagerStart + offset);
}
else
{
ThrowHelper.ThrowArgumentExceptionForUnsupportedType();
this.instance = null;
this.offset = default;
}
this.height = height;
this.width = width;
this.pitch = pitch;
}
this.height = height;
this.width = width;
this.pitch = pitch;
}
#endif
/// <summary>
@ -602,19 +602,19 @@ public readonly struct Memory2D<T> : IEquatable<Memory2D<T>>
if (this.instance is not null)
{
#if NETSTANDARD2_1_OR_GREATER
if (this.instance is MemoryManager<T> memoryManager)
{
ref T r0 = ref memoryManager.GetSpan().DangerousGetReference();
ref T r1 = ref Unsafe.Add(ref r0, this.offset);
if (this.instance is MemoryManager<T> memoryManager)
{
ref T r0 = ref memoryManager.GetSpan().DangerousGetReference();
ref T r1 = ref Unsafe.Add(ref r0, this.offset);
return new Span2D<T>(ref r1, this.height, this.width, this.pitch);
}
else
{
ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(this.instance, this.offset);
return new Span2D<T>(ref r1, this.height, this.width, this.pitch);
}
else
{
ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(this.instance, this.offset);
return new Span2D<T>(ref r0, this.height, this.width, this.pitch);
}
return new Span2D<T>(ref r0, this.height, this.width, this.pitch);
}
#else
return new Span2D<T>(this.instance, this.offset, this.height, this.width, this.pitch);
#endif
@ -625,26 +625,26 @@ public readonly struct Memory2D<T> : IEquatable<Memory2D<T>>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Slices the current instance with the specified parameters.
/// </summary>
/// <param name="rows">The target range of rows to select.</param>
/// <param name="columns">The target range of columns to select.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="rows"/> or <paramref name="columns"/> are invalid.
/// </exception>
/// <returns>A new <see cref="Memory2D{T}"/> instance representing a slice of the current one.</returns>
public Memory2D<T> this[Range rows, Range columns]
/// <summary>
/// Slices the current instance with the specified parameters.
/// </summary>
/// <param name="rows">The target range of rows to select.</param>
/// <param name="columns">The target range of columns to select.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="rows"/> or <paramref name="columns"/> are invalid.
/// </exception>
/// <returns>A new <see cref="Memory2D{T}"/> instance representing a slice of the current one.</returns>
public Memory2D<T> this[Range rows, Range columns]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
(int row, int height) = rows.GetOffsetAndLength(this.height);
(int column, int width) = columns.GetOffsetAndLength(this.width);
(int row, int height) = rows.GetOffsetAndLength(this.height);
(int column, int width) = columns.GetOffsetAndLength(this.width);
return Slice(row, column, height, width);
}
return Slice(row, column, height, width);
}
}
#endif
/// <summary>
@ -795,14 +795,14 @@ public readonly struct Memory2D<T> : IEquatable<Memory2D<T>>
memory = array.AsMemory(index, this.height * this.width);
}
#if NETSTANDARD2_1_OR_GREATER
else if (this.instance.GetType() == typeof(T[,]) ||
this.instance.GetType() == typeof(T[,,]))
{
// If the object is a 2D or 3D array, we can create a Memory<T> from the RawObjectMemoryManager<T> type.
// We just need to use the precomputed offset pointing to the first item in the current instance,
// and the current usable length. We don't need to retrieve the current index, as the manager just offsets.
memory = new RawObjectMemoryManager<T>(this.instance, this.offset, this.height * this.width).Memory;
}
else if (this.instance.GetType() == typeof(T[,]) ||
this.instance.GetType() == typeof(T[,,]))
{
// If the object is a 2D or 3D array, we can create a Memory<T> from the RawObjectMemoryManager<T> type.
// We just need to use the precomputed offset pointing to the first item in the current instance,
// and the current usable length. We don't need to retrieve the current index, as the manager just offsets.
memory = new RawObjectMemoryManager<T>(this.instance, this.offset, this.height * this.width).Memory;
}
#endif
else
{
@ -863,12 +863,12 @@ public readonly struct Memory2D<T> : IEquatable<Memory2D<T>>
if (this.instance is not null)
{
#if !NETSTANDARD1_4
return HashCode.Combine(
RuntimeHelpers.GetHashCode(this.instance),
this.offset,
this.height,
this.width,
this.pitch);
return HashCode.Combine(
RuntimeHelpers.GetHashCode(this.instance),
this.offset,
this.height,
this.width,
this.pitch);
#else
Span<int> values = stackalloc int[]
{

Просмотреть файл

@ -330,180 +330,180 @@ public readonly struct ReadOnlyMemory2D<T> : IEquatable<ReadOnlyMemory2D<T>>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyMemory2D{T}"/> struct.
/// </summary>
/// <param name="memoryManager">The target <see cref="MemoryManager{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="memoryManager"/>.</remarks>
public ReadOnlyMemory2D(MemoryManager<T> memoryManager, int height, int width)
: this(memoryManager, 0, height, width, 0)
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyMemory2D{T}"/> struct.
/// </summary>
/// <param name="memoryManager">The target <see cref="MemoryManager{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="memoryManager"/>.</remarks>
public ReadOnlyMemory2D(MemoryManager<T> memoryManager, int height, int width)
: this(memoryManager, 0, height, width, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyMemory2D{T}"/> struct.
/// </summary>
/// <param name="memoryManager">The target <see cref="MemoryManager{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="memoryManager"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memoryManager"/>.
/// </exception>
public ReadOnlyMemory2D(MemoryManager<T> memoryManager, int offset, int height, int width, int pitch)
{
int length = memoryManager.GetSpan().Length;
if ((uint)offset > (uint)length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyMemory2D{T}"/> struct.
/// </summary>
/// <param name="memoryManager">The target <see cref="MemoryManager{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="memoryManager"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memoryManager"/>.
/// </exception>
public ReadOnlyMemory2D(MemoryManager<T> memoryManager, int offset, int height, int width, int pitch)
if (height < 0)
{
int length = memoryManager.GetSpan().Length;
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if ((uint)offset > (uint)length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (width == 0 || height == 0)
{
this = default;
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
return;
}
if (width == 0 || height == 0)
{
this = default;
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
int remaining = length - offset;
return;
}
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
int remaining = length - offset;
this.instance = memoryManager;
this.offset = (nint)(uint)offset;
this.height = height;
this.width = width;
this.pitch = pitch;
}
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyMemory2D{T}"/> struct.
/// </summary>
/// <param name="memory">The target <see cref="Memory{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="memory"/>.</remarks>
internal ReadOnlyMemory2D(ReadOnlyMemory<T> memory, int height, int width)
: this(memory, 0, height, width, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyMemory2D{T}"/> struct.
/// </summary>
/// <param name="memory">The target <see cref="ReadOnlyMemory{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="memory"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
internal ReadOnlyMemory2D(ReadOnlyMemory<T> memory, int offset, int height, int width, int pitch)
{
if ((uint)offset > (uint)memory.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width == 0 || height == 0)
{
this = default;
return;
}
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
int remaining = memory.Length - offset;
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
// Check the supported underlying objects, like in Memory2D<T>
if (typeof(T) == typeof(char) &&
MemoryMarshal.TryGetString(Unsafe.As<ReadOnlyMemory<T>, ReadOnlyMemory<char>>(ref memory), out string? text, out int textStart, out _))
{
ref char r0 = ref text.DangerousGetReferenceAt(textStart + offset);
this.instance = text;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(text, ref r0);
}
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
{
T[] array = segment.Array!;
this.instance = array;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(segment.Offset + offset));
}
else if (MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<T>? memoryManager, out int memoryManagerStart, out _))
{
this.instance = memoryManager;
this.offset = (nint)(uint)offset;
this.height = height;
this.width = width;
this.pitch = pitch;
this.offset = (nint)(uint)(memoryManagerStart + offset);
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyMemory2D{T}"/> struct.
/// </summary>
/// <param name="memory">The target <see cref="Memory{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="memory"/>.</remarks>
internal ReadOnlyMemory2D(ReadOnlyMemory<T> memory, int height, int width)
: this(memory, 0, height, width, 0)
else
{
ThrowHelper.ThrowArgumentExceptionForUnsupportedType();
this.instance = null;
this.offset = default;
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyMemory2D{T}"/> struct.
/// </summary>
/// <param name="memory">The target <see cref="ReadOnlyMemory{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="memory"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="memory"/>.
/// </exception>
internal ReadOnlyMemory2D(ReadOnlyMemory<T> memory, int offset, int height, int width, int pitch)
{
if ((uint)offset > (uint)memory.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width == 0 || height == 0)
{
this = default;
return;
}
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
int remaining = memory.Length - offset;
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
// Check the supported underlying objects, like in Memory2D<T>
if (typeof(T) == typeof(char) &&
MemoryMarshal.TryGetString(Unsafe.As<ReadOnlyMemory<T>, ReadOnlyMemory<char>>(ref memory), out string? text, out int textStart, out _))
{
ref char r0 = ref text.DangerousGetReferenceAt(textStart + offset);
this.instance = text;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(text, ref r0);
}
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
{
T[] array = segment.Array!;
this.instance = array;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(segment.Offset + offset));
}
else if (MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<T>? memoryManager, out int memoryManagerStart, out _))
{
this.instance = memoryManager;
this.offset = (nint)(uint)(memoryManagerStart + offset);
}
else
{
ThrowHelper.ThrowArgumentExceptionForUnsupportedType();
this.instance = null;
this.offset = default;
}
this.height = height;
this.width = width;
this.pitch = pitch;
}
this.height = height;
this.width = width;
this.pitch = pitch;
}
#endif
/// <summary>
@ -614,20 +614,20 @@ public readonly struct ReadOnlyMemory2D<T> : IEquatable<ReadOnlyMemory2D<T>>
if (this.instance is not null)
{
#if NETSTANDARD2_1_OR_GREATER
if (this.instance is MemoryManager<T> memoryManager)
{
ref T r0 = ref memoryManager.GetSpan().DangerousGetReference();
ref T r1 = ref Unsafe.Add(ref r0, this.offset);
if (this.instance is MemoryManager<T> memoryManager)
{
ref T r0 = ref memoryManager.GetSpan().DangerousGetReference();
ref T r1 = ref Unsafe.Add(ref r0, this.offset);
return new ReadOnlySpan2D<T>(in r1, this.height, this.width, this.pitch);
}
else
{
// This handles both arrays and strings
ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(this.instance, this.offset);
return new ReadOnlySpan2D<T>(in r1, this.height, this.width, this.pitch);
}
else
{
// This handles both arrays and strings
ref T r0 = ref ObjectMarshal.DangerousGetObjectDataReferenceAt<T>(this.instance, this.offset);
return new ReadOnlySpan2D<T>(in r0, this.height, this.width, this.pitch);
}
return new ReadOnlySpan2D<T>(in r0, this.height, this.width, this.pitch);
}
#else
return new ReadOnlySpan2D<T>(this.instance, this.offset, this.height, this.width, this.pitch);
#endif
@ -638,26 +638,26 @@ public readonly struct ReadOnlyMemory2D<T> : IEquatable<ReadOnlyMemory2D<T>>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Slices the current instance with the specified parameters.
/// </summary>
/// <param name="rows">The target range of rows to select.</param>
/// <param name="columns">The target range of columns to select.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="rows"/> or <paramref name="columns"/> are invalid.
/// </exception>
/// <returns>A new <see cref="ReadOnlyMemory2D{T}"/> instance representing a slice of the current one.</returns>
public ReadOnlyMemory2D<T> this[Range rows, Range columns]
/// <summary>
/// Slices the current instance with the specified parameters.
/// </summary>
/// <param name="rows">The target range of rows to select.</param>
/// <param name="columns">The target range of columns to select.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="rows"/> or <paramref name="columns"/> are invalid.
/// </exception>
/// <returns>A new <see cref="ReadOnlyMemory2D{T}"/> instance representing a slice of the current one.</returns>
public ReadOnlyMemory2D<T> this[Range rows, Range columns]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
(int row, int height) = rows.GetOffsetAndLength(this.height);
(int column, int width) = columns.GetOffsetAndLength(this.width);
(int row, int height) = rows.GetOffsetAndLength(this.height);
(int column, int width) = columns.GetOffsetAndLength(this.width);
return Slice(row, column, height, width);
}
return Slice(row, column, height, width);
}
}
#endif
/// <summary>
@ -809,11 +809,11 @@ public readonly struct ReadOnlyMemory2D<T> : IEquatable<ReadOnlyMemory2D<T>>
memory = array.AsMemory(index, this.height * this.width);
}
#if NETSTANDARD2_1_OR_GREATER
else if (this.instance.GetType() == typeof(T[,]) ||
this.instance.GetType() == typeof(T[,,]))
{
memory = new RawObjectMemoryManager<T>(this.instance, this.offset, this.height * this.width).Memory;
}
else if (this.instance.GetType() == typeof(T[,]) ||
this.instance.GetType() == typeof(T[,,]))
{
memory = new RawObjectMemoryManager<T>(this.instance, this.offset, this.height * this.width).Memory;
}
#endif
else
{
@ -874,12 +874,12 @@ public readonly struct ReadOnlyMemory2D<T> : IEquatable<ReadOnlyMemory2D<T>>
if (this.instance is not null)
{
#if !NETSTANDARD1_4
return HashCode.Combine(
RuntimeHelpers.GetHashCode(this.instance),
this.offset,
this.height,
this.width,
this.pitch);
return HashCode.Combine(
RuntimeHelpers.GetHashCode(this.instance),
this.offset,
this.height,
this.width,
this.pitch);
#else
Span<int> values = stackalloc int[]
{

Просмотреть файл

@ -38,7 +38,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
ref T r1 = ref Unsafe.Add(ref r0, startIndex);
#if NETSTANDARD2_1_OR_GREATER
return new ReadOnlyRefEnumerable<T>(in r1, Width, 1);
return new ReadOnlyRefEnumerable<T>(in r1, Width, 1);
#else
IntPtr offset = RuntimeHelpers.GetObjectDataOrReferenceByteOffset(this.instance, ref r1);
@ -65,7 +65,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
ref T r1 = ref Unsafe.Add(ref r0, (nint)(uint)column);
#if NETSTANDARD2_1_OR_GREATER
return new ReadOnlyRefEnumerable<T>(in r1, Height, this.stride);
return new ReadOnlyRefEnumerable<T>(in r1, Height, this.stride);
#else
IntPtr offset = RuntimeHelpers.GetObjectDataOrReferenceByteOffset(this.instance, ref r1);
@ -89,11 +89,11 @@ public readonly ref partial struct ReadOnlySpan2D<T>
public ref struct Enumerator
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>Just like in <see cref="ReadOnlySpan2D{T}"/>, the length is the height of the 2D region.</remarks>
private readonly ReadOnlySpan<T> span;
/// <summary>
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>Just like in <see cref="ReadOnlySpan2D{T}"/>, the length is the height of the 2D region.</remarks>
private readonly ReadOnlySpan<T> span;
#else
/// <summary>
/// The target <see cref="object"/> instance, if present.
@ -138,7 +138,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
internal Enumerator(ReadOnlySpan2D<T> span)
{
#if NETSTANDARD2_1_OR_GREATER
this.span = span.span;
this.span = span.span;
#else
this.instance = span.instance;
this.offset = span.offset;
@ -172,7 +172,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
this.x = 0;
#if NETSTANDARD2_1_OR_GREATER
return ++this.y < this.span.Length;
return ++this.y < this.span.Length;
#else
return ++this.y < this.height;
#endif
@ -187,7 +187,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T r0 = ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
#endif

Просмотреть файл

@ -30,10 +30,10 @@ namespace CommunityToolkit.HighPerformance;
public readonly ref partial struct ReadOnlySpan2D<T>
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
private readonly ReadOnlySpan<T> span;
/// <summary>
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
private readonly ReadOnlySpan<T> span;
#else
/// <summary>
/// The target <see cref="object"/> instance, if present.
@ -62,20 +62,20 @@ public readonly ref partial struct ReadOnlySpan2D<T>
private readonly int stride;
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlySpan2D{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="height">The height of the 2D memory area to map.</param>
/// <param name="width">The width of the 2D memory area to map.</param>
/// <param name="pitch">The pitch of the 2D memory area to map (the distance between each row).</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ReadOnlySpan2D(in T value, int height, int width, int pitch)
{
this.span = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(value), height);
this.width = width;
this.stride = width + pitch;
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlySpan2D{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="height">The height of the 2D memory area to map.</param>
/// <param name="width">The width of the 2D memory area to map.</param>
/// <param name="pitch">The pitch of the 2D memory area to map (the distance between each row).</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ReadOnlySpan2D(in T value, int height, int width, int pitch)
{
this.span = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(value), height);
this.width = width;
this.stride = width + pitch;
}
#endif
/// <summary>
@ -111,7 +111,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
OverflowHelper.EnsureIsInNativeIntRange(height, width, pitch);
#if NETSTANDARD2_1_OR_GREATER
this.span = new ReadOnlySpan<T>(pointer, height);
this.span = new ReadOnlySpan<T>(pointer, height);
#else
this.instance = null;
this.offset = (IntPtr)pointer;
@ -208,7 +208,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(offset), height);
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(offset), height);
#else
this.instance = array;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(offset));
@ -232,7 +232,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReference(), array.GetLength(0));
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReference(), array.GetLength(0));
#else
this.instance = array;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(0, 0));
@ -291,7 +291,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(row, column), height);
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(row, column), height);
#else
this.instance = array;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(row, column));
@ -315,7 +315,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(depth, 0, 0), array.GetLength(1));
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(depth, 0, 0), array.GetLength(1));
#else
this.instance = array;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(depth, 0, 0));
@ -365,7 +365,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(depth, row, column), height);
this.span = MemoryMarshal.CreateReadOnlySpan(ref array.DangerousGetReferenceAt(depth, row, column), height);
#else
this.instance = array;
this.offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(depth, row, column));
@ -376,109 +376,108 @@ public readonly ref partial struct ReadOnlySpan2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlySpan2D{T}"/> struct.
/// </summary>
/// <param name="span">The target <see cref="ReadOnlySpan{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="span"/>.</remarks>
internal ReadOnlySpan2D(ReadOnlySpan<T> span, int height, int width)
: this(span, 0, height, width, 0)
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlySpan2D{T}"/> struct.
/// </summary>
/// <param name="span">The target <see cref="ReadOnlySpan{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="span"/>.</remarks>
internal ReadOnlySpan2D(ReadOnlySpan<T> span, int height, int width)
: this(span, 0, height, width, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlySpan2D{T}"/> struct.
/// </summary>
/// <param name="span">The target <see cref="ReadOnlySpan{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="span"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
internal ReadOnlySpan2D(ReadOnlySpan<T> span, int offset, int height, int width, int pitch)
{
if ((uint)offset > (uint)span.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlySpan2D{T}"/> struct.
/// </summary>
/// <param name="span">The target <see cref="ReadOnlySpan{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="span"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
internal ReadOnlySpan2D(ReadOnlySpan<T> span, int offset, int height, int width, int pitch)
if (height < 0)
{
if ((uint)offset > (uint)span.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width == 0 || height == 0)
{
this = default;
return;
}
int
area = OverflowHelper.ComputeInt32Area(height, width, pitch),
remaining = span.Length - offset;
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
this.span = MemoryMarshal.CreateSpan(ref span.DangerousGetReferenceAt(offset), height);
this.width = width;
this.stride = width + pitch;
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
/// <summary>
/// Creates a new instance of the <see cref="ReadOnlySpan2D{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="height">The height of the 2D memory area to map.</param>
/// <param name="width">The width of the 2D memory area to map.</param>
/// <param name="pitch">The pitch of the 2D memory area to map (the distance between each row).</param>
/// <returns>A <see cref="ReadOnlySpan2D{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static ReadOnlySpan2D<T> DangerousCreate(in T value, int height, int width, int pitch)
if (width < 0)
{
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
OverflowHelper.EnsureIsInNativeIntRange(height, width, pitch);
return new ReadOnlySpan2D<T>(in value, height, width, pitch);
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width == 0 || height == 0)
{
this = default;
return;
}
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
int remaining = span.Length - offset;
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
this.span = MemoryMarshal.CreateSpan(ref span.DangerousGetReferenceAt(offset), height);
this.width = width;
this.stride = width + pitch;
}
/// <summary>
/// Creates a new instance of the <see cref="ReadOnlySpan2D{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="height">The height of the 2D memory area to map.</param>
/// <param name="width">The width of the 2D memory area to map.</param>
/// <param name="pitch">The pitch of the 2D memory area to map (the distance between each row).</param>
/// <returns>A <see cref="ReadOnlySpan2D{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static ReadOnlySpan2D<T> DangerousCreate(in T value, int height, int width, int pitch)
{
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
OverflowHelper.EnsureIsInNativeIntRange(height, width, pitch);
return new ReadOnlySpan2D<T>(in value, height, width, pitch);
}
#endif
/// <summary>
@ -513,7 +512,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
return this.span.Length;
return this.span.Length;
#else
return this.height;
#endif
@ -554,41 +553,41 @@ public readonly ref partial struct ReadOnlySpan2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Gets the element at the specified zero-based indices.
/// </summary>
/// <param name="row">The target row to get the element from.</param>
/// <param name="column">The target column to get the element from.</param>
/// <returns>A reference to the element at the specified indices.</returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when either <paramref name="row"/> or <paramref name="column"/> are invalid.
/// </exception>
public ref readonly T this[Index row, Index column]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref this[row.GetOffset(Height), column.GetOffset(this.width)];
}
/// <summary>
/// Gets the element at the specified zero-based indices.
/// </summary>
/// <param name="row">The target row to get the element from.</param>
/// <param name="column">The target column to get the element from.</param>
/// <returns>A reference to the element at the specified indices.</returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when either <paramref name="row"/> or <paramref name="column"/> are invalid.
/// </exception>
public ref readonly T this[Index row, Index column]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref this[row.GetOffset(Height), column.GetOffset(this.width)];
}
/// <summary>
/// Slices the current instance with the specified parameters.
/// </summary>
/// <param name="rows">The target range of rows to select.</param>
/// <param name="columns">The target range of columns to select.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="rows"/> or <paramref name="columns"/> are invalid.
/// </exception>
/// <returns>A new <see cref="ReadOnlySpan2D{T}"/> instance representing a slice of the current one.</returns>
public ReadOnlySpan2D<T> this[Range rows, Range columns]
/// <summary>
/// Slices the current instance with the specified parameters.
/// </summary>
/// <param name="rows">The target range of rows to select.</param>
/// <param name="columns">The target range of columns to select.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="rows"/> or <paramref name="columns"/> are invalid.
/// </exception>
/// <returns>A new <see cref="ReadOnlySpan2D{T}"/> instance representing a slice of the current one.</returns>
public ReadOnlySpan2D<T> this[Range rows, Range columns]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
(int row, int height) = rows.GetOffsetAndLength(Height);
(int column, int width) = columns.GetOffsetAndLength(this.width);
(int row, int height) = rows.GetOffsetAndLength(Height);
(int column, int width) = columns.GetOffsetAndLength(this.width);
return Slice(row, column, height, width);
}
return Slice(row, column, height, width);
}
}
#endif
/// <summary>
@ -618,10 +617,10 @@ public readonly ref partial struct ReadOnlySpan2D<T>
// Copy each row individually
#if NETSTANDARD2_1_OR_GREATER
for (int i = 0, j = 0; i < Height; i++, j += this.width)
{
GetRowSpan(i).CopyTo(destination.Slice(j));
}
for (int i = 0, j = 0; i < Height; i++, j += this.width)
{
GetRowSpan(i).CopyTo(destination.Slice(j));
}
#else
int height = Height;
nint width = (nint)(uint)this.width;
@ -674,10 +673,10 @@ public readonly ref partial struct ReadOnlySpan2D<T>
{
// Copy each row individually
#if NETSTANDARD2_1_OR_GREATER
for (int i = 0; i < Height; i++)
{
GetRowSpan(i).CopyTo(destination.GetRowSpan(i));
}
for (int i = 0; i < Height; i++)
{
GetRowSpan(i).CopyTo(destination.GetRowSpan(i));
}
#else
int height = Height;
nint width = (nint)(uint)this.width;
@ -751,7 +750,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
if (Length != 0)
{
#if NETSTANDARD2_1_OR_GREATER
r0 = ref MemoryMarshal.GetReference(this.span);
r0 = ref MemoryMarshal.GetReference(this.span);
#else
r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
#endif
@ -769,7 +768,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
public ref T DangerousGetReference()
{
#if NETSTANDARD2_1_OR_GREATER
return ref MemoryMarshal.GetReference(this.span);
return ref MemoryMarshal.GetReference(this.span);
#else
return ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
#endif
@ -786,7 +785,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
public ref T DangerousGetReferenceAt(int i, int j)
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T r0 = ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
#endif
@ -834,9 +833,9 @@ public readonly ref partial struct ReadOnlySpan2D<T>
int pitch = this.stride - width;
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref this.span.DangerousGetReferenceAt(shift);
ref T r0 = ref this.span.DangerousGetReferenceAt(shift);
return new ReadOnlySpan2D<T>(in r0, height, width, pitch);
return new ReadOnlySpan2D<T>(in r0, height, width, pitch);
#else
IntPtr offset = this.offset + (shift * (nint)(uint)Unsafe.SizeOf<T>());
@ -845,24 +844,24 @@ public readonly ref partial struct ReadOnlySpan2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Gets a <see cref="ReadOnlySpan{T}"/> for a specified row.
/// </summary>
/// <param name="row">The index of the target row to retrieve.</param>
/// <exception cref="ArgumentOutOfRangeException">Throw when <paramref name="row"/> is out of range.</exception>
/// <returns>The resulting row <see cref="ReadOnlySpan{T}"/>.</returns>
[Pure]
public ReadOnlySpan<T> GetRowSpan(int row)
/// <summary>
/// Gets a <see cref="ReadOnlySpan{T}"/> for a specified row.
/// </summary>
/// <param name="row">The index of the target row to retrieve.</param>
/// <exception cref="ArgumentOutOfRangeException">Throw when <paramref name="row"/> is out of range.</exception>
/// <returns>The resulting row <see cref="ReadOnlySpan{T}"/>.</returns>
[Pure]
public ReadOnlySpan<T> GetRowSpan(int row)
{
if ((uint)row >= (uint)Height)
{
if ((uint)row >= (uint)Height)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForRow();
}
ref T r0 = ref DangerousGetReferenceAt(row, 0);
return MemoryMarshal.CreateReadOnlySpan(ref r0, this.width);
ThrowHelper.ThrowArgumentOutOfRangeExceptionForRow();
}
ref T r0 = ref DangerousGetReferenceAt(row, 0);
return MemoryMarshal.CreateReadOnlySpan(ref r0, this.width);
}
#endif
/// <summary>
@ -877,9 +876,9 @@ public readonly ref partial struct ReadOnlySpan2D<T>
Length <= int.MaxValue)
{
#if NETSTANDARD2_1_OR_GREATER
span = MemoryMarshal.CreateReadOnlySpan(ref MemoryMarshal.GetReference(this.span), (int)Length);
span = MemoryMarshal.CreateReadOnlySpan(ref MemoryMarshal.GetReference(this.span), (int)Length);
return true;
return true;
#else
// An empty Span2D<T> is still valid
if (IsEmpty)
@ -928,7 +927,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
T[,] array = new T[Height, this.width];
#if NETSTANDARD2_1_OR_GREATER
CopyTo(array.AsSpan());
CopyTo(array.AsSpan());
#else
// Skip the initialization if the array is empty
if (Length > 0)
@ -989,14 +988,15 @@ public readonly ref partial struct ReadOnlySpan2D<T>
{
return
#if NETSTANDARD2_1_OR_GREATER
left.span == right.span &&
left.span == right.span &&
#else
ReferenceEquals(left.instance, right.instance) &&
left.offset == right.offset &&
left.height == right.height &&
ReferenceEquals(
left.instance, right.instance) &&
left.offset == right.offset &&
left.height == right.height &&
#endif
left.width == right.width &&
left.stride == right.stride;
left.stride == right.stride;
}
/// <summary>
@ -1023,7 +1023,7 @@ public readonly ref partial struct ReadOnlySpan2D<T>
public static implicit operator ReadOnlySpan2D<T>(Span2D<T> span)
{
#if NETSTANDARD2_1_OR_GREATER
return new ReadOnlySpan2D<T>(in span.DangerousGetReference(), span.Height, span.Width, span.Stride - span.Width);
return new ReadOnlySpan2D<T>(in span.DangerousGetReference(), span.Height, span.Width, span.Stride - span.Width);
#else
return new ReadOnlySpan2D<T>(span.Instance!, span.Offset, span.Height, span.Width, span.Stride - span.Width);
#endif

Просмотреть файл

@ -38,7 +38,7 @@ public readonly ref partial struct Span2D<T>
ref T r1 = ref Unsafe.Add(ref r0, startIndex);
#if NETSTANDARD2_1_OR_GREATER
return new RefEnumerable<T>(ref r1, Width, 1);
return new RefEnumerable<T>(ref r1, Width, 1);
#else
IntPtr offset = RuntimeHelpers.GetObjectDataOrReferenceByteOffset(this.Instance, ref r1);
@ -65,7 +65,7 @@ public readonly ref partial struct Span2D<T>
ref T r1 = ref Unsafe.Add(ref r0, (nint)(uint)column);
#if NETSTANDARD2_1_OR_GREATER
return new RefEnumerable<T>(ref r1, Height, this.Stride);
return new RefEnumerable<T>(ref r1, Height, this.Stride);
#else
IntPtr offset = RuntimeHelpers.GetObjectDataOrReferenceByteOffset(this.Instance, ref r1);
@ -89,11 +89,11 @@ public readonly ref partial struct Span2D<T>
public ref struct Enumerator
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// The <see cref="Span{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>Just like in <see cref="Span2D{T}"/>, the length is the height of the 2D region.</remarks>
private readonly Span<T> span;
/// <summary>
/// The <see cref="Span{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>Just like in <see cref="Span2D{T}"/>, the length is the height of the 2D region.</remarks>
private readonly Span<T> span;
#else
/// <summary>
/// The target <see cref="object"/> instance, if present.
@ -138,7 +138,7 @@ public readonly ref partial struct Span2D<T>
internal Enumerator(Span2D<T> span)
{
#if NETSTANDARD2_1_OR_GREATER
this.span = span.span;
this.span = span.span;
#else
this.instance = span.Instance;
this.offset = span.Offset;
@ -172,7 +172,7 @@ public readonly ref partial struct Span2D<T>
this.x = 0;
#if NETSTANDARD2_1_OR_GREATER
return ++this.y < this.span.Length;
return ++this.y < this.span.Length;
#else
return ++this.y < this.height;
#endif
@ -187,7 +187,7 @@ public readonly ref partial struct Span2D<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T r0 = ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.instance, this.offset);
#endif

Просмотреть файл

@ -57,14 +57,14 @@ public readonly ref partial struct Span2D<T>
// can be used to internally represent a 2D span. This gives
// users much more flexibility when creating spans from data.
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// The <see cref="Span{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>
/// The <see cref="Span{T}.Length"/> field maps to the height of the 2D region.
/// This is done to save 4 bytes in the layout of the <see cref="Span2D{T}"/> type.
/// </remarks>
private readonly Span<T> span;
/// <summary>
/// The <see cref="Span{T}"/> instance pointing to the first item in the target memory area.
/// </summary>
/// <remarks>
/// The <see cref="Span{T}.Length"/> field maps to the height of the 2D region.
/// This is done to save 4 bytes in the layout of the <see cref="Span2D{T}"/> type.
/// </remarks>
private readonly Span<T> span;
#else
/// <summary>
/// The target <see cref="object"/> instance, if present.
@ -97,20 +97,20 @@ public readonly ref partial struct Span2D<T>
internal readonly int Stride;
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Span2D{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="height">The height of the 2D memory area to map.</param>
/// <param name="width">The width of the 2D memory area to map.</param>
/// <param name="pitch">The pitch of the 2D memory area to map (the distance between each row).</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Span2D(ref T value, int height, int width, int pitch)
{
this.span = MemoryMarshal.CreateSpan(ref value, height);
this.width = width;
this.Stride = width + pitch;
}
/// <summary>
/// Initializes a new instance of the <see cref="Span2D{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="height">The height of the 2D memory area to map.</param>
/// <param name="width">The width of the 2D memory area to map.</param>
/// <param name="pitch">The pitch of the 2D memory area to map (the distance between each row).</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Span2D(ref T value, int height, int width, int pitch)
{
this.span = MemoryMarshal.CreateSpan(ref value, height);
this.width = width;
this.Stride = width + pitch;
}
#endif
/// <summary>
@ -146,7 +146,7 @@ public readonly ref partial struct Span2D<T>
OverflowHelper.EnsureIsInNativeIntRange(height, width, pitch);
#if NETSTANDARD2_1_OR_GREATER
this.span = new Span<T>(pointer, height);
this.span = new Span<T>(pointer, height);
#else
this.Instance = null;
this.Offset = (IntPtr)pointer;
@ -247,7 +247,7 @@ public readonly ref partial struct Span2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(offset), height);
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(offset), height);
#else
this.Instance = array;
this.Offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(offset));
@ -279,7 +279,7 @@ public readonly ref partial struct Span2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReference(), array.GetLength(0));
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReference(), array.GetLength(0));
#else
this.Instance = array;
this.Offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(0, 0));
@ -346,7 +346,7 @@ public readonly ref partial struct Span2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(row, column), height);
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(row, column), height);
#else
this.Instance = array;
this.Offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(row, column));
@ -378,7 +378,7 @@ public readonly ref partial struct Span2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(depth, 0, 0), array.GetLength(1));
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(depth, 0, 0), array.GetLength(1));
#else
this.Instance = array;
this.Offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(depth, 0, 0));
@ -436,7 +436,7 @@ public readonly ref partial struct Span2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(depth, row, column), height);
this.span = MemoryMarshal.CreateSpan(ref array.DangerousGetReferenceAt(depth, row, column), height);
#else
this.Instance = array;
this.Offset = ObjectMarshal.DangerousGetObjectDataByteOffset(array, ref array.DangerousGetReferenceAt(depth, row, column));
@ -447,109 +447,108 @@ public readonly ref partial struct Span2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="Span2D{T}"/> struct.
/// </summary>
/// <param name="span">The target <see cref="Span{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="span"/>.</remarks>
internal Span2D(Span<T> span, int height, int width)
: this(span, 0, height, width, 0)
/// <summary>
/// Initializes a new instance of the <see cref="Span2D{T}"/> struct.
/// </summary>
/// <param name="span">The target <see cref="Span{T}"/> to wrap.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="height"/> or <paramref name="width"/> are invalid.
/// </exception>
/// <remarks>The total area must match the length of <paramref name="span"/>.</remarks>
internal Span2D(Span<T> span, int height, int width)
: this(span, 0, height, width, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Span2D{T}"/> struct.
/// </summary>
/// <param name="span">The target <see cref="Span{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="span"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
internal Span2D(Span<T> span, int offset, int height, int width, int pitch)
{
if ((uint)offset > (uint)span.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
/// <summary>
/// Initializes a new instance of the <see cref="Span2D{T}"/> struct.
/// </summary>
/// <param name="span">The target <see cref="Span{T}"/> to wrap.</param>
/// <param name="offset">The initial offset within <paramref name="span"/>.</param>
/// <param name="height">The height of the resulting 2D area.</param>
/// <param name="width">The width of each row in the resulting 2D area.</param>
/// <param name="pitch">The pitch in the resulting 2D area.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when one of the input parameters is out of range.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when the requested area is outside of bounds for <paramref name="span"/>.
/// </exception>
internal Span2D(Span<T> span, int offset, int height, int width, int pitch)
if (height < 0)
{
if ((uint)offset > (uint)span.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForOffset();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width == 0 || height == 0)
{
this = default;
return;
}
int
area = OverflowHelper.ComputeInt32Area(height, width, pitch),
remaining = span.Length - offset;
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
this.span = MemoryMarshal.CreateSpan(ref span.DangerousGetReferenceAt(offset), height);
this.width = width;
this.Stride = width + pitch;
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
/// <summary>
/// Creates a new instance of the <see cref="Span2D{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="height">The height of the 2D memory area to map.</param>
/// <param name="width">The width of the 2D memory area to map.</param>
/// <param name="pitch">The pitch of the 2D memory area to map (the distance between each row).</param>
/// <returns>A <see cref="Span2D{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static Span2D<T> DangerousCreate(ref T value, int height, int width, int pitch)
if (width < 0)
{
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
OverflowHelper.EnsureIsInNativeIntRange(height, width, pitch);
return new Span2D<T>(ref value, height, width, pitch);
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
if (width == 0 || height == 0)
{
this = default;
return;
}
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
int remaining = span.Length - offset;
if (area > remaining)
{
ThrowHelper.ThrowArgumentException();
}
this.span = MemoryMarshal.CreateSpan(ref span.DangerousGetReferenceAt(offset), height);
this.width = width;
this.Stride = width + pitch;
}
/// <summary>
/// Creates a new instance of the <see cref="Span2D{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="value">The reference to the first <typeparamref name="T"/> item to map.</param>
/// <param name="height">The height of the 2D memory area to map.</param>
/// <param name="width">The width of the 2D memory area to map.</param>
/// <param name="pitch">The pitch of the 2D memory area to map (the distance between each row).</param>
/// <returns>A <see cref="Span2D{T}"/> instance with the specified parameters.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when one of the parameters are negative.</exception>
[Pure]
public static Span2D<T> DangerousCreate(ref T value, int height, int width, int pitch)
{
if (width < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForWidth();
}
if (height < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForHeight();
}
if (pitch < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
}
OverflowHelper.EnsureIsInNativeIntRange(height, width, pitch);
return new Span2D<T>(ref value, height, width, pitch);
}
#endif
/// <summary>
@ -584,7 +583,7 @@ public readonly ref partial struct Span2D<T>
get
{
#if NETSTANDARD2_1_OR_GREATER
return this.span.Length;
return this.span.Length;
#else
return this.height;
#endif
@ -625,41 +624,41 @@ public readonly ref partial struct Span2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Gets the element at the specified zero-based indices.
/// </summary>
/// <param name="row">The target row to get the element from.</param>
/// <param name="column">The target column to get the element from.</param>
/// <returns>A reference to the element at the specified indices.</returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when either <paramref name="row"/> or <paramref name="column"/> are invalid.
/// </exception>
public ref T this[Index row, Index column]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref this[row.GetOffset(Height), column.GetOffset(this.width)];
}
/// <summary>
/// Gets the element at the specified zero-based indices.
/// </summary>
/// <param name="row">The target row to get the element from.</param>
/// <param name="column">The target column to get the element from.</param>
/// <returns>A reference to the element at the specified indices.</returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when either <paramref name="row"/> or <paramref name="column"/> are invalid.
/// </exception>
public ref T this[Index row, Index column]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref this[row.GetOffset(Height), column.GetOffset(this.width)];
}
/// <summary>
/// Slices the current instance with the specified parameters.
/// </summary>
/// <param name="rows">The target range of rows to select.</param>
/// <param name="columns">The target range of columns to select.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="rows"/> or <paramref name="columns"/> are invalid.
/// </exception>
/// <returns>A new <see cref="Span2D{T}"/> instance representing a slice of the current one.</returns>
public Span2D<T> this[Range rows, Range columns]
/// <summary>
/// Slices the current instance with the specified parameters.
/// </summary>
/// <param name="rows">The target range of rows to select.</param>
/// <param name="columns">The target range of columns to select.</param>
/// <exception cref="ArgumentException">
/// Thrown when either <paramref name="rows"/> or <paramref name="columns"/> are invalid.
/// </exception>
/// <returns>A new <see cref="Span2D{T}"/> instance representing a slice of the current one.</returns>
public Span2D<T> this[Range rows, Range columns]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
(int row, int height) = rows.GetOffsetAndLength(Height);
(int column, int width) = columns.GetOffsetAndLength(this.width);
(int row, int height) = rows.GetOffsetAndLength(Height);
(int column, int width) = columns.GetOffsetAndLength(this.width);
return Slice(row, column, height, width);
}
return Slice(row, column, height, width);
}
}
#endif
/// <summary>
@ -680,10 +679,10 @@ public readonly ref partial struct Span2D<T>
{
// Clear one row at a time
#if NETSTANDARD2_1_OR_GREATER
for (int i = 0; i < Height; i++)
{
GetRowSpan(i).Clear();
}
for (int i = 0; i < Height; i++)
{
GetRowSpan(i).Clear();
}
#else
int height = Height;
nint width = (nint)(uint)this.width;
@ -731,10 +730,10 @@ public readonly ref partial struct Span2D<T>
// Copy each row individually
#if NETSTANDARD2_1_OR_GREATER
for (int i = 0, j = 0; i < Height; i++, j += this.width)
{
GetRowSpan(i).CopyTo(destination.Slice(j));
}
for (int i = 0, j = 0; i < Height; i++, j += this.width)
{
GetRowSpan(i).CopyTo(destination.Slice(j));
}
#else
int height = Height;
nint width = (nint)(uint)this.width;
@ -787,10 +786,10 @@ public readonly ref partial struct Span2D<T>
{
// Copy each row individually
#if NETSTANDARD2_1_OR_GREATER
for (int i = 0; i < Height; i++)
{
GetRowSpan(i).CopyTo(destination.GetRowSpan(i));
}
for (int i = 0; i < Height; i++)
{
GetRowSpan(i).CopyTo(destination.GetRowSpan(i));
}
#else
int height = Height;
nint width = (nint)(uint)this.width;
@ -867,10 +866,10 @@ public readonly ref partial struct Span2D<T>
{
// Fill one row at a time
#if NETSTANDARD2_1_OR_GREATER
for (int i = 0; i < Height; i++)
{
GetRowSpan(i).Fill(value);
}
for (int i = 0; i < Height; i++)
{
GetRowSpan(i).Fill(value);
}
#else
int height = Height;
nint width = (nint)(uint)this.width;
@ -907,7 +906,7 @@ public readonly ref partial struct Span2D<T>
if (Length != 0)
{
#if NETSTANDARD2_1_OR_GREATER
r0 = ref MemoryMarshal.GetReference(this.span);
r0 = ref MemoryMarshal.GetReference(this.span);
#else
r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
#endif
@ -925,7 +924,7 @@ public readonly ref partial struct Span2D<T>
public ref T DangerousGetReference()
{
#if NETSTANDARD2_1_OR_GREATER
return ref MemoryMarshal.GetReference(this.span);
return ref MemoryMarshal.GetReference(this.span);
#else
return ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
#endif
@ -942,7 +941,7 @@ public readonly ref partial struct Span2D<T>
public ref T DangerousGetReferenceAt(int i, int j)
{
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref MemoryMarshal.GetReference(this.span);
ref T r0 = ref MemoryMarshal.GetReference(this.span);
#else
ref T r0 = ref RuntimeHelpers.GetObjectDataAtOffsetOrPointerReference<T>(this.Instance, this.Offset);
#endif
@ -990,9 +989,9 @@ public readonly ref partial struct Span2D<T>
int pitch = this.Stride - width;
#if NETSTANDARD2_1_OR_GREATER
ref T r0 = ref this.span.DangerousGetReferenceAt(shift);
ref T r0 = ref this.span.DangerousGetReferenceAt(shift);
return new Span2D<T>(ref r0, height, width, pitch);
return new Span2D<T>(ref r0, height, width, pitch);
#else
IntPtr offset = this.Offset + (shift * (nint)(uint)Unsafe.SizeOf<T>());
@ -1001,24 +1000,24 @@ public readonly ref partial struct Span2D<T>
}
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Gets a <see cref="Span{T}"/> for a specified row.
/// </summary>
/// <param name="row">The index of the target row to retrieve.</param>
/// <exception cref="ArgumentOutOfRangeException">Throw when <paramref name="row"/> is out of range.</exception>
/// <returns>The resulting row <see cref="Span{T}"/>.</returns>
[Pure]
public Span<T> GetRowSpan(int row)
/// <summary>
/// Gets a <see cref="Span{T}"/> for a specified row.
/// </summary>
/// <param name="row">The index of the target row to retrieve.</param>
/// <exception cref="ArgumentOutOfRangeException">Throw when <paramref name="row"/> is out of range.</exception>
/// <returns>The resulting row <see cref="Span{T}"/>.</returns>
[Pure]
public Span<T> GetRowSpan(int row)
{
if ((uint)row >= (uint)Height)
{
if ((uint)row >= (uint)Height)
{
ThrowHelper.ThrowArgumentOutOfRangeExceptionForRow();
}
ref T r0 = ref DangerousGetReferenceAt(row, 0);
return MemoryMarshal.CreateSpan(ref r0, this.width);
ThrowHelper.ThrowArgumentOutOfRangeExceptionForRow();
}
ref T r0 = ref DangerousGetReferenceAt(row, 0);
return MemoryMarshal.CreateSpan(ref r0, this.width);
}
#endif
/// <summary>
@ -1033,9 +1032,9 @@ public readonly ref partial struct Span2D<T>
Length <= int.MaxValue)
{
#if NETSTANDARD2_1_OR_GREATER
span = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(this.span), (int)Length);
span = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(this.span), (int)Length);
return true;
return true;
#else
// An empty Span2D<T> is still valid
if (IsEmpty)
@ -1084,7 +1083,7 @@ public readonly ref partial struct Span2D<T>
T[,] array = new T[Height, this.width];
#if NETSTANDARD2_1_OR_GREATER
CopyTo(array.AsSpan());
CopyTo(array.AsSpan());
#else
// Skip the initialization if the array is empty
if (Length > 0)
@ -1145,14 +1144,15 @@ public readonly ref partial struct Span2D<T>
{
return
#if NETSTANDARD2_1_OR_GREATER
left.span == right.span &&
left.span == right.span &&
#else
ReferenceEquals(left.Instance, right.Instance) &&
left.Offset == right.Offset &&
left.height == right.height &&
ReferenceEquals(
left.Instance, right.Instance) &&
left.Offset == right.Offset &&
left.height == right.height &&
#endif
left.width == right.width &&
left.Stride == right.Stride;
left.Stride == right.Stride;
}
/// <summary>

Просмотреть файл

@ -8,131 +8,130 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace CommunityToolkit.HighPerformance
namespace CommunityToolkit.HighPerformance;
/// <summary>
/// A <see langword="struct"/> that can store an optional readonly reference to a value of a specified type.
/// </summary>
/// <typeparam name="T">The type of value to reference.</typeparam>
public readonly ref struct NullableReadOnlyRef<T>
{
/// <summary>
/// A <see langword="struct"/> that can store an optional readonly reference to a value of a specified type.
/// The 1-length <see cref="ReadOnlySpan{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
/// <typeparam name="T">The type of value to reference.</typeparam>
public readonly ref struct NullableReadOnlyRef<T>
private readonly ReadOnlySpan<T> span;
/// <summary>
/// Initializes a new instance of the <see cref="NullableReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="value">The readonly reference to the target <typeparamref name="T"/> value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NullableReadOnlyRef(in T value)
{
/// <summary>
/// The 1-length <see cref="ReadOnlySpan{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
private readonly ReadOnlySpan<T> span;
ref T r0 = ref Unsafe.AsRef(value);
/// <summary>
/// Initializes a new instance of the <see cref="NullableReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="value">The readonly reference to the target <typeparamref name="T"/> value.</param>
this.span = MemoryMarshal.CreateReadOnlySpan(ref r0, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="NullableReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="span">The <see cref="ReadOnlySpan{T}"/> instance to track the target <typeparamref name="T"/> reference.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private NullableReadOnlyRef(ReadOnlySpan<T> span)
{
this.span = span;
}
/// <summary>
/// Gets a <see cref="NullableReadOnlyRef{T}"/> instance representing a <see langword="null"/> reference.
/// </summary>
public static NullableReadOnlyRef<T> Null
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NullableReadOnlyRef(in T value)
{
ref T r0 = ref Unsafe.AsRef(value);
get => default;
}
this.span = MemoryMarshal.CreateReadOnlySpan(ref r0, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="NullableReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="span">The <see cref="ReadOnlySpan{T}"/> instance to track the target <typeparamref name="T"/> reference.</param>
/// <summary>
/// Gets a value indicating whether or not the current <see cref="NullableReadOnlyRef{T}"/> instance wraps a valid reference that can be accessed.
/// </summary>
public unsafe bool HasValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private NullableReadOnlyRef(ReadOnlySpan<T> span)
get
{
this.span = span;
}
// See comment in NullableRef<T> about this
byte length = unchecked((byte)this.span.Length);
/// <summary>
/// Gets a <see cref="NullableReadOnlyRef{T}"/> instance representing a <see langword="null"/> reference.
/// </summary>
public static NullableReadOnlyRef<T> Null
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => default;
return *(bool*)&length;
}
}
/// <summary>
/// Gets a value indicating whether or not the current <see cref="NullableReadOnlyRef{T}"/> instance wraps a valid reference that can be accessed.
/// </summary>
public unsafe bool HasValue
/// <summary>
/// Gets the <typeparamref name="T"/> reference represented by the current <see cref="NullableReadOnlyRef{T}"/> instance.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if <see cref="HasValue"/> is <see langword="false"/>.</exception>
public ref readonly T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
if (!HasValue)
{
// See comment in NullableRef<T> about this
byte length = unchecked((byte)this.span.Length);
return *(bool*)&length;
ThrowInvalidOperationException();
}
}
/// <summary>
/// Gets the <typeparamref name="T"/> reference represented by the current <see cref="NullableReadOnlyRef{T}"/> instance.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if <see cref="HasValue"/> is <see langword="false"/>.</exception>
public ref readonly T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (!HasValue)
{
ThrowInvalidOperationException();
}
return ref MemoryMarshal.GetReference(this.span);
}
return ref MemoryMarshal.GetReference(this.span);
}
}
/// <summary>
/// Implicitly converts a <see cref="Ref{T}"/> instance into a <see cref="NullableReadOnlyRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableReadOnlyRef<T>(Ref<T> reference)
{
return new(reference.Span);
}
/// <summary>
/// Implicitly converts a <see cref="Ref{T}"/> instance into a <see cref="NullableReadOnlyRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableReadOnlyRef<T>(Ref<T> reference)
{
return new(reference.Span);
}
/// <summary>
/// Implicitly converts a <see cref="ReadOnlyRef{T}"/> instance into a <see cref="NullableReadOnlyRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="ReadOnlyRef{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableReadOnlyRef<T>(ReadOnlyRef<T> reference)
{
return new(reference.Span);
}
/// <summary>
/// Implicitly converts a <see cref="ReadOnlyRef{T}"/> instance into a <see cref="NullableReadOnlyRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="ReadOnlyRef{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableReadOnlyRef<T>(ReadOnlyRef<T> reference)
{
return new(reference.Span);
}
/// <summary>
/// Implicitly converts a <see cref="NullableRef{T}"/> instance into a <see cref="NullableReadOnlyRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableReadOnlyRef<T>(NullableRef<T> reference)
{
return new(reference.Span);
}
/// <summary>
/// Implicitly converts a <see cref="NullableRef{T}"/> instance into a <see cref="NullableReadOnlyRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableReadOnlyRef<T>(NullableRef<T> reference)
{
return new(reference.Span);
}
/// <summary>
/// Explicitly gets the <typeparamref name="T"/> value from a given <see cref="NullableReadOnlyRef{T}"/> instance.
/// </summary>
/// <param name="reference">The input <see cref="NullableReadOnlyRef{T}"/> instance.</param>
/// <exception cref="InvalidOperationException">Thrown if <see cref="HasValue"/> is <see langword="false"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator T(NullableReadOnlyRef<T> reference)
{
return reference.Value;
}
/// <summary>
/// Explicitly gets the <typeparamref name="T"/> value from a given <see cref="NullableReadOnlyRef{T}"/> instance.
/// </summary>
/// <param name="reference">The input <see cref="NullableReadOnlyRef{T}"/> instance.</param>
/// <exception cref="InvalidOperationException">Thrown if <see cref="HasValue"/> is <see langword="false"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator T(NullableReadOnlyRef<T> reference)
{
return reference.Value;
}
/// <summary>
/// Throws a <see cref="InvalidOperationException"/> when trying to access <see cref="Value"/> for a default instance.
/// </summary>
private static void ThrowInvalidOperationException()
{
throw new InvalidOperationException("The current instance doesn't have a value that can be accessed");
}
/// <summary>
/// Throws a <see cref="InvalidOperationException"/> when trying to access <see cref="Value"/> for a default instance.
/// </summary>
private static void ThrowInvalidOperationException()
{
throw new InvalidOperationException("The current instance doesn't have a value that can be accessed");
}
}

Просмотреть файл

@ -8,115 +8,114 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace CommunityToolkit.HighPerformance
namespace CommunityToolkit.HighPerformance;
/// <summary>
/// A <see langword="struct"/> that can store an optional reference to a value of a specified type.
/// </summary>
/// <typeparam name="T">The type of value to reference.</typeparam>
public readonly ref struct NullableRef<T>
{
/// <summary>
/// A <see langword="struct"/> that can store an optional reference to a value of a specified type.
/// The 1-length <see cref="Span{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
/// <typeparam name="T">The type of value to reference.</typeparam>
public readonly ref struct NullableRef<T>
internal readonly Span<T> Span;
/// <summary>
/// Initializes a new instance of the <see cref="NullableRef{T}"/> struct.
/// </summary>
/// <param name="value">The reference to the target <typeparamref name="T"/> value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NullableRef(ref T value)
{
/// <summary>
/// The 1-length <see cref="Span{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
internal readonly Span<T> Span;
Span = MemoryMarshal.CreateSpan(ref value, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="NullableRef{T}"/> struct.
/// </summary>
/// <param name="value">The reference to the target <typeparamref name="T"/> value.</param>
/// <summary>
/// Initializes a new instance of the <see cref="NullableRef{T}"/> struct.
/// </summary>
/// <param name="span">The <see cref="Span{T}"/> instance to track the target <typeparamref name="T"/> reference.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private NullableRef(Span<T> span)
{
Span = span;
}
/// <summary>
/// Gets a <see cref="NullableRef{T}"/> instance representing a <see langword="null"/> reference.
/// </summary>
public static NullableRef<T> Null
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public NullableRef(ref T value)
{
Span = MemoryMarshal.CreateSpan(ref value, 1);
}
get => default;
}
/// <summary>
/// Initializes a new instance of the <see cref="NullableRef{T}"/> struct.
/// </summary>
/// <param name="span">The <see cref="Span{T}"/> instance to track the target <typeparamref name="T"/> reference.</param>
/// <summary>
/// Gets a value indicating whether or not the current <see cref="NullableRef{T}"/> instance wraps a valid reference that can be accessed.
/// </summary>
public unsafe bool HasValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private NullableRef(Span<T> span)
get
{
Span = span;
}
// We know that the span will always have a length of either
// 1 or 0, so instead of using a cmp instruction and setting the
// zero flag to produce our boolean value, we can just cast
// the length to byte without overflow checks (doing a cast will
// also account for the byte endianness of the current system),
// and then reinterpret that value to a bool flag.
// This results in a single movzx instruction on x86-64.
byte length = unchecked((byte)Span.Length);
/// <summary>
/// Gets a <see cref="NullableRef{T}"/> instance representing a <see langword="null"/> reference.
/// </summary>
public static NullableRef<T> Null
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => default;
return *(bool*)&length;
}
}
/// <summary>
/// Gets a value indicating whether or not the current <see cref="NullableRef{T}"/> instance wraps a valid reference that can be accessed.
/// </summary>
public unsafe bool HasValue
/// <summary>
/// Gets the <typeparamref name="T"/> reference represented by the current <see cref="NullableRef{T}"/> instance.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if <see cref="HasValue"/> is <see langword="false"/>.</exception>
public ref T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
if (!HasValue)
{
// We know that the span will always have a length of either
// 1 or 0, so instead of using a cmp instruction and setting the
// zero flag to produce our boolean value, we can just cast
// the length to byte without overflow checks (doing a cast will
// also account for the byte endianness of the current system),
// and then reinterpret that value to a bool flag.
// This results in a single movzx instruction on x86-64.
byte length = unchecked((byte)Span.Length);
return *(bool*)&length;
ThrowInvalidOperationException();
}
}
/// <summary>
/// Gets the <typeparamref name="T"/> reference represented by the current <see cref="NullableRef{T}"/> instance.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if <see cref="HasValue"/> is <see langword="false"/>.</exception>
public ref T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (!HasValue)
{
ThrowInvalidOperationException();
}
return ref MemoryMarshal.GetReference(Span);
}
return ref MemoryMarshal.GetReference(Span);
}
}
/// <summary>
/// Implicitly converts a <see cref="Ref{T}"/> instance into a <see cref="NullableRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableRef<T>(Ref<T> reference)
{
return new(reference.Span);
}
/// <summary>
/// Implicitly converts a <see cref="Ref{T}"/> instance into a <see cref="NullableRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NullableRef<T>(Ref<T> reference)
{
return new(reference.Span);
}
/// <summary>
/// Explicitly gets the <typeparamref name="T"/> value from a given <see cref="NullableRef{T}"/> instance.
/// </summary>
/// <param name="reference">The input <see cref="NullableRef{T}"/> instance.</param>
/// <exception cref="InvalidOperationException">Thrown if <see cref="HasValue"/> is <see langword="false"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator T(NullableRef<T> reference)
{
return reference.Value;
}
/// <summary>
/// Explicitly gets the <typeparamref name="T"/> value from a given <see cref="NullableRef{T}"/> instance.
/// </summary>
/// <param name="reference">The input <see cref="NullableRef{T}"/> instance.</param>
/// <exception cref="InvalidOperationException">Thrown if <see cref="HasValue"/> is <see langword="false"/>.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator T(NullableRef<T> reference)
{
return reference.Value;
}
/// <summary>
/// Throws a <see cref="InvalidOperationException"/> when trying to access <see cref="Value"/> for a default instance.
/// </summary>
private static void ThrowInvalidOperationException()
{
throw new InvalidOperationException("The current instance doesn't have a value that can be accessed");
}
/// <summary>
/// Throws a <see cref="InvalidOperationException"/> when trying to access <see cref="Value"/> for a default instance.
/// </summary>
private static void ThrowInvalidOperationException()
{
throw new InvalidOperationException("The current instance doesn't have a value that can be accessed");
}
}

Просмотреть файл

@ -19,51 +19,51 @@ namespace CommunityToolkit.HighPerformance;
public readonly ref struct ReadOnlyRef<T>
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// The 1-length <see cref="ReadOnlySpan{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
internal readonly ReadOnlySpan<T> Span;
/// <summary>
/// The 1-length <see cref="ReadOnlySpan{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
internal readonly ReadOnlySpan<T> Span;
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="value">The readonly reference to the target <typeparamref name="T"/> value.</param>
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="value">The readonly reference to the target <typeparamref name="T"/> value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlyRef(in T value)
{
ref T r0 = ref Unsafe.AsRef(value);
Span = MemoryMarshal.CreateReadOnlySpan(ref r0, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="pointer">The pointer to the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe ReadOnlyRef(void* pointer)
: this(in Unsafe.AsRef<T>(pointer))
{
}
/// <summary>
/// Gets the readonly <typeparamref name="T"/> reference represented by the current <see cref="Ref{T}"/> instance.
/// </summary>
public ref readonly T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlyRef(in T value)
{
ref T r0 = ref Unsafe.AsRef(value);
get => ref MemoryMarshal.GetReference(Span);
}
Span = MemoryMarshal.CreateReadOnlySpan(ref r0, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyRef{T}"/> struct.
/// </summary>
/// <param name="pointer">The pointer to the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe ReadOnlyRef(void* pointer)
: this(in Unsafe.AsRef<T>(pointer))
{
}
/// <summary>
/// Gets the readonly <typeparamref name="T"/> reference represented by the current <see cref="Ref{T}"/> instance.
/// </summary>
public ref readonly T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref MemoryMarshal.GetReference(Span);
}
/// <summary>
/// Implicitly converts a <see cref="Ref{T}"/> instance into a <see cref="ReadOnlyRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlyRef<T>(Ref<T> reference)
{
return new(in reference.Value);
}
/// <summary>
/// Implicitly converts a <see cref="Ref{T}"/> instance into a <see cref="ReadOnlyRef{T}"/> one.
/// </summary>
/// <param name="reference">The input <see cref="Ref{T}"/> instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlyRef<T>(Ref<T> reference)
{
return new(in reference.Value);
}
#else
/// <summary>
/// The owner <see cref="object"/> the current instance belongs to

Просмотреть файл

@ -19,39 +19,39 @@ namespace CommunityToolkit.HighPerformance;
public readonly ref struct Ref<T>
{
#if NETSTANDARD2_1_OR_GREATER
/// <summary>
/// The 1-length <see cref="Span{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
internal readonly Span<T> Span;
/// <summary>
/// The 1-length <see cref="Span{T}"/> instance used to track the target <typeparamref name="T"/> value.
/// </summary>
internal readonly Span<T> Span;
/// <summary>
/// Initializes a new instance of the <see cref="Ref{T}"/> struct.
/// </summary>
/// <param name="value">The reference to the target <typeparamref name="T"/> value.</param>
/// <summary>
/// Initializes a new instance of the <see cref="Ref{T}"/> struct.
/// </summary>
/// <param name="value">The reference to the target <typeparamref name="T"/> value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Ref(ref T value)
{
Span = MemoryMarshal.CreateSpan(ref value, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="Ref{T}"/> struct.
/// </summary>
/// <param name="pointer">The pointer to the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe Ref(void* pointer)
: this(ref Unsafe.AsRef<T>(pointer))
{
}
/// <summary>
/// Gets the <typeparamref name="T"/> reference represented by the current <see cref="Ref{T}"/> instance.
/// </summary>
public ref T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Ref(ref T value)
{
Span = MemoryMarshal.CreateSpan(ref value, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="Ref{T}"/> struct.
/// </summary>
/// <param name="pointer">The pointer to the target value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe Ref(void* pointer)
: this(ref Unsafe.AsRef<T>(pointer))
{
}
/// <summary>
/// Gets the <typeparamref name="T"/> reference represented by the current <see cref="Ref{T}"/> instance.
/// </summary>
public ref T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref MemoryMarshal.GetReference(Span);
}
get => ref MemoryMarshal.GetReference(Span);
}
#else
/// <summary>
/// The owner <see cref="object"/> the current instance belongs to

Просмотреть файл

@ -9,67 +9,66 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace CommunityToolkit.HighPerformance.Streams
namespace CommunityToolkit.HighPerformance.Streams;
/// <inheritdoc cref="IBufferWriterStream{TWriter}"/>
internal sealed partial class IBufferWriterStream<TWriter>
{
/// <inheritdoc cref="IBufferWriterStream{TWriter}"/>
internal sealed partial class IBufferWriterStream<TWriter>
/// <inheritdoc/>
public override void CopyTo(Stream destination, int bufferSize)
{
/// <inheritdoc/>
public override void CopyTo(Stream destination, int bufferSize)
throw MemoryStream.GetNotSupportedException();
}
/// <inheritdoc/>
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
throw MemoryStream.GetNotSupportedException();
}
/// <inheritdoc/>
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
throw MemoryStream.GetNotSupportedException();
return new ValueTask(Task.FromCanceled(cancellationToken));
}
/// <inheritdoc/>
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
try
{
throw MemoryStream.GetNotSupportedException();
Write(buffer.Span);
return default;
}
catch (OperationCanceledException e)
{
return new ValueTask(Task.FromCanceled(e.CancellationToken));
}
catch (Exception e)
{
return new ValueTask(Task.FromException(e));
}
}
/// <inheritdoc/>
public override int Read(Span<byte> buffer)
{
throw MemoryStream.GetNotSupportedException();
}
/// <inheritdoc/>
public override void Write(ReadOnlySpan<byte> buffer)
{
MemoryStream.ValidateDisposed(this.disposed);
Span<byte> destination = this.bufferWriter.GetSpan(buffer.Length);
if (!buffer.TryCopyTo(destination))
{
MemoryStream.ThrowArgumentExceptionForEndOfStreamOnWrite();
}
/// <inheritdoc/>
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask(Task.FromCanceled(cancellationToken));
}
try
{
Write(buffer.Span);
return default;
}
catch (OperationCanceledException e)
{
return new ValueTask(Task.FromCanceled(e.CancellationToken));
}
catch (Exception e)
{
return new ValueTask(Task.FromException(e));
}
}
/// <inheritdoc/>
public override int Read(Span<byte> buffer)
{
throw MemoryStream.GetNotSupportedException();
}
/// <inheritdoc/>
public override void Write(ReadOnlySpan<byte> buffer)
{
MemoryStream.ValidateDisposed(this.disposed);
Span<byte> destination = this.bufferWriter.GetSpan(buffer.Length);
if (!buffer.TryCopyTo(destination))
{
MemoryStream.ThrowArgumentExceptionForEndOfStreamOnWrite();
}
this.bufferWriter.Advance(buffer.Length);
}
this.bufferWriter.Advance(buffer.Length);
}
}

Просмотреть файл

@ -9,104 +9,103 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace CommunityToolkit.HighPerformance.Streams
namespace CommunityToolkit.HighPerformance.Streams;
/// <inheritdoc cref="MemoryStream{TSource}"/>
internal partial class MemoryStream<TSource>
{
/// <inheritdoc cref="MemoryStream{TSource}"/>
internal partial class MemoryStream<TSource>
/// <inheritdoc/>
public sealed override void CopyTo(Stream destination, int bufferSize)
{
/// <inheritdoc/>
public sealed override void CopyTo(Stream destination, int bufferSize)
MemoryStream.ValidateDisposed(this.disposed);
Span<byte> source = this.source.Span.Slice(this.position);
this.position += source.Length;
destination.Write(source);
}
/// <inheritdoc/>
public sealed override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
MemoryStream.ValidateDisposed(this.disposed);
Span<byte> source = this.source.Span.Slice(this.position);
this.position += source.Length;
destination.Write(source);
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
}
/// <inheritdoc/>
public sealed override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
try
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
}
int result = Read(buffer.Span);
try
{
int result = Read(buffer.Span);
return new ValueTask<int>(result);
}
catch (OperationCanceledException e)
{
return new ValueTask<int>(Task.FromCanceled<int>(e.CancellationToken));
}
catch (Exception e)
{
return new ValueTask<int>(Task.FromException<int>(e));
}
}
return new ValueTask<int>(result);
}
catch (OperationCanceledException e)
{
return new ValueTask<int>(Task.FromCanceled<int>(e.CancellationToken));
}
catch (Exception e)
{
return new ValueTask<int>(Task.FromException<int>(e));
}
/// <inheritdoc/>
public sealed override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask(Task.FromCanceled(cancellationToken));
}
/// <inheritdoc/>
public sealed override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
try
{
if (cancellationToken.IsCancellationRequested)
{
return new ValueTask(Task.FromCanceled(cancellationToken));
}
Write(buffer.Span);
try
{
Write(buffer.Span);
return default;
}
catch (OperationCanceledException e)
{
return new ValueTask(Task.FromCanceled(e.CancellationToken));
}
catch (Exception e)
{
return new ValueTask(Task.FromException(e));
}
}
return default;
}
catch (OperationCanceledException e)
{
return new ValueTask(Task.FromCanceled(e.CancellationToken));
}
catch (Exception e)
{
return new ValueTask(Task.FromException(e));
}
/// <inheritdoc/>
public sealed override int Read(Span<byte> buffer)
{
MemoryStream.ValidateDisposed(this.disposed);
int
bytesAvailable = this.source.Length - this.position,
bytesCopied = Math.Min(bytesAvailable, buffer.Length);
Span<byte> source = this.source.Span.Slice(this.position, bytesCopied);
source.CopyTo(buffer);
this.position += bytesCopied;
return bytesCopied;
}
/// <inheritdoc/>
public sealed override void Write(ReadOnlySpan<byte> buffer)
{
MemoryStream.ValidateDisposed(this.disposed);
MemoryStream.ValidateCanWrite(CanWrite);
Span<byte> destination = this.source.Span.Slice(this.position);
if (!buffer.TryCopyTo(destination))
{
MemoryStream.ThrowArgumentExceptionForEndOfStreamOnWrite();
}
/// <inheritdoc/>
public sealed override int Read(Span<byte> buffer)
{
MemoryStream.ValidateDisposed(this.disposed);
int
bytesAvailable = this.source.Length - this.position,
bytesCopied = Math.Min(bytesAvailable, buffer.Length);
Span<byte> source = this.source.Span.Slice(this.position, bytesCopied);
source.CopyTo(buffer);
this.position += bytesCopied;
return bytesCopied;
}
/// <inheritdoc/>
public sealed override void Write(ReadOnlySpan<byte> buffer)
{
MemoryStream.ValidateDisposed(this.disposed);
MemoryStream.ValidateCanWrite(CanWrite);
Span<byte> destination = this.source.Span.Slice(this.position);
if (!buffer.TryCopyTo(destination))
{
MemoryStream.ThrowArgumentExceptionForEndOfStreamOnWrite();
}
this.position += buffer.Length;
}
this.position += buffer.Length;
}
}

Просмотреть файл

@ -66,9 +66,9 @@ internal readonly struct ArrayOwner : ISpanOwner
get
{
#if NETSTANDARD2_1_OR_GREATER
ref byte r0 = ref this.array.DangerousGetReferenceAt(this.offset);
ref byte r0 = ref this.array.DangerousGetReferenceAt(this.offset);
return MemoryMarshal.CreateSpan(ref r0, this.length);
return MemoryMarshal.CreateSpan(ref r0, this.length);
#else
return this.array.AsSpan(this.offset, this.length);
#endif

Просмотреть файл

@ -142,7 +142,7 @@ public class Test_ArrayPoolBufferWriterOfT
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void Test_ArrayPoolBufferWriterOfT_InvalidRequestedSize()
{
ArrayPoolBufferWriter<byte>? writer = new(-1);
_ = new ArrayPoolBufferWriter<byte>(-1);
Assert.Fail("You shouldn't be here");
}

Просмотреть файл

@ -8,34 +8,33 @@ using System.Numerics;
using CommunityToolkit.HighPerformance.Extensions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace CommunityToolkit.HighPerformance.UnitTests.Extensions
namespace CommunityToolkit.HighPerformance.UnitTests.Extensions;
[TestClass]
public class Test_NullableExtensions
{
[TestClass]
public class Test_NullableExtensions
[TestCategory("NullableExtensions")]
[TestMethod]
public void Test_NullableExtensions_DangerousGetReference()
{
[TestCategory("NullableExtensions")]
[TestMethod]
public void Test_NullableExtensions_DangerousGetReference()
static void Test<T>(T before, T after)
where T : struct
{
static void Test<T>(T before, T after)
where T : struct
{
T? nullable = before;
ref T reference = ref nullable.DangerousGetValueOrDefaultReference();
T? nullable = before;
ref T reference = ref nullable.DangerousGetValueOrDefaultReference();
Assert.AreEqual(nullable!.Value, before);
Assert.AreEqual(nullable!.Value, before);
reference = after;
reference = after;
Assert.AreEqual(nullable.Value, after);
}
Test(0, 42);
Test(1.3f, 3.14f);
Test(0.555, 8.49);
Test(Vector4.Zero, new Vector4(1, 5.55f, 2, 3.14f));
Test(Matrix4x4.Identity, Matrix4x4.CreateOrthographic(35, 88.34f, 9.99f, 24.6f));
Assert.AreEqual(nullable.Value, after);
}
Test(0, 42);
Test(1.3f, 3.14f);
Test(0.555, 8.49);
Test(Vector4.Zero, new Vector4(1, 5.55f, 2, 3.14f));
Test(Matrix4x4.Identity, Matrix4x4.CreateOrthographic(35, 88.34f, 9.99f, 24.6f));
}
}

Просмотреть файл

@ -211,7 +211,7 @@ public partial class Test_ReadOnlySpanExtensions
{
ReadOnlySpan<int> data = Array.Empty<int>();
foreach (HighPerformance.Enumerables.ReadOnlySpanEnumerable<int>.Item item in data.Enumerate())
foreach (HighPerformance.Enumerables.ReadOnlySpanEnumerable<int>.Item _ in data.Enumerate())
{
Assert.Fail("Empty source sequence");
}

Просмотреть файл

@ -163,7 +163,7 @@ public class Test_SpanExtensions
{
Span<int> data = Array.Empty<int>();
foreach (HighPerformance.Enumerables.SpanEnumerable<int>.Item item in data.Enumerate())
foreach (HighPerformance.Enumerables.SpanEnumerable<int>.Item _ in data.Enumerate())
{
Assert.Fail("Empty source sequence");
}

Просмотреть файл

@ -47,11 +47,11 @@ public class Test_SpinLockExtensions
for (int j = 0; j < 10; j++)
{
#if WINDOWS_UWP
using (SpinLockExtensions.Enter(spinLockOwner, ref spinLockOwner.Lock))
using (SpinLockExtensions.Enter(spinLockOwner, ref spinLockOwner.Lock))
#else
using (spinLockOwner.Lock.Enter())
using (spinLockOwner.Lock.Enter())
#endif
{
{
sum++;
}
}

Просмотреть файл

@ -339,8 +339,8 @@ public class Test_Memory2DT
bool success = memory2d.TryGetMemory(out Memory<int> memory);
#if WINDOWS_UWP
Assert.IsFalse(success);
Assert.IsTrue(memory.IsEmpty);
Assert.IsFalse(success);
Assert.IsTrue(memory.IsEmpty);
#else
Assert.IsTrue(success);
Assert.AreEqual(memory.Length, array.Length);

Просмотреть файл

@ -305,8 +305,8 @@ public class Test_ReadOnlyMemory2DT
bool success = memory2d.TryGetMemory(out ReadOnlyMemory<int> memory);
#if WINDOWS_UWP
Assert.IsFalse(success);
Assert.IsTrue(memory.IsEmpty);
Assert.IsFalse(success);
Assert.IsTrue(memory.IsEmpty);
#else
Assert.IsTrue(success);
Assert.AreEqual(memory.Length, array.Length);

Просмотреть файл

@ -645,9 +645,9 @@ public class Test_ReadOnlySpan2DT
bool success = span2d.TryGetSpan(out ReadOnlySpan<int> span);
#if WINDOWS_UWP
// Can't get a ReadOnlySpan<T> over a T[,] array on UWP
Assert.IsFalse(success);
Assert.AreEqual(span.Length, 0);
// Can't get a ReadOnlySpan<T> over a T[,] array on UWP
Assert.IsFalse(success);
Assert.AreEqual(span.Length, 0);
#else
Assert.IsTrue(success);
Assert.AreEqual(span.Length, span2d.Length);

Просмотреть файл

@ -840,9 +840,9 @@ public class Test_Span2DT
bool success = span2d.TryGetSpan(out Span<int> span);
#if WINDOWS_UWP
// Can't get a Span<T> over a T[,] array on UWP
Assert.IsFalse(success);
Assert.AreEqual(span.Length, 0);
// Can't get a Span<T> over a T[,] array on UWP
Assert.IsFalse(success);
Assert.AreEqual(span.Length, 0);
#else
Assert.IsTrue(success);
Assert.AreEqual(span.Length, span2d.Length);

Просмотреть файл

@ -13,22 +13,22 @@ public class Test_ReadOnlyRefOfT
[TestCategory("ReadOnlyRefOfT")]
[TestMethod]
#if WINDOWS_UWP
public void Test_RefOfT_CreateRefOfT()
{
var model = new ReadOnlyFieldOwner();
var reference = new ReadOnlyRef<int>(model, model.Value);
public void Test_RefOfT_CreateRefOfT()
{
var model = new ReadOnlyFieldOwner();
var reference = new ReadOnlyRef<int>(model, model.Value);
Assert.IsTrue(Unsafe.AreSame(ref Unsafe.AsRef(model.Value), ref Unsafe.AsRef(reference.Value)));
}
Assert.IsTrue(Unsafe.AreSame(ref Unsafe.AsRef(model.Value), ref Unsafe.AsRef(reference.Value)));
}
/// <summary>
/// A dummy model that owns an <see cref="int"/> field.
/// </summary>
private sealed class ReadOnlyFieldOwner
{
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401", Justification = "Ref readonly access for tests")]
public readonly int Value = 1;
}
/// <summary>
/// A dummy model that owns an <see cref="int"/> field.
/// </summary>
private sealed class ReadOnlyFieldOwner
{
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401", Justification = "Ref readonly access for tests")]
public readonly int Value = 1;
}
#else
public void Test_RefOfT_CreateRefOfT()
{

Просмотреть файл

@ -13,26 +13,26 @@ public class Test_RefOfT
[TestCategory("RefOfT")]
[TestMethod]
#if WINDOWS_UWP
public void Test_RefOfT_CreateRefOfT()
{
var model = new FieldOwner { Value = 1 };
var reference = new Ref<int>(model, ref model.Value);
public void Test_RefOfT_CreateRefOfT()
{
var model = new FieldOwner { Value = 1 };
var reference = new Ref<int>(model, ref model.Value);
Assert.IsTrue(Unsafe.AreSame(ref model.Value, ref reference.Value));
Assert.IsTrue(Unsafe.AreSame(ref model.Value, ref reference.Value));
reference.Value++;
reference.Value++;
Assert.AreEqual(model.Value, 2);
}
Assert.AreEqual(model.Value, 2);
}
/// <summary>
/// A dummy model that owns an <see cref="int"/> field.
/// </summary>
private sealed class FieldOwner
{
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401", Justification = "Quick ref access for tests")]
public int Value;
}
/// <summary>
/// A dummy model that owns an <see cref="int"/> field.
/// </summary>
private sealed class FieldOwner
{
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401", Justification = "Quick ref access for tests")]
public int Value;
}
#else
public void Test_RefOfT_CreateRefOfT()
{

Просмотреть файл

@ -52,7 +52,7 @@ public partial class Test_Messenger
{
IMessenger? messenger = (IMessenger)Activator.CreateInstance(type)!;
int result = messenger.Send<NumberRequestMessage>();
_ = messenger.Send<NumberRequestMessage>();
}
[TestCategory("Mvvm")]
@ -65,7 +65,7 @@ public partial class Test_Messenger
IMessenger? messenger = (IMessenger)Activator.CreateInstance(type)!;
object? recipient = new();
void Receive(object recipient, NumberRequestMessage m)
static void Receive(object recipient, NumberRequestMessage m)
{
m.Reply(42);
m.Reply(42);
@ -91,7 +91,7 @@ public partial class Test_Messenger
IMessenger? messenger = (IMessenger)Activator.CreateInstance(type)!;
object? recipient = new();
void Receive(object recipient, AsyncNumberRequestMessage m)
static void Receive(object recipient, AsyncNumberRequestMessage m)
{
Assert.IsFalse(m.HasReceivedResponse);
@ -152,7 +152,7 @@ public partial class Test_Messenger
{
IMessenger? messenger = (IMessenger)Activator.CreateInstance(type)!;
int result = await messenger.Send<AsyncNumberRequestMessage>();
_ = await messenger.Send<AsyncNumberRequestMessage>();
}
[TestCategory("Mvvm")]
@ -165,7 +165,7 @@ public partial class Test_Messenger
IMessenger? messenger = (IMessenger)Activator.CreateInstance(type)!;
object? recipient = new();
void Receive(object recipient, AsyncNumberRequestMessage m)
static void Receive(object recipient, AsyncNumberRequestMessage m)
{
m.Reply(42);
m.Reply(42);
@ -191,7 +191,7 @@ public partial class Test_Messenger
IMessenger? messenger = (IMessenger)Activator.CreateInstance(type)!;
object? recipient = new();
void Receive(object recipient, NumbersCollectionRequestMessage m)
static void Receive(object recipient, NumbersCollectionRequestMessage m)
{
}
@ -267,7 +267,7 @@ public partial class Test_Messenger
IMessenger? messenger = (IMessenger)Activator.CreateInstance(type)!;
object? recipient = new();
void Receive(object recipient, AsyncNumbersCollectionRequestMessage m)
static void Receive(object recipient, AsyncNumbersCollectionRequestMessage m)
{
}