A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections; 3using System.Collections.Generic; 4using System.Diagnostics; 5using System.Runtime.CompilerServices; 6using System.Runtime.InteropServices; 7using System.Threading; 8using Unity.Burst; 9using Unity.Collections.LowLevel.Unsafe; 10using Unity.Jobs; 11 12namespace Unity.Collections 13{ 14 /// <summary> 15 /// An indexable collection. 16 /// </summary> 17 /// <typeparam name="T">The type of the elements in the collection.</typeparam> 18 public interface IIndexable<T> where T : unmanaged 19 { 20 /// <summary> 21 /// The current number of elements in the collection. 22 /// </summary> 23 /// <value>The current number of elements in the collection.</value> 24 int Length { get; set; } 25 26 /// <summary> 27 /// Returns a reference to the element at a given index. 28 /// </summary> 29 /// <param name="index">The index to access. Must be in the range of [0..Length).</param> 30 /// <returns>A reference to the element at the index.</returns> 31 ref T ElementAt(int index); 32 } 33 34 /// <summary> 35 /// A resizable list. 36 /// </summary> 37 /// <typeparam name="T">The type of the elements.</typeparam> 38 public interface INativeList<T> : IIndexable<T> where T : unmanaged 39 { 40 /// <summary> 41 /// The number of elements that fit in the current allocation. 42 /// </summary> 43 /// <value>The number of elements that fit in the current allocation.</value> 44 /// <param name="value">A new capacity.</param> 45 int Capacity { get; set; } 46 47 /// <summary> 48 /// Whether this list is empty. 49 /// </summary> 50 /// <value>True if this list is empty.</value> 51 bool IsEmpty { get; } 52 53 /// <summary> 54 /// The element at an index. 55 /// </summary> 56 /// <param name="index">An index.</param> 57 /// <value>The element at the index.</value> 58 /// <exception cref="IndexOutOfRangeException">Thrown if index is out of bounds.</exception> 59 T this[int index] { get; set; } 60 61 /// <summary> 62 /// Sets the length to 0. 63 /// </summary> 64 /// <remarks>Does not change the capacity.</remarks> 65 void Clear(); 66 } 67 68 /// <summary> 69 /// An unmanaged, resizable list. 70 /// </summary> 71 /// <remarks>The elements are stored contiguously in a buffer rather than as linked nodes.</remarks> 72 /// <typeparam name="T">The type of the elements.</typeparam> 73 [StructLayout(LayoutKind.Sequential)] 74 [NativeContainer] 75 [DebuggerDisplay("Length = {m_ListData == null ? default : m_ListData->Length}, Capacity = {m_ListData == null ? default : m_ListData->Capacity}")] 76 [DebuggerTypeProxy(typeof(NativeListDebugView<>))] 77 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 78 public unsafe struct NativeList<T> 79 : INativeDisposable 80 , INativeList<T> 81 , IEnumerable<T> // Used by collection initializers. 82 where T : unmanaged 83 { 84#if ENABLE_UNITY_COLLECTIONS_CHECKS 85 internal AtomicSafetyHandle m_Safety; 86 internal int m_SafetyIndexHint; 87 internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeList<T>>(); 88#endif 89 90 [NativeDisableUnsafePtrRestriction] 91 internal UnsafeList<T>* m_ListData; 92 93 /// <summary> 94 /// Initializes and returns a NativeList with a capacity of one. 95 /// </summary> 96 /// <param name="allocator">The allocator to use.</param> 97 public NativeList(AllocatorManager.AllocatorHandle allocator) 98 : this(1, allocator) 99 { 100 } 101 102 /// <summary> 103 /// Initializes and returns a NativeList. 104 /// </summary> 105 /// <param name="initialCapacity">The initial capacity of the list.</param> 106 /// <param name="allocator">The allocator to use.</param> 107 public NativeList(int initialCapacity, AllocatorManager.AllocatorHandle allocator) 108 { 109 this = default; 110 AllocatorManager.AllocatorHandle temp = allocator; 111 Initialize(initialCapacity, ref temp); 112 } 113 114 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(AllocatorManager.AllocatorHandle) })] 115 internal void Initialize<U>(int initialCapacity, ref U allocator) where U : unmanaged, AllocatorManager.IAllocator 116 { 117 var totalSize = sizeof(T) * (long)initialCapacity; 118#if ENABLE_UNITY_COLLECTIONS_CHECKS 119 CollectionHelper.CheckAllocator(allocator.Handle); 120 CheckInitialCapacity(initialCapacity); 121 CheckTotalSize(initialCapacity, totalSize); 122 123 m_Safety = CollectionHelper.CreateSafetyHandle(allocator.Handle); 124 CollectionHelper.InitNativeContainer<T>(m_Safety); 125 126 CollectionHelper.SetStaticSafetyId<NativeList<T>>(ref m_Safety, ref s_staticSafetyId.Data); 127 128 m_SafetyIndexHint = (allocator.Handle).AddSafetyHandle(m_Safety); 129 130 AtomicSafetyHandle.SetBumpSecondaryVersionOnScheduleWrite(m_Safety, true); 131#endif 132 m_ListData = UnsafeList<T>.Create(initialCapacity, ref allocator, NativeArrayOptions.UninitializedMemory); 133 } 134 135 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(AllocatorManager.AllocatorHandle) })] 136 internal static NativeList<T> New<U>(int initialCapacity, ref U allocator) where U : unmanaged, AllocatorManager.IAllocator 137 { 138 var nativelist = new NativeList<T>(); 139 nativelist.Initialize(initialCapacity, ref allocator); 140 return nativelist; 141 } 142 143 /// <summary> 144 /// The element at a given index. 145 /// </summary> 146 /// <param name="index">An index into this list.</param> 147 /// <value>The value to store at the `index`.</value> 148 /// <exception cref="IndexOutOfRangeException">Thrown if `index` is out of bounds.</exception> 149 public T this[int index] 150 { 151 [MethodImpl(MethodImplOptions.AggressiveInlining)] 152 get 153 { 154#if ENABLE_UNITY_COLLECTIONS_CHECKS 155 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 156#endif 157 return (*m_ListData)[index]; 158 } 159 160 [MethodImpl(MethodImplOptions.AggressiveInlining)] 161 set 162 { 163#if ENABLE_UNITY_COLLECTIONS_CHECKS 164 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 165#endif 166 (*m_ListData)[index] = value; 167 } 168 } 169 170 /// <summary> 171 /// Returns a reference to the element at an index. 172 /// </summary> 173 /// <param name="index">An index.</param> 174 /// <returns>A reference to the element at the index.</returns> 175 /// <exception cref="IndexOutOfRangeException">Thrown if index is out of bounds.</exception> 176 public ref T ElementAt(int index) 177 { 178#if ENABLE_UNITY_COLLECTIONS_CHECKS 179 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 180#endif 181 return ref m_ListData->ElementAt(index); 182 } 183 184 /// <summary> 185 /// The count of elements. 186 /// </summary> 187 /// <value>The current count of elements. Always less than or equal to the capacity.</value> 188 /// <remarks>To decrease the memory used by a list, set <see cref="Capacity"/> after reducing the length of the list.</remarks> 189 /// <param name="value>">The new length. If the new length is greater than the current capacity, the capacity is increased. 190 /// Newly allocated memory is cleared.</param> 191 public int Length 192 { 193 [MethodImpl(MethodImplOptions.AggressiveInlining)] 194 readonly get 195 { 196#if ENABLE_UNITY_COLLECTIONS_CHECKS 197 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 198#endif 199 return CollectionHelper.AssumePositive(m_ListData->Length); 200 } 201 202 set 203 { 204 // Unity 2022.2.16f1 removes the global temp safety handle so only 205 // from this version onward is it not a breaking change to perform this check 206 // since all previous versions did not have this safety check and will 207 // likely break from safe usage that is blurred by sharing the temp safety handle 208 // between multiple containers 209#if ENABLE_UNITY_COLLECTIONS_CHECKS && UNITY_2022_2_16F1_OR_NEWER 210 211 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 212#endif 213 m_ListData->Resize(value, NativeArrayOptions.ClearMemory); 214 } 215 } 216 217 /// <summary> 218 /// The number of elements that fit in the current allocation. 219 /// </summary> 220 /// <value>The number of elements that fit in the current allocation.</value> 221 /// <param name="value">The new capacity. Must be greater or equal to the length.</param> 222 /// <exception cref="ArgumentOutOfRangeException">Thrown if the new capacity is smaller than the length.</exception> 223 public int Capacity 224 { 225 [MethodImpl(MethodImplOptions.AggressiveInlining)] 226 readonly get 227 { 228#if ENABLE_UNITY_COLLECTIONS_CHECKS 229 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 230#endif 231 return m_ListData->Capacity; 232 } 233 234 set 235 { 236#if ENABLE_UNITY_COLLECTIONS_CHECKS 237 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 238#endif 239 m_ListData->Capacity = value; 240 } 241 } 242 243 /// <summary> 244 /// Returns the internal unsafe list. 245 /// </summary> 246 /// <remarks>Internally, the elements of a NativeList are stored in an UnsafeList.</remarks> 247 /// <returns>The internal unsafe list.</returns> 248 public UnsafeList<T>* GetUnsafeList() => m_ListData; 249 250 /// <summary> 251 /// Appends an element to the end of this list. 252 /// </summary> 253 /// <param name="value">The value to add to the end of this list.</param> 254 /// <remarks> 255 /// Length is incremented by 1. Will not increase the capacity. 256 /// </remarks> 257 /// <exception cref="InvalidOperationException">Thrown if incrementing the length would exceed the capacity.</exception> 258 public void AddNoResize(T value) 259 { 260#if ENABLE_UNITY_COLLECTIONS_CHECKS 261 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 262#endif 263 m_ListData->AddNoResize(value); 264 } 265 266 /// <summary> 267 /// Appends elements from a buffer to the end of this list. 268 /// </summary> 269 /// <param name="ptr">The buffer to copy from.</param> 270 /// <param name="count">The number of elements to copy from the buffer.</param> 271 /// <remarks> 272 /// Length is increased by the count. Will not increase the capacity. 273 /// </remarks> 274 /// <exception cref="InvalidOperationException">Thrown if the increased length would exceed the capacity.</exception> 275 public void AddRangeNoResize(void* ptr, int count) 276 { 277#if ENABLE_UNITY_COLLECTIONS_CHECKS 278 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 279#endif 280 CheckArgPositive(count); 281 m_ListData->AddRangeNoResize(ptr, count); 282 } 283 284 /// <summary> 285 /// Appends the elements of another list to the end of this list. 286 /// </summary> 287 /// <param name="list">The other list to copy from.</param> 288 /// <remarks> 289 /// Length is increased by the length of the other list. Will not increase the capacity. 290 /// </remarks> 291 /// <exception cref="InvalidOperationException">Thrown if the increased length would exceed the capacity.</exception> 292 public void AddRangeNoResize(NativeList<T> list) 293 { 294#if ENABLE_UNITY_COLLECTIONS_CHECKS 295 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 296#endif 297 m_ListData->AddRangeNoResize(*list.m_ListData); 298 } 299 300 /// <summary> 301 /// Appends an element to the end of this list. 302 /// </summary> 303 /// <param name="value">The value to add to the end of this list.</param> 304 /// <remarks> 305 /// Length is incremented by 1. If necessary, the capacity is increased. 306 /// </remarks> 307 public void Add(in T value) 308 { 309#if ENABLE_UNITY_COLLECTIONS_CHECKS 310 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 311#endif 312 m_ListData->Add(in value); 313 } 314 315 /// <summary> 316 /// Appends the elements of an array to the end of this list. 317 /// </summary> 318 /// <param name="array">The array to copy from.</param> 319 /// <remarks> 320 /// Length is increased by the number of new elements. Does not increase the capacity. 321 /// </remarks> 322 /// <exception cref="ArgumentOutOfRangeException">Thrown if the increased length would exceed the capacity.</exception> 323 public void AddRange(NativeArray<T> array) 324 { 325 AddRange(array.GetUnsafeReadOnlyPtr(), array.Length); 326 } 327 328 /// <summary> 329 /// Appends the elements of a buffer to the end of this list. 330 /// </summary> 331 /// <param name="ptr">The buffer to copy from.</param> 332 /// <param name="count">The number of elements to copy from the buffer.</param> 333 /// <exception cref="ArgumentOutOfRangeException">Thrown if count is negative.</exception> 334 public void AddRange(void* ptr, int count) 335 { 336#if ENABLE_UNITY_COLLECTIONS_CHECKS 337 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 338#endif 339 CheckArgPositive(count); 340 m_ListData->AddRange(ptr, CollectionHelper.AssumePositive(count)); 341 } 342 343 /// <summary> 344 /// Appends value count times to the end of this list. 345 /// </summary> 346 /// <param name="value">The value to add to the end of this list.</param> 347 /// <param name="count">The number of times to replicate the value.</param> 348 /// <remarks> 349 /// Length is incremented by count. If necessary, the capacity is increased. 350 /// </remarks> 351 /// <exception cref="ArgumentOutOfRangeException">Thrown if count is negative.</exception> 352 public void AddReplicate(in T value, int count) 353 { 354#if ENABLE_UNITY_COLLECTIONS_CHECKS 355 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 356#endif 357 CheckArgPositive(count); 358 m_ListData->AddReplicate(in value, CollectionHelper.AssumePositive(count)); 359 } 360 361 /// <summary> 362 /// Shifts elements toward the end of this list, increasing its length. 363 /// </summary> 364 /// <remarks> 365 /// Right-shifts elements in the list so as to create 'free' slots at the beginning or in the middle. 366 /// 367 /// The length is increased by `end - begin`. If necessary, the capacity will be increased accordingly. 368 /// 369 /// If `end` equals `begin`, the method does nothing. 370 /// 371 /// The element at index `begin` will be copied to index `end`, the element at index `begin + 1` will be copied to `end + 1`, and so forth. 372 /// 373 /// The indexes `begin` up to `end` are not cleared: they will contain whatever values they held prior. 374 /// </remarks> 375 /// <param name="begin">The index of the first element that will be shifted up.</param> 376 /// <param name="end">The index where the first shifted element will end up.</param> 377 /// <exception cref="ArgumentException">Thrown if `end &lt; begin`.</exception> 378 /// <exception cref="ArgumentOutOfRangeException">Thrown if `begin` or `end` are out of bounds.</exception> 379 public void InsertRangeWithBeginEnd(int begin, int end) 380 { 381#if ENABLE_UNITY_COLLECTIONS_CHECKS 382 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 383#endif 384 m_ListData->InsertRangeWithBeginEnd(begin, end); 385 } 386 387 /// <summary> 388 /// Shifts elements toward the end of this list, increasing its length. 389 /// </summary> 390 /// <remarks> 391 /// Right-shifts elements in the list so as to create 'free' slots at the beginning or in the middle. 392 /// 393 /// The length is increased by `count`. If necessary, the capacity will be increased accordingly. 394 /// 395 /// If `count` equals `0`, the method does nothing. 396 /// 397 /// The element at index `index` will be copied to index `index + count`, the element at index `index + 1` will be copied to `index + count + 1`, and so forth. 398 /// 399 /// The indexes `index` up to `index + count` are not cleared: they will contain whatever values they held prior. 400 /// </remarks> 401 /// <param name="index">The index of the first element that will be shifted up.</param> 402 /// <param name="count">The number of elements to insert.</param> 403 /// <exception cref="ArgumentException">Thrown if `count` is negative.</exception> 404 /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds.</exception> 405 public void InsertRange(int index, int count) => InsertRangeWithBeginEnd(index, index + count); 406 407 /// <summary> 408 /// Copies the last element of this list to the specified index. Decrements the length by 1. 409 /// </summary> 410 /// <remarks>Useful as a cheap way to remove an element from this list when you don't care about preserving order.</remarks> 411 /// <param name="index">The index to overwrite with the last element.</param> 412 /// <exception cref="IndexOutOfRangeException">Thrown if `index` is out of bounds.</exception> 413 public void RemoveAtSwapBack(int index) 414 { 415#if ENABLE_UNITY_COLLECTIONS_CHECKS 416 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 417#endif 418 m_ListData->RemoveAtSwapBack(index); 419 } 420 421 /// <summary> 422 /// Copies the last *N* elements of this list to a range in this list. Decrements the length by *N*. 423 /// </summary> 424 /// <remarks> 425 /// Copies the last `count` elements to the indexes `index` up to `index + count`. 426 /// 427 /// Useful as a cheap way to remove elements from a list when you don't care about preserving order. 428 /// </remarks> 429 /// <param name="index">The index of the first element to overwrite.</param> 430 /// <param name="count">The number of elements to copy and remove.</param> 431 /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds, `count` is negative, 432 /// or `index + count` exceeds the length.</exception> 433 public void RemoveRangeSwapBack(int index, int count) 434 { 435#if ENABLE_UNITY_COLLECTIONS_CHECKS 436 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 437#endif 438 m_ListData->RemoveRangeSwapBack(index, count); 439 } 440 441 /// <summary> 442 /// Removes the element at an index, shifting everything above it down by one. Decrements the length by 1. 443 /// </summary> 444 /// <param name="index">The index of the item to remove.</param> 445 /// <remarks> 446 /// If you don't care about preserving the order of the elements, <see cref="RemoveAtSwapBack(int)"/> is a more efficient way to remove elements. 447 /// </remarks> 448 /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds.</exception> 449 public void RemoveAt(int index) 450 { 451#if ENABLE_UNITY_COLLECTIONS_CHECKS 452 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 453#endif 454 m_ListData->RemoveAt(index); 455 } 456 457 /// <summary> 458 /// Removes *N* elements in a range, shifting everything above the range down by *N*. Decrements the length by *N*. 459 /// </summary> 460 /// <param name="index">The index of the first element to remove.</param> 461 /// <param name="count">The number of elements to remove.</param> 462 /// <remarks> 463 /// If you don't care about preserving the order of the elements, `RemoveRangeSwapBackWithBeginEnd` 464 /// is a more efficient way to remove elements. 465 /// </remarks> 466 /// <exception cref="ArgumentOutOfRangeException">Thrown if `index` is out of bounds, `count` is negative, 467 /// or `index + count` exceeds the length.</exception> 468 public void RemoveRange(int index, int count) 469 { 470#if ENABLE_UNITY_COLLECTIONS_CHECKS 471 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 472#endif 473 m_ListData->RemoveRange(index, count); 474 } 475 476 /// <summary> 477 /// Whether this list is empty. 478 /// </summary> 479 /// <value>True if the list is empty or if the list has not been constructed.</value> 480 public readonly bool IsEmpty 481 { 482 [MethodImpl(MethodImplOptions.AggressiveInlining)] 483 get => m_ListData == null || m_ListData->Length == 0; 484 } 485 486 /// <summary> 487 /// Whether this list has been allocated (and not yet deallocated). 488 /// </summary> 489 /// <value>True if this list has been allocated (and not yet deallocated).</value> 490 public readonly bool IsCreated 491 { 492 [MethodImpl(MethodImplOptions.AggressiveInlining)] 493 get => m_ListData != null; 494 } 495 496 /// <summary> 497 /// Releases all resources (memory and safety handles). 498 /// </summary> 499 public void Dispose() 500 { 501#if ENABLE_UNITY_COLLECTIONS_CHECKS 502 if (!AtomicSafetyHandle.IsDefaultValue(m_Safety)) 503 { 504 AtomicSafetyHandle.CheckExistsAndThrow(m_Safety); 505 } 506#endif 507 if (!IsCreated) 508 { 509 return; 510 } 511 512#if ENABLE_UNITY_COLLECTIONS_CHECKS 513 CollectionHelper.DisposeSafetyHandle(ref m_Safety); 514#endif 515 UnsafeList<T>.Destroy(m_ListData); 516 m_ListData = null; 517 } 518 519 /// <summary> 520 /// Releases all resources (memory and safety handles). 521 /// <typeparam name="U">The type of allocator.</typeparam> 522 /// <param name="allocator">The allocator that was used to allocate this list.</param> 523 /// </summary> 524 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(AllocatorManager.AllocatorHandle) })] 525 internal void Dispose<U>(ref U allocator) where U : unmanaged, AllocatorManager.IAllocator 526 { 527#if ENABLE_UNITY_COLLECTIONS_CHECKS 528 if (!AtomicSafetyHandle.IsDefaultValue(m_Safety)) 529 { 530 AtomicSafetyHandle.CheckExistsAndThrow(m_Safety); 531 } 532#endif 533 if (!IsCreated) 534 { 535 return; 536 } 537 538 CheckHandleMatches(allocator.Handle); 539#if ENABLE_UNITY_COLLECTIONS_CHECKS 540 CollectionHelper.DisposeSafetyHandle(ref m_Safety); 541#endif 542 UnsafeList<T>.Destroy(m_ListData, ref allocator); 543 m_ListData = null; 544 } 545 546 /// <summary> 547 /// Creates and schedules a job that releases all resources (memory and safety handles) of this list. 548 /// </summary> 549 /// <param name="inputDeps">The dependency for the new job.</param> 550 /// <returns>The handle of the new job. The job depends upon `inputDeps` and releases all resources (memory and safety handles) of this list.</returns> 551 public JobHandle Dispose(JobHandle inputDeps) 552 { 553#if ENABLE_UNITY_COLLECTIONS_CHECKS 554 if (!AtomicSafetyHandle.IsDefaultValue(m_Safety)) 555 { 556 AtomicSafetyHandle.CheckExistsAndThrow(m_Safety); 557 } 558#endif 559 if (!IsCreated) 560 { 561 return inputDeps; 562 } 563 564#if ENABLE_UNITY_COLLECTIONS_CHECKS 565 var jobHandle = new NativeListDisposeJob { Data = new NativeListDispose { m_ListData = (UntypedUnsafeList*)m_ListData, m_Safety = m_Safety } }.Schedule(inputDeps); 566 AtomicSafetyHandle.Release(m_Safety); 567#else 568 var jobHandle = new NativeListDisposeJob { Data = new NativeListDispose { m_ListData = (UntypedUnsafeList*)m_ListData } }.Schedule(inputDeps); 569#endif 570 m_ListData = null; 571 572 return jobHandle; 573 } 574 575 /// <summary> 576 /// Sets the length to 0. 577 /// </summary> 578 /// <remarks>Does not change the capacity.</remarks> 579 public void Clear() 580 { 581#if ENABLE_UNITY_COLLECTIONS_CHECKS 582 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 583#endif 584 m_ListData->Clear(); 585 } 586 587 /// <summary> 588 /// **Obsolete.** Use <see cref="AsArray"/> method to do explicit cast instead. 589 /// </summary> 590 /// <remarks> 591 /// Returns a native array that aliases the content of a list. 592 /// </remarks> 593 /// <param name="nativeList">The list to alias.</param> 594 /// <returns>A native array that aliases the content of the list.</returns> 595 [Obsolete("Implicit cast from `NativeList<T>` to `NativeArray<T>` has been deprecated; Use '.AsArray()' method to do explicit cast instead.", false)] 596 public static implicit operator NativeArray<T>(NativeList<T> nativeList) 597 { 598 return nativeList.AsArray(); 599 } 600 601 /// <summary> 602 /// Returns a native array that aliases the content of this list. 603 /// </summary> 604 /// <returns>A native array that aliases the content of this list.</returns> 605 public NativeArray<T> AsArray() 606 { 607#if ENABLE_UNITY_COLLECTIONS_CHECKS 608 AtomicSafetyHandle.CheckGetSecondaryDataPointerAndThrow(m_Safety); 609 var arraySafety = m_Safety; 610 AtomicSafetyHandle.UseSecondaryVersion(ref arraySafety); 611#endif 612 var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<T>(m_ListData->Ptr, m_ListData->Length, Allocator.None); 613 614#if ENABLE_UNITY_COLLECTIONS_CHECKS 615 NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, arraySafety); 616#endif 617 return array; 618 } 619 620 /// <summary> 621 /// Returns an array that aliases this list. The length of the array is updated when the length of 622 /// this array is updated in a prior job. 623 /// </summary> 624 /// <remarks> 625 /// Useful when a job populates a list that is then used by another job. 626 /// 627 /// If you pass both jobs the same list, you have to complete the first job before you schedule the second: 628 /// otherwise, the second job doesn't see the first job's changes to the list's length. 629 /// 630 /// If instead you pass the second job a deferred array that aliases the list, the array's length is kept in sync with 631 /// the first job's changes to the list's length. Consequently, the first job doesn't have to 632 /// be completed before you can schedule the second: the second job simply has to depend upon the first. 633 /// </remarks> 634 /// <returns>An array that aliases this list and whose length can be specially modified across jobs.</returns> 635 /// <example> 636 /// The following example populates a list with integers in one job and passes that data to a second job as 637 /// a deferred array. If we tried to pass the list directly to the second job, that job would not see any 638 /// modifications made to the list by the first job. To avoid this, we instead pass the second job a deferred array that aliases the list. 639 /// <code> 640 /// using UnityEngine; 641 /// using Unity.Jobs; 642 /// using Unity.Collections; 643 /// 644 /// public class DeferredArraySum : MonoBehaviour 645 ///{ 646 /// public struct Populate : IJob 647 /// { 648 /// public NativeList&lt;int&gt; list; 649 /// 650 /// public void Execute() 651 /// { 652 /// for (int i = list.Length; i &lt; list.Capacity; i++) 653 /// { 654 /// list.Add(i); 655 /// } 656 /// } 657 /// } 658 /// 659 /// // Sums all numbers from deferred. 660 /// public struct Sum : IJob 661 /// { 662 /// [ReadOnly] public NativeArray&lt;int&gt; deferred; 663 /// public NativeArray&lt;int&gt; sum; 664 /// 665 /// public void Execute() 666 /// { 667 /// sum[0] = 0; 668 /// for (int i = 0; i &lt; deferred.Length; i++) 669 /// { 670 /// sum[0] += deferred[i]; 671 /// } 672 /// } 673 /// } 674 /// 675 /// void Start() 676 /// { 677 /// var list = new NativeList&lt;int&gt;(100, Allocator.TempJob); 678 /// var deferred = list.AsDeferredJobArray(), 679 /// var output = new NativeArray&lt;int&gt;(1, Allocator.TempJob); 680 /// 681 /// // The Populate job increases the list's length from 0 to 100. 682 /// var populate = new Populate { list = list }.Schedule(); 683 /// 684 /// // At time of scheduling, the length of the deferred array given to Sum is 0. 685 /// // When Populate increases the list's length, the deferred array's length field in the 686 /// // Sum job is also modified, even though it has already been scheduled. 687 /// var sum = new Sum { deferred = deferred, sum = output }.Schedule(populate); 688 /// 689 /// sum.Complete(); 690 /// 691 /// Debug.Log("Result: " + output[0]); 692 /// 693 /// list.Dispose(); 694 /// output.Dispose(); 695 /// } 696 /// } 697 /// </code> 698 /// </example> 699 public NativeArray<T> AsDeferredJobArray() 700 { 701#if ENABLE_UNITY_COLLECTIONS_CHECKS 702 AtomicSafetyHandle.CheckExistsAndThrow(m_Safety); 703#endif 704 byte* buffer = (byte*)m_ListData; 705 // We use the first bit of the pointer to infer that the array is in list mode 706 // Thus the job scheduling code will need to patch it. 707 buffer += 1; 708 var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<T>(buffer, 0, Allocator.Invalid); 709 710#if ENABLE_UNITY_COLLECTIONS_CHECKS 711 NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, m_Safety); 712#endif 713 714 return array; 715 } 716 717 /// <summary> 718 /// Returns an array containing a copy of this list's content. 719 /// </summary> 720 /// <param name="allocator">The allocator to use.</param> 721 /// <returns>An array containing a copy of this list's content.</returns> 722 public NativeArray<T> ToArray(AllocatorManager.AllocatorHandle allocator) 723 { 724 NativeArray<T> result = CollectionHelper.CreateNativeArray<T>(Length, allocator, NativeArrayOptions.UninitializedMemory); 725#if ENABLE_UNITY_COLLECTIONS_CHECKS 726 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 727 AtomicSafetyHandle.CheckWriteAndThrow(result.m_Safety); 728#endif 729 UnsafeUtility.MemCpy((byte*)result.m_Buffer, (byte*)m_ListData->Ptr, Length * UnsafeUtility.SizeOf<T>()); 730 return result; 731 } 732 733 /// <summary> 734 /// Copies all elements of specified container to this container. 735 /// </summary> 736 /// <param name="other">An container to copy into this container.</param> 737 public void CopyFrom(in NativeArray<T> other) 738 { 739#if ENABLE_UNITY_COLLECTIONS_CHECKS 740 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 741 AtomicSafetyHandle.CheckReadAndThrow(other.m_Safety); 742#endif 743 m_ListData->CopyFrom(other); 744 } 745 746 /// <summary> 747 /// Copies all elements of specified container to this container. 748 /// </summary> 749 /// <param name="other">An container to copy into this container.</param> 750 public void CopyFrom(in UnsafeList<T> other) 751 { 752#if ENABLE_UNITY_COLLECTIONS_CHECKS 753 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 754#endif 755 m_ListData->CopyFrom(other); 756 } 757 758 /// <summary> 759 /// Copies all elements of specified container to this container. 760 /// </summary> 761 /// <param name="other">An container to copy into this container.</param> 762 public void CopyFrom(in NativeList<T> other) 763 { 764 CopyFrom(*other.m_ListData); 765 } 766 767 /// <summary> 768 /// Returns an enumerator over the elements of this list. 769 /// </summary> 770 /// <returns>An enumerator over the elements of this list.</returns> 771 public NativeArray<T>.Enumerator GetEnumerator() 772 { 773 var array = AsArray(); 774 return new NativeArray<T>.Enumerator(ref array); 775 } 776 777 /// <summary> 778 /// This method is not implemented. Use <see cref="GetEnumerator"/> instead. 779 /// </summary> 780 /// <returns>Throws NotImplementedException.</returns> 781 /// <exception cref="NotImplementedException">Method is not implemented.</exception> 782 IEnumerator IEnumerable.GetEnumerator() 783 { 784 throw new NotImplementedException(); 785 } 786 787 /// <summary> 788 /// This method is not implemented. Use <see cref="GetEnumerator"/> instead. 789 /// </summary> 790 /// <returns>Throws NotImplementedException.</returns> 791 /// <exception cref="NotImplementedException">Method is not implemented.</exception> 792 IEnumerator<T> IEnumerable<T>.GetEnumerator() 793 { 794 throw new NotImplementedException(); 795 } 796 797 /// <summary> 798 /// Sets the length of this list, increasing the capacity if necessary. 799 /// </summary> 800 /// <param name="length">The new length of this list.</param> 801 /// <param name="options">Whether to clear any newly allocated bytes to all zeroes.</param> 802 public void Resize(int length, NativeArrayOptions options) 803 { 804#if ENABLE_UNITY_COLLECTIONS_CHECKS 805 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 806#endif 807 m_ListData->Resize(length, options); 808 } 809 810 /// <summary> 811 /// Sets the length of this list, increasing the capacity if necessary. 812 /// </summary> 813 /// <remarks>Does not clear newly allocated bytes.</remarks> 814 /// <param name="length">The new length of this list.</param> 815 public void ResizeUninitialized(int length) 816 { 817 Resize(length, NativeArrayOptions.UninitializedMemory); 818 } 819 820 /// <summary> 821 /// Sets the capacity. 822 /// </summary> 823 /// <param name="capacity">The new capacity.</param> 824 public void SetCapacity(int capacity) 825 { 826 m_ListData->SetCapacity(capacity); 827 } 828 829 /// <summary> 830 /// Sets the capacity to match the length. 831 /// </summary> 832 public void TrimExcess() 833 { 834 m_ListData->TrimExcess(); 835 } 836 837 /// <summary> 838 /// Returns a read only of this list. 839 /// </summary> 840 /// <returns>A read only of this list.</returns> 841 public NativeArray<T>.ReadOnly AsReadOnly() 842 { 843#if ENABLE_UNITY_COLLECTIONS_CHECKS 844 return new NativeArray<T>.ReadOnly(m_ListData->Ptr, m_ListData->Length, ref m_Safety); 845#else 846 return new NativeArray<T>.ReadOnly(m_ListData->Ptr, m_ListData->Length); 847#endif 848 } 849 850 /// <summary> 851 /// Returns a parallel reader of this list. 852 /// </summary> 853 /// <returns>A parallel reader of this list.</returns> 854// [Obsolete("'AsParallelReader' has been deprecated; use 'AsReadOnly' instead. (UnityUpgradable) -> AsReadOnly")] 855 public NativeArray<T>.ReadOnly AsParallelReader() 856 { 857#if ENABLE_UNITY_COLLECTIONS_CHECKS 858 return new NativeArray<T>.ReadOnly(m_ListData->Ptr, m_ListData->Length, ref m_Safety); 859#else 860 return new NativeArray<T>.ReadOnly(m_ListData->Ptr, m_ListData->Length); 861#endif 862 } 863 864 /// <summary> 865 /// Returns a parallel writer of this list. 866 /// </summary> 867 /// <returns>A parallel writer of this list.</returns> 868 public ParallelWriter AsParallelWriter() 869 { 870#if ENABLE_UNITY_COLLECTIONS_CHECKS 871 return new ParallelWriter(m_ListData, ref m_Safety); 872#else 873 return new ParallelWriter(m_ListData); 874#endif 875 } 876 877 /// <summary> 878 /// A parallel writer for a NativeList. 879 /// </summary> 880 /// <remarks> 881 /// Use <see cref="AsParallelWriter"/> to create a parallel writer for a list. 882 /// </remarks> 883 [NativeContainer] 884 [NativeContainerIsAtomicWriteOnly] 885 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 886 public unsafe struct ParallelWriter 887 { 888 /// <summary> 889 /// The data of the list. 890 /// </summary> 891 public readonly void* Ptr 892 { 893 [MethodImpl(MethodImplOptions.AggressiveInlining)] 894 get => ListData->Ptr; 895 } 896 897 /// <summary> 898 /// The internal unsafe list. 899 /// </summary> 900 /// <value>The internal unsafe list.</value> 901 [NativeDisableUnsafePtrRestriction] 902 public UnsafeList<T>* ListData; 903 904#if ENABLE_UNITY_COLLECTIONS_CHECKS 905 internal AtomicSafetyHandle m_Safety; 906 internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<ParallelWriter>(); 907 908 [GenerateTestsForBurstCompatibility(CompileTarget = GenerateTestsForBurstCompatibilityAttribute.BurstCompatibleCompileTarget.Editor)] 909 internal unsafe ParallelWriter(UnsafeList<T>* listData, ref AtomicSafetyHandle safety) 910 { 911 ListData = listData; 912 m_Safety = safety; 913 CollectionHelper.SetStaticSafetyId<ParallelWriter>(ref m_Safety, ref s_staticSafetyId.Data); 914 } 915#else 916 internal unsafe ParallelWriter(UnsafeList<T>* listData) 917 { 918 ListData = listData; 919 } 920#endif 921 922 /// <summary> 923 /// Appends an element to the end of this list. 924 /// </summary> 925 /// <param name="value">The value to add to the end of this list.</param> 926 /// <remarks> 927 /// Increments the length by 1 unless doing so would exceed the current capacity. 928 /// </remarks> 929 /// <exception cref="InvalidOperationException">Thrown if adding an element would exceed the capacity.</exception> 930 public void AddNoResize(T value) 931 { 932#if ENABLE_UNITY_COLLECTIONS_CHECKS 933 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 934#endif 935 var idx = Interlocked.Increment(ref ListData->m_length) - 1; 936 CheckSufficientCapacity(ListData->Capacity, idx + 1); 937 938 UnsafeUtility.WriteArrayElement(ListData->Ptr, idx, value); 939 } 940 941 /// <summary> 942 /// Appends elements from a buffer to the end of this list. 943 /// </summary> 944 /// <param name="ptr">The buffer to copy from.</param> 945 /// <param name="count">The number of elements to copy from the buffer.</param> 946 /// <remarks> 947 /// Increments the length by `count` unless doing so would exceed the current capacity. 948 /// </remarks> 949 /// <exception cref="InvalidOperationException">Thrown if adding the elements would exceed the capacity.</exception> 950 public void AddRangeNoResize(void* ptr, int count) 951 { 952 CheckArgPositive(count); 953 954#if ENABLE_UNITY_COLLECTIONS_CHECKS 955 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 956#endif 957 var idx = Interlocked.Add(ref ListData->m_length, count) - count; 958 CheckSufficientCapacity(ListData->Capacity, idx + count); 959 960 var sizeOf = sizeof(T); 961 void* dst = (byte*)ListData->Ptr + idx * sizeOf; 962 UnsafeUtility.MemCpy(dst, ptr, count * sizeOf); 963 } 964 965 /// <summary> 966 /// Appends the elements of another list to the end of this list. 967 /// </summary> 968 /// <param name="list">The other list to copy from.</param> 969 /// <remarks> 970 /// Increments the length of this list by the length of the other list unless doing so would exceed the current capacity. 971 /// </remarks> 972 /// <exception cref="InvalidOperationException">Thrown if adding the elements would exceed the capacity.</exception> 973 public void AddRangeNoResize(UnsafeList<T> list) 974 { 975 AddRangeNoResize(list.Ptr, list.Length); 976 } 977 978 /// <summary> 979 /// Appends the elements of another list to the end of this list. 980 /// </summary> 981 /// <param name="list">The other list to copy from.</param> 982 /// <remarks> 983 /// Increments the length of this list by the length of the other list unless doing so would exceed the current capacity. 984 /// </remarks> 985 /// <exception cref="InvalidOperationException">Thrown if adding the elements would exceed the capacity.</exception> 986 public void AddRangeNoResize(NativeList<T> list) 987 { 988 AddRangeNoResize(*list.m_ListData); 989 } 990 } 991 992 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 993 static void CheckInitialCapacity(int initialCapacity) 994 { 995 if (initialCapacity < 0) 996 throw new ArgumentOutOfRangeException(nameof(initialCapacity), "Capacity must be >= 0"); 997 } 998 999 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 1000 static void CheckTotalSize(int initialCapacity, long totalSize) 1001 { 1002 // Make sure we cannot allocate more than int.MaxValue (2,147,483,647 bytes) 1003 // because the underlying UnsafeUtility.Malloc is expecting a int. 1004 // TODO: change UnsafeUtility.Malloc to accept a UIntPtr length instead to match C++ API 1005 if (totalSize > int.MaxValue) 1006 throw new ArgumentOutOfRangeException(nameof(initialCapacity), $"Capacity * sizeof(T) cannot exceed {int.MaxValue} bytes"); 1007 } 1008 1009 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 1010 static void CheckSufficientCapacity(int capacity, int length) 1011 { 1012 if (capacity < length) 1013 throw new InvalidOperationException($"Length {length} exceeds Capacity {capacity}"); 1014 } 1015 1016 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 1017 static void CheckIndexInRange(int value, int length) 1018 { 1019 if (value < 0) 1020 throw new IndexOutOfRangeException($"Value {value} must be positive."); 1021 1022 if ((uint)value >= (uint)length) 1023 throw new IndexOutOfRangeException( 1024 $"Value {value} is out of range in NativeList of '{length}' Length."); 1025 } 1026 1027 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 1028 static void CheckArgPositive(int value) 1029 { 1030 if (value < 0) 1031 throw new ArgumentOutOfRangeException($"Value {value} must be positive."); 1032 } 1033 1034 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 1035 void CheckHandleMatches(AllocatorManager.AllocatorHandle handle) 1036 { 1037 if(m_ListData == null) 1038 throw new ArgumentOutOfRangeException($"Allocator handle {handle} can't match because container is not initialized."); 1039 if(m_ListData->Allocator.Index != handle.Index) 1040 throw new ArgumentOutOfRangeException($"Allocator handle {handle} can't match because container handle index doesn't match."); 1041 if(m_ListData->Allocator.Version != handle.Version) 1042 throw new ArgumentOutOfRangeException($"Allocator handle {handle} matches container handle index, but has different version."); 1043 } 1044 } 1045 1046 [NativeContainer] 1047 [GenerateTestsForBurstCompatibility] 1048 internal unsafe struct NativeListDispose 1049 { 1050 [NativeDisableUnsafePtrRestriction] 1051 public UntypedUnsafeList* m_ListData; 1052 1053#if ENABLE_UNITY_COLLECTIONS_CHECKS 1054 internal AtomicSafetyHandle m_Safety; 1055#endif 1056 1057 public void Dispose() 1058 { 1059 var listData = (UnsafeList<int>*)m_ListData; 1060 UnsafeList<int>.Destroy(listData); 1061 } 1062 } 1063 1064 [BurstCompile] 1065 [GenerateTestsForBurstCompatibility] 1066 internal unsafe struct NativeListDisposeJob : IJob 1067 { 1068 internal NativeListDispose Data; 1069 1070 public void Execute() 1071 { 1072 Data.Dispose(); 1073 } 1074 } 1075 1076 sealed unsafe class NativeListDebugView<T> where T : unmanaged 1077 { 1078 UnsafeList<T>* Data; 1079 1080 public NativeListDebugView(NativeList<T> array) 1081 { 1082 Data = array.m_ListData; 1083 } 1084 1085 public T[] Items 1086 { 1087 get 1088 { 1089 if (Data == null) 1090 { 1091 return default; 1092 } 1093 1094 // Trying to avoid safety checks, so that container can be read in debugger if it's safety handle 1095 // is in write-only mode. 1096 var length = Data->Length; 1097 var dst = new T[length]; 1098 1099 fixed (T* pDst = &dst[0]) 1100 { 1101 UnsafeUtility.MemCpy(pDst, Data->Ptr, length * UnsafeUtility.SizeOf<T>()); 1102 } 1103 1104 return dst; 1105 } 1106 } 1107 } 1108 1109 /// <summary> 1110 /// Provides extension methods for UnsafeList. 1111 /// </summary> 1112 [GenerateTestsForBurstCompatibility] 1113 public unsafe static class NativeListExtensions 1114 { 1115 /// <summary> 1116 /// Returns true if a particular value is present in this list. 1117 /// </summary> 1118 /// <typeparam name="T">The type of elements in this list.</typeparam> 1119 /// <typeparam name="U">The value type.</typeparam> 1120 /// <param name="list">The list to search.</param> 1121 /// <param name="value">The value to locate.</param> 1122 /// <returns>True if the value is present in this list.</returns> 1123 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(int) })] 1124 public static bool Contains<T, U>(this NativeList<T> list, U value) 1125 where T : unmanaged, IEquatable<U> 1126 { 1127 return NativeArrayExtensions.IndexOf<T, U>(list.GetUnsafeReadOnlyPtr(), list.Length, value) != -1; 1128 } 1129 1130 /// <summary> 1131 /// Finds the index of the first occurrence of a particular value in this list. 1132 /// </summary> 1133 /// <typeparam name="T">The type of elements in the list.</typeparam> 1134 /// <typeparam name="U">The value type.</typeparam> 1135 /// <param name="list">The list to search.</param> 1136 /// <param name="value">The value to locate.</param> 1137 /// <returns>The index of the first occurrence of the value in this list. Returns -1 if no occurrence is found.</returns> 1138 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int), typeof(int) })] 1139 public static int IndexOf<T, U>(this NativeList<T> list, U value) 1140 where T : unmanaged, IEquatable<U> 1141 { 1142 return NativeArrayExtensions.IndexOf<T, U>(list.GetUnsafeReadOnlyPtr(), list.Length, value); 1143 } 1144 1145 /// <summary> 1146 /// Returns true if this container and another have equal length and content. 1147 /// </summary> 1148 /// <typeparam name="T">The type of the source container's elements.</typeparam> 1149 /// <param name="container">The container to compare for equality.</param> 1150 /// <param name="other">The other container to compare for equality.</param> 1151 /// <returns>True if the containers have equal length and content.</returns> 1152 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })] 1153 public static bool ArraysEqual<T>(this NativeArray<T> container, in NativeList<T> other) 1154 where T : unmanaged, IEquatable<T> 1155 { 1156 return container.ArraysEqual(other.AsArray()); 1157 } 1158 1159 /// <summary> 1160 /// Returns true if this container and another have equal length and content. 1161 /// </summary> 1162 /// <typeparam name="T">The type of the source container's elements.</typeparam> 1163 /// <param name="container">The container to compare for equality.</param> 1164 /// <param name="other">The other container to compare for equality.</param> 1165 /// <returns>True if the containers have equal length and content.</returns> 1166 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })] 1167 public static bool ArraysEqual<T>(this NativeList<T> container, in NativeArray<T> other) 1168 where T : unmanaged, IEquatable<T> 1169 { 1170 return other.ArraysEqual(container); 1171 } 1172 1173 /// <summary> 1174 /// Returns true if this container and another have equal length and content. 1175 /// </summary> 1176 /// <typeparam name="T">The type of the source container's elements.</typeparam> 1177 /// <param name="container">The container to compare for equality.</param> 1178 /// <param name="other">The other container to compare for equality.</param> 1179 /// <returns>True if the containers have equal length and content.</returns> 1180 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })] 1181 public static bool ArraysEqual<T>(this NativeList<T> container, in NativeList<T> other) 1182 where T : unmanaged, IEquatable<T> 1183 { 1184 return container.AsArray().ArraysEqual(other.AsArray()); 1185 } 1186 1187 /// <summary> 1188 /// Returns true if this container and another have equal length and content. 1189 /// </summary> 1190 /// <typeparam name="T">The type of the source container's elements.</typeparam> 1191 /// <param name="container">The container to compare for equality.</param> 1192 /// <param name="other">The other container to compare for equality.</param> 1193 /// <returns>True if the containers have equal length and content.</returns> 1194 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })] 1195 public static bool ArraysEqual<T>(this NativeList<T> container, in UnsafeList<T> other) 1196 where T : unmanaged, IEquatable<T> 1197 { 1198#if ENABLE_UNITY_COLLECTIONS_CHECKS 1199 AtomicSafetyHandle.CheckReadAndThrow(container.m_Safety); 1200#endif 1201 return container.m_ListData->ArraysEqual(other); 1202 } 1203 } 1204} 1205 1206namespace Unity.Collections.LowLevel.Unsafe 1207{ 1208 /// <summary> 1209 /// Provides unsafe utility methods for NativeList. 1210 /// </summary> 1211 [GenerateTestsForBurstCompatibility] 1212 public unsafe static class NativeListUnsafeUtility 1213 { 1214 /// <summary> 1215 /// Returns a pointer to this list's internal buffer. 1216 /// </summary> 1217 /// <remarks>Performs a job safety check for read-write access.</remarks> 1218 /// <param name="list">The list.</param> 1219 /// <typeparam name="T">The type of the elements.</typeparam> 1220 /// <returns>A pointer to this list's internal buffer.</returns> 1221 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 1222 public static T* GetUnsafePtr<T>(this NativeList<T> list) where T : unmanaged 1223 { 1224#if ENABLE_UNITY_COLLECTIONS_CHECKS 1225 AtomicSafetyHandle.CheckWriteAndThrow(list.m_Safety); 1226#endif 1227 return list.m_ListData->Ptr; 1228 } 1229 1230 /// <summary> 1231 /// Returns a pointer to this list's internal buffer. 1232 /// </summary> 1233 /// <remarks>Performs a job safety check for read-only access.</remarks> 1234 /// <param name="list">The list.</param> 1235 /// <typeparam name="T">The type of the elements.</typeparam> 1236 /// <returns>A pointer to this list's internal buffer.</returns> 1237 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 1238 public static unsafe T* GetUnsafeReadOnlyPtr<T>(this NativeList<T> list) where T : unmanaged 1239 { 1240#if ENABLE_UNITY_COLLECTIONS_CHECKS 1241 AtomicSafetyHandle.CheckReadAndThrow(list.m_Safety); 1242#endif 1243 return list.m_ListData->Ptr; 1244 } 1245 1246#if ENABLE_UNITY_COLLECTIONS_CHECKS 1247 /// <summary> 1248 /// Returns this list's <see cref="AtomicSafetyHandle"/>. 1249 /// </summary> 1250 /// <param name="list">The list.</param> 1251 /// <typeparam name="T">The type of the elements.</typeparam> 1252 /// <returns>The atomic safety handle for this list.</returns> 1253 /// <remarks> 1254 /// The job safety checks use a native collection's atomic safety handle to assert safety. 1255 /// 1256 /// This method is only available if the symbol `ENABLE_UNITY_COLLECTIONS_CHECKS` is defined.</remarks> 1257 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) }, RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS", CompileTarget = GenerateTestsForBurstCompatibilityAttribute.BurstCompatibleCompileTarget.Editor)] 1258 public static AtomicSafetyHandle GetAtomicSafetyHandle<T>(ref NativeList<T> list) where T : unmanaged 1259 { 1260 return list.m_Safety; 1261 } 1262 1263#endif 1264 1265 /// <summary> 1266 /// Returns a pointer to this list's internal unsafe list. 1267 /// </summary> 1268 /// <remarks>Performs no job safety checks.</remarks> 1269 /// <param name="list">The list.</param> 1270 /// <typeparam name="T">The type of the elements.</typeparam> 1271 /// <returns>A pointer to this list's internal unsafe list.</returns> 1272 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 1273 public static void* GetInternalListDataPtrUnchecked<T>(ref NativeList<T> list) where T : unmanaged 1274 { 1275 return list.m_ListData; 1276 } 1277 } 1278}