BitArray.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. [ComVisible(true)]
  36. [Serializable]
  37. #if INSIDE_CORLIB
  38. public
  39. #else
  40. internal
  41. #endif
  42. sealed class BitArray : ICollection, ICloneable {
  43. int [] m_array;
  44. int m_length;
  45. int _version = 0;
  46. #region Constructors
  47. public BitArray (BitArray bits)
  48. {
  49. if (bits == null)
  50. throw new ArgumentNullException ("bits");
  51. m_length = bits.m_length;
  52. m_array = new int [(m_length + 31) / 32];
  53. if (m_array.Length == 1)
  54. m_array [0] = bits.m_array [0];
  55. else
  56. Array.Copy(bits.m_array, m_array, m_array.Length);
  57. }
  58. public BitArray (bool [] values)
  59. {
  60. if (values == null)
  61. throw new ArgumentNullException ("values");
  62. m_length = values.Length;
  63. m_array = new int [(m_length + 31) / 32];
  64. for (int i = 0; i < values.Length; i++)
  65. this [i] = values [i];
  66. }
  67. public BitArray (byte [] bytes)
  68. {
  69. if (bytes == null)
  70. throw new ArgumentNullException ("bytes");
  71. m_length = bytes.Length * 8;
  72. m_array = new int [(m_length + 31) / 32];
  73. for (int i = 0; i < bytes.Length; i++)
  74. setByte (i, bytes [i]);
  75. }
  76. public BitArray (int [] values)
  77. {
  78. if (values == null)
  79. throw new ArgumentNullException ("values");
  80. int arrlen = values.Length;
  81. m_length = arrlen*32;
  82. m_array = new int [arrlen];
  83. Array.Copy (values, m_array, arrlen);
  84. }
  85. public BitArray (int length)
  86. {
  87. if (length < 0)
  88. throw new ArgumentOutOfRangeException ("length");
  89. m_length = length;
  90. m_array = new int [(m_length + 31) / 32];
  91. }
  92. public BitArray (int length, bool defaultValue) : this (length)
  93. {
  94. if (defaultValue) {
  95. for (int i = 0; i < m_array.Length; i++)
  96. m_array[i] = ~0;
  97. }
  98. }
  99. #endregion
  100. #region Utility Methods
  101. byte getByte (int byteIndex)
  102. {
  103. int index = byteIndex / 4;
  104. int shift = (byteIndex % 4) * 8;
  105. int theByte = m_array [index] & (0xff << shift);
  106. return (byte)((theByte >> shift) & 0xff);
  107. }
  108. void setByte (int byteIndex, byte value)
  109. {
  110. int index = byteIndex / 4;
  111. int shift = (byteIndex % 4) * 8;
  112. // clear the byte
  113. m_array [index] &= ~(0xff << shift);
  114. // or in the new byte
  115. m_array [index] |= value << shift;
  116. _version++;
  117. }
  118. void checkOperand (BitArray operand)
  119. {
  120. if (operand == null)
  121. throw new ArgumentNullException ();
  122. if (operand.m_length != m_length)
  123. throw new ArgumentException ();
  124. }
  125. #endregion
  126. public int Count {
  127. get { return m_length; }
  128. }
  129. public bool IsReadOnly {
  130. get { return false; }
  131. }
  132. public bool IsSynchronized {
  133. get { return false; }
  134. }
  135. public bool this [int index] {
  136. get { return Get (index); }
  137. set { Set (index, value); }
  138. }
  139. public int Length {
  140. get { return m_length; }
  141. set {
  142. if (m_length == value)
  143. return;
  144. if (value < 0)
  145. throw new ArgumentOutOfRangeException ();
  146. // Currently we never shrink the array
  147. if (value > m_length) {
  148. int numints = (value + 31) / 32;
  149. int old_numints = (m_length + 31) / 32;
  150. if (numints > m_array.Length) {
  151. int [] newArr = new int [numints];
  152. Array.Copy (m_array, newArr, m_array.Length);
  153. m_array = newArr;
  154. } else {
  155. Array.Clear(m_array, old_numints, numints - old_numints);
  156. }
  157. int mask = m_length % 32;
  158. if (mask > 0)
  159. m_array [old_numints - 1] &= (1 << mask) - 1;
  160. }
  161. // set the internal state
  162. m_length = value;
  163. _version++;
  164. }
  165. }
  166. public object SyncRoot {
  167. get { return this; }
  168. }
  169. public object Clone ()
  170. {
  171. // LAMESPEC: docs say shallow, MS makes deep.
  172. return new BitArray (this);
  173. }
  174. public void CopyTo (Array array, int index)
  175. {
  176. if (array == null)
  177. throw new ArgumentNullException ("array");
  178. if (index < 0)
  179. throw new ArgumentOutOfRangeException ("index");
  180. if (array.Rank != 1)
  181. throw new ArgumentException ("array", "Array rank must be 1");
  182. if (index >= array.Length && m_length > 0)
  183. throw new ArgumentException ("index", "index is greater than array.Length");
  184. // in each case, check to make sure enough space in array
  185. if (array is bool []) {
  186. if (array.Length - index < m_length)
  187. throw new ArgumentException ();
  188. bool [] barray = (bool []) array;
  189. // Copy the bits into the array
  190. for (int i = 0; i < m_length; i++)
  191. barray[index + i] = this [i];
  192. } else if (array is byte []) {
  193. int numbytes = (m_length + 7) / 8;
  194. if ((array.Length - index) < numbytes)
  195. throw new ArgumentException ();
  196. byte [] barray = (byte []) array;
  197. // Copy the bytes into the array
  198. for (int i = 0; i < numbytes; i++)
  199. barray [index + i] = getByte (i);
  200. } else if (array is int []) {
  201. Array.Copy (m_array, 0, array, index, (m_length + 31) / 32);
  202. } else {
  203. throw new ArgumentException ("array", "Unsupported type");
  204. }
  205. }
  206. public BitArray Not ()
  207. {
  208. int ints = (m_length + 31) / 32;
  209. for (int i = 0; i < ints; i++)
  210. m_array [i] = ~m_array [i];
  211. _version++;
  212. return this;
  213. }
  214. public BitArray And (BitArray value)
  215. {
  216. checkOperand (value);
  217. int ints = (m_length + 31) / 32;
  218. for (int i = 0; i < ints; i++)
  219. m_array [i] &= value.m_array [i];
  220. _version++;
  221. return this;
  222. }
  223. public BitArray Or (BitArray value)
  224. {
  225. checkOperand (value);
  226. int ints = (m_length + 31) / 32;
  227. for (int i = 0; i < ints; i++)
  228. m_array [i] |= value.m_array [i];
  229. _version++;
  230. return this;
  231. }
  232. public BitArray Xor (BitArray value)
  233. {
  234. checkOperand (value);
  235. int ints = (m_length + 31) / 32;
  236. for (int i = 0; i < ints; i++)
  237. m_array [i] ^= value.m_array [i];
  238. _version++;
  239. return this;
  240. }
  241. public bool Get (int index)
  242. {
  243. if (index < 0 || index >= m_length)
  244. throw new ArgumentOutOfRangeException ();
  245. return (m_array [index >> 5] & (1 << (index & 31))) != 0;
  246. }
  247. public void Set (int index, bool value)
  248. {
  249. if (index < 0 || index >= m_length)
  250. throw new ArgumentOutOfRangeException ();
  251. if (value)
  252. m_array [index >> 5] |= (1 << (index & 31));
  253. else
  254. m_array [index >> 5] &= ~(1 << (index & 31));
  255. _version++;
  256. }
  257. public void SetAll (bool value)
  258. {
  259. if (value) {
  260. for (int i = 0; i < m_array.Length; i++)
  261. m_array[i] = ~0;
  262. }
  263. else
  264. Array.Clear (m_array, 0, m_array.Length);
  265. _version++;
  266. }
  267. public IEnumerator GetEnumerator ()
  268. {
  269. return new BitArrayEnumerator (this);
  270. }
  271. [Serializable]
  272. class BitArrayEnumerator : IEnumerator, ICloneable {
  273. BitArray _bitArray;
  274. bool _current;
  275. int _index, _version;
  276. public object Clone () {
  277. return MemberwiseClone ();
  278. }
  279. public BitArrayEnumerator (BitArray ba)
  280. {
  281. _index = -1;
  282. _bitArray = ba;
  283. _version = ba._version;
  284. }
  285. public object Current {
  286. get {
  287. if (_index == -1)
  288. throw new InvalidOperationException ("Enum not started");
  289. if (_index >= _bitArray.Count)
  290. throw new InvalidOperationException ("Enum Ended");
  291. return _current;
  292. }
  293. }
  294. public bool MoveNext ()
  295. {
  296. checkVersion ();
  297. if (_index < (_bitArray.Count - 1)) {
  298. _current = _bitArray [++_index];
  299. return true;
  300. }
  301. _index = _bitArray.Count;
  302. return false;
  303. }
  304. public void Reset ()
  305. {
  306. checkVersion ();
  307. _index = -1;
  308. }
  309. void checkVersion ()
  310. {
  311. if (_version != _bitArray._version)
  312. throw new InvalidOperationException ();
  313. }
  314. }
  315. }
  316. }