using NUnit.Framework; using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using Unity.Collections; namespace UnityEditor.Rendering.Tests { unsafe class CoreUnsafeUtilsTests { public struct TestData : IEquatable { public int intValue; public float floatValue; public bool Equals(TestData other) { return intValue == other.intValue && floatValue == other.floatValue; } public override bool Equals(object obj) { if (!(obj is TestData)) return false; return Equals((TestData)obj); } public override int GetHashCode() { fixed (float* fptr = &floatValue) return intValue ^ *(int*)fptr; } } static object[][] s_CopyToList = new object[][] { new object[] { new List { new TestData { floatValue = 2, intValue = 1 }, new TestData { floatValue = 3, intValue = 2 }, new TestData { floatValue = 4, intValue = 3 }, new TestData { floatValue = 5, intValue = 4 }, new TestData { floatValue = 6, intValue = 5 }, } } }; [Test] [TestCaseSource("s_CopyToList")] public void CopyToList(List datas) { var dest = stackalloc TestData[datas.Count]; datas.CopyTo(dest, datas.Count); for (int i = 0; i < datas.Count; ++i) Assert.AreEqual(datas[i], dest[i]); } static object[][] s_CopyToArray = new object[][] { new object[] { new TestData[] { new TestData { floatValue = 2, intValue = 1 }, new TestData { floatValue = 3, intValue = 2 }, new TestData { floatValue = 4, intValue = 3 }, new TestData { floatValue = 5, intValue = 4 }, new TestData { floatValue = 6, intValue = 5 }, } } }; [Test] [TestCaseSource("s_CopyToArray")] public void CopyToArray(TestData[] datas) { var dest = stackalloc TestData[datas.Length]; datas.CopyTo(dest, datas.Length); for (int i = 0; i < datas.Length; ++i) Assert.AreEqual(datas[i], dest[i]); } static object[][] s_QuickSort = new object[][] { new object[] { new int[] { 0, 1 } }, new object[] { new int[] { 1, 0 } }, new object[] { new int[] { 0, 4, 2, 6, 3, 7, 1, 5 } }, // Test with unique set new object[] { new int[] { 0, 4, 2, 6, 4, 7, 1, 5 } }, // Test with non unique set }; [Test] [TestCaseSource("s_QuickSort")] public void QuickSort(int[] values) { // We must perform a copy to avoid messing the test data directly var ptrValues = stackalloc int[values.Length]; values.CopyTo(ptrValues, values.Length); CoreUnsafeUtils.QuickSort(values.Length, ptrValues); for (int i = 0; i < values.Length - 1; ++i) Assert.LessOrEqual(ptrValues[i], ptrValues[i + 1]); } static object[][] s_QuickSortHash = new object[][] { new object[] { new Hash128[] { Hash128.Parse("78b27b84a9011b5403e836b9dfa51e33"), Hash128.Parse("c7417d322c083197631326bccf3f9ea0"), Hash128.Parse("dd27f0dc4ffe20b0f8ecc0e4fdf618fe") }, new Hash128[] { Hash128.Parse("dd27f0dc4ffe20b0f8ecc0e4fdf618fe"), Hash128.Parse("c7417d322c083197631326bccf3f9ea0"), Hash128.Parse("78b27b84a9011b5403e836b9dfa51e33") }, }, }; [Test] [TestCaseSource("s_QuickSortHash")] public void QuickSortHash(Hash128[] l, Hash128[] r) { var lPtr = stackalloc Hash128[l.Length]; var rPtr = stackalloc Hash128[r.Length]; for (int i = 0; i < l.Length; ++i) { lPtr[i] = l[i]; rPtr[i] = r[i]; } CoreUnsafeUtils.QuickSort(l.Length, lPtr); CoreUnsafeUtils.QuickSort(r.Length, rPtr); for (int i = 0; i < l.Length - 1; ++i) { Assert.LessOrEqual(lPtr[i], lPtr[i + 1]); Assert.LessOrEqual(rPtr[i], rPtr[i + 1]); } for (int i = 0; i < l.Length; ++i) { Assert.AreEqual(lPtr[i], rPtr[i]); } } static object[][] s_UintSortData = new object[][] { new object[] { new uint[] { 0 } }, new object[] { new uint[] { 0, 1, 20123, 29, 0xffffff } }, new object[] { new uint[] { 0xff1235, 92, 22125, 67358, 92123, 7012, 1234, 10000 } }, // Test with unique set }; [Test] [TestCaseSource("s_UintSortData")] public void InsertionSort(uint[] values) { var array = new NativeArray(values, Allocator.Temp); CoreUnsafeUtils.InsertionSort(array, array.Length); for (int i = 0; i < array.Length - 1; ++i) Assert.LessOrEqual(array[i], array[i + 1]); array.Dispose(); } [Test] [TestCaseSource("s_UintSortData")] public void MergeSort(uint[] values) { NativeArray supportArray = new NativeArray(); var array = new NativeArray(values, Allocator.Temp); CoreUnsafeUtils.MergeSort(array, array.Length, ref supportArray); for (int i = 0; i < array.Length - 1; ++i) Assert.LessOrEqual(array[i], array[i + 1]); array.Dispose(); supportArray.Dispose(); } [Test] [TestCaseSource("s_UintSortData")] public void RadixSort(uint[] values) { NativeArray supportArray = new NativeArray(); var array = new NativeArray(values, Allocator.Temp); CoreUnsafeUtils.RadixSort(array, array.Length, ref supportArray); for (int i = 0; i < array.Length - 1; ++i) Assert.LessOrEqual(array[i], array[i + 1]); array.Dispose(); supportArray.Dispose(); } static object[][] s_PartialSortData = new object[][] { new object[] { new uint[] { 2, 8, 9, 2, 4, 0, 1, 0, 1, 0 } } }; private enum SortAlgorithm { Insertion, Merge, Radix }; [Test] [TestCaseSource("s_PartialSortData")] public void PartialSortInsertionMergeRadix(uint[] values) { NativeArray supportArray = new NativeArray(); int sortCount = 5; foreach (var algorithmId in Enum.GetValues(typeof(SortAlgorithm))) { var algorithmValue = (SortAlgorithm)algorithmId; var array = new NativeArray(values, Allocator.Temp); if (algorithmValue == SortAlgorithm.Insertion) CoreUnsafeUtils.InsertionSort(array, sortCount); else if (algorithmValue == SortAlgorithm.Merge) CoreUnsafeUtils.MergeSort(array, sortCount, ref supportArray); else if (algorithmValue == SortAlgorithm.Radix) CoreUnsafeUtils.RadixSort(array, sortCount, ref supportArray); for (int i = 0; i < sortCount - 1; ++i) Assert.LessOrEqual(array[i], array[i + 1]); for (int i = sortCount; i < array.Length; ++i) Assert.That(array[i] == 0 || array[i] == 1); array.Dispose(); } supportArray.Dispose(); } } }