Fix incorrect whitespaces, minor code style tweaks
This commit is contained in:
Родитель
6afdd81742
Коммит
93cb82a0d0
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче