Browse Source

BitArray (first pass)

David Rose 20 years ago
parent
commit
ecec0779f0

+ 9 - 4
panda/src/putil/Sources.pp

@@ -11,8 +11,9 @@
     animInterface.h animInterface.I \
     bam.h bamEndian.h \
     bamReader.I bamReader.N bamReader.h bamReaderParam.I \
-    bamReaderParam.h bamWriter.I bamWriter.h bitMask.I \
-    bitMask.h \
+    bamReaderParam.h bamWriter.I bamWriter.h \
+    bitArray.I bitArray.h \
+    bitMask.I bitMask.h \
     buttonHandle.I \
     buttonHandle.h buttonRegistry.I buttonRegistry.h \
     cachedTypedWritableReferenceCount.h cachedTypedWritableReferenceCount.I \
@@ -62,7 +63,9 @@
  #define INCLUDED_SOURCES \
     animInterface.cxx \
     bamEndian.cxx \
-    bamReader.cxx bamReaderParam.cxx bamWriter.cxx bitMask.cxx \
+    bamReader.cxx bamReaderParam.cxx bamWriter.cxx \
+    bitArray.cxx \
+    bitMask.cxx \
     buttonHandle.cxx buttonRegistry.cxx \
     cachedTypedWritableReferenceCount.cxx \
     config_util.cxx configurable.cxx \
@@ -99,7 +102,9 @@
     animInterface.h animInterface.I \
     bam.h bamEndian.h \
     bamReader.I bamReader.h bamReaderParam.I bamReaderParam.h \
-    bamWriter.I bamWriter.h bitMask.I bitMask.h \
+    bamWriter.I bamWriter.h \
+    bitArray.I bitArray.h \
+    bitMask.I bitMask.h \
     buttonHandle.I buttonHandle.h buttonRegistry.I \
     buttonRegistry.h \
     cachedTypedWritableReferenceCount.h cachedTypedWritableReferenceCount.I \

+ 518 - 0
panda/src/putil/bitArray.I

@@ -0,0 +1,518 @@
+// Filename: bitArray.I
+// Created by:  drose (20Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray::
+BitArray() {
+  _highest_bits = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray::
+BitArray(WordType init_value) {
+  if (init_value != 0) {
+    _array.push_back(MaskType(init_value));
+  }
+  _highest_bits = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Copy Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray::
+BitArray(const BitArray &copy) :
+  _array(copy._array),
+  _highest_bits(copy._highest_bits)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Copy Assignment Operator
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void BitArray::
+operator = (const BitArray &copy) {
+  _array = copy._array;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Named all_on constructor
+//       Access: Published, Static
+//  Description: Returns a BitArray with an infinite array of bits,
+//               all on.
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+all_on() {
+  BitArray result;
+  result._highest_bits = 1;
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Named all_on constructor
+//       Access: Published, Static
+//  Description: Returns a BitArray whose bits are all off.
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+all_off() {
+  return BitArray();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Named lower_on constructor
+//       Access: Published, Static
+//  Description: Returns a BitArray whose lower on_bits bits are on.
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+lower_on(int on_bits) {
+  BitArray result;
+  result.set_range(0, on_bits);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Named bit constructor
+//       Access: Published, Static
+//  Description: Returns a BitArray with only the indicated bit on.
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+bit(int index) {
+  BitArray result;
+  result.set_bit(index);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Named range constructor
+//       Access: Published, Static
+//  Description: Returns a BitArray whose size bits, beginning at
+//               low_bit, are on.
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+range(int low_bit, int size) {
+  BitArray result;
+  result.set_range(low_bit, size);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray::
+~BitArray() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::has_max_num_bits
+//       Access: Published, Static
+//  Description: Returns true if there is a maximum number of bits
+//               that may be stored in this structure, false
+//               otherwise.  If this returns true, the number may be
+//               queried in get_max_num_bits().
+//
+//               This method always returns false.  The BitArray has
+//               no maximum number of bits.  This method is defined so
+//               generic programming algorithms can use BitMask or
+//               BitArray interchangeably.
+////////////////////////////////////////////////////////////////////
+INLINE bool BitArray::
+has_max_num_bits() {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_max_num_bits
+//       Access: Published, Static
+//  Description: If get_max_num_bits() returned true, this method may
+//               be called to return the maximum number of bits that
+//               may be stored in this structure.  It is an error to
+//               call this if get_max_num_bits() return false.
+//
+//               It is always an error to call this method.  The
+//               BitArray has no maximum number of bits.  This method
+//               is defined so generic programming algorithms can use
+//               BitMask or BitArray interchangeably.
+////////////////////////////////////////////////////////////////////
+INLINE int BitArray::
+get_max_num_bits() {
+  nassertr(false, 0);
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_num_bits_per_word
+//       Access: Published, Static
+//  Description: Returns the number of bits stored per word
+//               internally.  This is of interest only in that it
+//               limits the maximum number of bits that may be queried
+//               or set at once by extract() and store().
+////////////////////////////////////////////////////////////////////
+INLINE int BitArray::
+get_num_bits_per_word() {
+  return num_bits_per_word;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_num_bits
+//       Access: Published
+//  Description: Returns the current number of possibly different bits
+//               in this array.  There are actually an infinite number
+//               of bits, but every bit higher than this bit will have
+//               the same value, either 0 or 1 (see
+//               get_highest_bits()).
+//
+//               This number may grow and/or shrink automatically as
+//               needed.
+////////////////////////////////////////////////////////////////////
+INLINE int BitArray::
+get_num_bits() const {
+  return get_num_words() * num_bits_per_word;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_bit
+//       Access: Published
+//  Description: Returns true if the nth bit is set, false if it is
+//               cleared.  It is valid for n to increase beyond
+//               get_num_bits(), but the return value get_num_bits()
+//               will always be the same.
+////////////////////////////////////////////////////////////////////
+INLINE bool BitArray::
+get_bit(int index) const {
+  nassertr(index >= 0, false);
+  int w = index / num_bits_per_word;
+  int b = index % num_bits_per_word;
+  if (w >= get_num_words()) {
+    return get_highest_bits();
+  } else {
+    return (_array[w].get_bit(b));
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::set_bit
+//       Access: Published
+//  Description: Sets the nth bit on.  If n >= get_num_bits(), this
+//               automatically extends the array.
+////////////////////////////////////////////////////////////////////
+INLINE void BitArray::
+set_bit(int index) {
+  nassertv(index >= 0);
+  int w = index / num_bits_per_word;
+  int b = index % num_bits_per_word;
+  if (w >= get_num_words() && _highest_bits) {
+    // All the highest bits are already on.
+    return;
+  }
+  ensure_has_word(w);
+  _array[w].set_bit(b);
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::clear_bit
+//       Access: Published
+//  Description: Sets the nth bit off.  If n >= get_num_bits(), this
+//               automatically extends the array.
+////////////////////////////////////////////////////////////////////
+INLINE void BitArray::
+clear_bit(int index) {
+  nassertv(index >= 0);
+  int w = index / num_bits_per_word;
+  int b = index % num_bits_per_word;
+  if (w >= get_num_words() && !_highest_bits) {
+    // All the highest bits are already off.
+    return;
+  }
+  ensure_has_word(w);
+  _array[w].clear_bit(b);
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::set_bit_to
+//       Access: Published
+//  Description: Sets the nth bit either on or off, according to the
+//               indicated bool value.
+////////////////////////////////////////////////////////////////////
+INLINE void BitArray::
+set_bit_to(int index, bool value) {
+  if (value) {
+    set_bit(index);
+  } else {
+    clear_bit(index);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_highest_bits
+//       Access: Published
+//  Description: Returns true if the infinite set of bits beyond
+//               get_num_bits() are all on, or false of they are all
+//               off.
+////////////////////////////////////////////////////////////////////
+INLINE bool BitArray::
+get_highest_bits() const {
+  return (_highest_bits != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::extract
+//       Access: Published
+//  Description: Returns a word that represents only the indicated
+//               range of bits within this BitArray, shifted to the
+//               least-significant position.  size must be <=
+//               get_num_bits_per_word().
+////////////////////////////////////////////////////////////////////
+INLINE BitArray::WordType BitArray::
+extract(int low_bit, int size) const {
+  nassertr(size >= 0 && size <= num_bits_per_word, 0);
+  int w = low_bit / num_bits_per_word;
+  int b = low_bit % num_bits_per_word;
+
+  if (b + size < num_bits_per_word) {
+    // The whole thing fits within one word of the array.
+    return get_word(w).extract(b, size);
+
+  } else {
+    // We have to split it across two words.
+    int num_lower_bits = num_bits_per_word - b;
+    int num_higher_bits = size - num_lower_bits;
+
+    return get_word(w).extract(b, num_lower_bits) |
+      (get_word(w + 1).extract(0, num_higher_bits) << num_lower_bits);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::store
+//       Access: Published
+//  Description: Stores the indicated word into the indicated range of
+//               bits with this BitArray.
+////////////////////////////////////////////////////////////////////
+INLINE void BitArray::
+store(WordType value, int low_bit, int size) {
+  nassertv(size >= 0);
+  int w = low_bit / num_bits_per_word;
+  int b = low_bit % num_bits_per_word;
+
+  if (b + size < num_bits_per_word) {
+    // The whole thing fits within one word of the array.
+    ensure_has_word(w);
+    _array[w].store(value, b, size);
+
+  } else {
+    // We have to split it across two words.
+    int num_lower_bits = num_bits_per_word - b;
+    int num_higher_bits = size - num_lower_bits;
+
+    ensure_has_word(w + 1);
+    _array[w].store(value, b, num_lower_bits);
+    _array[w + 1].store(value >> num_lower_bits, 0, num_higher_bits);
+  }
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::set_range_to
+//       Access: Published
+//  Description: Sets the indicated range of bits to either on or off.
+////////////////////////////////////////////////////////////////////
+INLINE void BitArray::
+set_range_to(bool value, int low_bit, int size) {
+  if (value) {
+    set_range(low_bit, size);
+  } else {
+    clear_range(low_bit, size);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_num_words
+//       Access: Published
+//  Description: Returns the number of possibly-unique words stored in
+//               the array.
+////////////////////////////////////////////////////////////////////
+INLINE int BitArray::
+get_num_words() const {
+  return _array.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_word
+//       Access: Published
+//  Description: Returns the nth word in the array.  It is valid for n
+//               to be greater than get_num_words(), but the return
+//               value beyond get_num_words() will always be the same.
+////////////////////////////////////////////////////////////////////
+INLINE BitArray::MaskType BitArray::
+get_word(int n) const {
+  nassertr(n >= 0, MaskType::all_off());
+  if (n < get_num_words()) {
+    return _array[n];
+  }
+  if (_highest_bits) {
+    return MaskType::all_on();
+  } else {
+    return MaskType::all_off();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::set_word
+//       Access: Published
+//  Description: Replaces the nth word in the array.  If n >=
+//               get_num_words(), this automatically extends the
+//               array.
+////////////////////////////////////////////////////////////////////
+INLINE void BitArray::
+set_word(int n, MaskType value) {
+  nassertv(n >= 0);
+  ensure_has_word(n);
+  _array[n] = value;
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::clear
+//       Access: Published
+//  Description: Sets all the bits in the BitArray off.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+clear() {
+  _array.clear();
+  _highest_bits = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator ==
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool BitArray::
+operator == (const BitArray &other) const {
+  return compare_to(other) == 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator !=
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool BitArray::
+operator != (const BitArray &other) const {
+  return compare_to(other) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator <
+//       Access: Published
+//  Description: Returns true if the unsigned integer which is
+//               represented by this BitArray is less than that of the
+//               other one, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool BitArray::
+operator < (const BitArray &other) const {
+  return compare_to(other) < 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator &
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+operator & (const BitArray &other) const {
+  BitArray result(*this);
+  result &= other;
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator |
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+operator | (const BitArray &other) const {
+  BitArray result(*this);
+  result |= other;
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator ^
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+operator ^ (const BitArray &other) const {
+  BitArray result(*this);
+  result ^= other;
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator ~
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+operator ~ () const {
+  BitArray result(*this);
+  result.invert_in_place();
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator <<
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+operator << (int shift) const {
+  BitArray result(*this);
+  result <<= shift;
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator >>
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BitArray BitArray::
+operator >> (int shift) const {
+  BitArray result(*this);
+  result >>= shift;
+  return result;
+}

+ 626 - 0
panda/src/putil/bitArray.cxx

@@ -0,0 +1,626 @@
+// Filename: bitArray.cxx
+// Created by:  drose (20Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "bitArray.h"
+
+TypeHandle BitArray::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::is_zero
+//       Access: Published
+//  Description: Returns true if the entire bitmask is zero, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool BitArray::
+is_zero() const {
+  if (_highest_bits) {
+    // If all the infinite highest bits are set, certainly the bitmask
+    // is nonzero.
+    return false;
+  }
+
+  // Start from the high end, since that's more likely to be nonzero.
+  Array::const_reverse_iterator ai;
+  for (ai = _array.rbegin(); ai != _array.rend(); ++ai) {
+    if ((*ai) != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::set_range
+//       Access: Published
+//  Description: Sets the indicated range of bits on.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+set_range(int low_bit, int size) {
+  int w = low_bit / num_bits_per_word;
+  int b = low_bit % num_bits_per_word;
+
+  if (w >= get_num_words() && _highest_bits) {
+    // All the highest bits are already on.
+    return;
+  }
+  if (b + size <= num_bits_per_word) {
+    // The whole thing fits within one word of the array.
+    ensure_has_word(w);
+    _array[w].set_range(b, size);
+    normalize();
+    return;
+  }
+
+  while (size > 0) {
+    if (size <= num_bits_per_word) {
+      // The remainder fits within one word of the array.
+      ensure_has_word(w);
+      _array[w].set_range(0, size);
+      normalize();
+      return;
+    }
+
+    // Keep going.
+    ensure_has_word(w);
+    _array[w] = MaskType::all_on();
+    size -= num_bits_per_word;
+    ++w;
+
+    if (w >= get_num_words() && _highest_bits) {
+      // All the highest bits are already on.
+      normalize();
+      return;
+    }
+  }
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::clear_range
+//       Access: Published
+//  Description: Sets the indicated range of bits off.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+clear_range(int low_bit, int size) {
+  int w = low_bit / num_bits_per_word;
+  int b = low_bit % num_bits_per_word;
+
+  if (w >= get_num_words() && !_highest_bits) {
+    // All the highest bits are already off.
+    return;
+  }
+  if (b + size <= num_bits_per_word) {
+    // The whole thing fits within one word of the array.
+    ensure_has_word(w);
+    _array[w].clear_range(b, size);
+    normalize();
+    return;
+  }
+
+  while (size > 0) {
+    if (size <= num_bits_per_word) {
+      // The remainder fits within one word of the array.
+      ensure_has_word(w);
+      _array[w].clear_range(0, size);
+      normalize();
+      return;
+    }
+
+    // Keep going.
+    ensure_has_word(w);
+    _array[w] = MaskType::all_on();
+    size -= num_bits_per_word;
+    ++w;
+
+    if (w >= get_num_words() && !_highest_bits) {
+      // All the highest bits are already off.
+      normalize();
+      return;
+    }
+  }
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::invert_in_place
+//       Access: Published
+//  Description: Inverts all the bits in the BitArray.  This is
+//               equivalent to array = ~array.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+invert_in_place() {
+  _highest_bits = !_highest_bits;
+  Array::iterator ai;
+  for (ai = _array.begin(); ai != _array.end(); ++ai) {
+    (*ai) = ~(*ai);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::has_bits_in_common
+//       Access: Published
+//  Description: Returns true if this BitArray has any "one" bits in
+//               common with the other one, false otherwise.
+//
+//               This is equivalent to (array & other) != 0, but may
+//               be faster.
+////////////////////////////////////////////////////////////////////
+bool BitArray::
+has_bits_in_common(const BitArray &other) const {
+  if (_highest_bits && other._highest_bits) {
+    // Yup, in fact we have an infinite number of bits in common.
+    return true;
+  }
+
+  size_t num_common_words = min(_array.size(), other._array.size());
+
+  // Consider the words that are on top of either array.
+  if (other._array.size() < _array.size() && other._highest_bits) {
+    // The other array has fewer actual words, and the top n words of
+    // the other array are all ones.  We have bits in common if any of
+    // our top n words are nonzero.
+    Array::const_iterator ai;
+    for (ai = _array.begin() + other._array.size(); 
+         ai != _array.end(); 
+         ++ai) {
+      if (!(*ai).is_zero()) {
+	return true;
+      }
+    }
+    
+  } else if (_array.size() < other._array.size() && _highest_bits) {
+    // This array has fewer actual words, and the top n words of this
+    // array are all ones.  We have bits in common if any of the the
+    // other's top n words are nonzero.
+    Array::const_iterator ai;
+    for (ai = other._array.begin() + _array.size(); 
+         ai != other._array.end(); 
+         ++ai) {
+      if (!(*ai).is_zero()) {
+	return true;
+      }
+    }
+  }
+
+  // Consider the words that both arrays have in common.
+  for (size_t i = 0; i < num_common_words; ++i) {
+    if (!(_array[i] & other._array[i]).is_zero()) {
+      return true;
+    }
+  }
+
+  // Nope, nothing.
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::output
+//       Access: Published
+//  Description: Writes the BitArray out as a binary or a hex number,
+//               according to the number of bits.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+output(ostream &out) const {
+  if (get_num_bits() >= 40) {
+    output_hex(out);
+  } else {
+    output_binary(out);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::output_binary
+//       Access: Published
+//  Description: Writes the BitArray out as a binary number, with
+//               spaces every four bits.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+output_binary(ostream &out, int spaces_every) const {
+  if (_highest_bits) {
+    out << "...1 ";
+  }
+  int num_bits = max(get_num_bits(), spaces_every);
+  for (int i = num_bits - 1; i >= 0; i--) {
+    if (spaces_every != 0 && ((i % spaces_every) == spaces_every - 1)) {
+      out << ' ';
+    }
+    out << (get_bit(i) ? '1' : '0');
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::output_hex
+//       Access: Published
+//  Description: Writes the BitArray out as a hexadecimal number, with
+//               spaces every four digits.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+output_hex(ostream &out, int spaces_every) const {
+  int num_bits = get_num_bits();
+  int num_digits = max((num_bits + 3) / 4, spaces_every);
+
+  if (_highest_bits) {
+    out << "...f ";
+  }
+
+  for (int i = num_digits - 1; i >= 0; i--) {
+    WordType digit = extract(i * 4, 4);
+    if (spaces_every != 0 && ((i % spaces_every) == spaces_every - 1)) {
+      out << ' ';
+    }
+    if (digit > 9) {
+      out << (char)(digit - 10 + 'a');
+    } else {
+      out << (char)(digit + '0');
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::write
+//       Access: Published
+//  Description: Writes the BitArray out as a binary or a hex number,
+//               according to the number of bits.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level) << *this << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::compare_to
+//       Access: Published
+//  Description: Returns a number less than zero if this BitArray sorts
+//               before the indicated other BitArray, greater than zero
+//               if it sorts after, or 0 if they are equivalent.  This
+//               is based on the same ordering defined by operator <.
+////////////////////////////////////////////////////////////////////
+int BitArray::
+compare_to(const BitArray &other) const {
+  if (_highest_bits != other._highest_bits) {
+    return _highest_bits ? 1 : -1;
+  }
+
+  int num_words = max(get_num_words(), other.get_num_words());
+
+  // Compare from highest-order to lowest-order word.
+  for (int i = num_words - 1; i >= 0; --i) {
+    int compare = get_word(i).compare_to(other.get_word(i));
+    if (compare != 0) {
+      return compare;
+    }
+  }
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator &=
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+void BitArray::
+operator &= (const BitArray &other) {
+  size_t num_common_words = min(_array.size(), other._array.size());
+
+  // Consider the words that are on top of either array.
+  if (other._array.size() < _array.size() && !other._highest_bits) {
+    // The other array has fewer actual words, and the top n words of
+    // the other array are all zeroes.  "mask off" the top n words of
+    // this array.
+    _array.erase(_array.begin() + other._array.size(), _array.end());
+
+  } else if (_array.size() < other._array.size() && _highest_bits) {
+    // This array has fewer actual words, and the top n words of this
+    // array are all ones.  "mask on" the top n words of the other
+    // array.
+    Array::const_iterator ai;
+    for (ai = other._array.begin() + _array.size(); 
+         ai != other._array.end(); 
+         ++ai) {
+      _array.push_back(*ai);
+    }
+  }
+
+  // Consider the words that both arrays have in common.
+  for (size_t i = 0; i < num_common_words; ++i) {
+    _array[i] &= other._array[i];
+  }
+
+  _highest_bits &= other._highest_bits;
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator |=
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+void BitArray::
+operator |= (const BitArray &other) {
+  size_t num_common_words = min(_array.size(), other._array.size());
+
+  // Consider the words that are on top of either array.
+  if (other._array.size() < _array.size() && other._highest_bits) {
+    // The other array has fewer actual words, and the top n words of
+    // the other array are all ones.  The top n words of this array
+    // become ones too (which means we can drop them out).
+    _array.erase(_array.begin() + other._array.size(), _array.end());
+
+  } else if (_array.size() < other._array.size() && !_highest_bits) {
+    // This array has fewer actual words, and the top n words of this
+    // array are all zeros.  Copy in the top n words of the other
+    // array.
+    Array::const_iterator ai;
+    for (ai = other._array.begin() + _array.size(); 
+         ai != other._array.end(); 
+         ++ai) {
+      _array.push_back(*ai);
+    }
+  }
+
+  // Consider the words that both arrays have in common.
+  for (size_t i = 0; i < num_common_words; ++i) {
+    _array[i] |= other._array[i];
+  }
+
+  _highest_bits |= other._highest_bits;
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator ^=
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+void BitArray::
+operator ^= (const BitArray &other) {
+  size_t num_common_words = min(_array.size(), other._array.size());
+
+  // Consider the words that are on top of either array.
+  if (other._array.size() < _array.size() && other._highest_bits) {
+    // The other array has fewer actual words, and the top n words of
+    // the other array are all ones.  The top n words of this array
+    // get inverted.
+    Array::iterator ai;
+    for (ai = _array.begin() + other._array.size(); 
+         ai != _array.end(); 
+         ++ai) {
+      (*ai).invert_in_place();
+    }
+
+  } else if (_array.size() < other._array.size()) {
+    if (!_highest_bits) {
+      // This array has fewer actual words, and the top n words of this
+      // array are all zeros.  Copy in the top n words of the other
+      // array.
+      Array::const_iterator ai;
+      for (ai = other._array.begin() + _array.size(); 
+           ai != other._array.end(); 
+           ++ai) {
+        _array.push_back(*ai);
+      }
+    } else {
+      // This array has fewer actual words, and the top n words of this
+      // array are all ones.  Copy in the top n words of the other
+      // array, inverted.
+      Array::const_iterator ai;
+      for (ai = other._array.begin() + _array.size(); 
+           ai != other._array.end(); 
+           ++ai) {
+        _array.push_back(~(*ai));
+      }
+    }
+  }
+
+  // Consider the words that both arrays have in common.
+  for (size_t i = 0; i < num_common_words; ++i) {
+    _array[i] ^= other._array[i];
+  }
+
+  _highest_bits ^= other._highest_bits;
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator <<=
+//       Access: Published
+//  Description: Logical left shift.  The rightmost bits are filled in
+//               with zeroes.  Since this is an infinite bit array,
+//               none of the bits on the left are lost.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+operator <<= (int shift) {
+  if (shift == 0 || _array.empty()) {
+    return;
+  }
+  if (shift < 0) {
+    operator >>= (-shift);
+    return;
+  }
+
+  int w = shift / num_bits_per_word;
+  int b = shift % num_bits_per_word;
+
+  if (b == 0) {
+    // Easy case--word-at-a-time.
+    Array new_array;
+    new_array.reserve(_array.size() + w);
+    for (int i = 0; i < w; ++i) {
+      new_array.push_back(MaskType::all_off());
+    }
+    Array::const_iterator ai;
+    for (ai = _array.begin(); ai != _array.end(); ++ai) {
+      new_array.push_back(*ai);
+    }
+    _array.swap(new_array);
+
+  } else {
+    // Harder case--we have to shuffle bits between words.
+    Array new_array;
+    new_array.reserve(_array.size() + w + 1);
+    for (int i = 0; i < w; ++i) {
+      new_array.push_back(MaskType::all_off());
+    }
+
+    int downshift_count = num_bits_per_word - b;
+    MaskType lower_mask = MaskType::lower_on(downshift_count);
+    MaskType upper_mask = ~lower_mask;
+
+    Array::const_iterator ai = _array.begin();
+    nassertv(ai != _array.end());
+    MaskType next_bits = ((*ai) & upper_mask) >> downshift_count;
+    new_array.push_back(((*ai) & lower_mask) << b);
+    ++ai;
+    while (ai != _array.end()) {
+      new_array.push_back((((*ai) & lower_mask) << b) | next_bits);
+      next_bits = ((*ai) & upper_mask) >> downshift_count;
+      ++ai;
+    }
+
+    // Finally, the top n bits.
+    if (_highest_bits) {
+      next_bits |= upper_mask;
+    }
+    new_array.push_back(next_bits);
+    _array.swap(new_array);
+  }
+
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::operator >>=
+//       Access: Published
+//  Description: Logical right shift.  The rightmost bits are lost.
+//               Since this is an infinite bit array, there is no
+//               question of sign extension; there is no need to
+//               synthesize bits on the left.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+operator >>= (int shift) {
+  if (shift == 0 || _array.empty()) {
+    return;
+  }
+  if (shift < 0) {
+    operator <<= (-shift);
+    return;
+  }
+
+  int w = shift / num_bits_per_word;
+  int b = shift % num_bits_per_word;
+
+  if (w >= (int)_array.size()) {
+    // Trivial case--shift to nothing.
+    _array.clear();
+    return;
+  }
+
+  if (b == 0) {
+    // Easy case--word-at-a-time.
+    Array new_array;
+    new_array.reserve(_array.size() - w);
+    Array::const_iterator ai;
+    for (ai = _array.begin() + w; ai != _array.end(); ++ai) {
+      new_array.push_back(*ai);
+    }
+    _array.swap(new_array);
+
+  } else {
+    // Harder case--we have to shuffle bits between words.
+    Array new_array;
+    new_array.reserve(_array.size() - w);
+
+    int upshift_count = num_bits_per_word - b;
+    MaskType lower_mask = MaskType::lower_on(b);
+    MaskType upper_mask = ~lower_mask;
+
+    Array::const_iterator ai = _array.begin() + w;
+    nassertv(ai < _array.end());
+    MaskType next_bits = ((*ai) & upper_mask) >> b;
+    
+    ++ai;
+    while (ai != _array.end()) {
+      new_array.push_back((((*ai) & lower_mask) << upshift_count) | next_bits);
+      next_bits = ((*ai) & upper_mask) >> b;
+      ++ai;
+    }
+
+    // Finally, the top n bits.
+    if (_highest_bits) {
+      next_bits |= upper_mask;
+    }
+    new_array.push_back(next_bits);
+    _array.swap(new_array);
+  }
+
+  normalize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::generate_hash
+//       Access: Public
+//  Description: Adds the bitmask to the indicated hash generator.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+generate_hash(ChecksumHashGenerator &hashgen) const {
+  hashgen.add_int(_highest_bits);
+  Array::const_iterator ai;
+  for (ai = _array.begin(); ai != _array.end(); ++ai) {
+    hashgen.add_int((*ai).get_word());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::ensure_has_word
+//       Access: Private
+//  Description: Ensures that at least word n has been allocated into
+//               the array.
+////////////////////////////////////////////////////////////////////
+void BitArray::
+ensure_has_word(int n) {
+  if (_highest_bits) {
+    while (n >= (int)_array.size()) {
+      _array.push_back(MaskType::all_on());
+    }
+  } else {
+    while (n >= (int)_array.size()) {
+      _array.push_back(MaskType::all_off());
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::normalize
+//       Access: Private
+//  Description: Ensures that the array is the smallest array that
+//               represents this same value, by removing the topmost
+//               words that are all bits off (or on).
+////////////////////////////////////////////////////////////////////
+void BitArray::
+normalize() {
+  if (_highest_bits) {
+    while (!_array.empty() && _array.back() == MaskType::all_on()) {
+      _array.pop_back();
+    }
+  } else {
+    while (!_array.empty() && _array.back().is_zero()) {
+      _array.pop_back();
+    }
+  }
+}

+ 152 - 0
panda/src/putil/bitArray.h

@@ -0,0 +1,152 @@
+// Filename: bitArray.h
+// Created by:  drose (20Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef BITARRAY_H
+#define BITARRAY_H
+
+#include "pandabase.h"
+
+#include "bitMask.h"
+#include "numeric_types.h"
+#include "typedObject.h"
+#include "indent.h"
+
+#include "checksumHashGenerator.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : BitArray
+// Description : A dynamic array with an unlimited number of bits.
+//
+//               This is similar to a BitMask, except it appears to
+//               contain an infinite number of bits.  You can use it
+//               very much as you would use a BitMask.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA BitArray {
+public:
+  typedef BitMask32 MaskType;
+  typedef MaskType::WordType WordType;
+  enum { num_bits_per_word = MaskType::num_bits };
+
+PUBLISHED:
+
+  INLINE BitArray();
+  INLINE BitArray(WordType init_value);
+  INLINE BitArray(const BitArray &copy);
+  INLINE void operator = (const BitArray &copy);
+
+  INLINE static BitArray all_on();
+  INLINE static BitArray all_off();
+  INLINE static BitArray lower_on(int on_bits);
+  INLINE static BitArray bit(int index);
+  INLINE static BitArray range(int low_bit, int size);
+
+  INLINE ~BitArray();
+
+  INLINE static bool has_max_num_bits();
+  INLINE static int get_max_num_bits();
+
+  INLINE static int get_num_bits_per_word();
+  INLINE int get_num_bits() const;
+  INLINE bool get_bit(int index) const;
+  INLINE void set_bit(int index);
+  INLINE void clear_bit(int index);
+  INLINE void set_bit_to(int index, bool value);
+  INLINE bool get_highest_bits() const;
+  bool is_zero() const;
+
+  INLINE WordType extract(int low_bit, int size) const;
+  INLINE void store(WordType value, int low_bit, int size);
+  void set_range(int low_bit, int size);
+  void clear_range(int low_bit, int size);
+  INLINE void set_range_to(bool value, int low_bit, int size);
+
+  INLINE int get_num_words() const;
+  INLINE MaskType get_word(int n) const;
+  INLINE void set_word(int n, MaskType value);
+
+  void invert_in_place();
+  bool has_bits_in_common(const BitArray &other) const;
+  INLINE void clear();
+
+  void output(ostream &out) const;
+  void output_binary(ostream &out, int spaces_every = 4) const;
+  void output_hex(ostream &out, int spaces_every = 4) const;
+  void write(ostream &out, int indent_level = 0) const;
+
+  INLINE bool operator == (const BitArray &other) const;
+  INLINE bool operator != (const BitArray &other) const;
+  INLINE bool operator < (const BitArray &other) const;
+  int compare_to(const BitArray &other) const;
+
+  INLINE BitArray
+  operator & (const BitArray &other) const;
+
+  INLINE BitArray
+  operator | (const BitArray &other) const;
+
+  INLINE BitArray
+  operator ^ (const BitArray &other) const;
+
+  INLINE BitArray
+  operator ~ () const;
+
+  INLINE BitArray
+  operator << (int shift) const;
+
+  INLINE BitArray
+  operator >> (int shift) const;
+
+  void operator &= (const BitArray &other);
+  void operator |= (const BitArray &other);
+  void operator ^= (const BitArray &other);
+  void operator <<= (int shift);
+  void operator >>= (int shift);
+
+public:
+  void generate_hash(ChecksumHashGenerator &hashgen) const;
+
+private:
+  void ensure_has_word(int n);
+  void normalize();
+
+private:
+  typedef pvector<MaskType> Array;
+  Array _array;
+  int _highest_bits;  // Either 0 or 1.
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    register_type(_type_handle, "BitArray");
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "bitArray.I"
+
+INLINE ostream &
+operator << (ostream &out, const BitArray &array) {
+  array.output(out);
+  return out;
+}
+
+#endif

+ 208 - 117
panda/src/putil/bitMask.I

@@ -16,16 +16,16 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-template<class WordType, int num_bits>
-TypeHandle BitMask<WordType, num_bits>::_type_handle;
+template<class WType, int nbits>
+TypeHandle BitMask<WType, nbits>::_type_handle;
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BitMask::Constructor
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits>::
 BitMask() :
   _word(0)
 {
@@ -36,8 +36,8 @@ BitMask() :
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits>::
 BitMask(WordType init_value) :
   _word(init_value)
 {
@@ -48,9 +48,9 @@ BitMask(WordType init_value) :
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits>::
-BitMask(const BitMask<WordType, num_bits> &copy) :
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits>::
+BitMask(const BitMask<WType, nbits> &copy) :
   _word(copy._word)
 {
 }
@@ -60,9 +60,9 @@ BitMask(const BitMask<WordType, num_bits> &copy) :
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
-operator = (const BitMask<WordType, num_bits> &copy) {
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
+operator = (const BitMask<WType, nbits> &copy) {
   _word = copy._word;
 }
 
@@ -71,8 +71,8 @@ operator = (const BitMask<WordType, num_bits> &copy) {
 //       Access: Published, Static
 //  Description: Returns a BitMask whose bits are all on.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
 all_on() {
   BitMask result;
   result._word = ~0;
@@ -84,8 +84,8 @@ all_on() {
 //       Access: Published, Static
 //  Description: Returns a BitMask whose bits are all off.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
 all_off() {
   BitMask result;
   result._word = 0;
@@ -95,10 +95,10 @@ all_off() {
 ////////////////////////////////////////////////////////////////////
 //     Function: BitMask::Named lower_on constructor
 //       Access: Published, Static
-//  Description: Returns a BitMask whose lower num_bits bits are on.
+//  Description: Returns a BitMask whose lower on_bits bits are on.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
 lower_on(int on_bits) {
   if (on_bits <= 0) {
     return all_off();
@@ -115,8 +115,8 @@ lower_on(int on_bits) {
 //       Access: Published, Static
 //  Description: Returns a BitMask with only the indicated bit on.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
 bit(int index) {
   BitMask result;
   result.set_bit(index);
@@ -129,8 +129,8 @@ bit(int index) {
 //  Description: Returns a BitMask whose size bits, beginning at
 //               low_bit, are on.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
 range(int low_bit, int size) {
   BitMask result;
   if (size <= 0) {
@@ -149,19 +149,56 @@ range(int low_bit, int size) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits>::
 ~BitMask() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BitMask::has_max_num_bits
+//       Access: Published, Static
+//  Description: Returns true if there is a maximum number of bits
+//               that may be stored in this structure, false
+//               otherwise.  If this returns true, the number may be
+//               queried in get_max_num_bits().
+//
+//               This method always returns true.  This method is
+//               defined so generic programming algorithms can use
+//               BitMask or BitArray interchangeably.
+////////////////////////////////////////////////////////////////////
+template<class WType, int nbits>
+INLINE bool BitMask<WType, nbits>::
+has_max_num_bits() {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitMask::get_max_num_bits
+//       Access: Published, Static
+//  Description: If get_max_num_bits() returned true, this method may
+//               be called to return the maximum number of bits that
+//               may be stored in this structure.  It is an error to
+//               call this if get_max_num_bits() return false.
+//
+//               It is never an error to call this method.  This
+//               returns the same thing as get_num_bits().  This
+//               method is defined so generic programming algorithms
+//               can use BitMask or BitArray interchangeably.
+////////////////////////////////////////////////////////////////////
+template<class WType, int nbits>
+INLINE int BitMask<WType, nbits>::
+get_max_num_bits() {
+  return num_bits;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BitMask::get_num_bits
 //       Access: Published, Static
 //  Description: Returns the number of bits available to set in the
 //               bitmask.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE int BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE int BitMask<WType, nbits>::
 get_num_bits() {
   return num_bits;
 }
@@ -171,10 +208,10 @@ get_num_bits() {
 //       Access: Published
 //  Description: Returns true if the nth bit is set, false if it is
 //               cleared.  index must be in the range [0,
-//               get_num_bits).
+//               num_bits).
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE bool BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE bool BitMask<WType, nbits>::
 get_bit(int index) const {
   nassertr(index >= 0 && index < num_bits, false);
   return (_word & ((WordType)1 << index)) != 0;
@@ -184,10 +221,10 @@ get_bit(int index) const {
 //     Function: BitMask::set_bit
 //       Access: Published
 //  Description: Sets the nth bit on.  index must be in the range
-//               [0, get_num_bits).
+//               [0, num_bits).
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 set_bit(int index) {
   nassertv(index >= 0 && index < num_bits);
   _word |= ((WordType)1 << index);
@@ -197,10 +234,10 @@ set_bit(int index) {
 //     Function: BitMask::clear_bit
 //       Access: Published
 //  Description: Sets the nth bit off.  index must be in the range
-//               [0, get_num_bits).
+//               [0, num_bits).
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 clear_bit(int index) {
   nassertv(index >= 0 && index < num_bits);
   _word &= ~((WordType)1 << index);
@@ -211,10 +248,10 @@ clear_bit(int index) {
 //       Access: Published
 //  Description: Sets the nth bit either on or off, according to the
 //               indicated bool value.  index must be in the range [0,
-//               get_num_bits).
+//               num_bits).
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 set_bit_to(int index, bool value) {
   if (value) {
     set_bit(index);
@@ -229,8 +266,8 @@ set_bit_to(int index, bool value) {
 //  Description: Returns true if the entire bitmask is zero, false
 //               otherwise.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE bool BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE bool BitMask<WType, nbits>::
 is_zero() const {
   return (_word == 0);
 }
@@ -242,11 +279,11 @@ is_zero() const {
 //               range of bits within this BitMask, shifted to the
 //               least-significant position.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE WordType BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE TYPENAME BitMask<WType, nbits>::WordType BitMask<WType, nbits>::
 extract(int low_bit, int size) const {
   return (_word >> low_bit) &
-    BitMask<WordType, num_bits>::lower_on(size)._word;
+    BitMask<WType, nbits>::lower_on(size)._word;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -255,21 +292,59 @@ extract(int low_bit, int size) const {
 //  Description: Stores the indicated word into the indicated range of
 //               bits with this BitMask.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 store(WordType value, int low_bit, int size) {
-  WordType mask =
-    BitMask<WordType, num_bits>::lower_on(size)._word << low_bit;
+  WordType mask = BitMask<WType, nbits>::range(low_bit, size)._word;
   _word = (_word & ~mask) | ((value << low_bit) & mask);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BitMask::set_range
+//       Access: Published
+//  Description: Sets the indicated range of bits on.
+////////////////////////////////////////////////////////////////////
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
+set_range(int low_bit, int size) {
+  WordType mask = BitMask<WType, nbits>::range(low_bit, size)._word;
+  _word |= mask;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitMask::clear_range
+//       Access: Published
+//  Description: Sets the indicated range of bits off.
+////////////////////////////////////////////////////////////////////
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
+clear_range(int low_bit, int size) {
+  WordType mask = BitMask<WType, nbits>::range(low_bit, size)._word;
+  _word &= ~mask;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitMask::set_range_to
+//       Access: Published
+//  Description: Sets the indicated range of bits to either on or off.
+////////////////////////////////////////////////////////////////////
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
+set_range_to(bool value, int low_bit, int size) {
+  if (value) {
+    set_range(low_bit, size);
+  } else {
+    clear_range(low_bit, size);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BitMask::get_word
 //       Access: Published
 //  Description: Returns the entire BitMask as a single word.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE WordType BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE TYPENAME BitMask<WType, nbits>::WordType BitMask<WType, nbits>::
 get_word() const {
   return _word;
 }
@@ -280,8 +355,8 @@ get_word() const {
 //  Description: Sets the entire BitMask to the value indicated by the
 //               given word.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 set_word(WordType value) {
   _word = value;
 }
@@ -289,21 +364,39 @@ set_word(WordType value) {
 ////////////////////////////////////////////////////////////////////
 //     Function: BitMask::invert_in_place
 //       Access: Published
-//  Description: Inverts all the bits in the BitMask.
+//  Description: Inverts all the bits in the BitMask.  This is
+//               equivalent to mask = ~mask.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 invert_in_place() {
   _word = ~_word;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BitMask::has_bits_in_common
+//       Access: Published
+//  Description: Returns true if this BitMask has any "one" bits in
+//               common with the other one, false otherwise.
+//
+//               This is equivalent to (mask & other) != 0, but may be
+//               faster.  (Actually, it should only be faster in the
+//               BitArray case, but this method is provided for the
+//               benefit of generic programming algorithms).
+////////////////////////////////////////////////////////////////////
+template<class WType, int nbits>
+INLINE bool BitMask<WType, nbits>::
+has_bits_in_common(const BitMask<WType, nbits> &other) const {
+  return (_word & other._word) != 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BitMask::clear
 //       Access: Published
 //  Description: Sets all the bits in the BitMask off.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 clear() {
   _word = 0;
 }
@@ -314,8 +407,8 @@ clear() {
 //  Description: Writes the BitMask out as a binary or a hex number,
 //               according to the number of bits.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+void BitMask<WType, nbits>::
 output(ostream &out) const {
   if (num_bits >= 40) {
     output_hex(out);
@@ -330,8 +423,8 @@ output(ostream &out) const {
 //  Description: Writes the BitMask out as a binary number, with
 //               spaces every four bits.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+void BitMask<WType, nbits>::
 output_binary(ostream &out, int spaces_every) const {
   for (int i = num_bits - 1; i >= 0; i--) {
     if (spaces_every != 0 && ((i % spaces_every) == spaces_every - 1)) {
@@ -347,8 +440,8 @@ output_binary(ostream &out, int spaces_every) const {
 //  Description: Writes the BitMask out as a hexadecimal number, with
 //               spaces every four digits.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+void BitMask<WType, nbits>::
 output_hex(ostream &out, int spaces_every) const {
   int num_digits = (num_bits + 3) / 4;
 
@@ -371,8 +464,8 @@ output_hex(ostream &out, int spaces_every) const {
 //  Description: Writes the BitMask out as a binary or a hex number,
 //               according to the number of bits.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+void BitMask<WType, nbits>::
 write(ostream &out, int indent_level) const {
   indent(out, indent_level) << *this << "\n";
 }
@@ -382,9 +475,9 @@ write(ostream &out, int indent_level) const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE bool BitMask<WordType, num_bits>::
-operator == (const BitMask<WordType, num_bits> &other) const {
+template<class WType, int nbits>
+INLINE bool BitMask<WType, nbits>::
+operator == (const BitMask<WType, nbits> &other) const {
   return _word == other._word;
 }
 
@@ -393,9 +486,9 @@ operator == (const BitMask<WordType, num_bits> &other) const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE bool BitMask<WordType, num_bits>::
-operator != (const BitMask<WordType, num_bits> &other) const {
+template<class WType, int nbits>
+INLINE bool BitMask<WType, nbits>::
+operator != (const BitMask<WType, nbits> &other) const {
   return _word != other._word;
 }
 
@@ -410,9 +503,9 @@ operator != (const BitMask<WordType, num_bits> &other) const {
 //               export any STL container (ordered or unordered) of
 //               BitMask under Windows.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE bool BitMask<WordType, num_bits>::
-operator < (const BitMask<WordType, num_bits> &other) const {
+template<class WType, int nbits>
+INLINE bool BitMask<WType, nbits>::
+operator < (const BitMask<WType, nbits> &other) const {
   return _word < other._word;
 }
 
@@ -424,9 +517,9 @@ operator < (const BitMask<WordType, num_bits> &other) const {
 //               if it sorts after, or 0 if they are equivalent.  This
 //               is based on the same ordering defined by operator <.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE int BitMask<WordType, num_bits>::
-compare_to(const BitMask<WordType, num_bits> &other) const {
+template<class WType, int nbits>
+INLINE int BitMask<WType, nbits>::
+compare_to(const BitMask<WType, nbits> &other) const {
   if ((*this) < other) {
     return -1;
   } else if (other < (*this)) {
@@ -441,10 +534,10 @@ compare_to(const BitMask<WordType, num_bits> &other) const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
-operator & (const BitMask<WordType, num_bits> &other) const {
-  BitMask<WordType, num_bits> result(*this);
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
+operator & (const BitMask<WType, nbits> &other) const {
+  BitMask<WType, nbits> result(*this);
   result &= other;
   return result;
 }
@@ -454,10 +547,10 @@ operator & (const BitMask<WordType, num_bits> &other) const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
-operator | (const BitMask<WordType, num_bits> &other) const {
-  BitMask<WordType, num_bits> result(*this);
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
+operator | (const BitMask<WType, nbits> &other) const {
+  BitMask<WType, nbits> result(*this);
   result |= other;
   return result;
 }
@@ -467,10 +560,10 @@ operator | (const BitMask<WordType, num_bits> &other) const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
-operator ^ (const BitMask<WordType, num_bits> &other) const {
-  BitMask<WordType, num_bits> result(*this);
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
+operator ^ (const BitMask<WType, nbits> &other) const {
+  BitMask<WType, nbits> result(*this);
   result ^= other;
   return result;
 }
@@ -480,12 +573,10 @@ operator ^ (const BitMask<WordType, num_bits> &other) const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
 operator ~ () const {
-  BitMask<WordType, num_bits> result(*this);
-  result._word = ~result._word;
-  return result;
+  return BitMask<WType, nbits>(~_word);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -493,10 +584,10 @@ operator ~ () const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
 operator << (int shift) const {
-  BitMask<WordType, num_bits> result(*this);
+  BitMask<WType, nbits> result(*this);
   result <<= shift;
   return result;
 }
@@ -506,10 +597,10 @@ operator << (int shift) const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE BitMask<WordType, num_bits> BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE BitMask<WType, nbits> BitMask<WType, nbits>::
 operator >> (int shift) const {
-  BitMask<WordType, num_bits> result(*this);
+  BitMask<WType, nbits> result(*this);
   result >>= shift;
   return result;
 }
@@ -519,9 +610,9 @@ operator >> (int shift) const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
-operator &= (const BitMask<WordType, num_bits> &other) {
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
+operator &= (const BitMask<WType, nbits> &other) {
   _word &= other._word;
 }
 
@@ -530,9 +621,9 @@ operator &= (const BitMask<WordType, num_bits> &other) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
-operator |= (const BitMask<WordType, num_bits> &other) {
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
+operator |= (const BitMask<WType, nbits> &other) {
   _word |= other._word;
 }
 
@@ -541,9 +632,9 @@ operator |= (const BitMask<WordType, num_bits> &other) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
-operator ^= (const BitMask<WordType, num_bits> &other) {
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
+operator ^= (const BitMask<WType, nbits> &other) {
   _word ^= other._word;
 }
 
@@ -552,8 +643,8 @@ operator ^= (const BitMask<WordType, num_bits> &other) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 operator <<= (int shift) {
   _word <<= shift;
 }
@@ -563,8 +654,8 @@ operator <<= (int shift) {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 operator >>= (int shift) {
   _word >>= shift;
 }
@@ -574,8 +665,8 @@ operator >>= (int shift) {
 //       Access: Public
 //  Description: Adds the bitmask to the indicated hash generator.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-INLINE void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+INLINE void BitMask<WType, nbits>::
 generate_hash(ChecksumHashGenerator &hashgen) const {
   hashgen.add_int(_word);
 }
@@ -585,8 +676,8 @@ generate_hash(ChecksumHashGenerator &hashgen) const {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
-void BitMask<WordType, num_bits>::
+template<class WType, int nbits>
+void BitMask<WType, nbits>::
 init_type() {
   ostringstream str;
   str << "BitMask" << num_bits;

+ 37 - 26
panda/src/putil/bitMask.h

@@ -34,22 +34,29 @@
 //               bits of some length that must fit within a given word
 //               of the indicated type.  See also BitArray.
 ////////////////////////////////////////////////////////////////////
-template<class WordType, int num_bits>
+template<class WType, int nbits>
 class BitMask {
+public:
+  typedef WType WordType;
+  enum { num_bits = nbits };
+
 PUBLISHED:
   INLINE BitMask();
   INLINE BitMask(WordType init_value);
-  INLINE BitMask(const BitMask<WordType, num_bits> &copy);
-  INLINE void operator = (const BitMask<WordType, num_bits> &copy);
+  INLINE BitMask(const BitMask<WType, nbits> &copy);
+  INLINE void operator = (const BitMask<WType, nbits> &copy);
 
-  INLINE static BitMask<WordType, num_bits> all_on();
-  INLINE static BitMask<WordType, num_bits> all_off();
-  INLINE static BitMask<WordType, num_bits> lower_on(int on_bits);
-  INLINE static BitMask<WordType, num_bits> bit(int index);
-  INLINE static BitMask<WordType, num_bits> range(int low_bit, int size);
+  INLINE static BitMask<WType, nbits> all_on();
+  INLINE static BitMask<WType, nbits> all_off();
+  INLINE static BitMask<WType, nbits> lower_on(int on_bits);
+  INLINE static BitMask<WType, nbits> bit(int index);
+  INLINE static BitMask<WType, nbits> range(int low_bit, int size);
 
   INLINE ~BitMask();
 
+  INLINE static bool has_max_num_bits();
+  INLINE static int get_max_num_bits();
+
   INLINE static int get_num_bits();
   INLINE bool get_bit(int index) const;
   INLINE void set_bit(int index);
@@ -59,10 +66,14 @@ PUBLISHED:
 
   INLINE WordType extract(int low_bit, int size) const;
   INLINE void store(WordType value, int low_bit, int size);
+  INLINE void set_range(int low_bit, int size);
+  INLINE void clear_range(int low_bit, int size);
+  INLINE void set_range_to(bool value, int low_bit, int size);
   INLINE WordType get_word() const;
   INLINE void set_word(WordType value);
 
   INLINE void invert_in_place();
+  INLINE bool has_bits_in_common(const BitMask<WType, nbits> &other) const;
   INLINE void clear();
 
   void output(ostream &out) const;
@@ -70,32 +81,32 @@ PUBLISHED:
   void output_hex(ostream &out, int spaces_every = 4) const;
   void write(ostream &out, int indent_level = 0) const;
 
-  INLINE bool operator == (const BitMask<WordType, num_bits> &other) const;
-  INLINE bool operator != (const BitMask<WordType, num_bits> &other) const;
-  INLINE bool operator < (const BitMask<WordType, num_bits> &other) const;
-  INLINE int compare_to(const BitMask<WordType, num_bits> &other) const;
+  INLINE bool operator == (const BitMask<WType, nbits> &other) const;
+  INLINE bool operator != (const BitMask<WType, nbits> &other) const;
+  INLINE bool operator < (const BitMask<WType, nbits> &other) const;
+  INLINE int compare_to(const BitMask<WType, nbits> &other) const;
 
-  INLINE BitMask<WordType, num_bits>
-  operator & (const BitMask<WordType, num_bits> &other) const;
+  INLINE BitMask<WType, nbits>
+  operator & (const BitMask<WType, nbits> &other) const;
 
-  INLINE BitMask<WordType, num_bits>
-  operator | (const BitMask<WordType, num_bits> &other) const;
+  INLINE BitMask<WType, nbits>
+  operator | (const BitMask<WType, nbits> &other) const;
 
-  INLINE BitMask<WordType, num_bits>
-  operator ^ (const BitMask<WordType, num_bits> &other) const;
+  INLINE BitMask<WType, nbits>
+  operator ^ (const BitMask<WType, nbits> &other) const;
 
-  INLINE BitMask<WordType, num_bits>
+  INLINE BitMask<WType, nbits>
   operator ~ () const;
 
-  INLINE BitMask<WordType, num_bits>
+  INLINE BitMask<WType, nbits>
   operator << (int shift) const;
 
-  INLINE BitMask<WordType, num_bits>
+  INLINE BitMask<WType, nbits>
   operator >> (int shift) const;
 
-  INLINE void operator &= (const BitMask<WordType, num_bits> &other);
-  INLINE void operator |= (const BitMask<WordType, num_bits> &other);
-  INLINE void operator ^= (const BitMask<WordType, num_bits> &other);
+  INLINE void operator &= (const BitMask<WType, nbits> &other);
+  INLINE void operator |= (const BitMask<WType, nbits> &other);
+  INLINE void operator ^= (const BitMask<WType, nbits> &other);
   INLINE void operator <<= (int shift);
   INLINE void operator >>= (int shift);
 
@@ -117,8 +128,8 @@ private:
 
 #include "bitMask.I"
 
-template<class WordType, int num_bits>
-INLINE ostream &operator << (ostream &out, const BitMask<WordType, num_bits> &bitmask) {
+template<class WType, int nbits>
+INLINE ostream &operator << (ostream &out, const BitMask<WType, nbits> &bitmask) {
   bitmask.output(out);
   return out;
 }

+ 4 - 0
panda/src/putil/config_util.cxx

@@ -19,6 +19,8 @@
 #include "config_util.h"
 #include "animInterface.h"
 #include "bamReaderParam.h"
+#include "bitArray.h"
+#include "bitMask.h"
 #include "cachedTypedWritableReferenceCount.h"
 #include "clockObject.h"
 #include "configurable.h"
@@ -70,6 +72,8 @@ ConfigVariableSearchPath sound_path
 ConfigureFn(config_util) {
   AnimInterface::init_type();
   BamReaderParam::init_type();
+  BitArray::init_type();
+  BitMask32::init_type();
   CachedTypedWritableReferenceCount::init_type();
   Configurable::init_type();
   Datagram::init_type();

+ 1 - 0
panda/src/putil/putil_composite1.cxx

@@ -3,6 +3,7 @@
 #include "bamReader.cxx"
 #include "bamReaderParam.cxx"
 #include "bamWriter.cxx"
+#include "bitArray.cxx"
 #include "bitMask.cxx"
 #include "buttonHandle.cxx"
 #include "buttonRegistry.cxx"