Bez popisu
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 28KB

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