using System.Diagnostics; using System.Runtime.InteropServices; namespace UnityEngine.XR.MagicLeap.Unsafe { using System; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; internal static unsafe class UnsafeUtilityEx { public static T* Calloc(Allocator allocator, T initialValue = default) where T : unmanaged { var ptr = Malloc(allocator); *ptr = initialValue; return ptr; } public static T[] GetManagedArray(IntPtr buffer, int length) where T : unmanaged { return GetManagedArray((T*)buffer, length); } public static T[] GetManagedArray(T* buffer, int length) where T: unmanaged { var result = new T[length]; for (int i = 0; i < length; i++) { result[i] = buffer[i]; } return result; } public static T* CallocTracked(Allocator allocator, T initialValue = default, int callstacksToSkip = 1) where T : unmanaged { var ptr = MallocTracked(allocator, callstacksToSkip); *ptr = initialValue; return ptr; } public static T* Malloc(Allocator allocator) where T : unmanaged => (T*)UnsafeUtility.Malloc(sizeof(T), UnsafeUtility.AlignOf(), allocator); public static T* MallocTracked(Allocator allocator, int callstacksToSkip = 1) where T : unmanaged => (T*)UnsafeUtility.MallocTracked(sizeof(T), UnsafeUtility.AlignOf(), allocator, callstacksToSkip); #if ENABLE_UNITY_COLLECTIONS_CHECKS public static AtomicSafetyHandle CreateAtomicSafetyHandleForAllocator(Allocator allocator) { switch (allocator) { case Allocator.Invalid: throw new InvalidOperationException("Cannot create safety handle for invalid allocator"); case Allocator.Temp: return AtomicSafetyHandle.GetTempMemoryHandle(); default: return AtomicSafetyHandle.Create(); } } #endif public static U* PunRefTypeUnchecked(ref T obj) where T : unmanaged where U : unmanaged => (U*)UnsafeUtility.AddressOf(ref UnsafeUtility.As(ref obj)); public static U* PunType(T* obj) where T : unmanaged where U : unmanaged { CheckTypeSizeAndThrow(); return PunTypeUnchecked(obj); } public static T* PunType(void* obj, int expectedSize) where T : unmanaged { CheckTypeSizeAndThrow(expectedSize); return PunTypeUnchecked(obj); } public static U* PunTypeUnchecked(void* obj) where U : unmanaged => (U*)UnsafeUtility.AddressOf(ref UnsafeUtility.AsRef(obj)); public static U* PunTypeUnchecked(T* obj) where T: unmanaged where U : unmanaged => (U*)UnsafeUtility.AddressOf(ref UnsafeUtility.AsRef(obj)); public static string FormatAddress(void* ptr) { var i64 = new IntPtr(ptr).ToInt64(); return $"0x{i64:X}"; } [Conditional("DEVELOPMENT_BUILD")] public static void CheckTypeSizeAndThrow() where T : unmanaged where U : unmanaged { var szT = sizeof(T); var szU = sizeof(U); if (szT != szU) throw new InvalidOperationException( $"Type size mismatch! sizeof({typeof(T).Name}) = {szT}, sizeof({typeof(U).FullName}) = {szU}"); } [Conditional("DEVELOPMENT_BUILD")] public static void CheckTypeSizeAndThrow(int expectedTypeSize) where T : unmanaged { var szT = sizeof(T); if (szT != expectedTypeSize) throw new InvalidOperationException( $"Type size mismatch! Expected sizeof({typeof(T).FullName}) to be {expectedTypeSize}, was instead {szT}"); } } }