internal static void SelfSweep <T>(BucketSlices bucket, T processor) where T : struct, IFindPairsProcessor
        {
            int count = bucket.xmins.Length;

            for (int i = 0; i < count - 1; i++)
            {
                for (int j = i + 1; j < count && bucket.xmins[j] <= bucket.xmaxs[i]; j++)
                {
                    float4 less = new float4(bucket.yzminmaxs[i].z, bucket.yzminmaxs[j].z, bucket.yzminmaxs[i].w, bucket.yzminmaxs[j].w);
                    float4 more = new float4(bucket.yzminmaxs[j].x, bucket.yzminmaxs[i].x, bucket.yzminmaxs[j].y, bucket.yzminmaxs[i].y);

                    bool4 tests = less < more;
                    if (math.bitmask(tests) == 0)
                    {
                        processor.Execute(new FindPairsResult
                        {
                            bodyA      = bucket.bodies[i],
                            bodyB      = bucket.bodies[j],
                            bodyAIndex = i,
                            bodyBIndex = j,
                        });
                    }
                }
            }
        }
        internal static void BipartiteSweep <T>(BucketSlices bucketA, BucketSlices bucketB, T processor) where T : struct, IFindPairsProcessor
        {
            int countA = bucketA.xmins.Length;
            int countB = bucketB.xmins.Length;

            if (countA == 0 || countB == 0)
            {
                return;
            }

            //Check for b starting in a's x range
            int bstart = 0;

            for (int i = 0; i < countA; i++)
            {
                //Advance to b.xmin >= a.xmin
                //Include equals case by stopping when equal
                while (bstart < countB && bucketB.xmins[bstart] < bucketA.xmins[i])
                {
                    bstart++;
                }
                if (bstart >= countB)
                {
                    break;
                }

                for (int j = bstart; j < countB && bucketB.xmins[j] <= bucketA.xmaxs[i]; j++)
                {
                    float4 less = new float4(bucketA.yzminmaxs[i].z, bucketB.yzminmaxs[j].z, bucketA.yzminmaxs[i].w, bucketB.yzminmaxs[j].w);
                    float4 more = new float4(bucketB.yzminmaxs[j].x, bucketA.yzminmaxs[i].x, bucketB.yzminmaxs[j].y, bucketA.yzminmaxs[i].y);

                    bool4 tests = less < more;

                    if (math.bitmask(tests) == 0)
                    {
                        processor.Execute(new FindPairsResult
                        {
                            bodyA      = bucketA.bodies[i],
                            bodyB      = bucketB.bodies[j],
                            bodyAIndex = i,
                            bodyBIndex = j,
                        });
                    }
                }
            }

            //Check for a starting in b's x range
            int astart = 0;

            for (int i = 0; i < countB; i++)
            {
                //Advance to a.xmin > b.xmin
                //Exclude equals case this time by continuing if equal
                while (astart < countA && bucketA.xmins[astart] <= bucketB.xmins[i])
                {
                    astart++;
                }
                if (astart >= countA)
                {
                    break;
                }

                for (int j = astart; j < countA && bucketA.xmins[j] <= bucketB.xmaxs[i]; j++)
                {
                    float4 less = new float4(bucketB.yzminmaxs[i].z, bucketA.yzminmaxs[j].z, bucketB.yzminmaxs[i].w, bucketA.yzminmaxs[j].w);
                    float4 more = new float4(bucketA.yzminmaxs[j].x, bucketB.yzminmaxs[i].x, bucketA.yzminmaxs[j].y, bucketB.yzminmaxs[i].y);

                    bool4 tests = less < more;

                    if (math.bitmask(tests) == 0)
                    {
                        processor.Execute(new FindPairsResult
                        {
                            bodyA      = bucketA.bodies[j],
                            bodyB      = bucketB.bodies[i],
                            bodyAIndex = i,
                            bodyBIndex = j,
                        });
                    }
                }
            }
        }