using System; using System.Collections.Generic; using NUnit.Framework; using Unity.Collections; using Unity.Collections.Tests; using Unity.Jobs; using Assert = FastAssert; internal class MathTests : CollectionsTestCommonBase { [Test] public void Tests() { Assert.AreEqual(0, CollectionHelper.Log2Floor(1)); Assert.AreEqual(1, CollectionHelper.Log2Floor(2)); Assert.AreEqual(1, CollectionHelper.Log2Floor(3)); Assert.AreEqual(2, CollectionHelper.Log2Floor(4)); Assert.AreEqual(3, CollectionHelper.Log2Floor(15)); Assert.AreEqual(4, CollectionHelper.Log2Floor(16)); Assert.AreEqual(4, CollectionHelper.Log2Floor(19)); Assert.AreEqual(30, CollectionHelper.Log2Floor(int.MaxValue)); Assert.AreEqual(16, CollectionHelper.Log2Floor(1 << 16)); Assert.AreEqual(-1, CollectionHelper.Log2Floor(0)); } } internal class NativeArraySortTests : CollectionsTestCommonBase { [Test] public void SortNativeArray_RandomInts_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = random.NextInt(int.MinValue, int.MaxValue); } array.Sort(); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } [Test] public void SortNativeArray_SortedInts_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = i; } array.Sort(); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } [Test] public void SortNativeArray_RandomBytes_ReturnSorted([Values(0, 1, 10, 1000, 10000, 100000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = (byte)random.NextInt(byte.MinValue, byte.MinValue); } array.Sort(); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } [Test] public void SortNativeArray_RandomShorts_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = (short)random.NextInt(short.MinValue, short.MaxValue); } array.Sort(); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } [Test] public void SortNativeArray_RandomFloats_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = (float)random.NextDouble(); } array.Sort(); float min = float.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } struct ComparableType : IComparable { public int value; public int CompareTo(ComparableType other) => value.CompareTo(other.value); } [Test] public void SortNativeArray_RandomComparableType_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = new ComparableType { value = random.NextInt(int.MinValue, int.MaxValue) }; } array.Sort(); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i.value); min = i.value; } array.Dispose(); } struct NonComparableType { public int value; } struct NonComparableTypeComparator : IComparer { public int Compare(NonComparableType lhs, NonComparableType rhs) { return lhs.value.CompareTo(rhs.value); } } [Test] public void SortNativeArray_RandomNonComparableType_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = new NonComparableType { value = random.NextInt(int.MinValue, int.MaxValue) }; } array.Sort(new NonComparableTypeComparator()); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i.value); min = i.value; } array.Dispose(); } [Test] public void SortNativeSlice_ReturnSorted() { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(1000, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; ++i) { array[i] = random.NextInt(int.MinValue, int.MaxValue); } var slice = new NativeSlice(array, 200, 600); slice.Sort(); int min = int.MinValue; foreach (var i in slice) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } [Test] public void SortNativeSlice_DoesNotChangeArrayBeyondLimits() { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(1000, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; ++i) { array[i] = random.NextInt(int.MinValue, int.MaxValue); } var backupArray = new NativeArray(array.Length, Allocator.Persistent); backupArray.CopyFrom(array); var slice = new NativeSlice(array, 200, 600); slice.Sort(); for (var i = 0; i < 200; ++i) { Assert.AreEqual(backupArray[i], array[i]); } for (var i = 800; i < 1000; ++i) { Assert.AreEqual(backupArray[i], array[i]); } array.Dispose(); backupArray.Dispose(); } [Test] [TestRequiresDotsDebugOrCollectionChecks] public void SortNativeSlice_WithCustomStride_ThrowsInvalidOperationException() { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(10, Allocator.Persistent); for (int i = 0; i < array.Length; ++i) { array[i] = random.NextInt(int.MinValue, int.MaxValue); } var slice = new NativeSlice(array, 2, 6); var sliceWithCustomStride = slice.SliceWithStride(); Assert.DoesNotThrow(() => slice.Sort()); Assert.Throws(() => sliceWithCustomStride.Sort()); array.Dispose(); } } internal class NativeSliceTests : CollectionsTestCommonBase { [Test] public void NativeSlice_CopyTo() { NativeArray array = new NativeArray(1000, Allocator.Persistent); for (int i = 0; i < array.Length; ++i) { array[i] = i; } var copyToArray = new int[600]; for (int i = 0; i < copyToArray.Length; ++i) { copyToArray[i] = 0x12345678; } var slice = new NativeSlice(array, 200, 600); slice.CopyTo(copyToArray); for (var i = 0; i < 600; ++i) { Assert.AreEqual(copyToArray[i], array[i + 200]); } array.Dispose(); } [Test] public void NativeSlice_CopyFrom() { NativeArray array = new NativeArray(1000, Allocator.Persistent); for (int i = 0; i < array.Length; ++i) { array[i] = i; } var copyFromArray = new int[600]; for (int i = 0; i < copyFromArray.Length; ++i) { copyFromArray[i] = 0x12345678; } var slice = new NativeSlice(array, 200, 600); slice.CopyFrom(copyFromArray); for (var i = 0; i < 600; ++i) { Assert.AreEqual(slice[i], 0x12345678); } array.Dispose(); } [Test] public void SortJobNativeArray_RandomInts_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = random.NextInt(int.MinValue, int.MaxValue); } array.SortJob().Schedule().Complete(); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } [Test] public void SortJobNativeArray_SortedInts_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = i; } array.SortJob().Schedule().Complete(); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } [Test] public void SortJobNativeArray_RandomBytes_ReturnSorted([Values(0, 1, 10, 1000, 10000, 100000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = (byte)random.NextInt(byte.MinValue, byte.MinValue); } array.SortJob().Schedule().Complete(); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } struct DescendingComparer : IComparer where T : IComparable { public int Compare(T x, T y) => y.CompareTo(x); } [Test] public void SortJobNativeArray_RandomBytes_ReturnSorted_Descending([Values(0, 1, 10, 1000, 10000, 100000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = (byte)random.NextInt(byte.MinValue, byte.MinValue); } array.SortJob(new DescendingComparer()).Schedule().Complete(); int max = int.MaxValue; foreach (var i in array) { Assert.GreaterOrEqual(max, i); max = i; } array.Dispose(); } [Test] public void SortJobNativeArray_RandomShorts_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = (short)random.NextInt(short.MinValue, short.MaxValue); } array.SortJob().Schedule().Complete(); int min = int.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } [Test] public void SortNativeArrayByJob_RandomShorts_ReturnSorted_Descending([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = (short)random.NextInt(short.MinValue, short.MaxValue); } array.SortJob(new DescendingComparer()).Schedule().Complete(); int max = int.MaxValue; foreach (var i in array) { Assert.GreaterOrEqual(max, i); max = i; } array.Dispose(); } [Test] public void SortJobNativeArray_RandomFloats_ReturnSorted([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = (float)random.NextDouble(); } array.SortJob().Schedule().Complete(); float min = float.MinValue; foreach (var i in array) { Assert.LessOrEqual(min, i); min = i; } array.Dispose(); } [Test] public void SortJobNativeArray_RandomFloats_ReturnSorted_Descending([Values(0, 1, 10, 1000, 10000)] int size) { var random = new Unity.Mathematics.Random(1); NativeArray array = new NativeArray(size, Allocator.Persistent); Assert.IsTrue(array.IsCreated); for (int i = 0; i < array.Length; i++) { array[i] = (float)random.NextDouble(); } array.SortJob(new DescendingComparer()).Schedule().Complete(); float max = float.MaxValue; foreach (var i in array) { Assert.GreaterOrEqual(max, i); max = i; } array.Dispose(); } struct FilterOdd : IJobFilter { public bool Execute(int index) => index % 2 == 0; } [Test] public void SortJobNativeList_UseInPreviousJob() { var rng = new Unity.Mathematics.Random(123); NativeList indices = new NativeList(10, Allocator.TempJob); for (int i = 0; i < 10; i++) { indices.Add(rng.NextInt(100)); } var handle = new FilterOdd().ScheduleFilter(indices); var sortJob = indices.SortJobDefer(new DescendingComparer()); handle = sortJob.Schedule(handle); handle.Complete(); float max = float.MaxValue; foreach (var i in indices) { Assert.IsTrue(0 == (i & 1)); Assert.GreaterOrEqual(max, i); max = i; } indices.Dispose(); } }