unsafe ref TPair AllocatePair <TPair>(ref CollisionBatch batch, ref CollisionTaskReference reference) where TPair : ICollisionPair <TPair>
 {
     if (!batch.Pairs.Buffer.Allocated)
     {
         batch.Pairs = new UntypedList(Unsafe.SizeOf <TPair>(), reference.BatchSize, Pool);
         if (minimumBatchIndex > reference.TaskIndex)
         {
             minimumBatchIndex = reference.TaskIndex;
         }
         if (maximumBatchIndex < reference.TaskIndex)
         {
             maximumBatchIndex = reference.TaskIndex;
         }
     }
     return(ref batch.Pairs.AllocateUnsafely <TPair>());
 }
        void ResizeMatrix(int newSize)
        {
            var oldSize = topLevelMatrix != null ? topLevelMatrix.Length : 0;

            Array.Resize(ref topLevelMatrix, newSize);
            for (int i = 0; i < newSize; ++i)
            {
                Array.Resize(ref topLevelMatrix[i], newSize);
                for (int j = oldSize; j < newSize; ++j)
                {
                    topLevelMatrix[i][j] = new CollisionTaskReference {
                        TaskIndex = -1
                    };
                }
            }
        }
 private unsafe void Add(ref CollisionTaskReference reference, int flipMask, int shapeTypeA, int shapeTypeB, void *shapeA, void *shapeB,
                         in Vector3 offsetB, in Quaternion orientationA, in Quaternion orientationB, in BodyVelocity velocityA, in BodyVelocity velocityB, float speculativeMargin, float maximumExpansion,
        public int Register(CollisionTask task)
        {
            //Some tasks can generate tasks. Note that this can only be one level deep; nesting compounds is not allowed.
            //All such generators will be placed at the beginning.
            var index = task.SubtaskGenerator ? 0 : count;

            //This allocates a lot of garbage due to frequently resizing, but it does not matter- task registration a one time thing at program initialization.
            //Having tight bounds is more useful for performance in the end (by virtue of having a marginally simpler heap).
            int newCount = count + 1;

            if (tasks == null || newCount > tasks.Length)
            {
                Array.Resize(ref tasks, newCount);
            }
            if (index < count)
            {
                Array.Copy(tasks, index, tasks, index + 1, count - index);
                //Every task in the array that got moved needs to have its top level index bumped.
                for (int i = 0; i < topLevelMatrix.Length; ++i)
                {
                    for (int j = 0; j < topLevelMatrix.Length; ++j)
                    {
                        if (topLevelMatrix[i][j].TaskIndex >= index)
                        {
                            ++topLevelMatrix[i][j].TaskIndex;
                        }
                    }
                }
            }

            tasks[index] = task;
            count        = newCount;

            var a = task.ShapeTypeIndexA;
            var b = task.ShapeTypeIndexB;
            var highestShapeIndex = a > b ? a : b;

            if (highestShapeIndex >= 0)
            {
                //This only handles top level pairs (those associated with shape type pairs).
                //Some tasks are not directly associated with a top level entrypoint- instead, they're follow ups on top level tasks. Since they're not an entry point,
                //there is no need for them to appear in the top level matrix.
                if (highestShapeIndex >= topLevelMatrix.Length)
                {
                    ResizeMatrix(highestShapeIndex + 1);
                }
                var taskInfo = new CollisionTaskReference
                {
                    TaskIndex           = index,
                    BatchSize           = task.BatchSize,
                    ExpectedFirstTypeId = task.ShapeTypeIndexA,
                    PairType            = task.PairType
                };
                topLevelMatrix[a][b] = taskInfo;
                topLevelMatrix[b][a] = taskInfo;
            }

#if DEBUG
            //Ensure that no task dependency cycles exist.
            bool encounteredNongenerator = false;
            for (int i = 0; i < count; ++i)
            {
                if (encounteredNongenerator)
                {
                    Debug.Assert(!tasks[i].SubtaskGenerator,
                                 "To avoid cycles, the tasks list should be partitioned into two contiguous groups: subtask generators, followed by non-subtask generators.");
                }
                else
                {
                    if (!tasks[i].SubtaskGenerator)
                    {
                        encounteredNongenerator = true;
                    }
                }
            }
#endif
            return(index);
        }