A game about forced loneliness, made by TACStudios
at master 707 lines 31 kB view raw
1using System; 2using System.Diagnostics; 3using System.Runtime.CompilerServices; 4using System.Runtime.InteropServices; 5using Unity.Burst; 6using Unity.Collections.LowLevel.Unsafe; 7using Unity.Jobs; 8using static Unity.Collections.AllocatorManager; 9 10namespace Unity.Collections 11{ 12 /// <summary> 13 /// An arbitrarily-sized array of bits. 14 /// </summary> 15 /// <remarks> 16 /// The number of allocated bytes is always a multiple of 8. For example, a 65-bit array could fit in 9 bytes, but its allocation is actually 16 bytes. 17 /// </remarks> 18 [StructLayout(LayoutKind.Sequential)] 19 [NativeContainer] 20 [DebuggerDisplay("Length = {Length}, IsCreated = {IsCreated}")] 21 [GenerateTestsForBurstCompatibility] 22 public unsafe struct NativeBitArray 23 : INativeDisposable 24 { 25#if ENABLE_UNITY_COLLECTIONS_CHECKS 26 internal AtomicSafetyHandle m_Safety; 27 static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeBitArray>(); 28#endif 29 [NativeDisableUnsafePtrRestriction] 30 internal UnsafeBitArray* m_BitArray; 31 internal AllocatorHandle m_Allocator; 32 33 /// <summary> 34 /// Initializes and returns an instance of NativeBitArray. 35 /// </summary> 36 /// <param name="numBits">The number of bits.</param> 37 /// <param name="allocator">The allocator to use.</param> 38 /// <param name="options">Whether newly allocated bytes should be zeroed out.</param> 39 public NativeBitArray(int numBits, AllocatorManager.AllocatorHandle allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory) 40 { 41 CollectionHelper.CheckAllocator(allocator); 42#if ENABLE_UNITY_COLLECTIONS_CHECKS 43 m_Safety = CollectionHelper.CreateSafetyHandle(allocator); 44 CollectionHelper.SetStaticSafetyId(ref m_Safety, ref s_staticSafetyId.Data, "Unity.Collections.NativeBitArray"); 45#endif 46 m_BitArray = UnsafeBitArray.Alloc(allocator); 47 m_Allocator = allocator; 48 * m_BitArray = new UnsafeBitArray(numBits, allocator, options); 49 } 50 51 /// <summary> 52 /// Whether this array has been allocated (and not yet deallocated). 53 /// </summary> 54 /// <value>True if this array has been allocated (and not yet deallocated).</value> 55 public readonly bool IsCreated => m_BitArray != null && m_BitArray->IsCreated; 56 57 /// <summary> 58 /// Whether the container is empty. 59 /// </summary> 60 /// <value>True if the container is empty or the container has not been constructed.</value> 61 public readonly bool IsEmpty => !IsCreated || Length == 0; 62 63 /// <summary> 64 /// Sets the length, expanding the capacity if necessary. 65 /// </summary> 66 /// <param name="numBits">The new length in bits.</param> 67 /// <param name="options">Whether newly allocated data should be zeroed out.</param> 68 public void Resize(int numBits, NativeArrayOptions options = NativeArrayOptions.UninitializedMemory) 69 { 70#if ENABLE_UNITY_COLLECTIONS_CHECKS 71 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 72#endif 73 m_BitArray->Resize(numBits, options); 74 } 75 76 /// <summary> 77 /// Sets the capacity. 78 /// </summary> 79 /// <param name="capacityInBits">The new capacity.</param> 80 public void SetCapacity(int capacityInBits) 81 { 82#if ENABLE_UNITY_COLLECTIONS_CHECKS 83 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 84#endif 85 m_BitArray->SetCapacity(capacityInBits); 86 } 87 88 /// <summary> 89 /// Sets the capacity to match what it would be if it had been originally initialized with all its entries. 90 /// </summary> 91 public void TrimExcess() 92 { 93#if ENABLE_UNITY_COLLECTIONS_CHECKS 94 AtomicSafetyHandle.CheckWriteAndBumpSecondaryVersion(m_Safety); 95#endif 96 m_BitArray->TrimExcess(); 97 } 98 99 /// <summary> 100 /// Releases all resources (memory and safety handles). 101 /// </summary> 102 public void Dispose() 103 { 104#if ENABLE_UNITY_COLLECTIONS_CHECKS 105 if (!AtomicSafetyHandle.IsDefaultValue(m_Safety)) 106 { 107 AtomicSafetyHandle.CheckExistsAndThrow(m_Safety); 108 } 109#endif 110 if (!IsCreated) 111 { 112 return; 113 } 114 115#if ENABLE_UNITY_COLLECTIONS_CHECKS 116 CollectionHelper.DisposeSafetyHandle(ref m_Safety); 117#endif 118 UnsafeBitArray.Free(m_BitArray, m_Allocator); 119 m_BitArray = null; 120 m_Allocator = Invalid; 121 } 122 123 /// <summary> 124 /// Creates and schedules a job that will dispose this array. 125 /// </summary> 126 /// <param name="inputDeps">The handle of a job which the new job will depend upon.</param> 127 /// <returns>The handle of a new job that will dispose this array. The new job depends upon inputDeps.</returns> 128 public JobHandle Dispose(JobHandle inputDeps) 129 { 130#if ENABLE_UNITY_COLLECTIONS_CHECKS 131 if (!AtomicSafetyHandle.IsDefaultValue(m_Safety)) 132 { 133 AtomicSafetyHandle.CheckExistsAndThrow(m_Safety); 134 } 135#endif 136 if (!IsCreated) 137 { 138 return inputDeps; 139 } 140 141#if ENABLE_UNITY_COLLECTIONS_CHECKS 142 var jobHandle = new NativeBitArrayDisposeJob { Data = new NativeBitArrayDispose { m_BitArrayData = m_BitArray, m_Allocator = m_Allocator, m_Safety = m_Safety } }.Schedule(inputDeps); 143 AtomicSafetyHandle.Release(m_Safety); 144#else 145 var jobHandle = new NativeBitArrayDisposeJob { Data = new NativeBitArrayDispose { m_BitArrayData = m_BitArray, m_Allocator = m_Allocator } }.Schedule(inputDeps); 146#endif 147 m_BitArray = null; 148 m_Allocator = Invalid; 149 150 return jobHandle; 151 152 } 153 154 /// <summary> 155 /// Returns the number of bits. 156 /// </summary> 157 /// <value>The number of bits.</value> 158 public readonly int Length 159 { 160 [MethodImpl(MethodImplOptions.AggressiveInlining)] 161 get 162 { 163 CheckRead(); 164 return CollectionHelper.AssumePositive(m_BitArray->Length); 165 } 166 } 167 168 /// <summary> 169 /// Returns the capacity number of bits. 170 /// </summary> 171 /// <value>The capacity number of bits.</value> 172 public readonly int Capacity 173 { 174 [MethodImpl(MethodImplOptions.AggressiveInlining)] 175 get 176 { 177 CheckRead(); 178 return CollectionHelper.AssumePositive(m_BitArray->Capacity); 179 } 180 } 181 182 /// <summary> 183 /// Sets all the bits to 0. 184 /// </summary> 185 public void Clear() 186 { 187 CheckWrite(); 188 m_BitArray->Clear(); 189 } 190 191 /// <summary> 192 /// Returns a native array that aliases the content of this array. 193 /// </summary> 194 /// <typeparam name="T">The type of elements in the aliased array.</typeparam> 195 /// <exception cref="InvalidOperationException">Thrown if the number of bits in this array 196 /// is not evenly divisible by the size of T in bits (`sizeof(T) * 8`).</exception> 197 /// <returns>A native array that aliases the content of this array.</returns> 198 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 199 public NativeArray<T> AsNativeArray<T>() where T : unmanaged 200 { 201 CheckReadBounds<T>(); 202 203 var bitsPerElement = UnsafeUtility.SizeOf<T>() * 8; 204 var length = m_BitArray->Length / bitsPerElement; 205 206 var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<T>(m_BitArray->Ptr, length, Allocator.None); 207#if ENABLE_UNITY_COLLECTIONS_CHECKS 208 AtomicSafetyHandle.UseSecondaryVersion(ref m_Safety); 209 NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, m_Safety); 210#endif 211 return array; 212 } 213 214 /// <summary> 215 /// Sets the bit at an index to 0 or 1. 216 /// </summary> 217 /// <param name="pos">Index of the bit to set.</param> 218 /// <param name="value">True for 1, false for 0.</param> 219 public void Set(int pos, bool value) 220 { 221 CheckWrite(); 222 m_BitArray->Set(pos, value); 223 } 224 225 /// <summary> 226 /// Sets a range of bits to 0 or 1. 227 /// </summary> 228 /// <remarks> 229 /// The range runs from index `pos` up to (but not including) `pos + numBits`. 230 /// No exception is thrown if `pos + numBits` exceeds the length. 231 /// </remarks> 232 /// <param name="pos">Index of the first bit to set.</param> 233 /// <param name="value">True for 1, false for 0.</param> 234 /// <param name="numBits">Number of bits to set.</param> 235 /// <exception cref="ArgumentException">Thrown if pos is out of bounds or if numBits is less than 1.</exception> 236 public void SetBits(int pos, bool value, int numBits) 237 { 238 CheckWrite(); 239 m_BitArray->SetBits(pos, value, numBits); 240 } 241 242 /// <summary> 243 /// Copies bits of a ulong to bits in this array. 244 /// </summary> 245 /// <remarks> 246 /// The destination bits in this array run from index pos up to (but not including) `pos + numBits`. 247 /// No exception is thrown if `pos + numBits` exceeds the length. 248 /// 249 /// The lowest bit of the ulong is copied to the first destination bit; the second-lowest bit of the ulong is 250 /// copied to the second destination bit; and so forth. 251 /// </remarks> 252 /// <param name="pos">Index of the first bit to set.</param> 253 /// <param name="value">Unsigned long from which to copy bits.</param> 254 /// <param name="numBits">Number of bits to set (must be between 1 and 64).</param> 255 /// <exception cref="ArgumentException">Thrown if pos is out of bounds or if numBits is not between 1 and 64.</exception> 256 public void SetBits(int pos, ulong value, int numBits = 1) 257 { 258 CheckWrite(); 259 m_BitArray->SetBits(pos, value, numBits); 260 } 261 262 /// <summary> 263 /// Returns a ulong which has bits copied from this array. 264 /// </summary> 265 /// <remarks> 266 /// The source bits in this array run from index pos up to (but not including) `pos + numBits`. 267 /// No exception is thrown if `pos + numBits` exceeds the length. 268 /// 269 /// The first source bit is copied to the lowest bit of the ulong; the second source bit is copied to the second-lowest bit of the ulong; and so forth. Any remaining bits in the ulong will be 0. 270 /// </remarks> 271 /// <param name="pos">Index of the first bit to get.</param> 272 /// <param name="numBits">Number of bits to get (must be between 1 and 64).</param> 273 /// <exception cref="ArgumentException">Thrown if pos is out of bounds or if numBits is not between 1 and 64.</exception> 274 /// <returns>A ulong which has bits copied from this array.</returns> 275 public ulong GetBits(int pos, int numBits = 1) 276 { 277 CheckRead(); 278 return m_BitArray->GetBits(pos, numBits); 279 } 280 281 /// <summary> 282 /// Returns true if the bit at an index is 1. 283 /// </summary> 284 /// <param name="pos">Index of the bit to test.</param> 285 /// <returns>True if the bit at the index is 1.</returns> 286 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds.</exception> 287 public bool IsSet(int pos) 288 { 289 CheckRead(); 290 return m_BitArray->IsSet(pos); 291 } 292 293 /// <summary> 294 /// Copies a range of bits from this array to another range in this array. 295 /// </summary> 296 /// <remarks> 297 /// The bits to copy run from index `srcPos` up to (but not including) `srcPos + numBits`. 298 /// The bits to set run from index `dstPos` up to (but not including) `dstPos + numBits`. 299 /// 300 /// The ranges may overlap, but the result in the overlapping region is undefined. 301 /// </remarks> 302 /// <param name="dstPos">Index of the first bit to set.</param> 303 /// <param name="srcPos">Index of the first bit to copy.</param> 304 /// <param name="numBits">Number of bits to copy.</param> 305 /// <exception cref="ArgumentException">Thrown if either `dstPos + numBits` or `srcPos + numBits` exceed the length of this array.</exception> 306 public void Copy(int dstPos, int srcPos, int numBits) 307 { 308 CheckWrite(); 309 m_BitArray->Copy(dstPos, srcPos, numBits); 310 } 311 312 /// <summary> 313 /// Copies a range of bits from an array to a range of bits in this array. 314 /// </summary> 315 /// <remarks> 316 /// The bits to copy in the source array run from index srcPos up to (but not including) `srcPos + numBits`. 317 /// The bits to set in the destination array run from index dstPos up to (but not including) `dstPos + numBits`. 318 /// 319 /// When the source and destination are the same array, the ranges may still overlap, but the result in the overlapping region is undefined. 320 /// </remarks> 321 /// <param name="dstPos">Index of the first bit to set.</param> 322 /// <param name="srcBitArray">The source array.</param> 323 /// <param name="srcPos">Index of the first bit to copy.</param> 324 /// <param name="numBits">The number of bits to copy.</param> 325 /// <exception cref="ArgumentException">Thrown if either `dstPos + numBits` or `srcBitArray + numBits` exceed the length of this array.</exception> 326 public void Copy(int dstPos, ref NativeBitArray srcBitArray, int srcPos, int numBits) 327 { 328#if ENABLE_UNITY_COLLECTIONS_CHECKS 329 AtomicSafetyHandle.CheckReadAndThrow(srcBitArray.m_Safety); 330#endif 331 CheckWrite(); 332 m_BitArray->Copy(dstPos, ref *srcBitArray.m_BitArray, srcPos, numBits); 333 } 334 335 /// <summary> 336 /// Finds the first length-*N* contiguous sequence of 0 bits in this bit array. 337 /// </summary> 338 /// <param name="pos">Index at which to start searching.</param> 339 /// <param name="numBits">Number of contiguous 0 bits to look for.</param> 340 /// <returns>The index in this array where the sequence is found. The index will be greater than or equal to `pos`. 341 /// Returns -1 if no occurrence is found.</returns> 342 public int Find(int pos, int numBits) 343 { 344 CheckRead(); 345 return m_BitArray->Find(pos, numBits); 346 } 347 348 /// <summary> 349 /// Finds the first length-*N* contiguous sequence of 0 bits in this bit array. Searches only a subsection. 350 /// </summary> 351 /// <param name="pos">Index at which to start searching.</param> 352 /// <param name="numBits">Number of contiguous 0 bits to look for.</param> 353 /// <param name="count">Number of bits to search.</param> 354 /// <returns>The index in this array where the sequence is found. The index will be greater than or equal to `pos` but less than `pos + count`. 355 /// Returns -1 if no occurrence is found.</returns> 356 public int Find(int pos, int count, int numBits) 357 { 358 CheckRead(); 359 return m_BitArray->Find(pos, count, numBits); 360 } 361 362 /// <summary> 363 /// Returns true if none of the bits in a range are 1 (*i.e.* all bits in the range are 0). 364 /// </summary> 365 /// <param name="pos">Index of the bit at which to start searching.</param> 366 /// <param name="numBits">Number of bits to test. Defaults to 1.</param> 367 /// <returns>Returns true if none of the bits in range `pos` up to (but not including) `pos + numBits` are 1.</returns> 368 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds or `numBits` is less than 1.</exception> 369 public bool TestNone(int pos, int numBits = 1) 370 { 371 CheckRead(); 372 return m_BitArray->TestNone(pos, numBits); 373 } 374 375 /// <summary> 376 /// Returns true if at least one of the bits in a range is 1. 377 /// </summary> 378 /// <param name="pos">Index of the bit at which to start searching.</param> 379 /// <param name="numBits">Number of bits to test. Defaults to 1.</param> 380 /// <returns>True if one ore more of the bits in range `pos` up to (but not including) `pos + numBits` are 1.</returns> 381 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds or `numBits` is less than 1.</exception> 382 public bool TestAny(int pos, int numBits = 1) 383 { 384 CheckRead(); 385 return m_BitArray->TestAny(pos, numBits); 386 } 387 388 /// <summary> 389 /// Returns true if all of the bits in a range are 1. 390 /// </summary> 391 /// <param name="pos">Index of the bit at which to start searching.</param> 392 /// <param name="numBits">Number of bits to test. Defaults to 1.</param> 393 /// <returns>True if all of the bits in range `pos` up to (but not including) `pos + numBits` are 1.</returns> 394 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds or `numBits` is less than 1.</exception> 395 public bool TestAll(int pos, int numBits = 1) 396 { 397 CheckRead(); 398 return m_BitArray->TestAll(pos, numBits); 399 } 400 401 /// <summary> 402 /// Returns the number of bits in a range that are 1. 403 /// </summary> 404 /// <param name="pos">Index of the bit at which to start searching.</param> 405 /// <param name="numBits">Number of bits to test. Defaults to 1.</param> 406 /// <returns>The number of bits in a range of bits that are 1.</returns> 407 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds or `numBits` is less than 1.</exception> 408 public int CountBits(int pos, int numBits = 1) 409 { 410 CheckRead(); 411 return m_BitArray->CountBits(pos, numBits); 412 } 413 414 /// <summary> 415 /// Returns a readonly version of this NativeBitArray instance. 416 /// </summary> 417 /// <remarks>ReadOnly containers point to the same underlying data as the NativeBitArray it is made from.</remarks> 418 /// <returns>ReadOnly instance for this.</returns> 419 public ReadOnly AsReadOnly() 420 { 421 return new ReadOnly(ref this); 422 } 423 424 /// <summary> 425 /// A read-only alias for the value of a UnsafeBitArray. Does not have its own allocated storage. 426 /// </summary> 427 [NativeContainer] 428 [NativeContainerIsReadOnly] 429 public struct ReadOnly 430 { 431#if ENABLE_UNITY_COLLECTIONS_CHECKS 432 AtomicSafetyHandle m_Safety; 433 internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<ReadOnly>(); 434#endif 435 [NativeDisableUnsafePtrRestriction] 436 internal UnsafeBitArray.ReadOnly m_BitArray; 437 438 /// <summary> 439 /// Whether this array has been allocated (and not yet deallocated). 440 /// </summary> 441 /// <value>True if this array has been allocated (and not yet deallocated).</value> 442 public readonly bool IsCreated => m_BitArray.IsCreated; 443 444 /// <summary> 445 /// Whether the container is empty. 446 /// </summary> 447 /// <value>True if the container is empty or the container has not been constructed.</value> 448 public readonly bool IsEmpty => m_BitArray.IsEmpty; 449 450 internal ReadOnly(ref NativeBitArray data) 451 { 452 m_BitArray = data.m_BitArray->AsReadOnly(); 453#if ENABLE_UNITY_COLLECTIONS_CHECKS 454 m_Safety = data.m_Safety; 455 CollectionHelper.SetStaticSafetyId<ReadOnly>(ref m_Safety, ref s_staticSafetyId.Data); 456#endif 457 } 458 459 /// <summary> 460 /// Returns the number of bits. 461 /// </summary> 462 /// <value>The number of bits.</value> 463 public readonly int Length 464 { 465 get 466 { 467 CheckRead(); 468 return CollectionHelper.AssumePositive(m_BitArray.Length); 469 } 470 } 471 472 /// <summary> 473 /// Returns a ulong which has bits copied from this array. 474 /// </summary> 475 /// <remarks> 476 /// The source bits in this array run from index pos up to (but not including) `pos + numBits`. 477 /// No exception is thrown if `pos + numBits` exceeds the length. 478 /// 479 /// The first source bit is copied to the lowest bit of the ulong; the second source bit is copied to the second-lowest bit of the ulong; and so forth. Any remaining bits in the ulong will be 0. 480 /// </remarks> 481 /// <param name="pos">Index of the first bit to get.</param> 482 /// <param name="numBits">Number of bits to get (must be between 1 and 64).</param> 483 /// <exception cref="ArgumentException">Thrown if pos is out of bounds or if numBits is not between 1 and 64.</exception> 484 /// <returns>A ulong which has bits copied from this array.</returns> 485 public readonly ulong GetBits(int pos, int numBits = 1) 486 { 487 CheckRead(); 488 return m_BitArray.GetBits(pos, numBits); 489 } 490 491 /// <summary> 492 /// Returns true if the bit at an index is 1. 493 /// </summary> 494 /// <param name="pos">Index of the bit to test.</param> 495 /// <returns>True if the bit at the index is 1.</returns> 496 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds.</exception> 497 public readonly bool IsSet(int pos) 498 { 499 CheckRead(); 500 return m_BitArray.IsSet(pos); 501 } 502 503 /// <summary> 504 /// Finds the first length-*N* contiguous sequence of 0 bits in this bit array. 505 /// </summary> 506 /// <param name="pos">Index at which to start searching.</param> 507 /// <param name="numBits">Number of contiguous 0 bits to look for.</param> 508 /// <returns>The index in this array where the sequence is found. The index will be greater than or equal to `pos`. 509 /// Returns -1 if no occurrence is found.</returns> 510 public readonly int Find(int pos, int numBits) 511 { 512 CheckRead(); 513 return m_BitArray.Find(pos, numBits); 514 } 515 516 /// <summary> 517 /// Finds the first length-*N* contiguous sequence of 0 bits in this bit array. Searches only a subsection. 518 /// </summary> 519 /// <param name="pos">Index at which to start searching.</param> 520 /// <param name="numBits">Number of contiguous 0 bits to look for.</param> 521 /// <param name="count">Number of bits to search.</param> 522 /// <returns>The index in this array where the sequence is found. The index will be greater than or equal to `pos` but less than `pos + count`. 523 /// Returns -1 if no occurrence is found.</returns> 524 public readonly int Find(int pos, int count, int numBits) 525 { 526 CheckRead(); 527 return m_BitArray.Find(pos, count, numBits); 528 } 529 530 /// <summary> 531 /// Returns true if none of the bits in a range are 1 (*i.e.* all bits in the range are 0). 532 /// </summary> 533 /// <param name="pos">Index of the bit at which to start searching.</param> 534 /// <param name="numBits">Number of bits to test. Defaults to 1.</param> 535 /// <returns>Returns true if none of the bits in range `pos` up to (but not including) `pos + numBits` are 1.</returns> 536 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds or `numBits` is less than 1.</exception> 537 public readonly bool TestNone(int pos, int numBits = 1) 538 { 539 CheckRead(); 540 return m_BitArray.TestNone(pos, numBits); 541 } 542 543 /// <summary> 544 /// Returns true if at least one of the bits in a range is 1. 545 /// </summary> 546 /// <param name="pos">Index of the bit at which to start searching.</param> 547 /// <param name="numBits">Number of bits to test. Defaults to 1.</param> 548 /// <returns>True if one ore more of the bits in range `pos` up to (but not including) `pos + numBits` are 1.</returns> 549 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds or `numBits` is less than 1.</exception> 550 public readonly bool TestAny(int pos, int numBits = 1) 551 { 552 CheckRead(); 553 return m_BitArray.TestAny(pos, numBits); 554 } 555 556 /// <summary> 557 /// Returns true if all of the bits in a range are 1. 558 /// </summary> 559 /// <param name="pos">Index of the bit at which to start searching.</param> 560 /// <param name="numBits">Number of bits to test. Defaults to 1.</param> 561 /// <returns>True if all of the bits in range `pos` up to (but not including) `pos + numBits` are 1.</returns> 562 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds or `numBits` is less than 1.</exception> 563 public readonly bool TestAll(int pos, int numBits = 1) 564 { 565 CheckRead(); 566 return m_BitArray.TestAll(pos, numBits); 567 } 568 569 /// <summary> 570 /// Returns the number of bits in a range that are 1. 571 /// </summary> 572 /// <param name="pos">Index of the bit at which to start searching.</param> 573 /// <param name="numBits">Number of bits to test. Defaults to 1.</param> 574 /// <returns>The number of bits in a range of bits that are 1.</returns> 575 /// <exception cref="ArgumentException">Thrown if `pos` is out of bounds or `numBits` is less than 1.</exception> 576 public readonly int CountBits(int pos, int numBits = 1) 577 { 578 CheckRead(); 579 return m_BitArray.CountBits(pos, numBits); 580 } 581 582 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] 583 readonly void CheckRead() 584 { 585#if ENABLE_UNITY_COLLECTIONS_CHECKS 586 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 587#endif 588 } 589 } 590 591 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] 592 readonly void CheckRead() 593 { 594#if ENABLE_UNITY_COLLECTIONS_CHECKS 595 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 596#endif 597 } 598 599 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 600 void CheckReadBounds<T>() where T : unmanaged 601 { 602 CheckRead(); 603 604 var bitsPerElement = UnsafeUtility.SizeOf<T>() * 8; 605 var length = m_BitArray->Length / bitsPerElement; 606 607 if (length == 0) 608 { 609 throw new InvalidOperationException($"Number of bits in the NativeBitArray {m_BitArray->Length} is not sufficient to cast to NativeArray<T> {UnsafeUtility.SizeOf<T>() * 8}."); 610 } 611 else if (m_BitArray->Length != bitsPerElement* length) 612 { 613 throw new InvalidOperationException($"Number of bits in the NativeBitArray {m_BitArray->Length} couldn't hold multiple of T {UnsafeUtility.SizeOf<T>()}. Output array would be truncated."); 614 } 615 } 616 617 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")] 618 void CheckWrite() 619 { 620#if ENABLE_UNITY_COLLECTIONS_CHECKS 621 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 622#endif 623 } 624 } 625 626 [NativeContainer] 627 [GenerateTestsForBurstCompatibility] 628 internal unsafe struct NativeBitArrayDispose 629 { 630 [NativeDisableUnsafePtrRestriction] 631 public UnsafeBitArray* m_BitArrayData; 632 public AllocatorHandle m_Allocator; 633 634#if ENABLE_UNITY_COLLECTIONS_CHECKS 635 public AtomicSafetyHandle m_Safety; 636#endif 637 638 public void Dispose() 639 { 640 UnsafeBitArray.Free(m_BitArrayData, m_Allocator); 641 } 642 } 643 644 [BurstCompile] 645 internal unsafe struct NativeBitArrayDisposeJob : IJob 646 { 647 public NativeBitArrayDispose Data; 648 649 public void Execute() 650 { 651 Data.Dispose(); 652 } 653 } 654} 655 656namespace Unity.Collections.LowLevel.Unsafe 657{ 658 /// <summary> 659 /// Unsafe helper methods for NativeBitArray. 660 /// </summary> 661 [GenerateTestsForBurstCompatibility] 662 public static class NativeBitArrayUnsafeUtility 663 { 664#if ENABLE_UNITY_COLLECTIONS_CHECKS 665 /// <summary> 666 /// Returns an array's atomic safety handle. 667 /// </summary> 668 /// <param name="container">Array from which to get an AtomicSafetyHandle.</param> 669 /// <returns>This array's atomic safety handle.</returns> 670 [GenerateTestsForBurstCompatibility(RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS", CompileTarget = GenerateTestsForBurstCompatibilityAttribute.BurstCompatibleCompileTarget.Editor)] 671 public static AtomicSafetyHandle GetAtomicSafetyHandle(in NativeBitArray container) 672 { 673 return container.m_Safety; 674 } 675 676 /// <summary> 677 /// Sets an array's atomic safety handle. 678 /// </summary> 679 /// <param name="container">Array which the AtomicSafetyHandle is for.</param> 680 /// <param name="safety">Atomic safety handle for this array.</param> 681 [GenerateTestsForBurstCompatibility(RequiredUnityDefine = "ENABLE_UNITY_COLLECTIONS_CHECKS", CompileTarget = GenerateTestsForBurstCompatibilityAttribute.BurstCompatibleCompileTarget.Editor)] 682 public static void SetAtomicSafetyHandle(ref NativeBitArray container, AtomicSafetyHandle safety) 683 { 684 container.m_Safety = safety; 685 } 686#endif 687 688 /// <summary> 689 /// Returns a bit array with content aliasing a buffer. 690 /// </summary> 691 /// <param name="ptr">A buffer.</param> 692 /// <param name="sizeInBytes">Size of the buffer in bytes. Must be a multiple of 8.</param> 693 /// <param name="allocator">The allocator that was used to create the buffer.</param> 694 /// <returns>A bit array with content aliasing a buffer.</returns> 695 public static unsafe NativeBitArray ConvertExistingDataToNativeBitArray(void* ptr, int sizeInBytes, AllocatorManager.AllocatorHandle allocator) 696 { 697 var bitArray = UnsafeBitArray.Alloc(Allocator.Persistent); 698 *bitArray = new UnsafeBitArray(ptr, sizeInBytes, allocator); 699 700 return new NativeBitArray 701 { 702 m_BitArray = bitArray, 703 m_Allocator = Allocator.Persistent, 704 }; 705 } 706 } 707}