A game about forced loneliness, made by TACStudios
at master 130 lines 5.8 kB view raw
1using System; 2using System.Diagnostics; 3using System.Runtime.CompilerServices; 4using Unity.Mathematics; 5 6namespace Unity.Collections.LowLevel.Unsafe 7{ 8 /// <summary> 9 /// Provides utility methods for unsafe, untyped buffers. 10 /// </summary> 11 [GenerateTestsForBurstCompatibility] 12 public unsafe static class UnsafeUtilityExtensions 13 { 14 /// <summary> 15 /// Swaps bytes between two buffers. 16 /// </summary> 17 /// <param name="ptr">A buffer.</param> 18 /// <param name="otherPtr">Another buffer.</param> 19 /// <param name="size">The number of bytes to swap.</param> 20 /// <exception cref="System.InvalidOperationException">Thrown if the two ranges of bytes to swap overlap in memory.</exception> 21 internal static void MemSwap(void* ptr, void* otherPtr, long size) 22 { 23 byte* dst = (byte*) ptr; 24 byte* src = (byte*) otherPtr; 25 26 CheckMemSwapOverlap(dst, src, size); 27 28 var tmp = stackalloc byte[1024]; 29 30 while (size > 0) 31 { 32 var numBytes = math.min(size, 1024); 33 UnsafeUtility.MemCpy(tmp, dst, numBytes); 34 UnsafeUtility.MemCpy(dst, src, numBytes); 35 UnsafeUtility.MemCpy(src, tmp, numBytes); 36 37 size -= numBytes; 38 src += numBytes; 39 dst += numBytes; 40 } 41 } 42 43 /// <summary> 44 /// Reads an element from a buffer after bounds checking. 45 /// </summary> 46 /// <typeparam name="T">The type of element.</typeparam> 47 /// <param name="source">The buffer to read from.</param> 48 /// <param name="index">The index of the element.</param> 49 /// <param name="capacity">The buffer capacity (in number of elements). Used for the bounds checking.</param> 50 /// <returns>The element read from the buffer.</returns> 51 /// <exception cref="IndexOutOfRangeException">Thrown if the index is out of bounds.</exception> 52 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 53 public unsafe static T ReadArrayElementBoundsChecked<T>(void* source, int index, int capacity) 54 where T : unmanaged 55 { 56 CheckIndexRange(index, capacity); 57 58 return UnsafeUtility.ReadArrayElement<T>(source, index); 59 } 60 61 /// <summary> 62 /// Writes an element to a buffer after bounds checking. 63 /// </summary> 64 /// <typeparam name="T">The type of element.</typeparam> 65 /// <param name="destination">The buffer to write to.</param> 66 /// <param name="value">The value to write.</param> 67 /// <param name="index">The index at which to store the element.</param> 68 /// <param name="capacity">The buffer capacity (in number of elements). Used for the bounds checking.</param> 69 /// <exception cref="IndexOutOfRangeException">Thrown if the index is out of bounds.</exception> 70 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 71 public unsafe static void WriteArrayElementBoundsChecked<T>(void* destination, int index, T value, int capacity) 72 where T : unmanaged 73 { 74 CheckIndexRange(index, capacity); 75 76 UnsafeUtility.WriteArrayElement<T>(destination, index, value); 77 } 78 79 /// <summary> 80 /// Returns the address of a read-only reference. 81 /// </summary> 82 /// <typeparam name="T">The type of referenced value.</typeparam> 83 /// <param name="value">A read-only reference.</param> 84 /// <returns>A pointer to the referenced value.</returns> 85 [MethodImpl(MethodImplOptions.AggressiveInlining)] 86 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 87 public static void* AddressOf<T>(in T value) 88 where T : unmanaged 89 { 90 return ILSupport.AddressOf(in value); 91 } 92 93 /// <summary> 94 /// Returns a read-write reference from a read-only reference. 95 /// <remarks>Useful when you want to pass an `in` arg (read-only reference) where a `ref` arg (read-write reference) is expected. 96 /// Do not mutate the referenced value, as doing so may break the runtime's assumptions.</remarks> 97 /// </summary> 98 /// <typeparam name="T">The type of referenced value.</typeparam> 99 /// <param name="value">A read-only reference.</param> 100 /// <returns>A read-write reference to the value referenced by `item`.</returns> 101 [MethodImpl(MethodImplOptions.AggressiveInlining)] 102 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 103 public static ref T AsRef<T>(in T value) 104 where T : unmanaged 105 { 106 return ref ILSupport.AsRef(in value); 107 } 108 109 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 110 static unsafe void CheckMemSwapOverlap(byte* dst, byte* src, long size) 111 { 112 if (dst + size > src && src + size > dst) 113 { 114 throw new InvalidOperationException("MemSwap memory blocks are overlapped."); 115 } 116 } 117 118 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 119 static void CheckIndexRange(int index, int capacity) 120 { 121 if ((index > capacity - 1) || (index < 0)) 122 { 123 throw new IndexOutOfRangeException( 124 $"Attempt to read or write from array index {index}, which is out of bounds. Array capacity is {capacity}. " 125 +"This may lead to a crash, data corruption, or reading invalid data." 126 ); 127 } 128 } 129 } 130}