BitArray.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. //
  2. // Bit Array.cs
  3. //
  4. // Authors:
  5. // Ben Maurer ([email protected])
  6. // Marek Safar ([email protected])
  7. //
  8. // (C) 2003 Ben Maurer
  9. //
  10. //
  11. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. using System;
  33. using System.Runtime.InteropServices;
  34. namespace System.Collections {
  35. #if NET_2_0
  36. [ComVisible(true)]
  37. #endif
  38. [Serializable]
  39. #if INSIDE_CORLIB
  40. public
  41. #else
  42. internal
  43. #endif
  44. sealed class BitArray : ICollection, ICloneable {
  45. int [] m_array;
  46. int m_length;
  47. int _version = 0;
  48. #region Constructors
  49. public BitArray (BitArray bits)
  50. {
  51. if (bits == null)
  52. throw new ArgumentNullException ("bits");
  53. m_length = bits.m_length;
  54. m_array = new int [(m_length + 31) / 32];
  55. if (m_array.Length == 1)
  56. m_array [0] = bits.m_array [0];
  57. else
  58. Array.Copy(bits.m_array, m_array, m_array.Length);
  59. }
  60. public BitArray (bool [] values)
  61. {
  62. if (values == null)
  63. throw new ArgumentNullException ("values");
  64. m_length = values.Length;
  65. m_array = new int [(m_length + 31) / 32];
  66. for (int i = 0; i < values.Length; i++)
  67. this [i] = values [i];
  68. }
  69. public BitArray (byte [] bytes)
  70. {
  71. if (bytes == null)
  72. throw new ArgumentNullException ("bytes");
  73. m_length = bytes.Length * 8;
  74. m_array = new int [(m_length + 31) / 32];
  75. for (int i = 0; i < bytes.Length; i++)
  76. setByte (i, bytes [i]);
  77. }
  78. public BitArray (int [] values)
  79. {
  80. if (values == null)
  81. throw new ArgumentNullException ("values");
  82. int arrlen = values.Length;
  83. m_length = arrlen*32;
  84. m_array = new int [arrlen];
  85. Array.Copy (values, m_array, arrlen);
  86. }
  87. public BitArray (int length)
  88. {
  89. if (length < 0)
  90. throw new ArgumentOutOfRangeException ("length");
  91. m_length = length;
  92. m_array = new int [(m_length + 31) / 32];
  93. }
  94. public BitArray (int length, bool defaultValue) : this (length)
  95. {
  96. if (defaultValue) {
  97. for (int i = 0; i < m_array.Length; i++)
  98. m_array[i] = ~0;
  99. }
  100. }
  101. private BitArray (int [] array, int length)
  102. {
  103. m_array = array;
  104. m_length = length;
  105. }
  106. #endregion
  107. #region Utility Methods
  108. byte getByte (int byteIndex)
  109. {
  110. int index = byteIndex / 4;
  111. int shift = (byteIndex % 4) * 8;
  112. int theByte = m_array [index] & (0xff << shift);
  113. return (byte)((theByte >> shift) & 0xff);
  114. }
  115. void setByte (int byteIndex, byte value)
  116. {
  117. int index = byteIndex / 4;
  118. int shift = (byteIndex % 4) * 8;
  119. // clear the byte
  120. m_array [index] &= ~(0xff << shift);
  121. // or in the new byte
  122. m_array [index] |= value << shift;
  123. _version++;
  124. }
  125. void checkOperand (BitArray operand)
  126. {
  127. if (operand == null)
  128. throw new ArgumentNullException ();
  129. if (operand.m_length != m_length)
  130. throw new ArgumentException ();
  131. }
  132. #endregion
  133. public int Count {
  134. get { return m_length; }
  135. }
  136. public bool IsReadOnly {
  137. get { return false; }
  138. }
  139. public bool IsSynchronized {
  140. get { return false; }
  141. }
  142. public bool this [int index] {
  143. get { return Get (index); }
  144. set { Set (index, value); }
  145. }
  146. public int Length {
  147. get { return m_length; }
  148. set {
  149. if (m_length == value)
  150. return;
  151. if (value < 0)
  152. throw new ArgumentOutOfRangeException ();
  153. // Currently we never shrink the array
  154. if (value > m_length) {
  155. int numints = (value + 31) / 32;
  156. int old_numints = (m_length + 31) / 32;
  157. if (numints > m_array.Length) {
  158. int [] newArr = new int [numints];
  159. Array.Copy (m_array, newArr, m_array.Length);
  160. m_array = newArr;
  161. } else {
  162. Array.Clear(m_array, old_numints, numints - old_numints);
  163. }
  164. int mask = m_length % 32;
  165. if (mask > 0)
  166. m_array [old_numints - 1] &= (1 << mask) - 1;
  167. }
  168. // set the internal state
  169. m_length = value;
  170. _version++;
  171. }
  172. }
  173. public object SyncRoot {
  174. get { return this; }
  175. }
  176. public object Clone ()
  177. {
  178. // LAMESPEC: docs say shallow, MS makes deep.
  179. return new BitArray (this);
  180. }
  181. public void CopyTo (Array array, int index)
  182. {
  183. if (array == null)
  184. throw new ArgumentNullException ("array");
  185. if (index < 0)
  186. throw new ArgumentOutOfRangeException ("index");
  187. if (array.Rank != 1)
  188. throw new ArgumentException ("array", "Array rank must be 1");
  189. if (index >= array.Length)
  190. throw new ArgumentException ("index", "index is greater than array.Length");
  191. // in each case, check to make sure enough space in array
  192. if (array is bool []) {
  193. if (array.Length - index < m_length)
  194. throw new ArgumentException ();
  195. bool [] barray = (bool []) array;
  196. // Copy the bits into the array
  197. for (int i = 0; i < m_length; i++)
  198. barray[index + i] = this [i];
  199. } else if (array is byte []) {
  200. int numbytes = (m_length + 7) / 8;
  201. if ((array.Length - index) < numbytes)
  202. throw new ArgumentException ();
  203. byte [] barray = (byte []) array;
  204. // Copy the bytes into the array
  205. for (int i = 0; i < numbytes; i++)
  206. barray [index + i] = getByte (i);
  207. } else if (array is int []) {
  208. Array.Copy (m_array, 0, array, index, (m_length + 31) / 32);
  209. } else {
  210. throw new ArgumentException ("array", "Unsupported type");
  211. }
  212. }
  213. public BitArray Not ()
  214. {
  215. int ints = (m_length + 31) / 32;
  216. for (int i = 0; i < ints; i++)
  217. m_array [i] = ~m_array [i];
  218. _version++;
  219. return this;
  220. }
  221. public BitArray And (BitArray value)
  222. {
  223. checkOperand (value);
  224. int ints = (m_length + 31) / 32;
  225. for (int i = 0; i < ints; i++)
  226. m_array [i] &= value.m_array [i];
  227. _version++;
  228. return this;
  229. }
  230. public BitArray Or (BitArray value)
  231. {
  232. checkOperand (value);
  233. int ints = (m_length + 31) / 32;
  234. for (int i = 0; i < ints; i++)
  235. m_array [i] |= value.m_array [i];
  236. _version++;
  237. return this;
  238. }
  239. public BitArray Xor (BitArray value)
  240. {
  241. checkOperand (value);
  242. int ints = (m_length + 31) / 32;
  243. for (int i = 0; i < ints; i++)
  244. m_array [i] ^= value.m_array [i];
  245. _version++;
  246. return this;
  247. }
  248. public bool Get (int index)
  249. {
  250. if (index < 0 || index >= m_length)
  251. throw new ArgumentOutOfRangeException ();
  252. return (m_array [index >> 5] & (1 << (index & 31))) != 0;
  253. }
  254. public void Set (int index, bool value)
  255. {
  256. if (index < 0 || index >= m_length)
  257. throw new ArgumentOutOfRangeException ();
  258. if (value)
  259. m_array [index >> 5] |= (1 << (index & 31));
  260. else
  261. m_array [index >> 5] &= ~(1 << (index & 31));
  262. _version++;
  263. }
  264. public void SetAll (bool value)
  265. {
  266. if (value) {
  267. for (int i = 0; i < m_array.Length; i++)
  268. m_array[i] = ~0;
  269. }
  270. else
  271. Array.Clear (m_array, 0, m_array.Length);
  272. _version++;
  273. }
  274. public IEnumerator GetEnumerator ()
  275. {
  276. return new BitArrayEnumerator (this);
  277. }
  278. [Serializable]
  279. class BitArrayEnumerator : IEnumerator, ICloneable {
  280. BitArray _bitArray;
  281. bool _current;
  282. int _index, _max, _version;
  283. public object Clone () {
  284. return MemberwiseClone ();
  285. }
  286. public BitArrayEnumerator (BitArray ba)
  287. {
  288. _index = -1;
  289. _bitArray = ba;
  290. _max = ba.m_length;
  291. _version = ba._version;
  292. }
  293. public object Current {
  294. get {
  295. if (_index == -1)
  296. throw new InvalidOperationException ("Enum not started");
  297. if (_index >= _bitArray.Count)
  298. throw new InvalidOperationException ("Enum Ended");
  299. return _current;
  300. }
  301. }
  302. public bool MoveNext ()
  303. {
  304. checkVersion ();
  305. if (_index < (_bitArray.Count - 1)) {
  306. _current = _bitArray [++_index];
  307. return true;
  308. }
  309. else
  310. _index = _bitArray.Count;
  311. return false;
  312. }
  313. public void Reset ()
  314. {
  315. checkVersion ();
  316. _index = -1;
  317. }
  318. void checkVersion ()
  319. {
  320. if (_version != _bitArray._version)
  321. throw new InvalidOperationException ();
  322. }
  323. }
  324. }
  325. }