Geen omschrijving
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.

NativeBitArrayTests.cs 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. using NUnit.Framework;
  2. using System;
  3. using System.Runtime.InteropServices;
  4. using Unity.Burst;
  5. using Unity.Collections;
  6. using Unity.Collections.LowLevel.Unsafe;
  7. using Unity.Collections.Tests;
  8. using Unity.Jobs;
  9. using Unity.Mathematics;
  10. using UnityEngine;
  11. using UnityEngine.TestTools;
  12. using System.Text.RegularExpressions;
  13. using Assert = FastAssert;
  14. internal class NativeBitArrayTests : CollectionsTestFixture
  15. {
  16. [Test]
  17. public void NativeBitArray_Init()
  18. {
  19. var container = new NativeBitArray(0, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  20. Assert.True(container.IsCreated);
  21. Assert.True(container.IsEmpty);
  22. Assert.DoesNotThrow(() => container.Dispose());
  23. }
  24. [Test]
  25. public void NativeBitArray_Get_Set_Long()
  26. {
  27. var numBits = 256;
  28. var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  29. Assert.False(test.IsSet(123));
  30. test.Set(123, true);
  31. Assert.True(test.IsSet(123));
  32. Assert.False(test.TestAll(0, numBits));
  33. Assert.False(test.TestNone(0, numBits));
  34. Assert.True(test.TestAny(0, numBits));
  35. Assert.AreEqual(1, test.CountBits(0, numBits));
  36. Assert.False(test.TestAll(0, 122));
  37. Assert.True(test.TestNone(0, 122));
  38. Assert.False(test.TestAny(0, 122));
  39. test.Clear();
  40. Assert.False(test.IsSet(123));
  41. Assert.AreEqual(0, test.CountBits(0, numBits));
  42. test.SetBits(40, true, 4);
  43. Assert.AreEqual(4, test.CountBits(0, numBits));
  44. test.SetBits(0, true, numBits);
  45. Assert.False(test.TestNone(0, numBits));
  46. Assert.True(test.TestAll(0, numBits));
  47. test.SetBits(0, false, numBits);
  48. Assert.True(test.TestNone(0, numBits));
  49. Assert.False(test.TestAll(0, numBits));
  50. test.SetBits(123, true, 7);
  51. Assert.True(test.TestAll(123, 7));
  52. test.Clear();
  53. test.SetBits(64, true, 64);
  54. Assert.AreEqual(false, test.IsSet(63));
  55. Assert.AreEqual(true, test.TestAll(64, 64));
  56. Assert.AreEqual(false, test.IsSet(128));
  57. Assert.AreEqual(64, test.CountBits(64, 64));
  58. Assert.AreEqual(64, test.CountBits(0, numBits));
  59. test.Clear();
  60. test.SetBits(65, true, 62);
  61. Assert.AreEqual(false, test.IsSet(64));
  62. Assert.AreEqual(true, test.TestAll(65, 62));
  63. Assert.AreEqual(false, test.IsSet(127));
  64. Assert.AreEqual(62, test.CountBits(64, 64));
  65. Assert.AreEqual(62, test.CountBits(0, numBits));
  66. test.Clear();
  67. test.SetBits(66, true, 64);
  68. Assert.AreEqual(false, test.IsSet(65));
  69. Assert.AreEqual(true, test.TestAll(66, 64));
  70. Assert.AreEqual(false, test.IsSet(130));
  71. Assert.AreEqual(64, test.CountBits(66, 64));
  72. Assert.AreEqual(64, test.CountBits(0, numBits));
  73. test.Dispose();
  74. }
  75. [Test]
  76. public void NativeBitArray_Get_Set_Short()
  77. {
  78. var numBits = 31;
  79. var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  80. Assert.False(test.IsSet(13));
  81. test.Set(13, true);
  82. Assert.True(test.IsSet(13));
  83. Assert.False(test.TestAll(0, numBits));
  84. Assert.False(test.TestNone(0, numBits));
  85. Assert.True(test.TestAny(0, numBits));
  86. Assert.AreEqual(1, test.CountBits(0, numBits));
  87. Assert.False(test.TestAll(0, 12));
  88. Assert.True(test.TestNone(0, 12));
  89. Assert.False(test.TestAny(0, 12));
  90. test.Clear();
  91. Assert.False(test.IsSet(13));
  92. Assert.AreEqual(0, test.CountBits(0, numBits));
  93. test.SetBits(4, true, 4);
  94. Assert.AreEqual(4, test.CountBits(0, numBits));
  95. test.SetBits(0, true, numBits);
  96. Assert.False(test.TestNone(0, numBits));
  97. Assert.True(test.TestAll(0, numBits));
  98. test.SetBits(0, false, numBits);
  99. Assert.True(test.TestNone(0, numBits));
  100. Assert.False(test.TestAll(0, numBits));
  101. test.SetBits(13, true, 7);
  102. Assert.True(test.TestAll(13, 7));
  103. test.Clear();
  104. test.SetBits(4, true, 4);
  105. Assert.AreEqual(false, test.IsSet(3));
  106. Assert.AreEqual(true, test.TestAll(4, 4));
  107. Assert.AreEqual(false, test.IsSet(18));
  108. Assert.AreEqual(4, test.CountBits(4, 4));
  109. Assert.AreEqual(4, test.CountBits(0, numBits));
  110. test.Clear();
  111. test.SetBits(5, true, 2);
  112. Assert.AreEqual(false, test.IsSet(4));
  113. Assert.AreEqual(true, test.TestAll(5, 2));
  114. Assert.AreEqual(false, test.IsSet(17));
  115. Assert.AreEqual(2, test.CountBits(4, 4));
  116. Assert.AreEqual(2, test.CountBits(0, numBits));
  117. test.Clear();
  118. test.SetBits(6, true, 4);
  119. Assert.AreEqual(false, test.IsSet(5));
  120. Assert.AreEqual(true, test.TestAll(6, 4));
  121. Assert.AreEqual(false, test.IsSet(10));
  122. Assert.AreEqual(4, test.CountBits(6, 4));
  123. Assert.AreEqual(4, test.CountBits(0, numBits));
  124. test.Dispose();
  125. }
  126. [Test]
  127. public void NativeBitArray_Get_Set_Tiny()
  128. {
  129. var numBits = 7;
  130. var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  131. Assert.False(test.IsSet(3));
  132. test.Set(3, true);
  133. Assert.True(test.IsSet(3));
  134. Assert.False(test.TestAll(0, numBits));
  135. Assert.False(test.TestNone(0, numBits));
  136. Assert.True(test.TestAny(0, numBits));
  137. Assert.AreEqual(1, test.CountBits(0, numBits));
  138. Assert.False(test.TestAll(0, 2));
  139. Assert.True(test.TestNone(0, 2));
  140. Assert.False(test.TestAny(0, 2));
  141. test.Clear();
  142. Assert.False(test.IsSet(3));
  143. Assert.AreEqual(0, test.CountBits(0, numBits));
  144. test.SetBits(3, true, 4);
  145. Assert.AreEqual(4, test.CountBits(0, numBits));
  146. test.SetBits(0, true, numBits);
  147. Assert.False(test.TestNone(0, numBits));
  148. Assert.True(test.TestAll(0, numBits));
  149. test.SetBits(0, false, numBits);
  150. Assert.True(test.TestNone(0, numBits));
  151. Assert.False(test.TestAll(0, numBits));
  152. test.Dispose();
  153. }
  154. [Test]
  155. [TestRequiresDotsDebugOrCollectionChecks]
  156. public unsafe void NativeBitArray_Throws()
  157. {
  158. var numBits = 256;
  159. Assert.Throws<ArgumentException>(() => { new NativeBitArray(numBits, Allocator.None); });
  160. using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
  161. {
  162. Assert.DoesNotThrow(() => { test.TestAll(0, numBits); });
  163. Assert.DoesNotThrow(() => { test.TestAny(numBits - 1, numBits); });
  164. Assert.Throws<ArgumentException>(() => { test.IsSet(-1); });
  165. Assert.Throws<ArgumentException>(() => { test.IsSet(numBits); });
  166. Assert.Throws<ArgumentException>(() => { test.TestAny(0, 0); });
  167. Assert.Throws<ArgumentException>(() => { test.TestAny(numBits, 1); });
  168. Assert.Throws<ArgumentException>(() => { test.TestAny(numBits - 1, 0); });
  169. // GetBits numBits must be 1-64.
  170. Assert.Throws<ArgumentException>(() => { test.GetBits(0, 0); });
  171. Assert.Throws<ArgumentException>(() => { test.GetBits(0, 65); });
  172. Assert.DoesNotThrow(() => { test.GetBits(63, 2); });
  173. }
  174. }
  175. void GetBitsTest(ref NativeBitArray test, int pos, int numBits)
  176. {
  177. test.SetBits(pos, true, numBits);
  178. Assert.AreEqual(numBits, test.CountBits(0, test.Length));
  179. Assert.AreEqual(0xfffffffffffffffful >> (64 - numBits), test.GetBits(pos, numBits));
  180. test.Clear();
  181. }
  182. [Test]
  183. public void NativeBitArray_GetBits()
  184. {
  185. var numBits = 256;
  186. var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  187. GetBitsTest(ref test, 0, 5);
  188. GetBitsTest(ref test, 1, 3);
  189. GetBitsTest(ref test, 0, 63);
  190. GetBitsTest(ref test, 0, 64);
  191. GetBitsTest(ref test, 1, 63);
  192. GetBitsTest(ref test, 1, 64);
  193. GetBitsTest(ref test, 62, 5);
  194. GetBitsTest(ref test, 127, 3);
  195. GetBitsTest(ref test, 250, 6);
  196. GetBitsTest(ref test, 254, 2);
  197. test.Dispose();
  198. }
  199. static void SetBitsTest(ref NativeBitArray test, int pos, ulong value, int numBits)
  200. {
  201. test.SetBits(pos, value, numBits);
  202. if (value != test.GetBits(pos, numBits))
  203. throw new Exception("Assert.Equals(value, test.GetBits(pos, numBits)) failed");
  204. test.Clear();
  205. }
  206. [Test]
  207. public void NativeBitArray_SetBits()
  208. {
  209. var numBits = 256;
  210. var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  211. SetBitsTest(ref test, 0, 16, 5);
  212. SetBitsTest(ref test, 1, 7, 3);
  213. SetBitsTest(ref test, 1, 32, 64);
  214. SetBitsTest(ref test, 62, 6, 5);
  215. SetBitsTest(ref test, 127, 1, 3);
  216. SetBitsTest(ref test, 60, 0xaa, 8);
  217. test.Dispose();
  218. }
  219. static void CopyBitsTest(ref NativeBitArray test, int dstPos, int srcPos, int numBits)
  220. {
  221. for (int pos = 0; pos < test.Length; pos += 64)
  222. {
  223. test.SetBits(pos, 0xaaaaaaaaaaaaaaaaul, 64);
  224. }
  225. test.SetBits(srcPos, true, numBits);
  226. test.Copy(dstPos, srcPos, numBits);
  227. Assert.AreEqual(true, test.TestAll(dstPos, numBits));
  228. for (int pos = 0; pos < test.Length; ++pos)
  229. {
  230. if ((pos >= dstPos && pos < dstPos + numBits) ||
  231. (pos >= srcPos && pos < srcPos + numBits))
  232. {
  233. Assert.AreEqual(true, test.IsSet(pos));
  234. }
  235. else
  236. {
  237. Assert.AreEqual((0 != (pos & 1)), test.IsSet(pos));
  238. }
  239. }
  240. test.Clear();
  241. }
  242. static void CopyBitsTests(ref NativeBitArray test)
  243. {
  244. CopyBitsTest(ref test, 1, 16, 12); // short up to 64-bits copy
  245. CopyBitsTest(ref test, 1, 80, 63); // short up to 64-bits copy
  246. CopyBitsTest(ref test, 1, 11, 12); // short up to 64-bits copy overlapped
  247. CopyBitsTest(ref test, 11, 1, 12); // short up to 64-bits copy overlapped
  248. CopyBitsTest(ref test, 1, 16, 76); // short up to 128-bits copy
  249. CopyBitsTest(ref test, 1, 80, 127); // short up to 128-bits copy
  250. CopyBitsTest(ref test, 1, 11, 76); // short up to 128-bits copy overlapped
  251. CopyBitsTest(ref test, 11, 1, 76); // short up to 128-bits copy overlapped
  252. CopyBitsTest(ref test, 1, 81, 255); // long copy aligned
  253. CopyBitsTest(ref test, 8, 0, 255); // long copy overlapped aligned
  254. CopyBitsTest(ref test, 1, 80, 255); // long copy unaligned
  255. CopyBitsTest(ref test, 80, 1, 255); // long copy overlapped unaligned
  256. }
  257. [Test]
  258. public void NativeBitArray_Copy()
  259. {
  260. var numBits = 512;
  261. var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  262. CopyBitsTests(ref test);
  263. test.Dispose();
  264. }
  265. [Test]
  266. public void UnsafeBitArray_Resize()
  267. {
  268. var test = new NativeBitArray(1, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  269. Assert.AreEqual(1, test.Length);
  270. Assert.AreEqual(64, test.Capacity);
  271. test.SetCapacity(200); // expand
  272. Assert.AreEqual(1, test.Length);
  273. Assert.AreEqual(256, test.Capacity);
  274. test.Resize(100, NativeArrayOptions.ClearMemory);
  275. Assert.True(test.TestNone(0, test.Length));
  276. // prepare survival test
  277. test.Set(0, true);
  278. test.Set(99, true);
  279. Assert.True(test.IsSet(0));
  280. Assert.True(test.TestNone(1, 98));
  281. Assert.True(test.IsSet(99));
  282. test.SetCapacity(1000); // expand
  283. Assert.AreEqual(100, test.Length);
  284. Assert.AreEqual(1024, test.Capacity);
  285. // test resize survival
  286. Assert.True(test.IsSet(0));
  287. Assert.True(test.TestNone(1, 98));
  288. Assert.True(test.IsSet(99));
  289. // manual clear
  290. test.Resize(1);
  291. test.Set(0, false);
  292. test.SetCapacity(200); // truncate capacity
  293. Assert.AreEqual(1, test.Length);
  294. Assert.AreEqual(256, test.Capacity);
  295. test.Resize(512, NativeArrayOptions.ClearMemory); // resize
  296. Assert.AreEqual(512, test.Length);
  297. Assert.AreEqual(512, test.Capacity);
  298. Assert.True(test.TestNone(0, test.Length));
  299. CopyBitsTests(ref test);
  300. test.Resize(256); // truncate length
  301. Assert.AreEqual(256, test.Length);
  302. Assert.AreEqual(512, test.Capacity);
  303. test.TrimExcess();
  304. Assert.AreEqual(256, test.Length);
  305. Assert.AreEqual(256, test.Capacity);
  306. test.Dispose();
  307. }
  308. [Test]
  309. public unsafe void NativeBitArray_CopyBetweenBitArrays()
  310. {
  311. var numBits = 512;
  312. var str = new FixedString128Bytes("aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ");
  313. var test0 = NativeBitArrayUnsafeUtility.ConvertExistingDataToNativeBitArray(&str.bytes.offset0000, 64, Allocator.None);
  314. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  315. AtomicSafetyHandle ash = CollectionHelper.CreateSafetyHandle(Allocator.Temp);
  316. NativeBitArrayUnsafeUtility.SetAtomicSafetyHandle(ref test0, ash);
  317. #endif
  318. var test1 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  319. var test2 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  320. for (int pos = 0; pos < test0.Length; pos += 64)
  321. {
  322. test1.SetBits(pos, 0x5555555555555555ul, 64);
  323. test2.SetBits(pos, 0xaaaaaaaaaaaaaaaaul, 64);
  324. }
  325. test1.Copy(1, ref test0, 205, 211);
  326. test1.Copy(214, ref test0, 0, 205);
  327. test2.Copy(205, ref test1, 1, 211);
  328. test2.Copy(0, ref test1, 214, 205);
  329. test0.Copy(0, ref test2, 0, 512);
  330. Assert.AreEqual(str, "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ");
  331. test0.Dispose();
  332. test1.Dispose();
  333. test2.Dispose();
  334. }
  335. [Test]
  336. [TestRequiresDotsDebugOrCollectionChecks]
  337. public unsafe void NativeBitArray_Copy_Throws()
  338. {
  339. var numBits = 512;
  340. var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  341. Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, 0, numBits - 1, 16); }); // short up to 64-bits copy out of bounds
  342. Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, numBits - 1, 0, 16); }); // short up to 64-bits copy out of bounds
  343. Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, 0, numBits - 1, 80); }); // short up to 128-bits copy out of bounds
  344. Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, numBits - 1, 0, 80); }); // short up to 128-bits copy out of bounds
  345. Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, 1, numBits - 7, 127); }); // long copy aligned
  346. Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, numBits - 7, 1, 127); }); // long copy aligned
  347. Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, 2, numBits - 1, 127); }); // long copy unaligned
  348. Assert.Throws<ArgumentException>(() => { CopyBitsTest(ref test, numBits - 1, 2, 127); }); // long copy unaligned
  349. test.Dispose();
  350. }
  351. [Test]
  352. public unsafe void NativeBitArray_Find()
  353. {
  354. var numBits = 512;
  355. using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
  356. {
  357. test.SetBits(0, true, 11);
  358. for (var i = 0; i < 256; ++i)
  359. {
  360. Assert.AreEqual(11, test.Find(0, i + 1));
  361. }
  362. for (var j = 0; j < 64; ++j)
  363. {
  364. for (var i = 0; i < 256; ++i)
  365. {
  366. var numBitsToFind = 7 + i;
  367. var pos = 37 + j;
  368. test.SetBits(0, true, test.Length);
  369. test.SetBits(pos, false, numBitsToFind);
  370. Assert.AreEqual(pos, test.Find(0, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
  371. Assert.AreEqual(pos, test.Find(pos, numBitsToFind)); //, $"{j}/{i}:pos {pos}, numBitsToFind {numBitsToFind}");
  372. Assert.AreEqual(pos, test.Find(0, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
  373. Assert.AreEqual(pos, test.Find(pos, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
  374. Assert.IsTrue(test.TestNone(test.Find(0, numBitsToFind), numBitsToFind));
  375. Assert.AreEqual(int.MaxValue, test.Find(pos + 1, numBitsToFind)); //, $"{j}/{i}: pos {pos}, numBitsToFind {numBitsToFind}");
  376. }
  377. }
  378. }
  379. }
  380. [Test]
  381. public unsafe void NativeBitArray_Find_With_Begin_End()
  382. {
  383. var numBits = 512;
  384. using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
  385. {
  386. Assert.AreEqual(0, test.Find(0, 2, 1));
  387. Assert.AreEqual(1, test.Find(1, 2, 1));
  388. test.SetBits(0, true, 6);
  389. Assert.AreEqual(int.MaxValue, test.Find(0, 2, 1));
  390. for (var j = 0; j < 64; ++j)
  391. {
  392. for (var i = 0; i < 256; ++i)
  393. {
  394. var numBitsToFind = 7 + i;
  395. var padding = 11;
  396. var begin = 37 + j;
  397. var end = begin + padding + numBitsToFind;
  398. var count = end - begin;
  399. test.Clear();
  400. test.SetBits(begin, true, count);
  401. test.SetBits(begin + padding + 1, false, numBitsToFind - 1);
  402. Assert.AreEqual(begin + padding + 1, test.Find(begin, count, numBitsToFind - 1)); //, $"{j}/{i}: begin {begin}, end {end}, count {count}, numBitsToFind {numBitsToFind}");
  403. Assert.AreEqual(int.MaxValue, test.Find(begin, count, numBitsToFind)); //, $"{j}/{i}: begin {begin}, end {end}, count {count}, numBitsToFind {numBitsToFind}");
  404. }
  405. }
  406. }
  407. }
  408. [Test]
  409. [TestRequiresDotsDebugOrCollectionChecks]
  410. public unsafe void NativeBitArray_Find_Throws()
  411. {
  412. var numBits = 512;
  413. using (var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory))
  414. {
  415. Assert.Throws<ArgumentException>(() => { test.Find(0, 0, 1); }); // empty range
  416. Assert.Throws<ArgumentException>(() => { test.Find(0, 1, 0); }); // zero bits
  417. Assert.Throws<ArgumentException>(() => { test.Find(0, 1, 2); }); // numBits is larger than range
  418. Assert.Throws<ArgumentException>(() => { test.Find(10, 0, 0); }); // empty range, numBits is less than 1
  419. Assert.Throws<ArgumentException>(() => { test.Find(1, 10, -2); }); // numBits can't be negative
  420. }
  421. }
  422. [Test]
  423. public void NativeBitArray_AsNativeArray_Byte()
  424. {
  425. var numBits = 64;
  426. var test0 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  427. var test1 = test0.AsNativeArray<byte>();
  428. Assert.AreEqual(numBits / 8, test1.Length);
  429. test1[0] = 0x10;
  430. test1[1] = 0x32;
  431. test1[2] = 0x54;
  432. test1[3] = 0x76;
  433. test1[4] = 0x98;
  434. test1[5] = 0xba;
  435. test1[6] = 0xdc;
  436. test1[7] = 0xfe;
  437. for (var i = 0; i < 16; ++i)
  438. {
  439. NUnit.Framework.Assert.AreEqual(i, test0.GetBits(i * 4, 4));
  440. }
  441. test1.Dispose();
  442. test0.Dispose();
  443. }
  444. [Test]
  445. public void NativeBitArray_AsNativeArray_Uint()
  446. {
  447. var numBits = 64;
  448. var test0 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  449. var test1 = test0.AsNativeArray<uint>();
  450. Assert.AreEqual(numBits / 32, test1.Length);
  451. test1[0] = 0x76543210;
  452. test1[1] = 0xfedcba98;
  453. for (var i = 0; i < 16; ++i)
  454. {
  455. NUnit.Framework.Assert.AreEqual(i, test0.GetBits(i * 4, 4));
  456. }
  457. test1.Dispose();
  458. test0.Dispose();
  459. }
  460. [Test]
  461. public void NativeBitArray_AsNativeArray_Ulong()
  462. {
  463. var numBits = 64;
  464. var test0 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  465. var test1 = test0.AsNativeArray<ulong>();
  466. Assert.AreEqual(numBits / 64, test1.Length);
  467. test1[0] = 0xfedcba9876543210;
  468. for (var i = 0; i < 16; ++i)
  469. {
  470. NUnit.Framework.Assert.AreEqual(i, test0.GetBits(i * 4, 4));
  471. }
  472. test1.Dispose();
  473. test0.Dispose();
  474. }
  475. [StructLayout(LayoutKind.Explicit, Size = 16)]
  476. internal struct SizeMismatch128
  477. {
  478. }
  479. [StructLayout(LayoutKind.Explicit, Size=7)]
  480. internal struct SizeMismatch56
  481. {
  482. }
  483. [Test]
  484. [TestRequiresDotsDebugOrCollectionChecks]
  485. public void NativeBitArray_AsNativeArray_ThrowsOnSizeMismatch()
  486. {
  487. var numBits = 64;
  488. var test0 = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  489. Assert.Throws<InvalidOperationException>(() => { test0.AsNativeArray<SizeMismatch128>(); });
  490. Assert.Throws<InvalidOperationException>(() => { test0.AsNativeArray<SizeMismatch56>(); });
  491. test0.Dispose();
  492. }
  493. // Burst error BC1071: Unsupported assert type
  494. // [BurstCompile(CompileSynchronously = true)]
  495. struct NativeBitArrayTestReadOnly : IJob
  496. {
  497. public NativeBitArray.ReadOnly reader;
  498. public void Execute()
  499. {
  500. var rd = reader;
  501. Assert.True(reader.IsSet(7));
  502. Assert.AreEqual(1, reader.CountBits(0, reader.Length));
  503. }
  504. }
  505. [Test]
  506. [TestRequiresCollectionChecks]
  507. public void NativeBitArray_ReadOnly()
  508. {
  509. var numBits = 256;
  510. var reader = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  511. reader.Set(7, true);
  512. var readerJob = new NativeBitArrayTestReadOnly { reader = reader.AsReadOnly() }.Schedule();
  513. var from = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  514. Assert.Throws<InvalidOperationException>(() => { reader.Copy(7, ref from, 30, 10); } /* attempt to write into reader after job is scheduled */);
  515. from.Dispose();
  516. reader.Dispose(readerJob);
  517. readerJob.Complete();
  518. }
  519. [Test]
  520. [TestRequiresCollectionChecks]
  521. public void NativeBitArray_UseAfterFree_UsesCustomOwnerTypeName()
  522. {
  523. var numBits = 256;
  524. var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  525. SetBitsTest(ref test, 0, 16, 5);
  526. test.Dispose();
  527. NUnit.Framework.Assert.That(() => test.IsSet(0),
  528. Throws.Exception.TypeOf<ObjectDisposedException>()
  529. .With.Message.Contains($"The {test.GetType()} has been deallocated"));
  530. }
  531. [Test]
  532. [TestRequiresCollectionChecks]
  533. public void NativeBitArray_AtomicSafetyHandle_AllocatorTemp_UniqueStaticSafetyIds()
  534. {
  535. var numBits = 256;
  536. var test = new NativeBitArray(numBits, Allocator.Temp, NativeArrayOptions.ClearMemory);
  537. // All collections that use Allocator.Temp share the same core AtomicSafetyHandle.
  538. // This test verifies that containers can proceed to assign unique static safety IDs to each
  539. // AtomicSafetyHandle value, which will not be shared by other containers using Allocator.Temp.
  540. var test0 = new NativeBitArray(numBits, Allocator.Temp, NativeArrayOptions.ClearMemory);
  541. var test1 = new NativeBitArray(numBits, Allocator.Temp, NativeArrayOptions.ClearMemory);
  542. SetBitsTest(ref test0, 0, 16, 5);
  543. test0.Dispose();
  544. NUnit.Framework.Assert.That(() => test0.IsSet(0),
  545. Throws.Exception.With.TypeOf<ObjectDisposedException>()
  546. .With.Message.Contains($"The {test0.GetType()} has been deallocated"));
  547. SetBitsTest(ref test1, 0, 16, 5);
  548. test1.Dispose();
  549. NUnit.Framework.Assert.That(() => test1.IsSet(0),
  550. Throws.Exception.With.TypeOf<ObjectDisposedException>()
  551. .With.Message.Contains($"The {test1.GetType()} has been deallocated"));
  552. }
  553. [BurstCompile(CompileSynchronously = true)]
  554. struct NativeBitArrayCreateAndUseAfterFreeBurst : IJob
  555. {
  556. public void Execute()
  557. {
  558. var numBits = 256;
  559. var test = new NativeBitArray(numBits, Allocator.Temp, NativeArrayOptions.ClearMemory);
  560. SetBitsTest(ref test, 0, 16, 5);
  561. test.Dispose();
  562. SetBitsTest(ref test, 0, 16, 5);
  563. }
  564. }
  565. [Test]
  566. [TestRequiresCollectionChecks]
  567. public void NativeBitArray_CreateAndUseAfterFreeInBurstJob_UsesCustomOwnerTypeName()
  568. {
  569. // Make sure this isn't the first container of this type ever created, so that valid static safety data exists
  570. var numBits = 256;
  571. var test = new NativeBitArray(numBits, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  572. test.Dispose();
  573. var job = new NativeBitArrayCreateAndUseAfterFreeBurst
  574. {
  575. };
  576. // Two things:
  577. // 1. This exception is logged, not thrown; thus, we use LogAssert to detect it.
  578. // 2. Calling write operation after container.Dispose() emits an unintuitive error message. For now, all this test cares about is whether it contains the
  579. // expected type name.
  580. job.Run();
  581. LogAssert.Expect(LogType.Exception,
  582. new Regex($"InvalidOperationException: The {Regex.Escape(test.GetType().ToString())} has been declared as \\[ReadOnly\\] in the job, but you are writing to it"));
  583. }
  584. void findWithPattern(ref NativeBitArray test, byte pattern, int numBits)
  585. {
  586. for (int pos = 0; pos < test.Length; pos += 8)
  587. {
  588. test.SetBits(pos, pattern, 8);
  589. }
  590. var bitCount = math.countbits((int)pattern);
  591. var numEmptyBits = test.Length - (test.Length / 8 * bitCount);
  592. for (int i = 0; i < numEmptyBits; i += numBits)
  593. {
  594. var pos = test.Find(0, numBits);
  595. Assert.AreNotEqual(int.MaxValue, pos, $"{i}");
  596. test.SetBits(pos, true, numBits);
  597. }
  598. Assert.True(test.TestAll(0, test.Length));
  599. }
  600. [Test]
  601. public void NativeBitArray_FindWithPattern()
  602. {
  603. var test = new NativeBitArray(512, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  604. // Separated test for some more interesting patterns
  605. findWithPattern(ref test, 0x81, 1);
  606. findWithPattern(ref test, 0x81, 2);
  607. findWithPattern(ref test, 0x81, 3);
  608. findWithPattern(ref test, 0x81, 6);
  609. findWithPattern(ref test, 0x88, 3);
  610. findWithPattern(ref test, 0x99, 2);
  611. findWithPattern(ref test, 0xaa, 1);
  612. findWithPattern(ref test, 0xc3, 1);
  613. findWithPattern(ref test, 0xc3, 2);
  614. findWithPattern(ref test, 0xc3, 4);
  615. findWithPattern(ref test, 0xe7, 1);
  616. findWithPattern(ref test, 0xe7, 2);
  617. // Test all patterns
  618. for (int i = 0; i < 256; i++)
  619. {
  620. findWithPattern(ref test, (byte)i, 1);
  621. }
  622. test.Dispose();
  623. }
  624. [Test]
  625. public void NativeBitArray_FindInTinyBitArray()
  626. {
  627. var test = new NativeBitArray(3, Allocator.Persistent, NativeArrayOptions.ClearMemory);
  628. Assert.AreEqual(3, test.Length);
  629. test.SetBits(0, 0x55, test.Length);
  630. Assert.AreEqual(1, test.Find(0, 1));
  631. Assert.AreEqual(1, test.Find(0, test.Length, 1));
  632. test.SetBits(1, true, 1);
  633. Assert.True(test.TestAll(0, test.Length));
  634. Assert.AreEqual(int.MaxValue, test.Find(0, test.Length, 1));
  635. test.Dispose();
  636. }
  637. [Test]
  638. public void NativeBitArray_FindLastUnsetBit([NUnit.Framework.Range(1, 64)] int numBits)
  639. {
  640. using (var bits = new NativeBitArray(numBits, Allocator.Persistent))
  641. {
  642. // Set all bits to one then unset a single bit to find.
  643. for (int i = 0; i < numBits; ++i)
  644. {
  645. bits.SetBits(0, true, numBits);
  646. bits.Set(i, false);
  647. Assert.AreEqual(i, bits.Find(0, 1));
  648. }
  649. }
  650. }
  651. [Test]
  652. public void NativeBitArray_CustomAllocatorTest()
  653. {
  654. AllocatorManager.Initialize();
  655. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  656. allocatorHelper.Allocator.Initialize();
  657. using (var bitset = new NativeBitArray(1, allocatorHelper.Allocator.Handle))
  658. {
  659. }
  660. Assert.IsTrue(allocatorHelper.Allocator.WasUsed);
  661. allocatorHelper.Allocator.Dispose();
  662. allocatorHelper.Dispose();
  663. AllocatorManager.Shutdown();
  664. }
  665. [BurstCompile]
  666. struct BurstedCustomAllocatorJob : IJob
  667. {
  668. [NativeDisableUnsafePtrRestriction]
  669. public unsafe CustomAllocatorTests.CountingAllocator* Allocator;
  670. public void Execute()
  671. {
  672. unsafe
  673. {
  674. using (var container = new NativeBitArray(1, Allocator->Handle))
  675. {
  676. }
  677. }
  678. }
  679. }
  680. [Test]
  681. public unsafe void NativeBitArray_BurstedCustomAllocatorTest()
  682. {
  683. AllocatorManager.Initialize();
  684. var allocatorHelper = new AllocatorHelper<CustomAllocatorTests.CountingAllocator>(AllocatorManager.Persistent);
  685. ref var allocator = ref allocatorHelper.Allocator;
  686. allocatorHelper.Allocator.Initialize();
  687. var allocatorPtr = (CustomAllocatorTests.CountingAllocator*)UnsafeUtility.AddressOf<CustomAllocatorTests.CountingAllocator>(ref allocator);
  688. unsafe
  689. {
  690. var handle = new BurstedCustomAllocatorJob {Allocator = allocatorPtr}.Schedule();
  691. handle.Complete();
  692. }
  693. Assert.IsTrue(allocator.WasUsed);
  694. allocator.Dispose();
  695. allocatorHelper.Dispose();
  696. AllocatorManager.Shutdown();
  697. }
  698. }