3 namespace System.Collections
5 // do we really need to specify IEnumerable since ICollection extends it?
7 public class BitArray : ICollection, IEnumerable, ICloneable
9 private Int32[] m_array;
11 private int m_modCount = 0;
13 private static void clearJunk(Int32[] arr, int numbits)
15 int numjunkbits = 32 - (numbits%32);
16 UInt32 mask = (~0U >> numjunkbits);
17 arr[arr.Length - 1] &= (int)mask;
20 private static int bitsToInts(int bits)
29 private static int bitsToBytes(int bits)
39 private void setBit(int bitIndex, bool value)
41 int index = bitIndex/32;
42 int shift = bitIndex%32;
44 Int32 theBit = 1 << shift;
47 m_array[index] |= theBit;
49 m_array[index] &= ~theBit;
54 private bool getBit(int bitIndex)
56 int index = bitIndex/32;
57 int shift = bitIndex%32;
59 Int32 theBit = m_array[index] & (1 << shift);
61 return (theBit == 0) ? false : true;
64 private byte getByte(int byteIndex)
66 int index = byteIndex/4;
67 int shift = (byteIndex%4)*8;
69 Int32 theByte = m_array[index] & (0xff << shift);
71 return (byte)((theByte >> shift)&0xff);
74 private void setByte(int byteIndex, byte value)
76 int index = byteIndex/4;
77 int shift = (byteIndex%4)*8;
79 Int32 orig = m_array[index];
82 orig &= ~(0xff << shift);
84 orig |= value << shift;
86 m_array[index] = orig;
91 /* --- Constructors --- */
92 public BitArray(BitArray orig)
94 m_length = orig.m_length;
96 int numInts = bitsToInts(m_length);
97 m_array = new Int32[numInts];
98 Array.Copy(orig.m_array, m_array, numInts);
101 public BitArray(bool[] bits)
103 m_length = bits.Length;
105 int numInts = bitsToInts(m_length);
106 m_array = new Int32[numInts];
107 for (int i=0; i < bits.Length; i++)
111 public BitArray(byte[] bytes)
113 m_length = bytes.Length * 8;
115 m_array = new Int32[bitsToInts(m_length)];
116 for (int i=0; i < bytes.Length; i++)
117 setByte(i, bytes[i]);
120 public BitArray(int capacity)
123 m_array = new Int32[bitsToInts(m_length)];
126 public BitArray(int[] words)
128 int arrlen = words.Length;
129 m_length = arrlen*32;
130 m_array = new Int32[arrlen];
131 Array.Copy(words, m_array, arrlen);
134 public BitArray(int capacity, bool value) : this(capacity)
138 // FIXME: Maybe you can create an array pre filled?
139 for (int i = 0; i < m_array.Length; i++)
144 private BitArray(Int32 [] array, int length)
151 /* --- Public properties --- */
152 public virtual int Count
160 public virtual bool IsReadOnly
168 public virtual bool IsSynchronized
176 public virtual bool this[int index]
189 public virtual int Length
198 throw new ArgumentOutOfRangeException();
201 if (m_length != newLen)
203 int numints = bitsToInts(newLen);
204 Int32 [] newArr = new Int32[numints];
205 int copylen = (numints > m_array.Length ? m_array.Length : numints);
206 Array.Copy(m_array, newArr, copylen);
208 // clear out the junk bits at the end:
209 clearJunk(newArr, newLen);
211 // set the internal state
219 public virtual object SyncRoot
227 /* --- Public methods --- */
228 public BitArray And(BitArray operand)
231 throw new ArgumentNullException();
232 if (operand.m_length != m_length)
233 throw new ArgumentException();
235 Int32 [] newarr = new Int32[m_array.Length];
236 for (int i=0; i < m_array.Length; i++)
237 newarr[i] = m_array[i] & operand.m_array[i];
239 return new BitArray(newarr, m_length);
242 public object Clone()
244 // FIXME: according to the doc, this should be a shallow copy.
245 // But the MS implementation seems to do a deep copy.
246 return new BitArray((Int32 [])m_array.Clone(), m_length);
250 public void CopyTo(Array array, int index)
253 throw new ArgumentNullException();
255 throw new ArgumentOutOfRangeException();
257 // FIXME: Throw ArgumentException if array is multidimensional
258 if (index >= array.Length)
259 throw new ArgumentException();
261 // in each case, check to make sure enough space in array
265 if (index + m_length >= array.Length)
266 throw new ArgumentException();
268 bool [] barray = (bool []) array;
270 // Copy the bits into the array
271 for (int i = 0; i < m_length; i++)
272 barray[index + i] = getBit(i);
274 else if (array is byte[])
276 int numbytes = bitsToBytes(m_length);
277 if (index + numbytes >= array.Length)
278 throw new ArgumentException();
280 byte [] barray = (byte []) array;
281 // Copy the bytes into the array
282 for (int i = 0; i < numbytes; i++)
283 barray[index + i] = getByte(i);
285 else if (array is int[])
287 int numints = bitsToInts(m_length);
288 if (index + numints >= array.Length)
289 throw new ArgumentException();
290 Array.Copy(m_array, 0, array, index, numints);
294 throw new InvalidCastException();
300 * All this code for nothing... Apparently, The MS BitArray doesn't
302 *public override bool Equals(object obj)
304 // If it's not a BitArray, then it can't be equal to us.
305 if (!(obj is BitArray))
308 // If the references are equal, then clearly the instances are equal
312 // If its length is different, than it can't be equal.
313 BitArray b = (BitArray) obj;
314 if (m_length != b.m_length)
318 // Now compare the bits.
319 // This is a little tricky, because if length doesn't divide 32,
320 // then we shouldn't compare the unused bits in the last element
323 // Compare all full ints. If any differ, then we are not equal.
324 int numints = m_length/32;
325 for (int i = 0; i < numints; i++)
327 if (b.m_array[i] != m_array[i])
331 // Compare the left over bits (if any)
332 int extrabits = m_length%32;
335 // our mask is the "extrabits" least significant bits set to 1.
336 UInt32 comparemask = ~0U >> (32 - extrabits);
338 // numints is rounded down, so it's safe to use as an index here,
339 // as long as extrabits > 0.
340 if ((b.m_array[numints] & comparemask)
341 != (m_array[numints] & comparemask))
345 // We passed through all the above, so we are equal.
349 * End comment out of Equals()
352 public bool Get(int index)
354 if (index < 0 || index >= m_length)
355 throw new ArgumentOutOfRangeException();
356 return getBit(index);
359 public IEnumerator GetEnumerator()
361 return new BitArrayEnumerator(this);
365 * Since MS doesn't appear to override Equals/GetHashCode, we don't.
366 *public override int GetHashCode()
368 // We could make this a constant time function
369 // by just picking a constant number of bits, spread out
370 // evenly across the entire array. For now, this will suffice.
372 int retval = m_length;
374 // Add in each array element, except for the leftover bits.
375 int numints = m_length/32;
376 for (int i = 0; i < numints; i++)
377 retval += (int)m_array[i];
379 // That's enough. Adding in the leftover bits is tiring.
383 * End comment out of GetHashCode()
386 public BitArray Not()
388 Int32 [] newarr = new Int32[m_array.Length];
389 for (int i=0; i < m_array.Length; i++)
390 newarr[i] = ~m_array[i];
392 return new BitArray(newarr, m_length);
395 public BitArray Or(BitArray operand)
398 throw new ArgumentNullException();
399 if (operand.m_length != m_length)
400 throw new ArgumentException();
402 Int32 [] newarr = new Int32[m_array.Length];
403 for (int i=0; i < m_array.Length; i++)
404 newarr[i] = m_array[i] | operand.m_array[i];
406 return new BitArray(newarr, m_length);
409 public void Set(int index, bool value)
411 if (index < 0 || index >= m_length)
412 throw new ArgumentOutOfRangeException();
413 setBit(index, value);
416 public void SetAll(bool value)
420 for (int i = 0; i < m_array.Length; i++)
423 // clear out the junk bits that we might have set
424 clearJunk(m_array, m_length);
427 Array.Clear(m_array, 0, m_array.Length);
433 public BitArray Xor(BitArray operand)
436 throw new ArgumentNullException();
437 if (operand.m_length != m_length)
438 throw new ArgumentException();
440 Int32 [] newarr = new Int32[m_array.Length];
441 for (int i=0; i < m_array.Length; i++)
442 newarr[i] = m_array[i] ^ operand.m_array[i];
444 return new BitArray(newarr, m_length);
451 class BitArrayEnumerator : IEnumerator
454 private bool m_current;
457 private int m_modCount;
459 public BitArrayEnumerator(BitArray ba)
464 m_modCount = ba.m_modCount;
467 public object Current
471 if (m_index < 0 || m_index >= m_max)
472 throw new InvalidOperationException();
477 public bool MoveNext()
479 if (m_modCount != m_bitArray.m_modCount)
480 throw new InvalidOperationException();
482 if (m_index + 1 >= m_max)
486 m_current = m_bitArray[m_index];
492 if (m_modCount != m_bitArray.m_modCount)
493 throw new InvalidOperationException();