A game about forced loneliness, made by TACStudios
at master 316 lines 15 kB view raw
1using System; 2using System.Diagnostics; 3using Unity.Collections.LowLevel.Unsafe; 4using Unity.Burst; 5using static Unity.Collections.AllocatorManager; 6 7namespace Unity.Collections 8{ 9 /// <summary> 10 /// Extension methods for NativeArray. 11 /// </summary> 12 [GenerateTestsForBurstCompatibility] 13 public unsafe static class NativeArrayExtensions 14 { 15 /// <summary> 16 /// Provides a Burst compatible id for NativeArray<typeparamref name="T"/> types. Used by the Job Safety System. 17 /// </summary> 18 /// <typeparam name="T"></typeparam> 19 public struct NativeArrayStaticId<T> 20 where T : unmanaged 21 { 22 internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeArray<T>>(); 23 } 24 25 /// <summary> 26 /// Returns true if a particular value is present in this array. 27 /// </summary> 28 /// <typeparam name="T">The type of elements in this array.</typeparam> 29 /// <typeparam name="U">The value type.</typeparam> 30 /// <param name="array">The array to search.</param> 31 /// <param name="value">The value to locate.</param> 32 /// <returns>True if the value is present in this array.</returns> 33 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })] 34 public static bool Contains<T, U>(this NativeArray<T> array, U value) where T : unmanaged, IEquatable<U> 35 { 36 return IndexOf<T, U>(array.GetUnsafeReadOnlyPtr(), array.Length, value) != -1; 37 } 38 39 /// <summary> 40 /// Finds the index of the first occurrence of a particular value in this array. 41 /// </summary> 42 /// <typeparam name="T">The type of elements in this array.</typeparam> 43 /// <typeparam name="U">The value type.</typeparam> 44 /// <param name="array">The array to search.</param> 45 /// <param name="value">The value to locate.</param> 46 /// <returns>The index of the first occurrence of the value in this array. Returns -1 if no occurrence is found.</returns> 47 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })] 48 public static int IndexOf<T, U>(this NativeArray<T> array, U value) where T : unmanaged, IEquatable<U> 49 { 50 return IndexOf<T, U>(array.GetUnsafeReadOnlyPtr(), array.Length, value); 51 } 52 53 /// <summary> 54 /// Returns true if a particular value is present in this array. 55 /// </summary> 56 /// <typeparam name="T">The type of elements in this array.</typeparam> 57 /// <typeparam name="U">The value type.</typeparam> 58 /// <param name="array">The array to search.</param> 59 /// <param name="value">The value to locate.</param> 60 /// <returns>True if the value is present in this array.</returns> 61 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })] 62 public static bool Contains<T, U>(this NativeArray<T>.ReadOnly array, U value) where T : unmanaged, IEquatable<U> 63 { 64 return IndexOf<T, U>(array.GetUnsafeReadOnlyPtr(), array.m_Length, value) != -1; 65 } 66 67 /// <summary> 68 /// Finds the index of the first occurrence of a particular value in this array. 69 /// </summary> 70 /// <typeparam name="T">The type of elements in this array.</typeparam> 71 /// <typeparam name="U">The type of value to locate.</typeparam> 72 /// <param name="array">The array to search.</param> 73 /// <param name="value">The value to locate.</param> 74 /// <returns>The index of the first occurrence of the value in this array. Returns -1 if no occurrence is found.</returns> 75 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })] 76 public static int IndexOf<T, U>(this NativeArray<T>.ReadOnly array, U value) where T : unmanaged, IEquatable<U> 77 { 78 return IndexOf<T, U>(array.GetUnsafeReadOnlyPtr(), array.m_Length, value); 79 } 80 81 /// <summary> 82 /// Returns true if a particular value is present in a buffer. 83 /// </summary> 84 /// <typeparam name="T">The type of elements in the buffer.</typeparam> 85 /// <typeparam name="U">The value type.</typeparam> 86 /// <param name="ptr">The buffer.</param> 87 /// <param name="length">Number of elements in the buffer.</param> 88 /// <param name="value">The value to locate.</param> 89 /// <returns>True if the value is present in the buffer.</returns> 90 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })] 91 public static bool Contains<T, U>(void* ptr, int length, U value) where T : unmanaged, IEquatable<U> 92 { 93 return IndexOf<T, U>(ptr, length, value) != -1; 94 } 95 96 /// <summary> 97 /// Finds the index of the first occurrence of a particular value in a buffer. 98 /// </summary> 99 /// <typeparam name="T">The type of elements in the buffer.</typeparam> 100 /// <typeparam name="U">The value type.</typeparam> 101 /// <param name="ptr">A buffer.</param> 102 /// <param name="length">Number of elements in the buffer.</param> 103 /// <param name="value">The value to locate.</param> 104 /// <returns>The index of the first occurrence of the value in the buffer. Returns -1 if no occurrence is found.</returns> 105 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })] 106 public static int IndexOf<T, U>(void* ptr, int length, U value) where T : unmanaged, IEquatable<U> 107 { 108 for (int i = 0; i != length; i++) 109 { 110 if (UnsafeUtility.ReadArrayElement<T>(ptr, i).Equals(value)) 111 return i; 112 } 113 return -1; 114 } 115 116 /// <summary> 117 /// Copies all elements of specified container to array. 118 /// </summary> 119 /// <typeparam name="T">The type of elements in this container.</typeparam> 120 /// <param name="container">Container to copy to.</param> 121 /// <param name="other">An container to copy into this array.</param> 122 /// <exception cref="ArgumentException">Thrown if the array and container have unequal length.</exception> 123 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })] 124 public static void CopyFrom<T>(this ref NativeArray<T> container, NativeList<T> other) 125 where T : unmanaged, IEquatable<T> 126 { 127 container.CopyFrom(other.AsArray()); 128 } 129 130 /// <summary> 131 /// Copies all elements of specified container to array. 132 /// </summary> 133 /// <typeparam name="T">The type of elements in this container.</typeparam> 134 /// <param name="container">Container to copy to.</param> 135 /// <param name="other">An container to copy into this array.</param> 136 /// <exception cref="ArgumentException">Thrown if the array and container have unequal length.</exception> 137 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })] 138 public static void CopyFrom<T>(this ref NativeArray<T> container, in NativeHashSet<T> other) 139 where T : unmanaged, IEquatable<T> 140 { 141 using (var array = other.ToNativeArray(Allocator.TempJob)) 142 { 143 container.CopyFrom(array); 144 } 145 } 146 147 /// <summary> 148 /// Copies all elements of specified container to array. 149 /// </summary> 150 /// <typeparam name="T">The type of elements in this container.</typeparam> 151 /// <param name="container">Container to copy to.</param> 152 /// <param name="other">An container to copy into this array.</param> 153 /// <exception cref="ArgumentException">Thrown if the array and container have unequal length.</exception> 154 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })] 155 public static void CopyFrom<T>(this ref NativeArray<T> container, in UnsafeHashSet<T> other) 156 where T : unmanaged, IEquatable<T> 157 { 158 using (var array = other.ToNativeArray(Allocator.TempJob)) 159 { 160 container.CopyFrom(array); 161 } 162 } 163 164 /// <summary> 165 /// Returns the reinterpretation of this array into another kind of NativeArray. 166 /// See [Array reinterpretation](https://docs.unity3d.com/Packages/com.unity.collections@latest?subfolder=/manual/allocation.html#array-reinterpretation). 167 /// </summary> 168 /// <param name="array">The array to reinterpret.</param> 169 /// <typeparam name="T">Type of elements in the array.</typeparam> 170 /// <typeparam name="U">Type of elements in the reinterpreted array.</typeparam> 171 /// <returns>The reinterpretation of this array into another kind of NativeArray.</returns> 172 /// <exception cref="InvalidOperationException">Thrown if this array's capacity cannot be evenly divided by `sizeof(U)`.</exception> 173 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int), typeof(int) })] 174 public static NativeArray<U> Reinterpret<T, U>(this NativeArray<T> array) 175 where U : unmanaged 176 where T : unmanaged 177 { 178 var tSize = UnsafeUtility.SizeOf<T>(); 179 var uSize = UnsafeUtility.SizeOf<U>(); 180 181 var byteLen = ((long)array.Length) * tSize; 182 var uLen = byteLen / uSize; 183 184 CheckReinterpretSize<T, U>(ref array); 185 186 var ptr = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(array); 187 var result = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<U>(ptr, (int)uLen, Allocator.None); 188 189#if ENABLE_UNITY_COLLECTIONS_CHECKS 190 var handle = NativeArrayUnsafeUtility.GetAtomicSafetyHandle(array); 191 NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref result, handle); 192#endif 193 194 return result; 195 } 196 197 /// <summary> 198 /// Returns true if this array and another have equal length and content. 199 /// </summary> 200 /// <typeparam name="T">The type of the source array's elements.</typeparam> 201 /// <param name="container">The array to compare for equality.</param> 202 /// <param name="other">The other array to compare for equality.</param> 203 /// <returns>True if the arrays have equal length and content.</returns> 204 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 205 public static bool ArraysEqual<T>(this NativeArray<T> container, NativeArray<T> other) 206 where T : unmanaged, IEquatable<T> 207 { 208 if (container.Length != other.Length) 209 return false; 210 211 for (int i = 0; i != container.Length; i++) 212 { 213 if (!container[i].Equals(other[i])) 214 return false; 215 } 216 217 return true; 218 } 219 220 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 221 static void CheckReinterpretSize<T, U>(ref NativeArray<T> array) 222 where U : unmanaged 223 where T : unmanaged 224 { 225 var tSize = UnsafeUtility.SizeOf<T>(); 226 var uSize = UnsafeUtility.SizeOf<U>(); 227 228 var byteLen = ((long)array.Length) * tSize; 229 var uLen = byteLen / uSize; 230 231 if (uLen * uSize != byteLen) 232 { 233 throw new InvalidOperationException($"Types {typeof(T)} (array length {array.Length}) and {typeof(U)} cannot be aliased due to size constraints. The size of the types and lengths involved must line up."); 234 } 235 } 236 237 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })] 238 internal static void Initialize<T>(ref this NativeArray<T> array, 239 int length, 240 AllocatorManager.AllocatorHandle allocator, 241 NativeArrayOptions options = NativeArrayOptions.ClearMemory) 242 where T : unmanaged 243 { 244 AllocatorHandle handle = allocator; 245 array = default; 246 array.m_Buffer = handle.AllocateStruct(default(T), length); 247 array.m_Length = length; 248 array.m_AllocatorLabel = allocator.IsAutoDispose ? Allocator.None : allocator.ToAllocator; 249 if (options == NativeArrayOptions.ClearMemory) 250 { 251 UnsafeUtility.MemClear(array.m_Buffer, array.m_Length * UnsafeUtility.SizeOf<T>()); 252 } 253 254#if ENABLE_UNITY_COLLECTIONS_CHECKS 255 array.m_MinIndex = 0; 256 array.m_MaxIndex = length - 1; 257 array.m_Safety = CollectionHelper.CreateSafetyHandle(allocator); 258 259 CollectionHelper.SetStaticSafetyId<NativeArray<T>>(ref array.m_Safety, ref NativeArrayStaticId<T>.s_staticSafetyId.Data); 260 handle.AddSafetyHandle(array.m_Safety); 261#endif 262 } 263 264 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(AllocatorManager.AllocatorHandle) })] 265 internal static void Initialize<T, U>(ref this NativeArray<T> array, 266 int length, 267 ref U allocator, 268 NativeArrayOptions options = NativeArrayOptions.ClearMemory) 269 where T : unmanaged 270 where U : unmanaged, AllocatorManager.IAllocator 271 { 272 array = default; 273 array.m_Buffer = allocator.AllocateStruct(default(T), length); 274 array.m_Length = length; 275 array.m_AllocatorLabel = allocator.IsAutoDispose ? Allocator.None : allocator.ToAllocator; 276 if (options == NativeArrayOptions.ClearMemory) 277 { 278 UnsafeUtility.MemClear(array.m_Buffer, array.m_Length * UnsafeUtility.SizeOf<T>()); 279 } 280 281#if ENABLE_UNITY_COLLECTIONS_CHECKS 282 array.m_MinIndex = 0; 283 array.m_MaxIndex = length - 1; 284 array.m_Safety = CollectionHelper.CreateSafetyHandle(allocator.ToAllocator); 285 286 CollectionHelper.SetStaticSafetyId<NativeArray<T>>(ref array.m_Safety, ref NativeArrayStaticId<T>.s_staticSafetyId.Data); 287 allocator.Handle.AddSafetyHandle(array.m_Safety); 288#endif 289 } 290 291 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })] 292 internal static void DisposeCheckAllocator<T>(ref this NativeArray<T> array) 293 where T : unmanaged 294 { 295 if (array.m_Buffer == null) 296 { 297 throw new ObjectDisposedException("The NativeArray is already disposed."); 298 } 299 300 if (!AllocatorManager.IsCustomAllocator(array.m_AllocatorLabel)) 301 { 302 array.Dispose(); 303 } 304 else 305 { 306#if ENABLE_UNITY_COLLECTIONS_CHECKS 307 AtomicSafetyHandle.DisposeHandle(ref array.m_Safety); 308#endif 309 AllocatorManager.Free(array.m_AllocatorLabel, array.m_Buffer); 310 array.m_AllocatorLabel = Allocator.Invalid; 311 312 array.m_Buffer = null; 313 } 314 } 315 } 316}