説明なし
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

UnsafeParallelHashSetTests.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. internal class UnsafeParallelHashSetTests : CollectionsTestCommonBase
  9. {
  10. static void ExpectedCount<T>(ref UnsafeParallelHashSet<T> container, int expected)
  11. where T : unmanaged, IEquatable<T>
  12. {
  13. Assert.AreEqual(expected == 0, container.IsEmpty);
  14. Assert.AreEqual(expected, container.Count());
  15. }
  16. [Test]
  17. public void UnsafeParallelHashSet_IsEmpty()
  18. {
  19. var container = new UnsafeParallelHashSet<int>(0, Allocator.Persistent);
  20. Assert.IsTrue(container.IsEmpty);
  21. Assert.IsTrue(container.Add(0));
  22. Assert.IsFalse(container.IsEmpty);
  23. Assert.AreEqual(1, container.Capacity);
  24. ExpectedCount(ref container, 1);
  25. container.Remove(0);
  26. Assert.IsTrue(container.IsEmpty);
  27. Assert.IsTrue(container.Add(0));
  28. container.Clear();
  29. Assert.IsTrue(container.IsEmpty);
  30. container.Dispose();
  31. }
  32. [Test]
  33. public void UnsafeParallelHashSet_Capacity()
  34. {
  35. var container = new UnsafeParallelHashSet<int>(0, Allocator.Persistent);
  36. Assert.IsTrue(container.IsEmpty);
  37. Assert.AreEqual(0, container.Capacity);
  38. container.Capacity = 10;
  39. Assert.AreEqual(10, container.Capacity);
  40. container.Dispose();
  41. }
  42. [Test]
  43. [TestRequiresCollectionChecks]
  44. public void UnsafeParallelHashSet_Full_Throws()
  45. {
  46. var container = new UnsafeParallelHashSet<int>(16, Allocator.Temp);
  47. ExpectedCount(ref container, 0);
  48. for (int i = 0, capacity = container.Capacity; i < capacity; ++i)
  49. {
  50. Assert.DoesNotThrow(() => { container.Add(i); });
  51. }
  52. ExpectedCount(ref container, container.Capacity);
  53. // Make sure overallocating throws and exception if using the Concurrent version - normal hash map would grow
  54. var writer = container.AsParallelWriter();
  55. Assert.Throws<System.InvalidOperationException>(() => { writer.Add(100); });
  56. ExpectedCount(ref container, container.Capacity);
  57. container.Clear();
  58. ExpectedCount(ref container, 0);
  59. container.Dispose();
  60. }
  61. [Test]
  62. public void UnsafeParallelHashSet_RemoveOnEmptyMap_DoesNotThrow()
  63. {
  64. var container = new UnsafeParallelHashSet<int>(0, Allocator.Temp);
  65. Assert.DoesNotThrow(() => container.Remove(0));
  66. Assert.DoesNotThrow(() => container.Remove(-425196));
  67. container.Dispose();
  68. }
  69. [Test]
  70. public void UnsafeParallelHashSet_Collisions()
  71. {
  72. var container = new UnsafeParallelHashSet<int>(16, Allocator.Temp);
  73. Assert.IsFalse(container.Contains(0), "Contains on empty hash map did not fail");
  74. ExpectedCount(ref container, 0);
  75. // Make sure inserting values work
  76. for (int i = 0; i < 8; ++i)
  77. {
  78. Assert.IsTrue(container.Add(i), "Failed to add value");
  79. }
  80. ExpectedCount(ref container, 8);
  81. // The bucket size is capacity * 2, adding that number should result in hash collisions
  82. for (int i = 0; i < 8; ++i)
  83. {
  84. Assert.IsTrue(container.Add(i + 32), "Failed to add value with potential hash collision");
  85. }
  86. // Make sure reading the inserted values work
  87. for (int i = 0; i < 8; ++i)
  88. {
  89. Assert.IsTrue(container.Contains(i), "Failed get value from hash set");
  90. }
  91. for (int i = 0; i < 8; ++i)
  92. {
  93. Assert.IsTrue(container.Contains(i + 32), "Failed get value from hash set");
  94. }
  95. container.Dispose();
  96. }
  97. [Test]
  98. public void UnsafeParallelHashSet_SameElement()
  99. {
  100. using (var container = new UnsafeParallelHashSet<int>(0, Allocator.Persistent))
  101. {
  102. Assert.IsTrue(container.Add(0));
  103. Assert.IsFalse(container.Add(0));
  104. }
  105. }
  106. [Test]
  107. public void UnsafeParallelHashSet_ForEach_FixedStringInHashMap()
  108. {
  109. using (var stringList = new NativeList<FixedString32Bytes>(10, Allocator.Persistent) { "Hello", ",", "World", "!" })
  110. {
  111. var container = new NativeParallelHashSet<FixedString128Bytes>(50, Allocator.Temp);
  112. var seen = new NativeArray<int>(stringList.Length, Allocator.Temp);
  113. foreach (var str in stringList)
  114. {
  115. container.Add(str);
  116. }
  117. foreach (var value in container)
  118. {
  119. int index = stringList.IndexOf(value);
  120. Assert.AreEqual(stringList[index], value.ToString());
  121. seen[index] = seen[index] + 1;
  122. }
  123. for (int i = 0; i < stringList.Length; i++)
  124. {
  125. Assert.AreEqual(1, seen[i], $"Incorrect value count {stringList[i]}");
  126. }
  127. }
  128. }
  129. [Test]
  130. public void UnsafeParallelHashSet_ForEach([Values(10, 1000)]int n)
  131. {
  132. var seen = new NativeArray<int>(n, Allocator.Temp);
  133. using (var container = new UnsafeParallelHashSet<int>(32, CommonRwdAllocator.Handle))
  134. {
  135. for (int i = 0; i < n; i++)
  136. {
  137. container.Add(i);
  138. }
  139. var count = 0;
  140. foreach (var item in container)
  141. {
  142. Assert.True(container.Contains(item));
  143. seen[item] = seen[item] + 1;
  144. ++count;
  145. }
  146. Assert.AreEqual(container.Count(), count);
  147. for (int i = 0; i < n; i++)
  148. {
  149. Assert.AreEqual(1, seen[i], $"Incorrect item count {i}");
  150. }
  151. }
  152. }
  153. [Test]
  154. public void UnsafeParallelHashSet_EIU_ExceptWith_Empty()
  155. {
  156. var setA = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { };
  157. var setB = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { };
  158. setA.ExceptWith(setB);
  159. ExpectedCount(ref setA, 0);
  160. setA.Dispose();
  161. setB.Dispose();
  162. }
  163. [Test]
  164. public void UnsafeParallelHashSet_EIU_ExceptWith_AxB()
  165. {
  166. var setA = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 };
  167. var setB = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 };
  168. setA.ExceptWith(setB);
  169. ExpectedCount(ref setA, 3);
  170. Assert.True(setA.Contains(0));
  171. Assert.True(setA.Contains(1));
  172. Assert.True(setA.Contains(2));
  173. setA.Dispose();
  174. setB.Dispose();
  175. }
  176. [Test]
  177. public void UnsafeParallelHashSet_EIU_ExceptWith_BxA()
  178. {
  179. var setA = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 };
  180. var setB = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 };
  181. setB.ExceptWith(setA);
  182. ExpectedCount(ref setB, 3);
  183. Assert.True(setB.Contains(6));
  184. Assert.True(setB.Contains(7));
  185. Assert.True(setB.Contains(8));
  186. setA.Dispose();
  187. setB.Dispose();
  188. }
  189. [Test]
  190. public void UnsafeParallelHashSet_EIU_IntersectWith_Empty()
  191. {
  192. var setA = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { };
  193. var setB = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { };
  194. setA.IntersectWith(setB);
  195. ExpectedCount(ref setA, 0);
  196. setA.Dispose();
  197. setB.Dispose();
  198. }
  199. [Test]
  200. public void UnsafeParallelHashSet_EIU_IntersectWith()
  201. {
  202. var setA = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 };
  203. var setB = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 };
  204. setA.IntersectWith(setB);
  205. ExpectedCount(ref setA, 3);
  206. Assert.True(setA.Contains(3));
  207. Assert.True(setA.Contains(4));
  208. Assert.True(setA.Contains(5));
  209. setA.Dispose();
  210. setB.Dispose();
  211. }
  212. [Test]
  213. public void UnsafeParallelHashSet_EIU_UnionWith_Empty()
  214. {
  215. var setA = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { };
  216. var setB = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { };
  217. setA.UnionWith(setB);
  218. ExpectedCount(ref setA, 0);
  219. setA.Dispose();
  220. setB.Dispose();
  221. }
  222. [Test]
  223. public void UnsafeParallelHashSet_EIU_UnionWith()
  224. {
  225. var setA = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { 0, 1, 2, 3, 4, 5 };
  226. var setB = new UnsafeParallelHashSet<int>(8, CommonRwdAllocator.Handle) { 3, 4, 5, 6, 7, 8 };
  227. setA.UnionWith(setB);
  228. ExpectedCount(ref setA, 9);
  229. Assert.True(setA.Contains(0));
  230. Assert.True(setA.Contains(1));
  231. Assert.True(setA.Contains(2));
  232. Assert.True(setA.Contains(3));
  233. Assert.True(setA.Contains(4));
  234. Assert.True(setA.Contains(5));
  235. Assert.True(setA.Contains(6));
  236. Assert.True(setA.Contains(7));
  237. Assert.True(setA.Contains(8));
  238. setA.Dispose();
  239. setB.Dispose();
  240. }
  241. [Test]
  242. public void UnsafeParallelHashSet_CustomAllocatorTest()
  243. {
  244. AllocatorManager.Initialize();
  245. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  246. ref var allocator = ref allocatorHelper.Allocator;
  247. allocator.Initialize();
  248. using (var container = new UnsafeParallelHashSet<int>(1, allocator.Handle))
  249. {
  250. }
  251. Assert.IsTrue(allocator.WasUsed);
  252. allocator.Dispose();
  253. allocatorHelper.Dispose();
  254. AllocatorManager.Shutdown();
  255. }
  256. [BurstCompile]
  257. struct BurstedCustomAllocatorJob : IJob
  258. {
  259. [NativeDisableUnsafePtrRestriction]
  260. public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
  261. public void Execute()
  262. {
  263. unsafe
  264. {
  265. using (var container = new UnsafeParallelHashSet<int>(1, Allocator->Handle))
  266. {
  267. }
  268. }
  269. }
  270. }
  271. [Test]
  272. public unsafe void UnsafeParallelHashSet_BurstedCustomAllocatorTest()
  273. {
  274. AllocatorManager.Initialize();
  275. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  276. ref var allocator = ref allocatorHelper.Allocator;
  277. allocator.Initialize();
  278. var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
  279. unsafe
  280. {
  281. var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
  282. handle.Complete();
  283. }
  284. Assert.IsTrue(allocator.WasUsed);
  285. allocator.Dispose();
  286. allocatorHelper.Dispose();
  287. AllocatorManager.Shutdown();
  288. }
  289. struct UnsafeParallelHashSet_ForEach_Job : IJob
  290. {
  291. [ReadOnly]
  292. public UnsafeParallelHashSet<int>.ReadOnly Input;
  293. [ReadOnly]
  294. public int Num;
  295. public void Execute()
  296. {
  297. var seen = new NativeArray<int>(Num, Allocator.Temp);
  298. var count = 0;
  299. foreach (var item in Input)
  300. {
  301. Assert.True(Input.Contains(item));
  302. seen[item] = seen[item] + 1;
  303. ++count;
  304. }
  305. Assert.AreEqual(Input.Count(), count);
  306. for (int i = 0; i < Num; i++)
  307. {
  308. Assert.AreEqual(1, seen[i], $"Incorrect item count {i}");
  309. }
  310. seen.Dispose();
  311. }
  312. }
  313. [Test]
  314. public void UnsafeParallelHashSet_ForEach_From_Job([Values(10, 1000)] int n)
  315. {
  316. using (var container = new UnsafeParallelHashSet<int>(32, CommonRwdAllocator.Handle))
  317. {
  318. for (int i = 0; i < n; i++)
  319. {
  320. container.Add(i);
  321. }
  322. new UnsafeParallelHashSet_ForEach_Job
  323. {
  324. Input = container.AsReadOnly(),
  325. Num = n,
  326. }.Run();
  327. }
  328. }
  329. }