暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

NativeBitArray.cs 30KB

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