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