BitArray.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. using System;
  2. namespace System.Collections
  3. {
  4. // do we really need to specify IEnumerable since ICollection extends it?
  5. [Serializable]
  6. public sealed class BitArray : ICollection, IEnumerable, ICloneable
  7. {
  8. private Int32[] m_array;
  9. private int m_length;
  10. private int m_modCount = 0;
  11. private static void clearJunk(Int32[] arr, int numbits)
  12. {
  13. int numjunkbits = 32 - (numbits%32);
  14. UInt32 mask = (~0U >> numjunkbits);
  15. arr[arr.Length - 1] &= (int)mask;
  16. }
  17. private static int bitsToInts(int bits)
  18. {
  19. int retval = bits/32;
  20. if (bits % 32 != 0)
  21. retval++;
  22. return retval;
  23. }
  24. private static int bitsToBytes(int bits)
  25. {
  26. int retval = bits/8;
  27. if (bits % 8 != 0)
  28. retval++;
  29. return retval;
  30. }
  31. private void setBit(int bitIndex, bool value)
  32. {
  33. int index = bitIndex/32;
  34. int shift = bitIndex%32;
  35. Int32 theBit = 1 << shift;
  36. if(value)
  37. m_array[index] |= theBit;
  38. else
  39. m_array[index] &= ~theBit;
  40. m_modCount++;
  41. }
  42. private bool getBit(int bitIndex)
  43. {
  44. int index = bitIndex/32;
  45. int shift = bitIndex%32;
  46. Int32 theBit = m_array[index] & (1 << shift);
  47. return (theBit == 0) ? false : true;
  48. }
  49. private byte getByte(int byteIndex)
  50. {
  51. int index = byteIndex/4;
  52. int shift = (byteIndex%4)*8;
  53. Int32 theByte = m_array[index] & (0xff << shift);
  54. return (byte)((theByte >> shift)&0xff);
  55. }
  56. private void setByte(int byteIndex, byte value)
  57. {
  58. int index = byteIndex/4;
  59. int shift = (byteIndex%4)*8;
  60. Int32 orig = m_array[index];
  61. // clear the byte
  62. orig &= ~(0xff << shift);
  63. // or in the new byte
  64. orig |= value << shift;
  65. m_array[index] = orig;
  66. m_modCount++;
  67. }
  68. /* --- Constructors --- */
  69. public BitArray(BitArray orig)
  70. {
  71. m_length = orig.m_length;
  72. int numInts = bitsToInts(m_length);
  73. m_array = new Int32[numInts];
  74. Array.Copy(orig.m_array, m_array, numInts);
  75. }
  76. public BitArray(bool[] bits)
  77. {
  78. m_length = bits.Length;
  79. int numInts = bitsToInts(m_length);
  80. m_array = new Int32[numInts];
  81. for (int i=0; i < bits.Length; i++)
  82. setBit(i, bits[i]);
  83. }
  84. public BitArray(byte[] bytes)
  85. {
  86. m_length = bytes.Length * 8;
  87. m_array = new Int32[bitsToInts(m_length)];
  88. for (int i=0; i < bytes.Length; i++)
  89. setByte(i, bytes[i]);
  90. }
  91. public BitArray(int capacity)
  92. {
  93. m_length = capacity;
  94. m_array = new Int32[bitsToInts(m_length)];
  95. }
  96. public BitArray(int[] words)
  97. {
  98. int arrlen = words.Length;
  99. m_length = arrlen*32;
  100. m_array = new Int32[arrlen];
  101. Array.Copy(words, m_array, arrlen);
  102. }
  103. public BitArray(int capacity, bool value) : this(capacity)
  104. {
  105. if (value)
  106. {
  107. // FIXME: Maybe you can create an array pre filled?
  108. for (int i = 0; i < m_array.Length; i++)
  109. m_array[i] = ~0;
  110. }
  111. }
  112. private BitArray(Int32 [] array, int length)
  113. {
  114. m_array = array;
  115. m_length = length;
  116. }
  117. /* --- Public properties --- */
  118. public int Count
  119. {
  120. get
  121. {
  122. return m_length;
  123. }
  124. }
  125. public bool IsReadOnly
  126. {
  127. get
  128. {
  129. return false;
  130. }
  131. }
  132. public bool IsSynchronized
  133. {
  134. get
  135. {
  136. return false;
  137. }
  138. }
  139. public bool this[int index]
  140. {
  141. get
  142. {
  143. return Get(index);
  144. }
  145. set
  146. {
  147. Set(index, value);
  148. }
  149. }
  150. public int Length
  151. {
  152. get
  153. {
  154. return m_length;
  155. }
  156. set
  157. {
  158. if (value < 0)
  159. throw new ArgumentOutOfRangeException();
  160. int newLen = value;
  161. if (m_length != newLen)
  162. {
  163. int numints = bitsToInts(newLen);
  164. Int32 [] newArr = new Int32[numints];
  165. int copylen = (numints > m_array.Length ? m_array.Length : numints);
  166. Array.Copy(m_array, newArr, copylen);
  167. // clear out the junk bits at the end:
  168. clearJunk(newArr, newLen);
  169. // set the internal state
  170. m_array = newArr;
  171. m_length = newLen;
  172. m_modCount++;
  173. }
  174. }
  175. }
  176. public object SyncRoot
  177. {
  178. get
  179. {
  180. return this;
  181. }
  182. }
  183. /* --- Public methods --- */
  184. public BitArray And(BitArray operand)
  185. {
  186. if (operand == null)
  187. throw new ArgumentNullException();
  188. if (operand.m_length != m_length)
  189. throw new ArgumentException();
  190. Int32 [] newarr = new Int32[m_array.Length];
  191. for (int i=0; i < m_array.Length; i++)
  192. newarr[i] = m_array[i] & operand.m_array[i];
  193. return new BitArray(newarr, m_length);
  194. }
  195. public object Clone()
  196. {
  197. // FIXME: according to the doc, this should be a shallow copy.
  198. // But the MS implementation seems to do a deep copy.
  199. return new BitArray((Int32 [])m_array.Clone(), m_length);
  200. }
  201. public void CopyTo(Array array, int index)
  202. {
  203. if (array == null)
  204. throw new ArgumentNullException("array");
  205. if (index < 0)
  206. throw new ArgumentOutOfRangeException("index");
  207. if (array.Rank != 1)
  208. throw new ArgumentException ("Array rank must be 1", "array");
  209. if (index >= array.Length)
  210. throw new ArgumentException("index is greater than array.Length", "index");
  211. // in each case, check to make sure enough space in array
  212. if (array is bool[])
  213. {
  214. if (index + m_length >= array.Length)
  215. throw new ArgumentException();
  216. bool [] barray = (bool []) array;
  217. // Copy the bits into the array
  218. for (int i = 0; i < m_length; i++)
  219. barray[index + i] = getBit(i);
  220. }
  221. else if (array is byte[])
  222. {
  223. int numbytes = bitsToBytes(m_length);
  224. if (index + numbytes >= array.Length)
  225. throw new ArgumentException();
  226. byte [] barray = (byte []) array;
  227. // Copy the bytes into the array
  228. for (int i = 0; i < numbytes; i++)
  229. barray[index + i] = getByte(i);
  230. }
  231. else if (array is int[])
  232. {
  233. int numints = bitsToInts(m_length);
  234. if (index + numints >= array.Length)
  235. throw new ArgumentException();
  236. Array.Copy(m_array, 0, array, index, numints);
  237. }
  238. else
  239. {
  240. throw new ArgumentException("Unsupported type", "array");
  241. }
  242. }
  243. /*
  244. * All this code for nothing... Apparently, The MS BitArray doesn't
  245. * override Equals!
  246. *public override bool Equals(object obj)
  247. {
  248. // If it's not a BitArray, then it can't be equal to us.
  249. if (!(obj is BitArray))
  250. return false;
  251. // If the references are equal, then clearly the instances are equal
  252. if (this == obj)
  253. return true;
  254. // If its length is different, than it can't be equal.
  255. BitArray b = (BitArray) obj;
  256. if (m_length != b.m_length)
  257. return false;
  258. // Now compare the bits.
  259. // This is a little tricky, because if length doesn't divide 32,
  260. // then we shouldn't compare the unused bits in the last element
  261. // of m_array.
  262. // Compare all full ints. If any differ, then we are not equal.
  263. int numints = m_length/32;
  264. for (int i = 0; i < numints; i++)
  265. {
  266. if (b.m_array[i] != m_array[i])
  267. return false;
  268. }
  269. // Compare the left over bits (if any)
  270. int extrabits = m_length%32;
  271. if (extrabits != 0)
  272. {
  273. // our mask is the "extrabits" least significant bits set to 1.
  274. UInt32 comparemask = ~0U >> (32 - extrabits);
  275. // numints is rounded down, so it's safe to use as an index here,
  276. // as long as extrabits > 0.
  277. if ((b.m_array[numints] & comparemask)
  278. != (m_array[numints] & comparemask))
  279. return false;
  280. }
  281. // We passed through all the above, so we are equal.
  282. return true;
  283. }
  284. * End comment out of Equals()
  285. */
  286. public bool Get(int index)
  287. {
  288. if (index < 0 || index >= m_length)
  289. throw new ArgumentOutOfRangeException();
  290. return getBit(index);
  291. }
  292. public IEnumerator GetEnumerator()
  293. {
  294. return new BitArrayEnumerator(this);
  295. }
  296. /*
  297. * Since MS doesn't appear to override Equals/GetHashCode, we don't.
  298. *public override int GetHashCode()
  299. {
  300. // We could make this a constant time function
  301. // by just picking a constant number of bits, spread out
  302. // evenly across the entire array. For now, this will suffice.
  303. int retval = m_length;
  304. // Add in each array element, except for the leftover bits.
  305. int numints = m_length/32;
  306. for (int i = 0; i < numints; i++)
  307. retval += (int)m_array[i];
  308. // That's enough. Adding in the leftover bits is tiring.
  309. return retval;
  310. }
  311. * End comment out of GetHashCode()
  312. */
  313. public BitArray Not()
  314. {
  315. Int32 [] newarr = new Int32[m_array.Length];
  316. for (int i=0; i < m_array.Length; i++)
  317. newarr[i] = ~m_array[i];
  318. return new BitArray(newarr, m_length);
  319. }
  320. public BitArray Or(BitArray operand)
  321. {
  322. if (operand == null)
  323. throw new ArgumentNullException();
  324. if (operand.m_length != m_length)
  325. throw new ArgumentException();
  326. Int32 [] newarr = new Int32[m_array.Length];
  327. for (int i=0; i < m_array.Length; i++)
  328. newarr[i] = m_array[i] | operand.m_array[i];
  329. return new BitArray(newarr, m_length);
  330. }
  331. public void Set(int index, bool value)
  332. {
  333. if (index < 0 || index >= m_length)
  334. throw new ArgumentOutOfRangeException();
  335. setBit(index, value);
  336. }
  337. public void SetAll(bool value)
  338. {
  339. if (value)
  340. {
  341. for (int i = 0; i < m_array.Length; i++)
  342. m_array[i] = ~0;
  343. // clear out the junk bits that we might have set
  344. clearJunk(m_array, m_length);
  345. }
  346. else
  347. Array.Clear(m_array, 0, m_array.Length);
  348. m_modCount++;
  349. }
  350. public BitArray Xor(BitArray operand)
  351. {
  352. if (operand == null)
  353. throw new ArgumentNullException();
  354. if (operand.m_length != m_length)
  355. throw new ArgumentException();
  356. Int32 [] newarr = new Int32[m_array.Length];
  357. for (int i=0; i < m_array.Length; i++)
  358. newarr[i] = m_array[i] ^ operand.m_array[i];
  359. return new BitArray(newarr, m_length);
  360. }
  361. class BitArrayEnumerator : IEnumerator
  362. {
  363. BitArray m_bitArray;
  364. private bool m_current;
  365. private int m_index;
  366. private int m_max;
  367. private int m_modCount;
  368. public BitArrayEnumerator(BitArray ba)
  369. {
  370. m_index = -1;
  371. m_bitArray = ba;
  372. m_max = ba.m_length;
  373. m_modCount = ba.m_modCount;
  374. }
  375. public object Current
  376. {
  377. get
  378. {
  379. if (m_index < 0 || m_index >= m_max)
  380. throw new InvalidOperationException();
  381. return m_current;
  382. }
  383. }
  384. public bool MoveNext()
  385. {
  386. if (m_modCount != m_bitArray.m_modCount)
  387. throw new InvalidOperationException();
  388. if (m_index + 1 >= m_max)
  389. return false;
  390. m_index++;
  391. m_current = m_bitArray[m_index];
  392. return true;
  393. }
  394. public void Reset()
  395. {
  396. if (m_modCount != m_bitArray.m_modCount)
  397. throw new InvalidOperationException();
  398. m_index = -1;
  399. }
  400. }
  401. }
  402. }