Beispiel #1
0
    static void CopyBitsTest(ref NativeBitArray test, int dstPos, int srcPos, int numBits)
    {
        for (int pos = 0; pos < test.Length; pos += 64)
        {
            test.SetBits(pos, 0xaaaaaaaaaaaaaaaaul, 64);
        }

        test.SetBits(srcPos, true, numBits);
        test.Copy(dstPos, srcPos, numBits);
        Assert.AreEqual(true, test.TestAll(dstPos, numBits));

        for (int pos = 0; pos < test.Length; ++pos)
        {
            if ((pos >= dstPos && pos < dstPos + numBits) ||
                (pos >= srcPos && pos < srcPos + numBits))
            {
                Assert.AreEqual(true, test.IsSet(pos));
            }
            else
            {
                Assert.AreEqual((0 != (pos & 1)), test.IsSet(pos));
            }
        }

        test.Clear();
    }
Beispiel #2
0
    public unsafe void NativeBitArray_Find_With_Begin_End()
    {
        var numBits = 512;

        using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
        {
            Assert.AreEqual(0, test.Find(0, 2, 1));
            Assert.AreEqual(1, test.Find(1, 2, 1));
            test.SetBits(0, true, 6);
            Assert.AreEqual(int.MaxValue, test.Find(0, 2, 1));

            for (var j = 0; j < 64; ++j)
            {
                for (var i = 0; i < 256; ++i)
                {
                    var numBitsToFind = 7 + i;
                    var padding       = 11;
                    var begin         = 37 + j;
                    var end           = begin + padding + numBitsToFind;
                    var count         = end - begin;

                    test.Clear();
                    test.SetBits(begin, true, count);
                    test.SetBits(begin + padding + 1, false, numBitsToFind - 1);

                    Assert.AreEqual(begin + padding + 1, test.Find(begin, count, numBitsToFind - 1)); //, $"{j}/{i}: begin {begin}, end {end}, count {count}, numBitsToFind {numBitsToFind}");
                    Assert.AreEqual(int.MaxValue, test.Find(begin, count, numBitsToFind));            //, $"{j}/{i}: begin {begin}, end {end}, count {count}, numBitsToFind {numBitsToFind}");
                }
            }
        }
    }
Beispiel #3
0
    public void NativeBitArray_FindInTinyBitArray()
    {
        var test = new NativeBitArray(3, Allocator.Persistent, NativeArrayOptions.ClearMemory);

        Assert.AreEqual(3, test.Length);

        test.SetBits(0, 0x55, test.Length);

        Assert.AreEqual(1, test.Find(0, 1));
        Assert.AreEqual(1, test.Find(0, test.Length, 1));
        test.SetBits(1, true, 1);
        Assert.True(test.TestAll(0, test.Length));
        Assert.AreEqual(int.MaxValue, test.Find(0, test.Length, 1));

        test.Dispose();
    }
Beispiel #4
0
 void GetBitsTest(ref NativeBitArray test, int pos, int numBits)
 {
     test.SetBits(pos, true, numBits);
     Assert.AreEqual(numBits, test.CountBits(0, test.Length));
     Assert.AreEqual(0xfffffffffffffffful >> (64 - numBits), test.GetBits(pos, numBits));
     test.Clear();
 }
Beispiel #5
0
 static void SetBitsTest(ref NativeBitArray test, int pos, ulong value, int numBits)
 {
     test.SetBits(pos, value, numBits);
     if (value != test.GetBits(pos, numBits))
     {
         throw new Exception("Assert.Equals(value, test.GetBits(pos, numBits)) failed");
     }
     test.Clear();
 }
Beispiel #6
0
    void findWithPattern(ref NativeBitArray test, byte pattern, int numBits)
    {
        for (int pos = 0; pos < test.Length; pos += 8)
        {
            test.SetBits(pos, pattern, 8);
        }

        var bitCount     = math.countbits((int)pattern);
        var numEmptyBits = test.Length - (test.Length / 8 * bitCount);

        for (int i = 0; i < numEmptyBits; i += numBits)
        {
            var pos = test.Find(0, numBits);
            Assert.AreNotEqual(int.MaxValue, pos, $"{i}");
            test.SetBits(pos, true, numBits);
        }

        Assert.True(test.TestAll(0, test.Length));
    }
Beispiel #7
0
 public void NativeBitArray_FindLastUnsetBit([NUnit.Framework.Range(1, 64)] int numBits)
 {
     using (var bits = new NativeBitArray(numBits, Allocator.Persistent))
     {
         // Set all bits to one then unset a single bit to find.
         for (int i = 0; i < numBits; ++i)
         {
             bits.SetBits(0, true, numBits);
             bits.Set(i, false);
             Assert.AreEqual(i, bits.Find(0, 1));
         }
     }
 }
Beispiel #8
0
    public unsafe void NativeBitArray_Find()
    {
        var numBits = 512;

        using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
        {
            test.SetBits(0, true, 11);

            for (var i = 0; i < 256; ++i)
            {
                Assert.AreEqual(11, test.Find(0, i + 1));
            }

            for (var j = 0; j < 64; ++j)
            {
                for (var i = 0; i < 256; ++i)
                {
                    var numBitsToFind = 7 + i;
                    var pos           = 37 + j;

                    test.SetBits(0, true, test.Length);
                    test.SetBits(pos, false, numBitsToFind);

                    Assert.AreEqual(pos, test.Find(0, numBitsToFind));   //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
                    Assert.AreEqual(pos, test.Find(pos, numBitsToFind)); //, $"{j}/{i}:pos {pos}, numBitsToFind {numBitsToFind}");

                    Assert.AreEqual(pos, test.Find(0, numBitsToFind));   //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
                    Assert.AreEqual(pos, test.Find(pos, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");

                    Assert.IsTrue(test.TestNone(test.Find(0, numBitsToFind), numBitsToFind));

                    Assert.AreEqual(int.MaxValue, test.Find(pos + 1, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
                }
            }
        }
    }
Beispiel #9
0
    public void NativeBitArray_Get_Set_Tiny()
    {
        var numBits = 7;

        var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);

        Assert.False(test.IsSet(3));
        test.Set(3, true);
        Assert.True(test.IsSet(3));

        Assert.False(test.TestAll(0, numBits));
        Assert.False(test.TestNone(0, numBits));
        Assert.True(test.TestAny(0, numBits));
        Assert.AreEqual(1, test.CountBits(0, numBits));

        Assert.False(test.TestAll(0, 2));
        Assert.True(test.TestNone(0, 2));
        Assert.False(test.TestAny(0, 2));

        test.Clear();
        Assert.False(test.IsSet(3));
        Assert.AreEqual(0, test.CountBits(0, numBits));

        test.SetBits(3, true, 4);
        Assert.AreEqual(4, test.CountBits(0, numBits));

        test.SetBits(0, true, numBits);
        Assert.False(test.TestNone(0, numBits));
        Assert.True(test.TestAll(0, numBits));

        test.SetBits(0, false, numBits);
        Assert.True(test.TestNone(0, numBits));
        Assert.False(test.TestAll(0, numBits));

        test.Dispose();
    }
Beispiel #10
0
    public unsafe void NativeBitArray_CopyBetweenBitArrays()
    {
        var numBits = 512;

        var str = new FixedString128("aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ");

        AtomicSafetyHandle ash;
        DisposeSentinel    ds;

        DisposeSentinel.Create(out ash, out ds, 1, Allocator.Temp);

        var test0 = NativeBitArrayUnsafeUtility.ConvertExistingDataToNativeBitArray(&str.bytes.offset0000, 64, Allocator.None);

        NativeBitArrayUnsafeUtility.SetAtomicSafetyHandle(ref test0, ash);

        var test1 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
        var test2 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);

        for (int pos = 0; pos < test0.Length; pos += 64)
        {
            test1.SetBits(pos, 0x5555555555555555ul, 64);
            test2.SetBits(pos, 0xaaaaaaaaaaaaaaaaul, 64);
        }

        test1.Copy(1, ref test0, 205, 211);
        test1.Copy(214, ref test0, 0, 205);

        test2.Copy(205, ref test1, 1, 211);
        test2.Copy(0, ref test1, 214, 205);

        test0.Copy(0, ref test2, 0, 512);

        Assert.AreEqual(str, "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ");

        test0.Dispose();
        test1.Dispose();
        test2.Dispose();
    }
Beispiel #11
0
    public void NativeBitArray_Get_Set()
    {
        var numBits = 256;

        var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);

        Assert.False(test.IsSet(123));
        test.Set(123, true);
        Assert.True(test.IsSet(123));

        Assert.False(test.TestAll(0, numBits));
        Assert.False(test.TestNone(0, numBits));
        Assert.True(test.TestAny(0, numBits));
        Assert.AreEqual(1, test.CountBits(0, numBits));

        Assert.False(test.TestAll(0, 122));
        Assert.True(test.TestNone(0, 122));
        Assert.False(test.TestAny(0, 122));

        test.Clear();
        Assert.False(test.IsSet(123));
        Assert.AreEqual(0, test.CountBits(0, numBits));

        test.SetBits(40, true, 4);
        Assert.AreEqual(4, test.CountBits(0, numBits));

        test.SetBits(0, true, numBits);
        Assert.False(test.TestNone(0, numBits));
        Assert.True(test.TestAll(0, numBits));

        test.SetBits(0, false, numBits);
        Assert.True(test.TestNone(0, numBits));
        Assert.False(test.TestAll(0, numBits));

        test.SetBits(123, true, 7);
        Assert.True(test.TestAll(123, 7));

        test.Clear();
        test.SetBits(64, true, 64);
        Assert.AreEqual(false, test.IsSet(63));
        Assert.AreEqual(true, test.TestAll(64, 64));
        Assert.AreEqual(false, test.IsSet(128));
        Assert.AreEqual(64, test.CountBits(64, 64));
        Assert.AreEqual(64, test.CountBits(0, numBits));

        test.Clear();
        test.SetBits(65, true, 62);
        Assert.AreEqual(false, test.IsSet(64));
        Assert.AreEqual(true, test.TestAll(65, 62));
        Assert.AreEqual(false, test.IsSet(127));
        Assert.AreEqual(62, test.CountBits(64, 64));
        Assert.AreEqual(62, test.CountBits(0, numBits));

        test.Clear();
        test.SetBits(66, true, 64);
        Assert.AreEqual(false, test.IsSet(65));
        Assert.AreEqual(true, test.TestAll(66, 64));
        Assert.AreEqual(false, test.IsSet(130));
        Assert.AreEqual(64, test.CountBits(66, 64));
        Assert.AreEqual(64, test.CountBits(0, numBits));

        test.Dispose();
    }
Beispiel #12
0
 static void SetBitsTest(ref NativeBitArray test, int pos, ulong value, int numBits)
 {
     test.SetBits(pos, value, numBits);
     Assert.AreEqual(value, test.GetBits(pos, numBits));
     test.Clear();
 }
Beispiel #13
0
            public void Execute(int index)
            {
                int globalIndex = jobIndexStride + index;

                int startNodeIndex = startIndices[globalIndex];
                int endNodeIndex   = endIndices[globalIndex];

                // Note: Temp allocator can fall back to a very much slower version if the block of
                // memory that it uses is exhausted. By the looks of the tests that I have done, it
                // seems that this memory is released after the job is finished. I had this
                // originally in an IJobParallelFor and there were threads that introduced
                // significant bottlenecks due to this issue (the inner loop batch count didn't
                // matter), but after switching to a "batch of IJobs" this issue is gone, as the
                // maximum jobs that can run at the same time is just the number of logical threads
                // of the system, which shouldn't be more than ~32 in a high end system (although
                // some threadrippers can go up to 128, which eventually may be an issue again). I
                // have tested this in a complete flat map with no obstacles, and the time to
                // complete each job is reasonably similar.

                // Update: I have been exhaustively testing the new approach with thousands of IJobs
                // and simple paths. This approach is certainly much better than the one mentioned
                // above, but it has a considerably big issue: when there's tons of simple paths,
                // the dependencies become too complex and the main thread struggles more and more
                // as the number of paths increases, since the workers push hard to finish all the
                // tasks, but the main thread has to check every single jobhandle when calling
                // CompleteAll or combining dependencies (do note that this is speculation based on
                // my observations in the profiler though).

                // Update2: I have ended using IJobFor with very low iterations (8 seem to work fine
                // enough). I am now in a middle ground between 1. and 2. mentioned above. I think
                // it is a decent spot but with lots of paths and very low work, I am seeing that
                // some paths take extremely long time to be computed. At this point I think the
                // only way to get it better is going into micro-optimization and some kind of
                // hierarchiccal pathfinding, There are obviously other ways of computing
                // pathfinding for large crowds such as flow fields, but I'm currently only
                // interested in A*. If memory is really the problem, hierarchiccal pathfinding
                // should greatly increase performance as constraining the searchs to i.e a 16x16
                // grid (so we could use bytes for gCost and hCost and sub-indices). The open and
                // closed set would also be extremely constrained and it may also be possible to use
                // fixedlist for some of the info, which may give huge speedups.

                // I have tried swapping this by just a plain int3 and surprisingly, it is
                // substantially slower.
                NativeArray <NodePathFindInfo> nodesInfo = new NativeArray <NodePathFindInfo>(numNodes, Allocator.Temp);
                NativeBitArray closedSet       = new NativeBitArray(numNodes, Allocator.Temp);
                NativeBitArray openSetContains = new NativeBitArray(numNodes, Allocator.Temp);

                // Warning: 272 is a magical number due to the map layout and possible paths, which
                // seems to not throw errors about being too low for the test scene. This list
                // should be somewhat constrained to a low range in order to keep the algorithm
                // performant, otherwise it would be worth to look at implementing a native binary
                // heap to speed up the extaction of the lowest fcost node.
                NativeList <int> openSet = new NativeList <int>(272, Allocator.Temp);

                // set the info for the first node
                nodesInfo[startNodeIndex] = new NodePathFindInfo(0, GetHeuristic(startNodeIndex, endNodeIndex), -1);
                openSet.AddNoResize(startNodeIndex);

                while (openSet.Length > 0)
                {
                    int currNodeIndex = PopLowestFCostNodeIndexFromOpenSet(openSet, nodesInfo);

                    // we've reached the goal
                    if (currNodeIndex == endNodeIndex)
                    {
                        SaveNextNodeIndexToMoveTo(globalIndex, nodesInfo);
                        return;
                    }

                    // add it to the closed set by setting a flag at its index
                    closedSet.SetBits(currNodeIndex, true, 1);
                    NodePathFindInfo currNodeInfo = nodesInfo[currNodeIndex];

                    // go over the neighbors
                    int start = currNodeIndex * numNeighbors;
                    int end   = start + numNeighbors;

                    for (int i = start; i < end; ++i)
                    {
                        int neighborIndex = nodesNeighbors[i].neighborIndex;

                        // if it does not have neighbor, was already expanded or can't be walked by
                        if (!nodesNeighbors[i].isValid || closedSet.IsSet(neighborIndex) || (byte)nodesTypes[neighborIndex] > 0)
                        {
                            continue;
                        }

                        NodePathFindInfo neighborNodeInfo = nodesInfo[neighborIndex];
                        int newGCost = currNodeInfo.gCost + GetHeuristic(currNodeIndex, neighborIndex);

                        // not in open set
                        if (!openSetContains.IsSet(neighborIndex))
                        {
                            // update parent, costs, and add to the open set
                            neighborNodeInfo.gCost           = newGCost;
                            neighborNodeInfo.hCost           = GetHeuristic(neighborIndex, endNodeIndex);
                            neighborNodeInfo.parentNodeIndex = currNodeIndex;

                            nodesInfo[neighborIndex] = neighborNodeInfo;
                            openSet.AddNoResize(neighborIndex);
                            openSetContains.SetBits(neighborIndex, 1);
                        }
                        else if (newGCost < neighborNodeInfo.gCost)
                        {
                            // update parent, and gCost (hCost is already calculated)
                            neighborNodeInfo.gCost           = newGCost;
                            neighborNodeInfo.parentNodeIndex = currNodeIndex;

                            nodesInfo[neighborIndex] = neighborNodeInfo;
                        }
                    }
                }

                // Note: TODO? I think the only way to get here is if the way to a valid end node is
                // completely blocked, in which case I should decide what to do
                return;
            }
Beispiel #14
0
    public void NativeBitArray_Get_Set_Short()
    {
        var numBits = 31;

        var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);

        Assert.False(test.IsSet(13));
        test.Set(13, true);
        Assert.True(test.IsSet(13));

        Assert.False(test.TestAll(0, numBits));
        Assert.False(test.TestNone(0, numBits));
        Assert.True(test.TestAny(0, numBits));
        Assert.AreEqual(1, test.CountBits(0, numBits));

        Assert.False(test.TestAll(0, 12));
        Assert.True(test.TestNone(0, 12));
        Assert.False(test.TestAny(0, 12));

        test.Clear();
        Assert.False(test.IsSet(13));
        Assert.AreEqual(0, test.CountBits(0, numBits));

        test.SetBits(4, true, 4);
        Assert.AreEqual(4, test.CountBits(0, numBits));

        test.SetBits(0, true, numBits);
        Assert.False(test.TestNone(0, numBits));
        Assert.True(test.TestAll(0, numBits));

        test.SetBits(0, false, numBits);
        Assert.True(test.TestNone(0, numBits));
        Assert.False(test.TestAll(0, numBits));

        test.SetBits(13, true, 7);
        Assert.True(test.TestAll(13, 7));

        test.Clear();
        test.SetBits(4, true, 4);
        Assert.AreEqual(false, test.IsSet(3));
        Assert.AreEqual(true, test.TestAll(4, 4));
        Assert.AreEqual(false, test.IsSet(18));
        Assert.AreEqual(4, test.CountBits(4, 4));
        Assert.AreEqual(4, test.CountBits(0, numBits));

        test.Clear();
        test.SetBits(5, true, 2);
        Assert.AreEqual(false, test.IsSet(4));
        Assert.AreEqual(true, test.TestAll(5, 2));
        Assert.AreEqual(false, test.IsSet(17));
        Assert.AreEqual(2, test.CountBits(4, 4));
        Assert.AreEqual(2, test.CountBits(0, numBits));

        test.Clear();
        test.SetBits(6, true, 4);
        Assert.AreEqual(false, test.IsSet(5));
        Assert.AreEqual(true, test.TestAll(6, 4));
        Assert.AreEqual(false, test.IsSet(10));
        Assert.AreEqual(4, test.CountBits(6, 4));
        Assert.AreEqual(4, test.CountBits(0, numBits));

        test.Dispose();
    }