3 namespace System.Collections
5 // do we really need to specify IEnumerable since ICollection extends it?
6 public class BitArray : ICollection, IEnumerable, ICloneable
8 private Int32[] m_array;
10 private int m_modCount = 0;
12 private static void clearJunk(Int32[] arr, int numbits)
14 int numjunkbits = 32 - (numbits%32);
15 UInt32 mask = (~0U >> numjunkbits);
16 arr[arr.Length - 1] &= (int)mask;
19 private static int bitsToInts(int bits)
28 private static int bitsToBytes(int bits)
38 private void setBit(int bitIndex, bool value)
40 int index = bitIndex/32;
41 int shift = bitIndex%32;
43 Int32 theBit = 1 << shift;
46 m_array[index] |= theBit;
48 m_array[index] &= ~theBit;
53 private bool getBit(int bitIndex)
55 int index = bitIndex/32;
56 int shift = bitIndex%32;
58 Int32 theBit = m_array[index] & (1 << shift);
60 return (theBit == 0) ? false : true;
63 private byte getByte(int byteIndex)
65 int index = byteIndex/4;
66 int shift = (byteIndex%4)*8;
68 Int32 theByte = m_array[index] & (0xff << shift);
70 return (byte)((theByte >> shift)&0xff);
73 private void setByte(int byteIndex, byte value)
75 int index = byteIndex/4;
76 int shift = (byteIndex%4)*8;
78 Int32 orig = m_array[index];
81 orig &= ~(0xff << shift);
83 orig |= value << shift;
85 m_array[index] = orig;
90 /* --- Constructors --- */
91 public BitArray(BitArray orig)
93 m_length = orig.m_length;
95 int numInts = bitsToInts(m_length);
96 m_array = new Int32[numInts];
97 Array.Copy(orig.m_array, m_array, numInts);
100 public BitArray(bool[] bits)
102 m_length = bits.Length;
104 int numInts = bitsToInts(m_length);
105 m_array = new Int32[numInts];
106 for (int i=0; i < bits.Length; i++)
110 public BitArray(byte[] bytes)
112 m_length = bytes.Length * 8;
114 m_array = new Int32[bitsToInts(m_length)];
115 for (int i=0; i < bytes.Length; i++)
116 setByte(i, bytes[i]);
119 public BitArray(int capacity)
122 m_array = new Int32[bitsToInts(m_length)];
125 public BitArray(int[] words)
127 int arrlen = words.Length;
128 m_length = arrlen*32;
129 m_array = new Int32[arrlen];
130 Array.Copy(words, m_array, arrlen);
133 public BitArray(int capacity, bool value) : this(capacity)
137 // FIXME: Maybe you can create an array pre filled?
138 for (int i = 0; i < m_array.Length; i++)
143 private BitArray(Int32 [] array, int length)
150 /* --- Public properties --- */
151 public virtual int Count
159 public virtual bool IsReadOnly
167 public virtual bool IsSynchronized
175 public virtual bool this[int index]
188 public virtual int Length
197 throw new ArgumentOutOfRangeException();
200 if (m_length != newLen)
202 int numints = bitsToInts(newLen);
203 Int32 [] newArr = new Int32[numints];
204 int copylen = (numints > m_array.Length ? m_array.Length : numints);
205 Array.Copy(m_array, newArr, copylen);
207 // clear out the junk bits at the end:
208 clearJunk(newArr, newLen);
210 // set the internal state
218 public virtual object SyncRoot
226 /* --- Public methods --- */
227 public BitArray And(BitArray operand)
230 throw new ArgumentNullException();
231 if (operand.m_length != m_length)
232 throw new ArgumentException();
234 Int32 [] newarr = new Int32[m_array.Length];
235 for (int i=0; i < m_array.Length; i++)
236 newarr[i] = m_array[i] & operand.m_array[i];
238 return new BitArray(newarr, m_length);
241 public object Clone()
243 // FIXME: according to the doc, this should be a shallow copy.
244 // But the MS implementation seems to do a deep copy.
245 return new BitArray((Int32 [])m_array.Clone(), m_length);
249 public void CopyTo(Array array, int index)
252 throw new ArgumentNullException();
254 throw new ArgumentOutOfRangeException();
256 // FIXME: Throw ArgumentException if array is multidimensional
257 if (index >= array.Length)
258 throw new ArgumentException();
260 // in each case, check to make sure enough space in array
264 if (index + m_length >= array.Length)
265 throw new ArgumentException();
267 bool [] barray = (bool []) array;
269 // Copy the bits into the array
270 for (int i = 0; i < m_length; i++)
271 barray[index + i] = getBit(i);
273 else if (array is byte[])
275 int numbytes = bitsToBytes(m_length);
276 if (index + numbytes >= array.Length)
277 throw new ArgumentException();
279 byte [] barray = (byte []) array;
280 // Copy the bytes into the array
281 for (int i = 0; i < numbytes; i++)
282 barray[index + i] = getByte(i);
284 else if (array is int[])
286 int numints = bitsToInts(m_length);
287 if (index + numints >= array.Length)
288 throw new ArgumentException();
289 Array.Copy(m_array, 0, array, index, numints);
293 throw new InvalidCastException();
299 * All this code for nothing... Apparently, The MS BitArray doesn't
301 *public override bool Equals(object obj)
303 // If it's not a BitArray, then it can't be equal to us.
304 if (!(obj is BitArray))
307 // If the references are equal, then clearly the instances are equal
311 // If its length is different, than it can't be equal.
312 BitArray b = (BitArray) obj;
313 if (m_length != b.m_length)
317 // Now compare the bits.
318 // This is a little tricky, because if length doesn't divide 32,
319 // then we shouldn't compare the unused bits in the last element
322 // Compare all full ints. If any differ, then we are not equal.
323 int numints = m_length/32;
324 for (int i = 0; i < numints; i++)
326 if (b.m_array[i] != m_array[i])
330 // Compare the left over bits (if any)
331 int extrabits = m_length%32;
334 // our mask is the "extrabits" least significant bits set to 1.
335 UInt32 comparemask = ~0U >> (32 - extrabits);
337 // numints is rounded down, so it's safe to use as an index here,
338 // as long as extrabits > 0.
339 if ((b.m_array[numints] & comparemask)
340 != (m_array[numints] & comparemask))
344 // We passed through all the above, so we are equal.
348 * End comment out of Equals()
351 public bool Get(int index)
353 if (index < 0 || index >= m_length)
354 throw new ArgumentOutOfRangeException();
355 return getBit(index);
358 public IEnumerator GetEnumerator()
360 return new BitArrayEnumerator(this);
364 * Since MS doesn't appear to override Equals/GetHashCode, we don't.
365 *public override int GetHashCode()
367 // We could make this a constant time function
368 // by just picking a constant number of bits, spread out
369 // evenly across the entire array. For now, this will suffice.
371 int retval = m_length;
373 // Add in each array element, except for the leftover bits.
374 int numints = m_length/32;
375 for (int i = 0; i < numints; i++)
376 retval += (int)m_array[i];
378 // That's enough. Adding in the leftover bits is tiring.
382 * End comment out of GetHashCode()
385 public BitArray Not()
387 Int32 [] newarr = new Int32[m_array.Length];
388 for (int i=0; i < m_array.Length; i++)
389 newarr[i] = ~m_array[i];
391 return new BitArray(newarr, m_length);
394 public BitArray Or(BitArray operand)
397 throw new ArgumentNullException();
398 if (operand.m_length != m_length)
399 throw new ArgumentException();
401 Int32 [] newarr = new Int32[m_array.Length];
402 for (int i=0; i < m_array.Length; i++)
403 newarr[i] = m_array[i] | operand.m_array[i];
405 return new BitArray(newarr, m_length);
408 public void Set(int index, bool value)
410 if (index < 0 || index >= m_length)
411 throw new ArgumentOutOfRangeException();
412 setBit(index, value);
415 public void SetAll(bool value)
419 for (int i = 0; i < m_array.Length; i++)
422 // clear out the junk bits that we might have set
423 clearJunk(m_array, m_length);
426 Array.Clear(m_array, 0, m_array.Length);
432 public BitArray Xor(BitArray operand)
435 throw new ArgumentNullException();
436 if (operand.m_length != m_length)
437 throw new ArgumentException();
439 Int32 [] newarr = new Int32[m_array.Length];
440 for (int i=0; i < m_array.Length; i++)
441 newarr[i] = m_array[i] ^ operand.m_array[i];
443 return new BitArray(newarr, m_length);
450 class BitArrayEnumerator : IEnumerator
453 private bool m_current;
456 private int m_modCount;
458 public BitArrayEnumerator(BitArray ba)
463 m_modCount = ba.m_modCount;
466 public object Current
470 if (m_index < 0 || m_index >= m_max)
471 throw new InvalidOperationException();
476 public bool MoveNext()
478 if (m_modCount != m_bitArray.m_modCount)
479 throw new InvalidOperationException();
481 if (m_index + 1 >= m_max)
485 m_current = m_bitArray[m_index];
491 if (m_modCount != m_bitArray.m_modCount)
492 throw new InvalidOperationException();