Sin descripción
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnsafeHashSetTests.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. using System;
  2. using NUnit.Framework;
  3. using Unity.Burst;
  4. using Unity.Collections;
  5. using Unity.Collections.Tests;
  6. using Unity.Jobs;
  7. using Unity.Collections.LowLevel.Unsafe;
  8. using UnityEngine;
  9. using UnityEngine.TestTools;
  10. #if !UNITY_PORTABLE_TEST_RUNNER
  11. using System.Text.RegularExpressions;
  12. #endif
  13. internal class UnsafeHashSetTests : CollectionsTestCommonBase
  14. {
  15. static void ExpectedCount<T>(ref UnsafeHashSet<T> container, int expected)
  16. where T : unmanaged, IEquatable<T>
  17. {
  18. Assert.AreEqual(expected == 0, container.IsEmpty);
  19. Assert.AreEqual(expected, container.Count());
  20. }
  21. [Test]
  22. public void UnsafeHashSet_IsEmpty()
  23. {
  24. var container = new UnsafeHashSet<int>(0, Allocator.Persistent);
  25. Assert.IsTrue(container.IsEmpty);
  26. Assert.IsTrue(container.Add(0));
  27. Assert.IsFalse(container.IsEmpty);
  28. Assert.AreEqual(1, container.Capacity);
  29. ExpectedCount(ref container, 1);
  30. container.Remove(0);
  31. Assert.IsTrue(container.IsEmpty);
  32. Assert.IsTrue(container.Add(0));
  33. container.Clear();
  34. Assert.IsTrue(container.IsEmpty);
  35. container.Dispose();
  36. }
  37. [Test]
  38. public void UnsafeHashSet_Capacity()
  39. {
  40. var container = new UnsafeHashSet<int>(0, Allocator.Persistent);
  41. Assert.IsTrue(container.IsEmpty);
  42. Assert.AreEqual(0, container.Capacity);
  43. container.Capacity = 10;
  44. Assert.AreEqual(10, container.Capacity);
  45. container.Dispose();
  46. }
  47. #if !UNITY_DOTSRUNTIME // DOTS-Runtime has an assertion in the C++ layer, that can't be caught in C#
  48. [Test]
  49. public void UnsafeHashSet_Full_Throws()
  50. {
  51. var container = new UnsafeHashSet<int>(16, Allocator.Temp);
  52. ExpectedCount(ref container, 0);
  53. for (int i = 0, capacity = container.Capacity; i < capacity; ++i)
  54. {
  55. Assert.DoesNotThrow(() => { container.Add(i); });
  56. }
  57. ExpectedCount(ref container, container.Capacity);
  58. // Make sure overallocating throws and exception if using the Concurrent version - normal hash map would grow
  59. var writer = container.AsParallelWriter();
  60. Assert.Throws<System.InvalidOperationException>(() => { writer.Add(100); });
  61. ExpectedCount(ref container, container.Capacity);
  62. container.Clear();
  63. ExpectedCount(ref container, 0);
  64. container.Dispose();
  65. }
  66. #endif
  67. [Test]
  68. public void UnsafeHashSet_RemoveOnEmptyMap_DoesNotThrow()
  69. {
  70. var container = new UnsafeHashSet<int>(0, Allocator.Temp);
  71. Assert.DoesNotThrow(() => container.Remove(0));
  72. Assert.DoesNotThrow(() => container.Remove(-425196));
  73. container.Dispose();
  74. }
  75. [Test]
  76. public void UnsafeHashSet_Collisions()
  77. {
  78. var container = new UnsafeHashSet<int>(16, Allocator.Temp);
  79. Assert.IsFalse(container.Contains(0), "Contains on empty hash map did not fail");
  80. ExpectedCount(ref container, 0);
  81. // Make sure inserting values work
  82. for (int i = 0; i < 8; ++i)
  83. {
  84. Assert.IsTrue(container.Add(i), "Failed to add value");
  85. }
  86. ExpectedCount(ref container, 8);
  87. // The bucket size is capacity * 2, adding that number should result in hash collisions
  88. for (int i = 0; i < 8; ++i)
  89. {
  90. Assert.IsTrue(container.Add(i + 32), "Failed to add value with potential hash collision");
  91. }
  92. // Make sure reading the inserted values work
  93. for (int i = 0; i < 8; ++i)
  94. {
  95. Assert.IsTrue(container.Contains(i), "Failed get value from hash set");
  96. }
  97. for (int i = 0; i < 8; ++i)
  98. {
  99. Assert.IsTrue(container.Contains(i + 32), "Failed get value from hash set");
  100. }
  101. container.Dispose();
  102. }
  103. [Test]
  104. public void UnsafeHashSet_SameElement()
  105. {
  106. using (var container = new UnsafeHashSet<int>(0, Allocator.Persistent))
  107. {
  108. Assert.IsTrue(container.Add(0));
  109. Assert.IsFalse(container.Add(0));
  110. }
  111. }
  112. [Test]
  113. public void UnsafeHashSet_ForEach_FixedStringInHashMap()
  114. {
  115. using (var stringList = new NativeList<FixedString32Bytes>(10, Allocator.Persistent) { "Hello", ",", "World", "!" })
  116. {
  117. var container = new NativeHashSet<FixedString128Bytes>(50, Allocator.Temp);
  118. var seen = new NativeArray<int>(stringList.Length, Allocator.Temp);
  119. foreach (var str in stringList)
  120. {
  121. container.Add(str);
  122. }
  123. foreach (var value in container)
  124. {
  125. int index = stringList.IndexOf(value);
  126. Assert.AreEqual(stringList[index], value.ToString());
  127. seen[index] = seen[index] + 1;
  128. }
  129. for (int i = 0; i < stringList.Length; i++)
  130. {
  131. Assert.AreEqual(1, seen[i], $"Incorrect value count {stringList[i]}");
  132. }
  133. }
  134. }
  135. [Test]
  136. public void UnsafeHashSet_ForEach([Values(10, 1000)]int n)
  137. {
  138. var seen = new NativeArray<int>(n, Allocator.Temp);
  139. using (var container = new UnsafeHashSet<int>(32, CommonRwdAllocator.Handle))
  140. {
  141. for (int i = 0; i < n; i++)
  142. {
  143. container.Add(i);
  144. }
  145. var count = 0;
  146. foreach (var item in container)
  147. {
  148. Assert.True(container.Contains(item));
  149. seen[item] = seen[item] + 1;
  150. ++count;
  151. }
  152. Assert.AreEqual(container.Count(), count);
  153. for (int i = 0; i < n; i++)
  154. {
  155. Assert.AreEqual(1, seen[i], $"Incorrect item count {i}");
  156. }
  157. }
  158. }
  159. [Test]
  160. public void UnsafeHashSet_EIU_ExceptWith_Empty()
  161. {
  162. var setA = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { };
  163. var setB = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { };
  164. setA.ExceptWith(setB);
  165. ExpectedCount(ref setA, 0);
  166. setA.Dispose();
  167. setB.Dispose();
  168. }
  169. [Test]
  170. public void UnsafeHashSet_EIU_ExceptWith_AxB()
  171. {
  172. var setA = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 };
  173. var setB = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 };
  174. setA.ExceptWith(setB);
  175. ExpectedCount(ref setA, 3);
  176. Assert.True(setA.Contains(0));
  177. Assert.True(setA.Contains(1));
  178. Assert.True(setA.Contains(2));
  179. setA.Dispose();
  180. setB.Dispose();
  181. }
  182. [Test]
  183. public void UnsafeHashSet_EIU_ExceptWith_BxA()
  184. {
  185. var setA = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 };
  186. var setB = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 };
  187. setB.ExceptWith(setA);
  188. ExpectedCount(ref setB, 3);
  189. Assert.True(setB.Contains(6));
  190. Assert.True(setB.Contains(7));
  191. Assert.True(setB.Contains(8));
  192. setA.Dispose();
  193. setB.Dispose();
  194. }
  195. [Test]
  196. public void UnsafeHashSet_EIU_IntersectWith_Empty()
  197. {
  198. var setA = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { };
  199. var setB = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { };
  200. setA.IntersectWith(setB);
  201. ExpectedCount(ref setA, 0);
  202. setA.Dispose();
  203. setB.Dispose();
  204. }
  205. [Test]
  206. public void UnsafeHashSet_EIU_IntersectWith()
  207. {
  208. var setA = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 };
  209. var setB = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 };
  210. setA.IntersectWith(setB);
  211. ExpectedCount(ref setA, 3);
  212. Assert.True(setA.Contains(3));
  213. Assert.True(setA.Contains(4));
  214. Assert.True(setA.Contains(5));
  215. setA.Dispose();
  216. setB.Dispose();
  217. }
  218. [Test]
  219. public void UnsafeHashSet_EIU_UnionWith_Empty()
  220. {
  221. var setA = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { };
  222. var setB = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { };
  223. setA.UnionWith(setB);
  224. ExpectedCount(ref setA, 0);
  225. setA.Dispose();
  226. setB.Dispose();
  227. }
  228. [Test]
  229. public void UnsafeHashSet_EIU_UnionWith()
  230. {
  231. var setA = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 };
  232. var setB = new UnsafeHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 };
  233. setA.UnionWith(setB);
  234. ExpectedCount(ref setA, 9);
  235. Assert.True(setA.Contains(0));
  236. Assert.True(setA.Contains(1));
  237. Assert.True(setA.Contains(2));
  238. Assert.True(setA.Contains(3));
  239. Assert.True(setA.Contains(4));
  240. Assert.True(setA.Contains(5));
  241. Assert.True(setA.Contains(6));
  242. Assert.True(setA.Contains(7));
  243. Assert.True(setA.Contains(8));
  244. setA.Dispose();
  245. setB.Dispose();
  246. }
  247. [Test]
  248. public void UnsafeHashSet_CustomAllocatorTest()
  249. {
  250. AllocatorManager.Initialize();
  251. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  252. ref var allocator = ref allocatorHelper.Allocator;
  253. allocator.Initialize();
  254. using (var container = new UnsafeHashSet<int>(1, allocator.Handle))
  255. {
  256. }
  257. Assert.IsTrue(allocator.WasUsed);
  258. allocator.Dispose();
  259. allocatorHelper.Dispose();
  260. AllocatorManager.Shutdown();
  261. }
  262. [BurstCompile]
  263. struct BurstedCustomAllocatorJob : IJob
  264. {
  265. [NativeDisableUnsafePtrRestriction]
  266. public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
  267. public void Execute()
  268. {
  269. unsafe
  270. {
  271. using (var container = new UnsafeHashSet<int>(1, Allocator->Handle))
  272. {
  273. }
  274. }
  275. }
  276. }
  277. [Test]
  278. public unsafe void UnsafeHashSet_BurstedCustomAllocatorTest()
  279. {
  280. AllocatorManager.Initialize();
  281. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  282. ref var allocator = ref allocatorHelper.Allocator;
  283. allocator.Initialize();
  284. var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
  285. unsafe
  286. {
  287. var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
  288. handle.Complete();
  289. }
  290. Assert.IsTrue(allocator.WasUsed);
  291. allocator.Dispose();
  292. allocatorHelper.Dispose();
  293. AllocatorManager.Shutdown();
  294. }
  295. }