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 int bitsToInts(int bits)
21 private int bitsToBytes(int bits)
31 private void setBit(int bitIndex, bool value)
33 int index = bitIndex/32;
34 int shift = bitIndex%32;
36 Int32 theBit = 1 << shift;
39 m_array[index] |= theBit;
41 m_array[index] &= ~theBit;
46 private bool getBit(int bitIndex)
48 int index = bitIndex/32;
49 int shift = bitIndex%32;
51 Int32 theBit = m_array[index] & (1 << shift);
53 return (theBit == 0) ? false : true;
56 private byte getByte(int byteIndex)
58 int index = byteIndex/4;
59 int shift = (byteIndex%4)*8;
61 Int32 theByte = m_array[index] & (0xff << shift);
63 return (byte)((theByte >> shift)&0xff);
66 private void setByte(int byteIndex, byte value)
68 int index = byteIndex/4;
69 int shift = (byteIndex%4)*8;
71 Int32 orig = m_array[index];
74 orig &= ~(0xff << shift);
76 orig |= value << shift;
78 m_array[index] = orig;
83 /* --- Constructors --- */
84 public BitArray(BitArray orig)
86 m_length = orig.m_length;
88 int numInts = bitsToInts(m_length);
89 m_array = new Int32[numInts];
90 Array.Copy(orig.m_array, m_array, numInts);
93 public BitArray(bool[] bits)
95 m_length = bits.Length;
97 int numInts = bitsToInts(m_length);
98 m_array = new Int32[numInts];
99 for (int i=0; i < bits.Length; i++)
103 public BitArray(byte[] bytes)
105 m_length = bytes.Length * 8;
107 m_array = new Int32[bytes.Length/4];
108 for (int i=0; i < bytes.Length; i++)
109 setByte(i, bytes[i]);
112 public BitArray(int capacity)
115 m_array = new Int32[bitsToInts(m_length)];
118 public BitArray(int[] words)
120 int arrlen = words.Length;
121 m_length = arrlen*32;
122 m_array = new Int32[arrlen];
123 Array.Copy(words, m_array, arrlen);
126 public BitArray(int capacity, bool value) : this(capacity)
130 // FIXME: Maybe you can create an array pre filled?
131 for (int i = 0; i < m_array.Length; i++)
136 private BitArray(Int32 [] array, int length)
143 /* --- Public properties --- */
144 public virtual int Count
152 public virtual bool IsReadOnly
160 public virtual bool IsSynchronized
168 public virtual bool this[int index]
181 public virtual int Length
190 throw new ArgumentOutOfRangeException();
193 if (m_length != newLen)
195 int numints = bitsToInts(newLen);
196 Int32 [] newArr = new Int32[numints];
197 Array.Copy(m_array, newArr, numints);
199 // clear out the junk bits at the end:
200 int numjunkbits = 32 - (newLen%32);
201 UInt32 mask = (~0U >> numjunkbits);
202 newArr[numints - 1] &= (int)mask;
204 // set the internal state
212 public virtual object SyncRoot
220 /* --- Public methods --- */
221 public BitArray And(BitArray operand)
224 throw new ArgumentNullException();
225 if (operand.m_length != m_length)
226 throw new ArgumentException();
228 Int32 [] newarr = new Int32[m_array.Length];
229 for (int i=0; i < m_array.Length; i++)
230 newarr[i] = m_array[i] & operand.m_array[i];
232 return new BitArray(newarr, m_length);
235 public object Clone()
237 // FIXME: according to the doc, this should be a shallow copy.
238 // But the MS implementation seems to do a deep copy.
239 return new BitArray((Int32 [])m_array.Clone(), m_length);
242 public void CopyTo(Array array, int index)
245 throw new ArgumentNullException();
247 throw new ArgumentOutOfRangeException();
249 // FIXME: Throw ArgumentException if array is multidimensional
250 if (index >= array.Length)
251 throw new ArgumentException();
253 // in each case, check to make sure enough space in array
257 if (index + m_length >= array.Length)
258 throw new ArgumentException();
260 bool [] barray = (bool []) array;
262 // Copy the bits into the array
263 for (int i = 0; i < m_length; i++)
264 barray[index + i] = getBit(i);
266 else if (array is byte[])
268 int numbytes = bitsToBytes(m_length);
269 if (index + numbytes >= array.Length)
270 throw new ArgumentException();
272 byte [] barray = (byte []) array;
273 // Copy the bytes into the array
274 for (int i = 0; i < numbytes; i++)
275 barray[index + i] = getByte(i);
277 else if (array is int[])
279 int numints = bitsToInts(m_length);
280 if (index + numints >= array.Length)
281 throw new ArgumentException();
283 Array.Copy(m_array, array, numints);
287 throw new InvalidCastException();
293 * All this code for nothing... Apparently, The MS BitArray doesn't
295 *public override bool Equals(object obj)
297 // If it's not a BitArray, then it can't be equal to us.
298 if (!(obj is BitArray))
301 // If the references are equal, then clearly the instances are equal
305 // If its length is different, than it can't be equal.
306 BitArray b = (BitArray) obj;
307 if (m_length != b.m_length)
311 // Now compare the bits.
312 // This is a little tricky, because if length doesn't divide 32,
313 // then we shouldn't compare the unused bits in the last element
316 // Compare all full ints. If any differ, then we are not equal.
317 int numints = m_length/32;
318 for (int i = 0; i < numints; i++)
320 if (b.m_array[i] != m_array[i])
324 // Compare the left over bits (if any)
325 int extrabits = m_length%32;
328 // our mask is the "extrabits" least significant bits set to 1.
329 UInt32 comparemask = ~0U >> (32 - extrabits);
331 // numints is rounded down, so it's safe to use as an index here,
332 // as long as extrabits > 0.
333 if ((b.m_array[numints] & comparemask)
334 != (m_array[numints] & comparemask))
338 // We passed through all the above, so we are equal.
342 * End comment out of Equals()
345 public bool Get(int index)
347 if (index < 0 || index >= m_length)
348 throw new ArgumentOutOfRangeException();
349 return getBit(index);
352 public IEnumerator GetEnumerator()
355 return new BitArrayEnumerator(this);
359 * Since MS doesn't appear to override Equals/GetHashCode, we don't.
360 *public override int GetHashCode()
362 // We could make this a constant time function
363 // by just picking a constant number of bits, spread out
364 // evenly across the entire array. For now, this will suffice.
366 int retval = m_length;
368 // Add in each array element, except for the leftover bits.
369 int numints = m_length/32;
370 for (int i = 0; i < numints; i++)
371 retval += (int)m_array[i];
373 // That's enough. Adding in the leftover bits is tiring.
377 * End comment out of GetHashCode()
380 public BitArray Not()
382 Int32 [] newarr = new Int32[m_array.Length];
383 for (int i=0; i < m_array.Length; i++)
384 newarr[i] = ~m_array[i];
386 return new BitArray(newarr, m_length);
389 public BitArray Or(BitArray operand)
392 throw new ArgumentNullException();
393 if (operand.m_length != m_length)
394 throw new ArgumentException();
396 Int32 [] newarr = new Int32[m_array.Length];
397 for (int i=0; i < m_array.Length; i++)
398 newarr[i] = m_array[i] | operand.m_array[i];
400 return new BitArray(newarr, m_length);
403 public void Set(int index, bool value)
405 if (index < 0 || index >= m_length)
406 throw new ArgumentOutOfRangeException();
407 setBit(index, value);
410 public void SetAll(bool value)
414 for (int i = 0; i < m_array.Length; i++)
418 Array.Clear(m_array, 0, m_array.Length);
422 public BitArray Xor(BitArray operand)
425 throw new ArgumentNullException();
426 if (operand.m_length != m_length)
427 throw new ArgumentException();
429 Int32 [] newarr = new Int32[m_array.Length];
430 for (int i=0; i < m_array.Length; i++)
431 newarr[i] = m_array[i] ^ operand.m_array[i];
433 return new BitArray(newarr, m_length);
440 class BitArrayEnumerator : IEnumerator
443 private bool m_current;
446 private int m_modCount;
448 public BitArrayEnumerator(BitArray ba)
453 m_modCount = ba.m_modCount;
456 public object Current
460 if (m_index < 0 || m_index >= m_max)
461 throw new InvalidOperationException();
466 public bool MoveNext()
468 if (m_modCount != m_bitArray.m_modCount)
469 throw new InvalidOperationException();
471 if (m_index + 1 >= m_max)
475 m_current = m_bitArray[m_index];
481 if (m_modCount != m_bitArray.m_modCount)
482 throw new InvalidOperationException();