Added SpanExtensions and the reinterpret between Unity's structs to System.Numerics structs

This commit is contained in:
RealityProgrammer 2023-03-06 06:49:07 +07:00
parent 1e98e6910f
commit e1a7ac03c6
6 changed files with 104 additions and 9 deletions

View File

@ -1,5 +1,6 @@
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
namespace X10D.Unity.Numerics;
@ -18,7 +19,7 @@ public static class QuaternionExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static System.Numerics.Quaternion ToSystemQuaternion(this Quaternion quaternion)
{
return new System.Numerics.Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
return UnsafeUtility.As<Quaternion, System.Numerics.Quaternion>(ref quaternion);
}
/// <summary>
@ -30,6 +31,6 @@ public static class QuaternionExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion ToUnityQuaternion(this System.Numerics.Quaternion quaternion)
{
return new Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
return UnsafeUtility.As<System.Numerics.Quaternion, Quaternion>(ref quaternion);
}
}

View File

@ -1,5 +1,6 @@
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
namespace X10D.Unity.Numerics;
@ -18,7 +19,7 @@ public static class Vector2Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static System.Numerics.Vector2 ToSystemVector(this Vector2 vector)
{
return new System.Numerics.Vector2(vector.x, vector.y);
return UnsafeUtility.As<Vector2, System.Numerics.Vector2>(ref vector);
}
/// <summary>
@ -30,7 +31,7 @@ public static class Vector2Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 ToUnityVector(this System.Numerics.Vector2 vector)
{
return new Vector2(vector.X, vector.Y);
return UnsafeUtility.As<System.Numerics.Vector2, Vector2>(ref vector);
}
/// <summary>

View File

@ -1,5 +1,6 @@
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
namespace X10D.Unity.Numerics;
@ -18,7 +19,7 @@ public static class Vector3Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static System.Numerics.Vector3 ToSystemVector(this Vector3 vector)
{
return new System.Numerics.Vector3(vector.x, vector.y, vector.z);
return UnsafeUtility.As<Vector3, System.Numerics.Vector3>(ref vector);
}
/// <summary>
@ -30,7 +31,7 @@ public static class Vector3Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 ToUnityVector(this System.Numerics.Vector3 vector)
{
return new Vector3(vector.X, vector.Y, vector.Z);
return UnsafeUtility.As<System.Numerics.Vector3, Vector3>(ref vector);
}
/// <summary>

View File

@ -1,5 +1,6 @@
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
namespace X10D.Unity.Numerics;
@ -18,7 +19,8 @@ public static class Vector4Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static System.Numerics.Vector4 ToSystemVector(this Vector4 vector)
{
return new System.Numerics.Vector4(vector.x, vector.y, vector.z, vector.w);
return UnsafeUtility.As<Vector4, System.Numerics.Vector4>(ref vector);
}
/// <summary>
@ -30,7 +32,7 @@ public static class Vector4Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 ToUnityVector(this System.Numerics.Vector4 vector)
{
return new Vector4(vector.X, vector.Y, vector.Z, vector.W);
return UnsafeUtility.As<System.Numerics.Vector4, Vector4>(ref vector);
}
/// <summary>

View File

@ -80,7 +80,7 @@ public static class Int32Extensions
var shuffle = Avx2.Shuffle(vec, mask1);
var and = Avx2.AndNot(shuffle, mask2);
var cmp = Avx2.CompareEqual(and, Vector256<byte>.Zero);
var correctness = Avx2.And(cmp, Vector256.Create((byte)0x01));
var correctness = Avx2.And(cmp, Vector256.Create((byte)0x01));
Avx.Store((byte*)pDestination, correctness);
}
@ -110,6 +110,7 @@ public static class Int32Extensions
and = Sse2.AndNot(shuffle, mask2);
cmp = Sse2.CompareEqual(and, Vector128<byte>.Zero);
correctness = Sse2.And(cmp, one);
Sse2.Store((byte*)pDestination + 16, correctness);
}
}

View File

@ -0,0 +1,89 @@
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace X10D.Core;
/// <summary>
/// Extension methods for <see cref="Span{T}"/> and <see cref="ReadOnlySpan{T}"/>.
/// </summary>
public static class SpanExtensions
{
/// <summary>
/// Indicate whether a specific enumeration value is found in a span.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="span">The span to search from.</param>
/// <param name="value">The enum to search for.</param>
/// <returns><see langword="true"/> if found, <see langword="false"/> otherwise.</returns>
/// <exception cref="ArgumentException">Unexpected enum memory size.</exception>
#if NETSTANDARD2_1
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
#endif
public static bool Contains<T>(this Span<T> span, T value) where T : Enum
{
return Contains((ReadOnlySpan<T>)span, value);
}
/// <summary>
/// Indicate whether a specific enumeration value is found in a span.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="span">The span to search from.</param>
/// <param name="value">The enum to search for.</param>
/// <returns><see langword="true"/> if found, <see langword="false"/> otherwise.</returns>
/// <exception cref="ArgumentException">Unexpected enum memory size.</exception>
#if NETSTANDARD2_1
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#else
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
#endif
public static bool Contains<T>(this ReadOnlySpan<T> span, T value)
{
// Use MemoryMarshal.CreateSpan instead of using creating new Span instance from pointer will trim down a lot of instructions
// on Release mode.
// https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABABgAJiBGAOgCUBXAOwwEt8YaBJFmKCAA4BlPgDdWYGLgDcAWABQZSrUYt2nAMIR8A1gBs+IqOMkyFxAExVzFIQAtsUAQBlsweszYc588wGZyGCYGfHIAFSkMAFFg0JByVhZyAG8FcnTyAEE0cgAhHI0cgBE0BQBfBX9KC3INFLSMgG0AKVYMAHEgvgkACgwATwEYCAAzHojcaNiASmmAXQb0xoBZGAw7CAATLh09HtX1rZ2BPQB5ATYIJlwaTIBzO9hcXFZRGB49RMS78kJyA4221250u11uDyeLzeIPYrAAXthQfNFpQAtQkORmLhsCMYORgBAIHp/mtAVQADxhAB8PSEAmwTEpVPIuHpTByYXIomwegYMGm5AA7nY+HjOfEYiF6vIMrLyLARgkkkEQrhyABeeUwRUAVWuOM4mVwlJyiQwNIVJPw0H6y0cuAcehonQwdG1oqYkh6rIZsx8coyxAA7FabXaoA6eTQNLBETA6QyepaVfhcDkfUwaM4gnd1tNo1cMNhErgenrsbjbsawqaWBbtVyeXy/SiKjKMiiWm1OkxumA+oNhmMJlMQrMFu2lgCjrt9qSZycYVcbvdHlIoe8mJ8mN9fiTDkDFxdWMvwWvnq8YDD8PDESemMjJ6jlBisQb8YTidPNhYmbS2UyLJshyja8vyQoirA4TkBKsTSgG6TBuQvaCuQCaMmaNLlgaVYAAoQGafBJg2qzWlAtr2o6zprG6uKwJ6MDemyszpmyWY5nmBYsMW1xlvqlZGiaSrmsRircmBLZPm2ZRAA===
// TODO: Figure out some kind of way to directly pass the Span directly into Contains call, which make method smaller and more prone to inlining...
unsafe
{
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
switch (sizeof(T))
{
case 1:
{
ref byte enums = ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span));
return MemoryMarshal.CreateSpan(ref enums, span.Length).Contains(Unsafe.As<T, byte>(ref value));
}
case 2:
{
ref ushort enums = ref Unsafe.As<T, ushort>(ref MemoryMarshal.GetReference(span));
return MemoryMarshal.CreateSpan(ref enums, span.Length).Contains(Unsafe.As<T, ushort>(ref value));
}
case 4:
{
ref uint enums = ref Unsafe.As<T, uint>(ref MemoryMarshal.GetReference(span));
return MemoryMarshal.CreateSpan(ref enums, span.Length).Contains(Unsafe.As<T, uint>(ref value));
}
case 8:
{
ref ulong enums = ref Unsafe.As<T, ulong>(ref MemoryMarshal.GetReference(span));
return MemoryMarshal.CreateSpan(ref enums, span.Length).Contains(Unsafe.As<T, ulong>(ref value));
}
default:
#if NET7_0_OR_GREATER
throw new UnreachableException($"Enum with the size of {Unsafe.SizeOf<T>()} bytes is unexpected.");
#else
throw new ArgumentException($"Enum with the size of {Unsafe.SizeOf<T>()} bytes is unexpected.");
#endif
}
#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
}
}
}