BitArray.cs 11 KB

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