< Summary

Class:GDX.Collections.DisposeUnsafeSparseSetJob
Assembly:GDX
File(s):./Packages/com.dotbunny.gdx/GDX/Collections/UnsafeSparseSet.cs
Covered lines:0
Uncovered lines:3
Coverable lines:3
Total lines:1236
Line coverage:0% (0 of 3)
Covered branches:0
Total branches:0
Covered methods:0
Total methods:1
Method coverage:0% (0 of 1)

Coverage History

Metrics

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

File(s)

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

#LineLine coverage
 1#if GDX_UNSAFE_COLLECTIONS
 2// Copyright (c) 2020-2023 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 = (ulong*)Allocator.Allocate(sizeof(ulong), JobsUtility.CacheLineSize, currentCap
 252                UnsafeUtility.MemCpy(newVersionArray, versionArray, sizeof(ulong) * currentCapacity);
 253                for (int i = currentCapacity; i < newCapacity; i++)
 254                {
 255                    newVersionArray[i] = 1;
 256                }
 257
 258                Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 259                Allocator.Free(versionArray, sizeof(ulong), JobsUtility.CacheLineSize, currentCapacity);
 260                versionArray = newVersionArray;
 261
 262                Data = newData;
 263                Length = newCapacity;
 264            }
 265
 266            int nextFreeIndex = SparseArray[indexToClaim];
 267            DenseArray[Count] = indexToClaim; // Point the next dense id at our newly claimed sparse index.
 268            SparseArray[indexToClaim] = Count; // Point our newly claimed sparse index at the dense index.
 269            denseIndex = Count;
 270
 271            ++Count;
 272            FreeIndex = nextFreeIndex; // Set the free list head for next time.
 273
 274            sparseIndex = indexToClaim;
 275            return needsExpansion;
 276        }
 277
 278        /// <summary>
 279        ///     Adds a sparse/dense index pair to the set without checking if the set needs to expand.
 280        /// </summary>
 281        /// <param name="sparseIndex">The sparse index allocated.</param>
 282        /// <param name="denseIndex">The dense index allocated.</param>
 283        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 284        public void AddUnchecked(out int sparseIndex, out int denseIndex)
 285        {
 286            int indexToClaim = FreeIndex;
 287            int nextFreeIndex = SparseArray[indexToClaim];
 288            DenseArray[Count] = indexToClaim; // Point the next dense id at our newly claimed sparse index.
 289            SparseArray[indexToClaim] = Count; // Point our newly claimed sparse index at the dense index.
 290
 291            sparseIndex = indexToClaim;
 292            denseIndex = Count;
 293            ++Count;
 294            FreeIndex = nextFreeIndex; // Set the free list head for next time.
 295        }
 296
 297        /// <summary>
 298        ///     Adds a sparse/dense index pair to the set without checking if the set needs to expand.
 299        /// </summary>
 300        /// <param name="sparseIndex">The sparse index allocated.</param>
 301        /// <param name="denseIndex">The dense index allocated.</param>
 302        /// <param name="versionArray">The array containing the version number to check against.</param>
 303        /// <param name="version">Enables detection of use-after-free errors when using the sparse index as a reference.
 304        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 305        public void AddUnchecked(out int sparseIndex, out int denseIndex, ulong* versionArray, out ulong version)
 306        {
 307            int indexToClaim = FreeIndex;
 308            int nextFreeIndex = SparseArray[indexToClaim];
 309            DenseArray[Count] = indexToClaim; // Point the next dense id at our newly claimed sparse index.
 310            SparseArray[indexToClaim] = Count; // Point our newly claimed sparse index at the dense index.
 311
 312            version = versionArray[indexToClaim];
 313            sparseIndex = indexToClaim;
 314            denseIndex = Count;
 315
 316            ++Count;
 317            FreeIndex = nextFreeIndex; // Set the free list head for next time.
 318        }
 319
 320        /// <summary>
 321        ///     Gets the value of the sparse array at the given index without any data validation.
 322        /// </summary>
 323        /// <param name="sparseIndex">The index to check in the sparse array.</param>
 324        /// <returns>The dense index at the given sparse index.</returns>
 325        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 326        public int GetDenseIndexUnchecked(int sparseIndex)
 327        {
 328            return SparseArray[sparseIndex];
 329        }
 330
 331        /// <summary>
 332        ///     Gets the value of the sparse array at the given index,
 333        ///     or -1 if the dense and sparse indices don't point to each other or if the dense index is outside the den
 334        /// </summary>
 335        /// <param name="sparseIndex">The index in the sparse array to check against.</param>
 336        /// <returns>The dense index pointed to by the current sparse index, or -1 if invalid.</returns>
 337        public int GetDenseIndexWithBoundsCheck(int sparseIndex)
 338        {
 339            if (sparseIndex >= 0 && sparseIndex < Length)
 340            {
 341                int denseIndex = SparseArray[sparseIndex];
 342
 343                if (denseIndex < Count && denseIndex >= 0)
 344                {
 345                    int sparseIndexAtDenseIndex = DenseArray[denseIndex];
 346
 347                    if (sparseIndex == sparseIndexAtDenseIndex)
 348                    {
 349                        return denseIndex;
 350                    }
 351                }
 352            }
 353
 354            return -1;
 355        }
 356
 357        /// <summary>
 358        ///     Gets the value of the sparse array at the given index,
 359        ///     or -1 if the version number does not match.
 360        /// </summary>
 361        /// <param name="sparseIndex">The index in the sparse array to check against.</param>
 362        /// <param name="version">The version number associated with the sparse index.</param>
 363        /// <param name="versionArray">The array containing the version number to check against.</param>
 364        /// <returns>The dense index pointed to by the current sparse index, or -1 if invalid.</returns>
 365        public int GetDenseIndexWithVersionCheck(int sparseIndex, ulong version, ulong* versionArray)
 366        {
 367            int denseIndex = SparseArray[sparseIndex];
 368            ulong versionAtSparseIndex = versionArray[sparseIndex];
 369
 370            if (version == versionAtSparseIndex)
 371            {
 372                return denseIndex;
 373            }
 374
 375            return -1;
 376        }
 377
 378        /// <summary>
 379        ///     Gets the value of the sparse array at the given index,
 380        ///     or -1 if the given sparse index is invalid..
 381        /// </summary>
 382        /// <param name="sparseIndex">The index in the sparse array to check against.</param>
 383        /// <param name="version">The version number associated with the sparse index.</param>
 384        /// <param name="versionArray">The array containing the version number to check against.</param>
 385        /// <returns>The dense index pointed to by the current sparse index, or -1 if invalid.</returns>
 386        public int GetDenseIndexWithBoundsAndVersionCheck(int sparseIndex, ulong version, ulong* versionArray)
 387        {
 388            if (sparseIndex >= 0 && sparseIndex < Length)
 389            {
 390                int denseIndex = SparseArray[sparseIndex];
 391                ulong versionAtSparseIndex = versionArray[sparseIndex];
 392
 393                if (versionAtSparseIndex == version && denseIndex < Count && denseIndex >= 0)
 394                {
 395                    int sparseIndexAtDenseIndex = DenseArray[denseIndex];
 396
 397                    if (sparseIndex == sparseIndexAtDenseIndex)
 398                    {
 399                        return denseIndex;
 400                    }
 401                }
 402            }
 403
 404            return -1;
 405        }
 406
 407        /// <summary>
 408        ///     Removes the entry corresponding to the sparse index if the entry is within bounds and currently in use.
 409        /// </summary>
 410        /// <param name="sparseIndexToRemove">The sparse index corresponding to the entry to remove. Cleared to -1 in th
 411        /// <param name="dataIndexToSwapFrom">
 412        ///     Set the data array value at this index to default after swapping with the data array
 413        ///     value at indexToSwapTo.
 414        /// </param>
 415        /// <param name="dataIndexToSwapTo">Replace the data array value at this index with the data array value at inde
 416        /// <returns>True if the index reference was valid, and thus removed.</returns>
 417        public bool RemoveWithBoundsCheck(ref int sparseIndexToRemove, out int dataIndexToSwapFrom, out int dataIndexToS
 418        {
 419            dataIndexToSwapFrom = -1;
 420            dataIndexToSwapTo = -1;
 421            bool didRemove = false;
 422            if (sparseIndexToRemove >= 0 && sparseIndexToRemove < Length)
 423            {
 424                int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 425
 426                if (denseIndexToRemove >= 0 && denseIndexToRemove < Count)
 427                {
 428                    int sparseIndexAtDenseIndex = DenseArray[denseIndexToRemove];
 429                    int newLength = Count - 1;
 430                    int sparseIndexBeingSwapped = DenseArray[newLength];
 431
 432                    if (denseIndexToRemove < Count && sparseIndexAtDenseIndex == sparseIndexToRemove)
 433                    {
 434                        didRemove = true;
 435                        // Swap the entry being removed with the last entry.
 436                        SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 437                        DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 438
 439                        dataIndexToSwapFrom = newLength;
 440                        dataIndexToSwapTo = denseIndexToRemove;
 441
 442                        // Clear the dense index, for debugging purposes
 443                        DenseArray[newLength] = -1;
 444
 445                        // Add the sparse index to the free list.
 446                        SparseArray[sparseIndexToRemove] = FreeIndex;
 447                        FreeIndex = sparseIndexToRemove;
 448
 449                        Count = newLength;
 450                    }
 451                }
 452            }
 453
 454            sparseIndexToRemove = -1;
 455
 456            return didRemove;
 457        }
 458
 459        /// <summary>
 460        ///     Removes the associated sparse/dense index pair from active use.
 461        ///     calls.
 462        /// </summary>
 463        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 464        /// <param name="version">
 465        ///     The version number of the int used to access the sparse index. Used to guard against accessing
 466        ///     indices that have been removed and reused.
 467        /// </param>
 468        /// <param name="versionArray">The array containing the version number to check against.</param>
 469        /// <param name="indexToSwapFrom">
 470        ///     Set the data array value at this index to default after swapping with the data array
 471        ///     value at indexToSwapTo.
 472        /// </param>
 473        /// <param name="indexToSwapTo">Replace the data array value at this index with the data array value at indexToS
 474        /// <returns>True if the element was successfully removed.</returns>
 475        public bool RemoveWithBoundsAndVersionChecks(ref int sparseIndexToRemove, ulong version, ulong* versionArray, ou
 476        {
 477            indexToSwapFrom = -1;
 478            indexToSwapTo = -1;
 479            bool didRemove = false;
 480            if (sparseIndexToRemove >= 0 && sparseIndexToRemove < Length)
 481            {
 482                ulong sparseIndexVersion = versionArray[sparseIndexToRemove];
 483                int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 484
 485                if (sparseIndexVersion == version && denseIndexToRemove >= 0 && denseIndexToRemove < Count)
 486                {
 487                    int sparseIndexAtDenseIndex = DenseArray[denseIndexToRemove];
 488                    int newLength = Count - 1;
 489                    int sparseIndexBeingSwapped = DenseArray[newLength];
 490
 491                    if (denseIndexToRemove < Count && sparseIndexAtDenseIndex == sparseIndexToRemove)
 492                    {
 493                        didRemove = true;
 494                        versionArray[sparseIndexToRemove] = sparseIndexVersion + 1;
 495                        // Swap the entry being removed with the last entry.
 496                        SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 497                        DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 498
 499                        indexToSwapFrom = newLength;
 500                        indexToSwapTo = denseIndexToRemove;
 501
 502                        // Clear the dense index, for debugging purposes
 503                        DenseArray[newLength] = -1;
 504
 505                        // Add the sparse index to the free list.
 506                        SparseArray[sparseIndexToRemove] = FreeIndex;
 507                        FreeIndex = sparseIndexToRemove;
 508
 509                        Count = newLength;
 510                    }
 511                }
 512            }
 513
 514            sparseIndexToRemove = -1;
 515
 516            return didRemove;
 517        }
 518
 519        /// <summary>
 520        ///     Removes the associated sparse/dense index pair from active use.
 521        /// </summary>
 522        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 523        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 524        public void RemoveUnchecked(int sparseIndexToRemove)
 525        {
 526            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 527            int newLength = Count - 1;
 528            int sparseIndexBeingSwapped = DenseArray[newLength];
 529
 530            // Swap the entry being removed with the last entry.
 531            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 532            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 533
 534            // Clear the dense  index, for debugging purposes
 535            DenseArray[newLength] = -1;
 536
 537            // Add the sparse index to the free list.
 538            SparseArray[sparseIndexToRemove] = FreeIndex;
 539            FreeIndex = sparseIndexToRemove;
 540
 541            Count = newLength;
 542        }
 543
 544        /// <summary>
 545        ///     Removes the associated sparse/dense index pair from active use and increments the version.
 546        /// </summary>
 547        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 548        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 549        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 550        public void RemoveUnchecked(int sparseIndexToRemove, ulong* versionArray)
 551        {
 552            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 553            int newLength = Count - 1;
 554            int sparseIndexBeingSwapped = DenseArray[newLength];
 555
 556            // Swap the entry being removed with the last entry.
 557            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 558            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 559
 560            // Clear the dense  index, for debugging purposes
 561            DenseArray[newLength] = -1;
 562
 563            // Add the sparse index to the free list.
 564            SparseArray[sparseIndexToRemove] = FreeIndex;
 565            versionArray[sparseIndexToRemove] += 1;
 566            FreeIndex = sparseIndexToRemove;
 567
 568            Count = newLength;
 569        }
 570
 571        /// <summary>
 572        ///     Removes the associated sparse/dense index pair from active use.
 573        ///     Out parameters used to manage parallel data arrays.
 574        /// </summary>
 575        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 576        /// <param name="indexToSwapTo">Replace the data array value at this index with the data array value at indexToS
 577        /// <param name="indexToSwapFrom">
 578        ///     Set the data array value at this index to default after swapping with the data array
 579        ///     value at indexToSwapTo.
 580        /// </param>
 581        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 582        public void RemoveUnchecked(int sparseIndexToRemove, out int indexToSwapFrom, out int indexToSwapTo)
 583        {
 584            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 585            int newLength = Count - 1;
 586            int sparseIndexBeingSwapped = DenseArray[newLength];
 587
 588            // Swap the entry being removed with the last entry.
 589            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 590            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 591
 592            // Clear the dense  index, for debugging purposes
 593            DenseArray[newLength] = -1;
 594
 595            // Add the sparse index to the free list.
 596            SparseArray[sparseIndexToRemove] = FreeIndex;
 597            FreeIndex = sparseIndexToRemove;
 598
 599            Count = newLength;
 600
 601            indexToSwapTo = denseIndexToRemove;
 602            indexToSwapFrom = newLength;
 603        }
 604
 605        /// <summary>
 606        ///     Removes the associated sparse/dense index pair from active use and increments the version.
 607        ///     Out parameters used to manage parallel data arrays.
 608        /// </summary>
 609        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 610        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 611        /// <param name="indexToSwapTo">Replace the data array value at this index with the data array value at indexToS
 612        /// <param name="indexToSwapFrom">
 613        ///     Set the data array value at this index to default after swapping with the data array
 614        ///     value at indexToSwapTo.
 615        /// </param>
 616        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 617        public void RemoveUnchecked(int sparseIndexToRemove, ulong* versionArray, out int indexToSwapFrom, out int index
 618        {
 619            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 620            int newLength = Count - 1;
 621            int sparseIndexBeingSwapped = DenseArray[newLength];
 622
 623            // Swap the entry being removed with the last entry.
 624            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 625            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 626
 627            // Clear the dense  index, for debugging purposes
 628            DenseArray[newLength] = -1;
 629
 630            // Add the sparse index to the free list.
 631            SparseArray[sparseIndexToRemove] = FreeIndex;
 632            versionArray[sparseIndexToRemove] += 1;
 633            FreeIndex = sparseIndexToRemove;
 634
 635            Count = newLength;
 636
 637            indexToSwapTo = denseIndexToRemove;
 638            indexToSwapFrom = newLength;
 639        }
 640
 641        /// <summary>
 642        ///     Removes the associated sparse/dense index pair from active use.
 643        /// </summary>
 644        /// <param name="denseIndexToRemove">The dense index associated with the sparse index to remove.</param>
 645        public void RemoveUncheckedFromDenseIndex(int denseIndexToRemove)
 646        {
 647            int sparseIndexToRemove = DenseArray[denseIndexToRemove];
 648            int newLength = Count - 1;
 649            int sparseIndexBeingSwapped = DenseArray[newLength];
 650
 651            // Swap the entry being removed with the last entry.
 652            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 653            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 654
 655            // Clear the dense  index, for debugging purposes
 656            DenseArray[newLength] = -1;
 657
 658            // Add the sparse index to the free list.
 659            SparseArray[sparseIndexToRemove] = FreeIndex;
 660            FreeIndex = sparseIndexToRemove;
 661
 662            Count = newLength;
 663        }
 664
 665        /// <summary>
 666        ///     Removes the associated sparse/dense index pair from active use.
 667        /// </summary>
 668        /// <param name="denseIndexToRemove">The dense index associated with the sparse index to remove.</param>
 669        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 670        public void RemoveUncheckedFromDenseIndex(int denseIndexToRemove, ulong* versionArray)
 671        {
 672            int sparseIndexToRemove = DenseArray[denseIndexToRemove];
 673            int newLength = Count - 1;
 674            int sparseIndexBeingSwapped = DenseArray[newLength];
 675
 676            // Swap the entry being removed with the last entry.
 677            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 678            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 679
 680            // Clear the dense  index, for debugging purposes
 681            DenseArray[newLength] = -1;
 682
 683            // Add the sparse index to the free list.
 684            SparseArray[sparseIndexToRemove] = FreeIndex;
 685            versionArray[sparseIndexToRemove] += 1;
 686            FreeIndex = sparseIndexToRemove;
 687
 688            Count = newLength;
 689        }
 690
 691        /// <summary>
 692        ///     Removes the associated sparse/dense index pair from active use.
 693        ///     Out parameter used to manage parallel data arrays.
 694        /// </summary>
 695        /// <param name="denseIndexToRemove">The sparse index to remove.</param>
 696        /// <param name="indexToSwapFrom">
 697        ///     Set the data array value at this index to default after swapping with the data array
 698        ///     value at denseIndexToRemove.
 699        /// </param>
 700        public void RemoveUncheckedFromDenseIndex(int denseIndexToRemove, out int indexToSwapFrom)
 701        {
 702            int sparseIndexToRemove = DenseArray[denseIndexToRemove];
 703            int newLength = Count - 1;
 704            int sparseIndexBeingSwapped = DenseArray[newLength];
 705
 706            // Swap the entry being removed with the last entry.
 707            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 708            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 709
 710            // Clear the dense  index, for debugging purposes
 711            DenseArray[newLength] = -1;
 712
 713            // Add the sparse index to the free list.
 714            SparseArray[sparseIndexToRemove] = FreeIndex;
 715            FreeIndex = sparseIndexToRemove;
 716
 717            Count = newLength;
 718
 719            indexToSwapFrom = newLength;
 720        }
 721
 722        /// <summary>
 723        ///     Removes the associated sparse/dense index pair from active use.
 724        ///     Out parameter used to manage parallel data arrays.
 725        /// </summary>
 726        /// <param name="denseIndexToRemove">The sparse index to remove.</param>
 727        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 728        /// <param name="indexToSwapFrom">
 729        ///     Set the data array value at this index to default after swapping with the data array
 730        ///     value at denseIndexToRemove.
 731        /// </param>
 732        public void RemoveUncheckedFromDenseIndex(int denseIndexToRemove, ulong* versionArray, out int indexToSwapFrom)
 733        {
 734            int sparseIndexToRemove = DenseArray[denseIndexToRemove];
 735            int newLength = Count - 1;
 736            int sparseIndexBeingSwapped = DenseArray[newLength];
 737
 738            // Swap the entry being removed with the last entry.
 739            SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 740            DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 741
 742            // Clear the dense  index, for debugging purposes
 743            DenseArray[newLength] = -1;
 744
 745            // Add the sparse index to the free list.
 746            SparseArray[sparseIndexToRemove] = FreeIndex;
 747            versionArray[sparseIndexToRemove] += 1;
 748            FreeIndex = sparseIndexToRemove;
 749
 750            Count = newLength;
 751
 752            indexToSwapFrom = newLength;
 753        }
 754
 755        /// <summary>
 756        ///     Attempts to remove the associated sparse/dense index pair from active use and increments the version if 
 757        ///     Out parameters used to manage parallel data arrays.
 758        /// </summary>
 759        /// <param name="sparseIndexToRemove">The sparse index to remove.</param>
 760        /// <param name="version">
 761        ///     The version number of the int used to access the sparse index. Used to guard against accessing
 762        ///     indices that have been removed and reused.
 763        /// </param>
 764        /// <param name="versionArray">The array containing the version number to check against.</param>
 765        /// <param name="indexToSwapTo">Replace the data array value at this index with the data array value at indexToS
 766        /// <param name="indexToSwapFrom">
 767        ///     Set the data array value at this index to default after swapping with the data array
 768        ///     value at indexToSwapTo.
 769        /// </param>
 770        /// <returns>True if the entry was valid and thus removed.</returns>
 771        public bool RemoveWithVersionCheck(int sparseIndexToRemove, ulong version, ulong* versionArray, out int indexToS
 772        {
 773            int denseIndexToRemove = SparseArray[sparseIndexToRemove];
 774            ulong versionAtSparseIndex = versionArray[sparseIndexToRemove];
 775
 776            indexToSwapFrom = -1;
 777            indexToSwapTo = -1;
 778
 779            bool succeeded = versionAtSparseIndex == version;
 780
 781            if (succeeded)
 782            {
 783                int newLength = Count - 1;
 784                int sparseIndexBeingSwapped = DenseArray[newLength];
 785
 786                // Swap the entry being removed with the last entry.
 787                SparseArray[sparseIndexBeingSwapped] = denseIndexToRemove;
 788                DenseArray[denseIndexToRemove] = sparseIndexBeingSwapped;
 789
 790                // Clear the dense  index, for debugging purposes
 791                DenseArray[newLength] = -1;
 792
 793                // Add the sparse index to the free list.
 794                SparseArray[sparseIndexToRemove] = FreeIndex;
 795                versionArray[sparseIndexToRemove] += 1;
 796                FreeIndex = sparseIndexToRemove;
 797
 798                Count = newLength;
 799
 800                indexToSwapTo = denseIndexToRemove;
 801                indexToSwapFrom = newLength;
 802            }
 803
 804            return succeeded;
 805        }
 806
 807        /// <summary>
 808        ///     Clear the dense and sparse arrays.
 809        /// </summary>
 810        public void Clear()
 811        {
 812            int capacity = Length;
 813            for (int i = 0; i < capacity; i++)
 814            {
 815                DenseArray[i] = -1;
 816                SparseArray[i] = i + 1;
 817            }
 818
 819            FreeIndex = 0;
 820            Count = 0;
 821        }
 822
 823        /// <summary>
 824        ///     Clear the dense and sparse arrays.
 825        /// </summary>
 826        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 827        public void Clear(ulong* versionArray)
 828        {
 829            int capacity = Length;
 830            for (int i = 0; i < capacity; i++)
 831            {
 832                DenseArray[i] = -1;
 833                SparseArray[i] = i + 1;
 834                versionArray[i] += 1;
 835            }
 836
 837            FreeIndex = 0;
 838            Count = 0;
 839        }
 840
 841        /// <summary>
 842        ///     Clear the dense and sparse arrays and reset the version array.
 843        ///     Note: Only clear the version array if you are sure there are no outstanding dependencies on version numb
 844        /// </summary>
 845        /// ///
 846        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 847        public void ClearWithVersionArrayReset(ulong* versionArray)
 848        {
 849            int capacity = Length;
 850            for (int i = 0; i < capacity; i++)
 851            {
 852                DenseArray[i] = -1;
 853                SparseArray[i] = i + 1;
 854                versionArray[i] = 1;
 855            }
 856
 857            FreeIndex = 0;
 858            Count = 0;
 859        }
 860
 861        /// <summary>
 862        ///     Reallocate the dense and sparse arrays with additional capacity.
 863        /// </summary>
 864        /// <param name="extraCapacity">How many indices to expand the dense and sparse arrays by.</param>
 865        public void Expand(int extraCapacity)
 866        {
 867            int currentCapacity = Length;
 868            int newCapacity = currentCapacity + extraCapacity;
 869
 870            newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 871            --newCapacity;
 872            newCapacity |= newCapacity >> 1;
 873            newCapacity |= newCapacity >> 2;
 874            newCapacity |= newCapacity >> 4;
 875            newCapacity |= newCapacity >> 8;
 876            newCapacity |= newCapacity >> 16;
 877            ++newCapacity;
 878
 879            void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 880
 881            UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 882            int* newSparseArray = (int*)newData;
 883            for (int i = currentCapacity; i < newCapacity; i++)
 884            {
 885                newSparseArray[i] = i + 1;
 886            }
 887
 888            int* newDenseArray = newSparseArray + newCapacity;
 889            UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 890            for (int i = currentCapacity; i < newCapacity; i++)
 891            {
 892                newDenseArray[i] = -1;
 893            }
 894
 895            Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 896
 897            Data = newData;
 898            Length = newCapacity;
 899        }
 900
 901        /// <summary>
 902        ///     Reallocate the dense and sparse arrays with additional capacity.
 903        /// </summary>
 904        /// <param name="extraCapacity">How many indices to expand the dense and sparse arrays by.</param>
 905        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 906        public void Expand(int extraCapacity, ref ulong* versionArray)
 907        {
 908            int currentCapacity = Length;
 909            int newCapacity = currentCapacity + extraCapacity;
 910
 911            newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 912            --newCapacity;
 913            newCapacity |= newCapacity >> 1;
 914            newCapacity |= newCapacity >> 2;
 915            newCapacity |= newCapacity >> 4;
 916            newCapacity |= newCapacity >> 8;
 917            newCapacity |= newCapacity >> 16;
 918            ++newCapacity;
 919
 920            void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 921
 922            UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 923            int* newSparseArray = (int*)newData;
 924            for (int i = currentCapacity; i < newCapacity; i++)
 925            {
 926                newSparseArray[i] = i + 1;
 927            }
 928
 929            int* newDenseArray = newSparseArray + newCapacity;
 930            UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 931            for (int i = currentCapacity; i < newCapacity; i++)
 932            {
 933                newDenseArray[i] = -1;
 934            }
 935
 936            ulong* newVersionArray = (ulong*)Allocator.Allocate(sizeof(ulong), JobsUtility.CacheLineSize, currentCapacit
 937            UnsafeUtility.MemCpy(newVersionArray, versionArray, sizeof(ulong) * currentCapacity);
 938            for (int i = currentCapacity; i < newCapacity; i++)
 939            {
 940                newVersionArray[i] = 1;
 941            }
 942
 943            Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 944            Allocator.Free(versionArray, sizeof(ulong), JobsUtility.CacheLineSize, currentCapacity);
 945            versionArray = newVersionArray;
 946
 947            Data = newData;
 948            Length = newCapacity;
 949        }
 950
 951        /// <summary>
 952        /// Reallocate the dense and sparse arrays with additional capacity if there are not at least <paramref name="nu
 953        /// </summary>
 954        /// <param name="numberToReserve">The number of unused entries to ensure capacity for.</param>
 955        public void Reserve(int numberToReserve)
 956        {
 957            int currentCapacity = Length;
 958            int currentCount = Count;
 959            int newCapacity = currentCount + numberToReserve;
 960
 961            if (newCapacity > currentCapacity)
 962            {
 963                newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 964                --newCapacity;
 965                newCapacity |= newCapacity >> 1;
 966                newCapacity |= newCapacity >> 2;
 967                newCapacity |= newCapacity >> 4;
 968                newCapacity |= newCapacity >> 8;
 969                newCapacity |= newCapacity >> 16;
 970                ++newCapacity;
 971
 972                void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 973
 974                UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 975                int* newSparseArray = (int*)newData;
 976                for (int i = currentCapacity; i < newCapacity; i++)
 977                {
 978                    newSparseArray[i] = i + 1;
 979                }
 980
 981                int* newDenseArray = newSparseArray + newCapacity;
 982                UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 983                for (int i = currentCapacity; i < newCapacity; i++)
 984                {
 985                    newDenseArray[i] = -1;
 986                }
 987
 988                Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 989
 990                Data = newData;
 991                Length = newCapacity;
 992            }
 993        }
 994
 995        /// <summary>
 996        /// Reallocate the dense and sparse arrays with additional capacity if there are not at least <paramref name="nu
 997        /// </summary>
 998        /// <param name="numberToReserve">The number of unused entries to ensure capacity for.</param>
 999        /// <param name="versionArray">Enables detection of use-after-free errors when using sparse indices as reference
 1000        public void Reserve(int numberToReserve,  ref ulong* versionArray)
 1001        {
 1002            int currentCapacity = Length;
 1003            int currentCount = Count;
 1004            int newCapacity = currentCount + numberToReserve;
 1005
 1006            if (newCapacity > currentCapacity)
 1007            {
 1008                newCapacity = newCapacity > MinimumCapacity ? newCapacity : MinimumCapacity;
 1009                --newCapacity;
 1010                newCapacity |= newCapacity >> 1;
 1011                newCapacity |= newCapacity >> 2;
 1012                newCapacity |= newCapacity >> 4;
 1013                newCapacity |= newCapacity >> 8;
 1014                newCapacity |= newCapacity >> 16;
 1015                ++newCapacity;
 1016
 1017                void* newData = Allocator.Allocate(sizeof(int), JobsUtility.CacheLineSize, newCapacity * 2);
 1018
 1019                UnsafeUtility.MemCpy(newData, Data, sizeof(int) * currentCapacity);
 1020                int* newSparseArray = (int*)newData;
 1021                for (int i = currentCapacity; i < newCapacity; i++)
 1022                {
 1023                    newSparseArray[i] = i + 1;
 1024                }
 1025
 1026                int* newDenseArray = newSparseArray + newCapacity;
 1027                UnsafeUtility.MemCpy(newDenseArray, DenseArray, sizeof(int) * currentCapacity);
 1028                for (int i = currentCapacity; i < newCapacity; i++)
 1029                {
 1030                    newDenseArray[i] = -1;
 1031                }
 1032
 1033                ulong* newVersionArray = (ulong*)Allocator.Allocate(sizeof(ulong), JobsUtility.CacheLineSize, currentCap
 1034                UnsafeUtility.MemCpy(newVersionArray, versionArray, sizeof(ulong) * currentCapacity);
 1035                for (int i = currentCapacity; i < newCapacity; i++)
 1036                {
 1037                    newVersionArray[i] = 1;
 1038                }
 1039
 1040                Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, currentCapacity * 2);
 1041                Allocator.Free(versionArray, sizeof(ulong), JobsUtility.CacheLineSize, currentCapacity);
 1042                versionArray = newVersionArray;
 1043
 1044                Data = newData;
 1045                Length = newCapacity;
 1046            }
 1047        }
 1048
 1049        /// <summary>
 1050        /// Disposes the memory of this Sparse Set.
 1051        /// </summary>
 1052        public void Dispose()
 1053        {
 1054            if (Data != null)
 1055            {
 1056                Allocator.Free(Data, sizeof(int), JobsUtility.CacheLineSize, Length * 2);
 1057                Data = null;
 1058                Length = 0;
 1059                Count = 0;
 1060                FreeIndex = 0;
 1061                Allocator = Unity.Collections.Allocator.Invalid;
 1062            }
 1063        }
 1064
 1065        /// <summary>
 1066        /// Creates and schedules a job that disposes the memory of this Sparse Set.
 1067        /// </summary>
 1068        /// <param name="inputDeps">The dependency for the new job.</param>
 1069        /// <returns>The handle of the new job. The job depends upon `inputDeps` and frees the memory of this Sparse Set
 1070        [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to I
 1071        public JobHandle Dispose(JobHandle inputDeps)
 1072        {
 1073            if (CollectionHelper.ShouldDeallocate(Allocator))
 1074            {
 1075                var jobHandle = new DisposeUnsafeSparseSetJob { Ptr = Data, Capacity = Length, Allocator = Allocator }.S
 1076
 1077                Data = null;
 1078                Length = 0;
 1079                Count = 0;
 1080                FreeIndex = 0;
 1081                Allocator = Unity.Collections.Allocator.Invalid;
 1082
 1083                return jobHandle;
 1084            }
 1085
 1086            Data = null;
 1087            Length = 0;
 1088            Count = 0;
 1089            FreeIndex = 0;
 1090            Allocator = Unity.Collections.Allocator.Invalid;
 1091
 1092            return inputDeps;
 1093        }
 1094
 1095        /// <summary>
 1096        /// Creates and schedules a job that disposes the memory of this Sparse Set.
 1097        /// </summary>
 1098        /// <param name="inputDeps">The dependency for the new job.</param>
 1099        /// <returns>The handle of the new job. The job depends upon `inputDeps` and frees the memory of this Sparse Set
 1100        [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to I
 1101        public JobHandle Dispose(JobHandle inputDeps, ref ulong* versionArray)
 1102        {
 1103            if (CollectionHelper.ShouldDeallocate(Allocator))
 1104            {
 1105                var jobHandle = new DisposeUnsafeSparseSetAndVersionArrayJob { Ptr = Data, VersionArrayPtr = versionArra
 1106
 1107                Data = null;
 1108                Length = 0;
 1109                Count = 0;
 1110                FreeIndex = 0;
 1111                Allocator = Unity.Collections.Allocator.Invalid;
 1112                versionArray = null;
 1113
 1114                return jobHandle;
 1115            }
 1116
 1117            Data = null;
 1118            Length = 0;
 1119            Count = 0;
 1120            FreeIndex = 0;
 1121            Allocator = Unity.Collections.Allocator.Invalid;
 1122            versionArray = null;
 1123
 1124            return inputDeps;
 1125        }
 1126
 1127        /// <summary>
 1128        /// Disposes the memory of the version array for this Sparse Set.
 1129        /// </summary>
 1130        /// <param name="versionArray">The pointer of the versionArray to dispose of.</param>
 1131        public void DisposeVersionArray(ref ulong* versionArray)
 1132        {
 1133            Allocator.Free(versionArray, sizeof(ulong), JobsUtility.CacheLineSize, Length);
 1134            versionArray = null;
 1135        }
 1136
 1137        /// <summary>
 1138        /// Creates and schedules a job that disposes the memory of this Sparse Set.
 1139        /// </summary>
 1140        /// <param name="inputDeps">The dependency for the new job.</param>
 1141        /// <returns>The handle of the new job. The job depends upon `inputDeps` and disposes the memory of this Sparse 
 1142        [NotBurstCompatible /* This is not burst compatible because of IJob's use of a static IntPtr. Should switch to I
 1143        public JobHandle DisposeVersionArray(JobHandle inputDeps, ref ulong* versionArray)
 1144        {
 1145            if (CollectionHelper.ShouldDeallocate(Allocator))
 1146            {
 1147                var jobHandle = new DisposeUnsafeVersionArrayJob { Ptr = versionArray, Capacity = Length, Allocator = Al
 1148
 1149                versionArray = null;
 1150
 1151                return jobHandle;
 1152            }
 1153
 1154            versionArray = null;
 1155
 1156            return inputDeps;
 1157        }
 1158    }
 1159
 1160    [BurstCompile]
 1161    internal unsafe struct DisposeUnsafeSparseSetJob : IJob
 1162    {
 1163        [NativeDisableUnsafePtrRestriction]
 1164        public void* Ptr;
 1165        public int Capacity;
 1166        public AllocatorManager.AllocatorHandle Allocator;
 1167
 1168        public void Execute()
 01169        {
 01170            Allocator.Free(Ptr, UnsafeUtility.SizeOf<int>(), JobsUtility.CacheLineSize, Capacity * 2);
 01171        }
 1172    }
 1173
 1174    [BurstCompile]
 1175    internal unsafe struct DisposeUnsafeVersionArrayJob : IJob
 1176    {
 1177        [NativeDisableUnsafePtrRestriction]
 1178        public void* Ptr;
 1179        public int Capacity;
 1180        public AllocatorManager.AllocatorHandle Allocator;
 1181
 1182        public void Execute()
 1183        {
 1184            Allocator.Free(Ptr, UnsafeUtility.SizeOf<ulong>(), JobsUtility.CacheLineSize, Capacity);
 1185        }
 1186    }
 1187
 1188    [BurstCompile]
 1189    internal unsafe struct DisposeUnsafeSparseSetAndVersionArrayJob : IJob
 1190    {
 1191        [NativeDisableUnsafePtrRestriction]
 1192        public void* Ptr;
 1193        [NativeDisableUnsafePtrRestriction]
 1194        public void* VersionArrayPtr;
 1195        public int Capacity;
 1196        public AllocatorManager.AllocatorHandle Allocator;
 1197
 1198        public void Execute()
 1199        {
 1200            Allocator.Free(Ptr, UnsafeUtility.SizeOf<int>(), JobsUtility.CacheLineSize, Capacity * 2);
 1201            Allocator.Free(VersionArrayPtr, UnsafeUtility.SizeOf<ulong>(), JobsUtility.CacheLineSize, Capacity);
 1202        }
 1203    }
 1204
 1205    public struct SparseDenseIndexPair
 1206    {
 1207        public int SparseIndex;
 1208        public int DenseIndex;
 1209    }
 1210
 1211    internal sealed class UnsafeSparseSetDebugView
 1212    {
 1213        UnsafeSparseSet Data;
 1214
 1215        public UnsafeSparseSetDebugView(UnsafeSparseSet data)
 1216        {
 1217            Data = data;
 1218        }
 1219
 1220        public unsafe SparseDenseIndexPair[] Items
 1221        {
 1222            get
 1223            {
 1224                SparseDenseIndexPair[] result = new SparseDenseIndexPair[Data.Count];
 1225
 1226                for (var i = 0; i < Data.Count; ++i)
 1227                {
 1228                    result[i] = new SparseDenseIndexPair() { DenseIndex = i, SparseIndex = Data.DenseArray[i] };
 1229                }
 1230
 1231                return result;
 1232            }
 1233        }
 1234    }
 1235}
 1236#endif // GDX_UNSAFE_COLLECTIONS

Methods/Properties

Execute()