< Summary

Class:GDX.Collections.UnsafeSparseSetDebugView
Assembly:GDX
File(s):./Packages/com.dotbunny.gdx/GDX/Collections/UnsafeSparseSet.cs
Covered lines:0
Uncovered lines:12
Coverable lines:12
Total lines:1242
Line coverage:0% (0 of 12)
Covered branches:0
Total branches:0
Covered methods:0
Total methods:2
Method coverage:0% (0 of 2)

Coverage History

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
UnsafeSparseSetDebugView(...)0%2100%

File(s)

./Packages/com.dotbunny.gdx/GDX/Collections/UnsafeSparseSet.cs

#LineLine coverage
 1#if GDX_UNSAFE_COLLECTIONS
 2// Copyright (c) 2020-2024 dotBunny Inc.
 3// dotBunny licenses this file to you under the BSL-1.0 license.
 4// See the LICENSE file in the project root for more information.
 5
 6using System.Runtime.CompilerServices;
 7using Unity.Collections;
 8using Unity.Collections.LowLevel.Unsafe;
 9using Unity.Jobs;
 10using Unity.Jobs.LowLevel.Unsafe;
 11using System.Diagnostics;
 12using System.Runtime.InteropServices;
 13using Unity.Burst;
 14
 15namespace GDX.Collections
 16{
 17    /// <summary>
 18    ///     An adapter collection for external data arrays that allows constant-time insertion, deletion, and lookup by
 19    ///     handle, as well as array-like iteration.
 20    /// </summary>
 21    [DebuggerDisplay("Count = {Count}, Length = {Length}, IsCreated = {IsCreated}, IsEmpty = {IsEmpty}")]
 22    [DebuggerTypeProxy(typeof(UnsafeSparseSetDebugView))]
 23    [StructLayout(LayoutKind.Sequential)]
 24    [BurstCompatible(GenericTypeArguments = new[] { typeof(int) })]
 25    public unsafe struct UnsafeSparseSet : INativeDisposable
 26    {
 27        public const int MinimumCapacity = JobsUtility.CacheLineSize / (sizeof(int) * 2);
 28
 29        [NativeDisableUnsafePtrRestriction]
 30        public void* Data;
 31        /// <summary>
 32        ///     Holds references to the sparse array for swapping indices.
 33        /// </summary>
 34        public int* DenseArray
 35        {
 36            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 37            get => (int*)Data + Length;
 38        }
 39
 40        /// <summary>
 41        ///     Holds references to dense array indices.
 42        /// </summary>
 43        /// <remarks>
 44        ///     Its own indices are claimed and freed via a free-list.
 45        /// </remarks>
 46        public int* SparseArray
 47        {
 48            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 49            get => (int*)Data;
 50        }
 51
 52        /// <summary>
 53        ///     How many indices are being used currently?
 54        /// </summary>
 55        public int Count;
 56
 57        /// <summary>
 58        ///     The first free (currently unused) index in the sparse array.
 59        /// </summary>
 60        public int FreeIndex;
 61
 62        /// <summary>
 63        ///     The current capacity of both the sparse and dense arrays.
 64        /// </summary>
 65        public int Length;
 66
 67        public AllocatorManager.AllocatorHandle Allocator;
 68
 69        /// <summary>
 70        /// Whether this Sparse Set has been allocated (and not yet deallocated).
 71        /// </summary>
 72        /// <value>True if this list has been allocated (and not yet deallocated).</value>
 73        public bool IsCreated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Data != null; } }
 74
 75        /// <summary>
 76        /// Whether the Sparse Set is empty.
 77        /// </summary>
 78        /// <value>True if the Sparse Set is empty or has not been constructed.</value>
 79        public bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return !IsCreated || Length == 0;
 80
 81        /// <summary>
 82        ///     Create an <see cref="UnsafeSparseSet" /> with an <paramref name="initialCapacity" />.
 83        /// </summary>
 84        /// <param name="initialCapacity">The initial capacity of the sparse and dense int arrays.</param>
 85        /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle" /> type to use.</param>
 86        public UnsafeSparseSet(int initialCapacity, AllocatorManager.AllocatorHandle allocator)
 87        {
 88            initialCapacity = initialCapacity > MinimumCapacity ? initialCapacity : MinimumCapacity;
 89            --initialCapacity;
 90            initialCapacity |= initialCapacity >> 1;
 91            initialCapacity |= initialCapacity >> 2;
 92            initialCapacity |= initialCapacity >> 4;
 93            initialCapacity |= initialCapacity >> 8;
 94            initialCapacity |= initialCapacity >> 16;
 95            ++initialCapacity;
 96
 97            Data = allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, initialCapacity * 2);
 98            Count = 0;
 99            FreeIndex = 0;
 100            Length = initialCapacity;
 101            Allocator = allocator;
 102
 103            for (int i = 0; i < initialCapacity; i++)
 104            {
 105                DenseArray[i] = -1;
 106                SparseArray[i] = i + 1;
 107            }
 108        }
 109
 110        /// <summary>
 111        ///     Create an <see cref="UnsafeSparseSet" /> with an <paramref name="initialCapacity" />.
 112        /// </summary>
 113        /// <param name="initialCapacity">The initial capacity of the sparse and dense int arrays.</param>
 114        /// <param name="allocator">The <see cref="Unity.Collections.Allocator" /> type to use.</param>
 115        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 116        public UnsafeSparseSet(int initialCapacity, AllocatorManager.AllocatorHandle allocator, out ulong* versionArray)
 117        {
 118            initialCapacity = initialCapacity > MinimumCapacity ? initialCapacity : MinimumCapacity;
 119            --initialCapacity;
 120            initialCapacity |= initialCapacity >> 1;
 121            initialCapacity |= initialCapacity >> 2;
 122            initialCapacity |= initialCapacity >> 4;
 123            initialCapacity |= initialCapacity >> 8;
 124            initialCapacity |= initialCapacity >> 16;
 125            ++initialCapacity;
 126
 127            Data = allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, initialCapacity * 2);
 128            Count = 0;
 129            FreeIndex = 0;
 130            Length = initialCapacity;
 131            Allocator = allocator;
 132            versionArray = (ulong*)allocator.Allocate(sizeof(ulong), JobsUtility.CacheLineSize, initialCapacity);
 133
 134            for (int i = 0; i < initialCapacity; i++)
 135            {
 136                DenseArray[i] = -1;
 137                SparseArray[i] = i + 1;
 138                versionArray[i] = 1;
 139            }
 140        }
 141
 142        /// <summary>
 143        ///     Adds a sparse/dense index pair to the set and expands the arrays if necessary.
 144        /// </summary>
 145        /// <param name="expandBy">How many indices to expand by.</param>
 146        /// <param name="sparseIndex">The sparse index allocated.</param>
 147        /// <param name="denseIndex">The dense index allocated.</param>
 148        /// <returns>True if the index pool expanded.</returns>
 149        public bool AddWithExpandCheck(int expandBy, out int sparseIndex, out int denseIndex)
 150        {
 151            int indexToClaim = FreeIndex;
 152            int currentCapacity = Length;
 153            bool needsExpansion = false;
 154
 155            if (indexToClaim >= currentCapacity)
 156            {
 157                // We're out of space, the last free index points to nothing. Allocate more indices.
 158                needsExpansion = true;
 159
 160                int newCapacity = currentCapacity + expandBy;
 161
 162                newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 163                --newCapacity;
 164                newCapacity |= newCapacity >> 1;
 165                newCapacity |= newCapacity >> 2;
 166                newCapacity |= newCapacity >> 4;
 167                newCapacity |= newCapacity >> 8;
 168                newCapacity |= newCapacity >> 16;
 169                ++newCapacity;
 170
 171                void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 172
 173                UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 174                int* newSparseArray = (int*)newData;
 175                for (int i = currentCapacity; i < newCapacity; i++)
 176                {
 177                    newSparseArray[i] = i + 1;
 178                }
 179
 180                int* newDenseArray = newSparseArray + newCapacity;
 181                UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 182                for (int i = currentCapacity; i < newCapacity; i++)
 183                {
 184                    newDenseArray[i] = -1;
 185                }
 186
 187                Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 188
 189                Data = newData;
 190                Length = newCapacity;
 191            }
 192
 193            int nextFreeIndex = SparseArray[indexToClaim];
 194            DenseArray[Count] = indexToClaim; // Point the next dense id at our newly claimed sparse index.
 195            SparseArray[indexToClaim] = Count; // Point our newly claimed sparse index at the dense index.
 196            denseIndex = Count;
 197
 198            ++Count;
 199            FreeIndex = nextFreeIndex; // Set the free list head for next time.
 200
 201            sparseIndex = indexToClaim;
 202            return needsExpansion;
 203        }
 204
 205        /// <summary>
 206        ///     Adds a sparse/dense index pair to the set and expands the arrays if necessary.
 207        /// </summary>
 208        /// <param name="expandBy">How many indices to expand by.</param>
 209        /// <param name="sparseIndex">The sparse index allocated.</param>
 210        /// <param name="denseIndex">The dense index allocated.</param>
 211        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 212        /// <returns>True if the index pool expanded.</returns>
 213        public bool AddWithExpandCheck(int expandBy, out int sparseIndex, out int denseIndex, ref ulong* versionArray)
 214        {
 215            int indexToClaim = FreeIndex;
 216            int currentCapacity = Length;
 217            bool needsExpansion = false;
 218
 219            if (indexToClaim >= currentCapacity)
 220            {
 221                // We're out of space, the last free index points to nothing. Allocate more indices.
 222                needsExpansion = true;
 223
 224                int newCapacity = currentCapacity + expandBy;
 225
 226                newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 227                --newCapacity;
 228                newCapacity |= newCapacity >> 1;
 229                newCapacity |= newCapacity >> 2;
 230                newCapacity |= newCapacity >> 4;
 231                newCapacity |= newCapacity >> 8;
 232                newCapacity |= newCapacity >> 16;
 233                ++newCapacity;
 234
 235                void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 236
 237                UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 238                int* newSparseArray = (int*)newData;
 239                for (int i = currentCapacity; i < newCapacity; i++)
 240                {
 241                    newSparseArray[i] = i + 1;
 242                }
 243
 244                int* newDenseArray = newSparseArray + newCapacity;
 245                UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 246                for (int i = currentCapacity; i < newCapacity; i++)
 247                {
 248                    newDenseArray[i] = -1;
 249                }
 250
 251                ulong* newVersionArray =
 252                                                                                                                        
 253                UnsafeUtility.MemCpy(newVersionArray, versionArray, sizeof(ulong) * currentCapacity);
 254                for (int i = currentCapacity; i < newCapacity; i++)
 255                {
 256                    newVersionArray[i] = 1;
 257                }
 258
 259                Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 260                Allocator.Free(versionArray, sizeof(ulong), JobsUtility.CacheLineSize, currentCapacity);
 261                versionArray = newVersionArray;
 262
 263                Data = newData;
 264                Length = newCapacity;
 265            }
 266
 267            int nextFreeIndex = SparseArray[indexToClaim];
 268            DenseArray[Count] = indexToClaim; // Point the next dense id at our newly claimed sparse index.
 269            SparseArray[indexToClaim] = Count; // Point our newly claimed sparse index at the dense index.
 270            denseIndex = Count;
 271
 272            ++Count;
 273            FreeIndex = nextFreeIndex; // Set the free list head for next time.
 274
 275            sparseIndex = indexToClaim;
 276            return needsExpansion;
 277        }
 278
 279        /// <summary>
 280        ///     Adds a sparse/dense index pair to the set without checking if the set needs to expand.
 281        /// </summary>
 282        /// <param name="sparseIndex">The sparse index allocated.</param>
 283        /// <param name="denseIndex">The dense index allocated.</param>
 284        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 285        public void AddUnchecked(out int sparseIndex, out int denseIndex)
 286        {
 287            int indexToClaim = FreeIndex;
 288            int nextFreeIndex = SparseArray[indexToClaim];
 289            DenseArray[Count] = indexToClaim; // Point the next dense id at our newly claimed sparse index.
 290            SparseArray[indexToClaim] = Count; // Point our newly claimed sparse index at the dense index.
 291
 292            sparseIndex = indexToClaim;
 293            denseIndex = Count;
 294            ++Count;
 295            FreeIndex = nextFreeIndex; // Set the free list head for next time.
 296        }
 297
 298        /// <summary>
 299        ///     Adds a sparse/dense index pair to the set without checking if the set needs to expand.
 300        /// </summary>
 301        /// <param name="sparseIndex">The sparse index allocated.</param>
 302        /// <param name="denseIndex">The dense index allocated.</param>
 303        /// <param name="versionArray">The array containing the version number to check against.</param>
 304        /// <param name="version">Enables detection of use-after-free errors when using the sparse index as a reference.
 305        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 306        public void AddUnchecked(out int sparseIndex, out int denseIndex, ulong* versionArray, out ulong version)
 307        {
 308            int indexToClaim = FreeIndex;
 309            int nextFreeIndex = SparseArray[indexToClaim];
 310            DenseArray[Count] = indexToClaim; // Point the next dense id at our newly claimed sparse index.
 311            SparseArray[indexToClaim] = Count; // Point our newly claimed sparse index at the dense index.
 312
 313            version = versionArray[indexToClaim];
 314            sparseIndex = indexToClaim;
 315            denseIndex = Count;
 316
 317            ++Count;
 318            FreeIndex = nextFreeIndex; // Set the free list head for next time.
 319        }
 320
 321        /// <summary>
 322        ///     Gets the value of the sparse array at the given index without any data validation.
 323        /// </summary>
 324        /// <param name="sparseIndex">The index to check in the sparse array.</param>
 325        /// <returns>The dense index at the given sparse index.</returns>
 326        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 327        public int GetDenseIndexUnchecked(int sparseIndex)
 328        {
 329            return SparseArray[sparseIndex];
 330        }
 331
 332        /// <summary>
 333        ///     Gets the value of the sparse array at the given index,
 334        ///     or -1 if the dense and sparse indices don't point to each other or if the dense index is outside the den
 335        /// </summary>
 336        /// <param name="sparseIndex">The index in the sparse array to check against.</param>
 337        /// <returns>The dense index pointed to by the current sparse index, or -1 if invalid.</returns>
 338        public int GetDenseIndexWithBoundsCheck(int sparseIndex)
 339        {
 340            if (sparseIndex >= 0 && sparseIndex < Length)
 341            {
 342                int denseIndex = SparseArray[sparseIndex];
 343
 344                if (denseIndex < Count && denseIndex >= 0)
 345                {
 346                    int sparseIndexAtDenseIndex = DenseArray[denseIndex];
 347
 348                    if (sparseIndex == sparseIndexAtDenseIndex)
 349                    {
 350                        return denseIndex;
 351                    }
 352                }
 353            }
 354
 355            return -1;
 356        }
 357
 358        /// <summary>
 359        ///     Gets the value of the sparse array at the given index,
 360        ///     or -1 if the version number does not match.
 361        /// </summary>
 362        /// <param name="sparseIndex">The index in the sparse array to check against.</param>
 363        /// <param name="version">The version number associated with the sparse index.</param>
 364        /// <param name="versionArray">The array containing the version number to check against.</param>
 365        /// <returns>The dense index pointed to by the current sparse index, or -1 if invalid.</returns>
 366        public int GetDenseIndexWithVersionCheck(int sparseIndex, ulong version, ulong* versionArray)
 367        {
 368            int denseIndex = SparseArray[sparseIndex];
 369            ulong versionAtSparseIndex = versionArray[sparseIndex];
 370
 371            if (version == versionAtSparseIndex)
 372            {
 373                return denseIndex;
 374            }
 375
 376            return -1;
 377        }
 378
 379        /// <summary>
 380        ///     Gets the value of the sparse array at the given index,
 381        ///     or -1 if the given sparse index is invalid..
 382        /// </summary>
 383        /// <param name="sparseIndex">The index in the sparse array to check against.</param>
 384        /// <param name="version">The version number associated with the sparse index.</param>
 385        /// <param name="versionArray">The array containing the version number to check against.</param>
 386        /// <returns>The dense index pointed to by the current sparse index, or -1 if invalid.</returns>
 387        public int GetDenseIndexWithBoundsAndVersionCheck(int sparseIndex, ulong version, ulong* versionArray)
 388        {
 389            if (sparseIndex >= 0 && sparseIndex < Length)
 390            {
 391                int denseIndex = SparseArray[sparseIndex];
 392                ulong versionAtSparseIndex = versionArray[sparseIndex];
 393
 394                if (versionAtSparseIndex == version && denseIndex < Count && denseIndex >= 0)
 395                {
 396                    int sparseIndexAtDenseIndex = DenseArray[denseIndex];
 397
 398                    if (sparseIndex == sparseIndexAtDenseIndex)
 399                    {
 400                        return denseIndex;
 401                    }
 402                }
 403            }
 404
 405            return -1;
 406        }
 407
 408        /// <summary>
 409        ///     Removes the entry corresponding to the sparse index if the entry is within bounds and currently in use.
 410        /// </summary>
 411        /// <param name="sparseIndexToRemove">The sparse index corresponding to the entry to remove. Cleared to -1 in th
 412        /// <param name="dataIndexToSwapFrom">
 413        ///     Set the data array value at this index to default after swapping with the data array
 414        ///     value at indexToSwapTo.
 415        /// </param>
 416        /// <param name="dataIndexToSwapTo">Replace the data array value at this index with the data array value at inde
 417        /// <returns>True if the index reference was valid, and thus removed.</returns>
 418        public bool RemoveWithBoundsCheck(ref int sparseIndexToRemove, out int dataIndexToSwapFrom, out int dataIndexToS
 419        {
 420            dataIndexToSwapFrom = -1;
 421            dataIndexToSwapTo = -1;
 422            bool didRemove = false;
 423            if (sparseIndexToRemove >= 0 && sparseIndexToRemove < Length)
 424            {
 425                int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 426
 427                if (denseIndexToRemove >= 0 && denseIndexToRemove < Count)
 428                {
 429                    int sparseIndexAtDenseIndex = DenseArray[denseIndexToRemove];
 430                    int newLength = Count - 1;
 431                    int sparseIndexBeingSwapped = DenseArray[newLength];
 432
 433                    if (denseIndexToRemove < Count && sparseIndexAtDenseIndex == sparseIndexToRemove)
 434                    {
 435                        didRemove = true;
 436                        // Swap the entry being removed with the last entry.
 437                        SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 438                        DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 439
 440                        dataIndexToSwapFrom = newLength;
 441                        dataIndexToSwapTo = denseIndexToRemove;
 442
 443                        // Clear the dense index, for debugging purposes
 444                        DenseArray[newLength] = -1;
 445
 446                        // Add the sparse index to the free list.
 447                        SparseArray[sparseIndexToRemove] = FreeIndex;
 448                        FreeIndex = sparseIndexToRemove;
 449
 450                        Count = newLength;
 451                    }
 452                }
 453            }
 454
 455            sparseIndexToRemove = -1;
 456
 457            return didRemove;
 458        }
 459
 460        /// <summary>
 461        ///     Removes the associated sparse/dense index pair from active use.
 462        ///     calls.
 463        /// </summary>
 464        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 465        /// <param name="version">
 466        ///     The version number of the int used to access the sparse index. Used to guard against accessing
 467        ///     indices that have been removed and reused.
 468        /// </param>
 469        /// <param name="versionArray">The array containing the version number to check against.</param>
 470        /// <param name="indexToSwapFrom">
 471        ///     Set the data array value at this index to default after swapping with the data array
 472        ///     value at indexToSwapTo.
 473        /// </param>
 474        /// <param name="indexToSwapTo">Replace the data array value at this index with the data array value at indexToS
 475        /// <returns>True if the element was successfully removed.</returns>
 476        public bool RemoveWithBoundsAndVersionChecks(ref int sparseIndexToRemove, ulong version, ulong* versionArray, ou
 477        {
 478            indexToSwapFrom = -1;
 479            indexToSwapTo = -1;
 480            bool didRemove = false;
 481            if (sparseIndexToRemove >= 0 && sparseIndexToRemove < Length)
 482            {
 483                ulong sparseIndexVersion = versionArray[sparseIndexToRemove];
 484                int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 485
 486                if (sparseIndexVersion == version && denseIndexToRemove >= 0 && denseIndexToRemove < Count)
 487                {
 488                    int sparseIndexAtDenseIndex = DenseArray[denseIndexToRemove];
 489                    int newLength = Count - 1;
 490                    int sparseIndexBeingSwapped = DenseArray[newLength];
 491
 492                    if (denseIndexToRemove < Count && sparseIndexAtDenseIndex == sparseIndexToRemove)
 493                    {
 494                        didRemove = true;
 495                        versionArray[sparseIndexToRemove] = sparseIndexVersion + 1;
 496                        // Swap the entry being removed with the last entry.
 497                        SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 498                        DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 499
 500                        indexToSwapFrom = newLength;
 501                        indexToSwapTo = denseIndexToRemove;
 502
 503                        // Clear the dense index, for debugging purposes
 504                        DenseArray[newLength] = -1;
 505
 506                        // Add the sparse index to the free list.
 507                        SparseArray[sparseIndexToRemove] = FreeIndex;
 508                        FreeIndex = sparseIndexToRemove;
 509
 510                        Count = newLength;
 511                    }
 512                }
 513            }
 514
 515            sparseIndexToRemove = -1;
 516
 517            return didRemove;
 518        }
 519
 520        /// <summary>
 521        ///     Removes the associated sparse/dense index pair from active use.
 522        /// </summary>
 523        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 524        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 525        public void RemoveUnchecked(int sparseIndexToRemove)
 526        {
 527            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 528            int newLength = Count - 1;
 529            int sparseIndexBeingSwapped = DenseArray[newLength];
 530
 531            // Swap the entry being removed with the last entry.
 532            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 533            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 534
 535            // Clear the dense  index, for debugging purposes
 536            DenseArray[newLength] = -1;
 537
 538            // Add the sparse index to the free list.
 539            SparseArray[sparseIndexToRemove] = FreeIndex;
 540            FreeIndex = sparseIndexToRemove;
 541
 542            Count = newLength;
 543        }
 544
 545        /// <summary>
 546        ///     Removes the associated sparse/dense index pair from active use and increments the version.
 547        /// </summary>
 548        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 549        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 550        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 551        public void RemoveUnchecked(int sparseIndexToRemove, ulong* versionArray)
 552        {
 553            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 554            int newLength = Count - 1;
 555            int sparseIndexBeingSwapped = DenseArray[newLength];
 556
 557            // Swap the entry being removed with the last entry.
 558            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 559            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 560
 561            // Clear the dense  index, for debugging purposes
 562            DenseArray[newLength] = -1;
 563
 564            // Add the sparse index to the free list.
 565            SparseArray[sparseIndexToRemove] = FreeIndex;
 566            versionArray[sparseIndexToRemove] += 1;
 567            FreeIndex = sparseIndexToRemove;
 568
 569            Count = newLength;
 570        }
 571
 572        /// <summary>
 573        ///     Removes the associated sparse/dense index pair from active use.
 574        ///     Out parameters used to manage parallel data arrays.
 575        /// </summary>
 576        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 577        /// <param name="indexToSwapTo">Replace the data array value at this index with the data array value at indexToS
 578        /// <param name="indexToSwapFrom">
 579        ///     Set the data array value at this index to default after swapping with the data array
 580        ///     value at indexToSwapTo.
 581        /// </param>
 582        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 583        public void RemoveUnchecked(int sparseIndexToRemove, out int indexToSwapFrom, out int indexToSwapTo)
 584        {
 585            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 586            int newLength = Count - 1;
 587            int sparseIndexBeingSwapped = DenseArray[newLength];
 588
 589            // Swap the entry being removed with the last entry.
 590            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 591            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 592
 593            // Clear the dense  index, for debugging purposes
 594            DenseArray[newLength] = -1;
 595
 596            // Add the sparse index to the free list.
 597            SparseArray[sparseIndexToRemove] = FreeIndex;
 598            FreeIndex = sparseIndexToRemove;
 599
 600            Count = newLength;
 601
 602            indexToSwapTo = denseIndexToRemove;
 603            indexToSwapFrom = newLength;
 604        }
 605
 606        /// <summary>
 607        ///     Removes the associated sparse/dense index pair from active use and increments the version.
 608        ///     Out parameters used to manage parallel data arrays.
 609        /// </summary>
 610        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 611        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 612        /// <param name="indexToSwapTo">Replace the data array value at this index with the data array value at indexToS
 613        /// <param name="indexToSwapFrom">
 614        ///     Set the data array value at this index to default after swapping with the data array
 615        ///     value at indexToSwapTo.
 616        /// </param>
 617        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 618        public void RemoveUnchecked(int sparseIndexToRemove, ulong* versionArray, out int indexToSwapFrom, out int index
 619        {
 620            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 621            int newLength = Count - 1;
 622            int sparseIndexBeingSwapped = DenseArray[newLength];
 623
 624            // Swap the entry being removed with the last entry.
 625            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 626            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 627
 628            // Clear the dense  index, for debugging purposes
 629            DenseArray[newLength] = -1;
 630
 631            // Add the sparse index to the free list.
 632            SparseArray[sparseIndexToRemove] = FreeIndex;
 633            versionArray[sparseIndexToRemove] += 1;
 634            FreeIndex = sparseIndexToRemove;
 635
 636            Count = newLength;
 637
 638            indexToSwapTo = denseIndexToRemove;
 639            indexToSwapFrom = newLength;
 640        }
 641
 642        /// <summary>
 643        ///     Removes the associated sparse/dense index pair from active use.
 644        /// </summary>
 645        /// <param name="denseIndexToRemove">The dense index associated with the sparse index to remove.</param>
 646        public void RemoveUncheckedFromDenseIndex(int denseIndexToRemove)
 647        {
 648            int sparseIndexToRemove = DenseArray[denseIndexToRemove];
 649            int newLength = Count - 1;
 650            int sparseIndexBeingSwapped = DenseArray[newLength];
 651
 652            // Swap the entry being removed with the last entry.
 653            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 654            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 655
 656            // Clear the dense  index, for debugging purposes
 657            DenseArray[newLength] = -1;
 658
 659            // Add the sparse index to the free list.
 660            SparseArray[sparseIndexToRemove] = FreeIndex;
 661            FreeIndex = sparseIndexToRemove;
 662
 663            Count = newLength;
 664        }
 665
 666        /// <summary>
 667        ///     Removes the associated sparse/dense index pair from active use.
 668        /// </summary>
 669        /// <param name="denseIndexToRemove">The dense index associated with the sparse index to remove.</param>
 670        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 671        public void RemoveUncheckedFromDenseIndex(int denseIndexToRemove, ulong* versionArray)
 672        {
 673            int sparseIndexToRemove = DenseArray[denseIndexToRemove];
 674            int newLength = Count - 1;
 675            int sparseIndexBeingSwapped = DenseArray[newLength];
 676
 677            // Swap the entry being removed with the last entry.
 678            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 679            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 680
 681            // Clear the dense  index, for debugging purposes
 682            DenseArray[newLength] = -1;
 683
 684            // Add the sparse index to the free list.
 685            SparseArray[sparseIndexToRemove] = FreeIndex;
 686            versionArray[sparseIndexToRemove] += 1;
 687            FreeIndex = sparseIndexToRemove;
 688
 689            Count = newLength;
 690        }
 691
 692        /// <summary>
 693        ///     Removes the associated sparse/dense index pair from active use.
 694        ///     Out parameter used to manage parallel data arrays.
 695        /// </summary>
 696        /// <param name="denseIndexToRemove">The sparse index to remove.</param>
 697        /// <param name="indexToSwapFrom">
 698        ///     Set the data array value at this index to default after swapping with the data array
 699        ///     value at denseIndexToRemove.
 700        /// </param>
 701        public void RemoveUncheckedFromDenseIndex(int denseIndexToRemove, out int indexToSwapFrom)
 702        {
 703            int sparseIndexToRemove = DenseArray[denseIndexToRemove];
 704            int newLength = Count - 1;
 705            int sparseIndexBeingSwapped = DenseArray[newLength];
 706
 707            // Swap the entry being removed with the last entry.
 708            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 709            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 710
 711            // Clear the dense  index, for debugging purposes
 712            DenseArray[newLength] = -1;
 713
 714            // Add the sparse index to the free list.
 715            SparseArray[sparseIndexToRemove] = FreeIndex;
 716            FreeIndex = sparseIndexToRemove;
 717
 718            Count = newLength;
 719
 720            indexToSwapFrom = newLength;
 721        }
 722
 723        /// <summary>
 724        ///     Removes the associated sparse/dense index pair from active use.
 725        ///     Out parameter used to manage parallel data arrays.
 726        /// </summary>
 727        /// <param name="denseIndexToRemove">The sparse index to remove.</param>
 728        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 729        /// <param name="indexToSwapFrom">
 730        ///     Set the data array value at this index to default after swapping with the data array
 731        ///     value at denseIndexToRemove.
 732        /// </param>
 733        public void RemoveUncheckedFromDenseIndex(int denseIndexToRemove, ulong* versionArray, out int indexToSwapFrom)
 734        {
 735            int sparseIndexToRemove = DenseArray[denseIndexToRemove];
 736            int newLength = Count - 1;
 737            int sparseIndexBeingSwapped = DenseArray[newLength];
 738
 739            // Swap the entry being removed with the last entry.
 740            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 741            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 742
 743            // Clear the dense  index, for debugging purposes
 744            DenseArray[newLength] = -1;
 745
 746            // Add the sparse index to the free list.
 747            SparseArray[sparseIndexToRemove] = FreeIndex;
 748            versionArray[sparseIndexToRemove] += 1;
 749            FreeIndex = sparseIndexToRemove;
 750
 751            Count = newLength;
 752
 753            indexToSwapFrom = newLength;
 754        }
 755
 756        /// <summary>
 757        ///     Attempts to remove the associated sparse/dense index pair from active use and increments the version if 
 758        ///     Out parameters used to manage parallel data arrays.
 759        /// </summary>
 760        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 761        /// <param name="version">
 762        ///     The version number of the int used to access the sparse index. Used to guard against accessing
 763        ///     indices that have been removed and reused.
 764        /// </param>
 765        /// <param name="versionArray">The array containing the version number to check against.</param>
 766        /// <param name="indexToSwapTo">Replace the data array value at this index with the data array value at indexToS
 767        /// <param name="indexToSwapFrom">
 768        ///     Set the data array value at this index to default after swapping with the data array
 769        ///     value at indexToSwapTo.
 770        /// </param>
 771        /// <returns>True if the entry was valid and thus removed.</returns>
 772        public bool RemoveWithVersionCheck(int sparseIndexToRemove, ulong version, ulong* versionArray, out int indexToS
 773        {
 774            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 775            ulong versionAtSparseIndex = versionArray[sparseIndexToRemove];
 776
 777            indexToSwapFrom = -1;
 778            indexToSwapTo = -1;
 779
 780            bool succeeded = versionAtSparseIndex == version;
 781
 782            if (succeeded)
 783            {
 784                int newLength = Count - 1;
 785                int sparseIndexBeingSwapped = DenseArray[newLength];
 786
 787                // Swap the entry being removed with the last entry.
 788                SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 789                DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 790
 791                // Clear the dense  index, for debugging purposes
 792                DenseArray[newLength] = -1;
 793
 794                // Add the sparse index to the free list.
 795                SparseArray[sparseIndexToRemove] = FreeIndex;
 796                versionArray[sparseIndexToRemove] += 1;
 797                FreeIndex = sparseIndexToRemove;
 798
 799                Count = newLength;
 800
 801                indexToSwapTo = denseIndexToRemove;
 802                indexToSwapFrom = newLength;
 803            }
 804
 805            return succeeded;
 806        }
 807
 808        /// <summary>
 809        ///     Clear the dense and sparse arrays.
 810        /// </summary>
 811        public void Clear()
 812        {
 813            int capacity = Length;
 814            for (int i = 0; i < capacity; i++)
 815            {
 816                DenseArray[i] = -1;
 817                SparseArray[i] = i + 1;
 818            }
 819
 820            FreeIndex = 0;
 821            Count = 0;
 822        }
 823
 824        /// <summary>
 825        ///     Clear the dense and sparse arrays.
 826        /// </summary>
 827        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 828        public void Clear(ulong* versionArray)
 829        {
 830            int capacity = Length;
 831            for (int i = 0; i < capacity; i++)
 832            {
 833                DenseArray[i] = -1;
 834                SparseArray[i] = i + 1;
 835                versionArray[i] += 1;
 836            }
 837
 838            FreeIndex = 0;
 839            Count = 0;
 840        }
 841
 842        /// <summary>
 843        ///     Clear the dense and sparse arrays and reset the version array.
 844        ///     Note: Only clear the version array if you are sure there are no outstanding dependencies on version numb
 845        /// </summary>
 846        /// ///
 847        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 848        public void ClearWithVersionArrayReset(ulong* versionArray)
 849        {
 850            int capacity = Length;
 851            for (int i = 0; i < capacity; i++)
 852            {
 853                DenseArray[i] = -1;
 854                SparseArray[i] = i + 1;
 855                versionArray[i] = 1;
 856            }
 857
 858            FreeIndex = 0;
 859            Count = 0;
 860        }
 861
 862        /// <summary>
 863        ///     Reallocate the dense and sparse arrays with additional capacity.
 864        /// </summary>
 865        /// <param name="extraCapacity">How many indices to expand the dense and sparse arrays by.</param>
 866        public void Expand(int extraCapacity)
 867        {
 868            int currentCapacity = Length;
 869            int newCapacity = currentCapacity + extraCapacity;
 870
 871            newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 872            --newCapacity;
 873            newCapacity |= newCapacity >> 1;
 874            newCapacity |= newCapacity >> 2;
 875            newCapacity |= newCapacity >> 4;
 876            newCapacity |= newCapacity >> 8;
 877            newCapacity |= newCapacity >> 16;
 878            ++newCapacity;
 879
 880            void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 881
 882            UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 883            int* newSparseArray = (int*)newData;
 884            for (int i = currentCapacity; i < newCapacity; i++)
 885            {
 886                newSparseArray[i] = i + 1;
 887            }
 888
 889            int* newDenseArray = newSparseArray + newCapacity;
 890            UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 891            for (int i = currentCapacity; i < newCapacity; i++)
 892            {
 893                newDenseArray[i] = -1;
 894            }
 895
 896            Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 897
 898            Data = newData;
 899            Length = newCapacity;
 900        }
 901
 902        /// <summary>
 903        ///     Reallocate the dense and sparse arrays with additional capacity.
 904        /// </summary>
 905        /// <param name="extraCapacity">How many indices to expand the dense and sparse arrays by.</param>
 906        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 907        public void Expand(int extraCapacity, ref ulong* versionArray)
 908        {
 909            int currentCapacity = Length;
 910            int newCapacity = currentCapacity + extraCapacity;
 911
 912            newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 913            --newCapacity;
 914            newCapacity |= newCapacity >> 1;
 915            newCapacity |= newCapacity >> 2;
 916            newCapacity |= newCapacity >> 4;
 917            newCapacity |= newCapacity >> 8;
 918            newCapacity |= newCapacity >> 16;
 919            ++newCapacity;
 920
 921            void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 922
 923            UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 924            int* newSparseArray = (int*)newData;
 925            for (int i = currentCapacity; i < newCapacity; i++)
 926            {
 927                newSparseArray[i] = i + 1;
 928            }
 929
 930            int* newDenseArray = newSparseArray + newCapacity;
 931            UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 932            for (int i = currentCapacity; i < newCapacity; i++)
 933            {
 934                newDenseArray[i] = -1;
 935            }
 936
 937            ulong* newVersionArray =
 938                                                                                                                        
 939            UnsafeUtility.MemCpy(newVersionArray, versionArray, sizeof(ulong) * currentCapacity);
 940            for (int i = currentCapacity; i < newCapacity; i++)
 941            {
 942                newVersionArray[i] = 1;
 943            }
 944
 945            Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 946            Allocator.Free(versionArray, sizeof(ulong), JobsUtility.CacheLineSize, currentCapacity);
 947            versionArray = newVersionArray;
 948
 949            Data = newData;
 950            Length = newCapacity;
 951        }
 952
 953        /// <summary>
 954        /// Reallocate the dense and sparse arrays with additional capacity if there are not at least <paramref name="nu
 955        /// </summary>
 956        /// <param name="numberToReserve">The number of unused entries to ensure capacity for.</param>
 957        public void Reserve(int numberToReserve)
 958        {
 959            int currentCapacity = Length;
 960            int currentCount = Count;
 961            int newCapacity = currentCount + numberToReserve;
 962
 963            if (newCapacity > currentCapacity)
 964            {
 965                newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 966                --newCapacity;
 967                newCapacity |= newCapacity >> 1;
 968                newCapacity |= newCapacity >> 2;
 969                newCapacity |= newCapacity >> 4;
 970                newCapacity |= newCapacity >> 8;
 971                newCapacity |= newCapacity >> 16;
 972                ++newCapacity;
 973
 974                void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 975
 976                UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 977                int* newSparseArray = (int*)newData;
 978                for (int i = currentCapacity; i < newCapacity; i++)
 979                {
 980                    newSparseArray[i] = i + 1;
 981                }
 982
 983                int* newDenseArray = newSparseArray + newCapacity;
 984                UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 985                for (int i = currentCapacity; i < newCapacity; i++)
 986                {
 987                    newDenseArray[i] = -1;
 988                }
 989
 990                Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 991
 992                Data = newData;
 993                Length = newCapacity;
 994            }
 995        }
 996
 997        /// <summary>
 998        /// Reallocate the dense and sparse arrays with additional capacity if there are not at least <paramref name="nu
 999        /// </summary>
 1000        /// <param name="numberToReserve">The number of unused entries to ensure capacity for.</param>
 1001        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 1002        public void Reserve(int numberToReserve,  ref ulong* versionArray)
 1003        {
 1004            int currentCapacity = Length;
 1005            int currentCount = Count;
 1006            int newCapacity = currentCount + numberToReserve;
 1007
 1008            if (newCapacity > currentCapacity)
 1009            {
 1010                newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 1011                --newCapacity;
 1012                newCapacity |= newCapacity >> 1;
 1013                newCapacity |= newCapacity >> 2;
 1014                newCapacity |= newCapacity >> 4;
 1015                newCapacity |= newCapacity >> 8;
 1016                newCapacity |= newCapacity >> 16;
 1017                ++newCapacity;
 1018
 1019                void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 1020
 1021                UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 1022                int* newSparseArray = (int*)newData;
 1023                for (int i = currentCapacity; i < newCapacity; i++)
 1024                {
 1025                    newSparseArray[i] = i + 1;
 1026                }
 1027
 1028                int* newDenseArray = newSparseArray + newCapacity;
 1029                UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 1030                for (int i = currentCapacity; i < newCapacity; i++)
 1031                {
 1032                    newDenseArray[i] = -1;
 1033                }
 1034
 1035                ulong* newVersionArray =
 1036                                                                                                                        
 1037                UnsafeUtility.MemCpy(newVersionArray, versionArray, sizeof(ulong) * currentCapacity);
 1038                for (int i = currentCapacity; i < newCapacity; i++)
 1039                {
 1040                    newVersionArray[i] = 1;
 1041                }
 1042
 1043                Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 1044                Allocator.Free(versionArray, sizeof(ulong), JobsUtility.CacheLineSize, currentCapacity);
 1045                versionArray = newVersionArray;
 1046
 1047                Data = newData;
 1048                Length = newCapacity;
 1049            }
 1050        }
 1051
 1052        /// <summary>
 1053        /// Disposes the memory of this Sparse Set.
 1054        /// </summary>
 1055        public void Dispose()
 1056        {
 1057            if (Data != null)
 1058            {
 1059                Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, Length * 2);
 1060                Data = null;
 1061                Length = 0;
 1062                Count = 0;
 1063                FreeIndex = 0;
 1064                Allocator = Unity.Collections.Allocator.Invalid;
 1065            }
 1066        }
 1067
 1068        /// <summary>
 1069        /// Creates and schedules a job that disposes the memory of this Sparse Set.
 1070        /// </summary>
 1071        /// <param name="inputDeps">The dependency for the new job.</param>
 1072        /// <returns>The handle of the new job. The job depends upon `inputDeps` and frees the memory of this Sparse Set
 1073        [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to I
 1074        public JobHandle Dispose(JobHandle inputDeps)
 1075        {
 1076            if (CollectionHelper.ShouldDeallocate(Allocator))
 1077            {
 1078                var jobHandle = new DisposeUnsafeSparseSetJob { Ptr = Data, Capacity = Length, Allocator =
 1079                                                                                                                        
 1080
 1081                Data = null;
 1082                Length = 0;
 1083                Count = 0;
 1084                FreeIndex = 0;
 1085                Allocator = Unity.Collections.Allocator.Invalid;
 1086
 1087                return jobHandle;
 1088            }
 1089
 1090            Data = null;
 1091            Length = 0;
 1092            Count = 0;
 1093            FreeIndex = 0;
 1094            Allocator = Unity.Collections.Allocator.Invalid;
 1095
 1096            return inputDeps;
 1097        }
 1098
 1099        /// <summary>
 1100        /// Creates and schedules a job that disposes the memory of this Sparse Set.
 1101        /// </summary>
 1102        /// <param name="inputDeps">The dependency for the new job.</param>
 1103        /// <returns>The handle of the new job. The job depends upon `inputDeps` and frees the memory of this Sparse Set
 1104        [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to I
 1105        public JobHandle Dispose(JobHandle inputDeps, ref ulong* versionArray)
 1106        {
 1107            if (CollectionHelper.ShouldDeallocate(Allocator))
 1108            {
 1109                var jobHandle = new DisposeUnsafeSparseSetAndVersionArrayJob { Ptr = Data, VersionArrayPtr =
 1110                                                                                                                        
 1111
 1112                Data = null;
 1113                Length = 0;
 1114                Count = 0;
 1115                FreeIndex = 0;
 1116                Allocator = Unity.Collections.Allocator.Invalid;
 1117                versionArray = null;
 1118
 1119                return jobHandle;
 1120            }
 1121
 1122            Data = null;
 1123            Length = 0;
 1124            Count = 0;
 1125            FreeIndex = 0;
 1126            Allocator = Unity.Collections.Allocator.Invalid;
 1127            versionArray = null;
 1128
 1129            return inputDeps;
 1130        }
 1131
 1132        /// <summary>
 1133        /// Disposes the memory of the version array for this Sparse Set.
 1134        /// </summary>
 1135        /// <param name="versionArray">The pointer of the versionArray to dispose of.</param>
 1136        public void DisposeVersionArray(ref ulong* versionArray)
 1137        {
 1138            Allocator.Free(versionArray, sizeof(ulong), JobsUtility.CacheLineSize, Length);
 1139            versionArray = null;
 1140        }
 1141
 1142        /// <summary>
 1143        /// Creates and schedules a job that disposes the memory of this Sparse Set.
 1144        /// </summary>
 1145        /// <param name="inputDeps">The dependency for the new job.</param>
 1146        /// <returns>The handle of the new job. The job depends upon `inputDeps` and disposes the memory of this Sparse 
 1147        [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to I
 1148        public JobHandle DisposeVersionArray(JobHandle inputDeps, ref ulong* versionArray)
 1149        {
 1150            if (CollectionHelper.ShouldDeallocate(Allocator))
 1151            {
 1152                var jobHandle = new DisposeUnsafeVersionArrayJob { Ptr = versionArray, Capacity = Length, Allocator =
 1153                                                                                                                        
 1154
 1155                versionArray = null;
 1156
 1157                return jobHandle;
 1158            }
 1159
 1160            versionArray = null;
 1161
 1162            return inputDeps;
 1163        }
 1164    }
 1165
 1166    [BurstCompile]
 1167    internal unsafe struct DisposeUnsafeSparseSetJob : IJob
 1168    {
 1169        [NativeDisableUnsafePtrRestriction]
 1170        public void* Ptr;
 1171        public int Capacity;
 1172        public AllocatorManager.AllocatorHandle Allocator;
 1173
 1174        public void Execute()
 1175        {
 1176            Allocator.Free(Ptr, UnsafeUtility.SizeOf<int>(), JobsUtility.CacheLineSize, Capacity * 2);
 1177        }
 1178    }
 1179
 1180    [BurstCompile]
 1181    internal unsafe struct DisposeUnsafeVersionArrayJob : IJob
 1182    {
 1183        [NativeDisableUnsafePtrRestriction]
 1184        public void* Ptr;
 1185        public int Capacity;
 1186        public AllocatorManager.AllocatorHandle Allocator;
 1187
 1188        public void Execute()
 1189        {
 1190            Allocator.Free(Ptr, UnsafeUtility.SizeOf<ulong>(), JobsUtility.CacheLineSize, Capacity);
 1191        }
 1192    }
 1193
 1194    [BurstCompile]
 1195    internal unsafe struct DisposeUnsafeSparseSetAndVersionArrayJob : IJob
 1196    {
 1197        [NativeDisableUnsafePtrRestriction]
 1198        public void* Ptr;
 1199        [NativeDisableUnsafePtrRestriction]
 1200        public void* VersionArrayPtr;
 1201        public int Capacity;
 1202        public AllocatorManager.AllocatorHandle Allocator;
 1203
 1204        public void Execute()
 1205        {
 1206            Allocator.Free(Ptr, UnsafeUtility.SizeOf<int>(), JobsUtility.CacheLineSize, Capacity * 2);
 1207            Allocator.Free(VersionArrayPtr, UnsafeUtility.SizeOf<ulong>(), JobsUtility.CacheLineSize, Capacity);
 1208        }
 1209    }
 1210
 1211    public struct SparseDenseIndexPair
 1212    {
 1213        public int SparseIndex;
 1214        public int DenseIndex;
 1215    }
 1216
 1217    internal sealed class UnsafeSparseSetDebugView
 1218    {
 1219        UnsafeSparseSet Data;
 1220
 01221        public UnsafeSparseSetDebugView(UnsafeSparseSet data)
 01222        {
 01223            Data = data;
 01224        }
 1225
 1226        public unsafe SparseDenseIndexPair[] Items
 1227        {
 1228            get
 01229            {
 01230                SparseDenseIndexPair[] result = new SparseDenseIndexPair[Data.Count];
 1231
 01232                for (var i = 0; i < Data.Count; ++i)
 01233                {
 01234                    result[i] = new SparseDenseIndexPair() { DenseIndex = i, SparseIndex = Data.DenseArray[i] };
 01235                }
 1236
 01237                return result;
 01238            }
 1239        }
 1240    }
 1241}
 1242#endif // GDX_UNSAFE_COLLECTIONS