소스 검색

add get_num_on_bits(), etc.

David Rose 18 년 전
부모
커밋
a71cd2a689

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

@@ -305,6 +305,90 @@ clear_range(int low_bit, int size) {
   normalize();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_num_on_bits
+//       Access: Published
+//  Description: Returns the number of bits that are set to 1 in the
+//               array.  Returns -1 if there are an infinite number of
+//               1 bits.
+////////////////////////////////////////////////////////////////////
+int BitArray::
+get_num_on_bits() const {
+  if (_highest_bits) {
+    return -1;
+  }
+
+  int result = 0;
+  Array::const_iterator ai;
+  for (ai = _array.begin(); ai != _array.end(); ++ai) {
+    result += (*ai).get_num_on_bits();
+  }
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_num_off_bits
+//       Access: Published
+//  Description: Returns the number of bits that are set to 0 in the
+//               array.  Returns -1 if there are an infinite number of
+//               0 bits.
+////////////////////////////////////////////////////////////////////
+int BitArray::
+get_num_off_bits() const {
+  if (!_highest_bits) {
+    return -1;
+  }
+
+  int result = 0;
+  Array::const_iterator ai;
+  for (ai = _array.begin(); ai != _array.end(); ++ai) {
+    result += (*ai).get_num_off_bits();
+  }
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::get_next_higher_different_bit
+//       Access: Published
+//  Description: Returns the index of the next bit in the array, above
+//               low_bit, whose value is different that the value of
+//               low_bit.  Returns low_bit again if all bits higher
+//               than low_bit have the same value.
+//
+//               This can be used to quickly iterate through all of
+//               the bits in the array.
+////////////////////////////////////////////////////////////////////
+int BitArray::
+get_next_higher_different_bit(int low_bit) const {
+  int w = low_bit / num_bits_per_word;
+  int b = low_bit % num_bits_per_word;
+  int num_words = get_num_words();
+  if (w >= num_words) {
+    return low_bit;
+  }
+  int b2 = _array[w].get_next_higher_different_bit(b);
+  if (b2 != b) {
+    // The next higher bit is within the same word.
+    return w * num_bits_per_word + b2;
+  }
+  // Look for the next word with anything interesting.
+  MaskType skip_next = (_array[w].get_bit(b)) ? MaskType::all_on() : MaskType::all_off();
+  ++w;
+  while (w < num_words && _array[w] == skip_next) {
+    ++w;
+  }
+  if (w >= num_words) {
+    return low_bit;
+  }
+  if (_array[w].get_bit(0) != _array[w].get_bit(b)) {
+    // The first bit of word w is different.
+    return w * num_bits_per_word;
+  }
+
+  b2 = _array[w].get_next_higher_different_bit(0);
+  return w * num_bits_per_word + b2;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BitArray::invert_in_place
 //       Access: Published

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

@@ -85,6 +85,10 @@ PUBLISHED:
   void clear_range(int low_bit, int size);
   INLINE void set_range_to(bool value, int low_bit, int size);
 
+  int get_num_on_bits() const;
+  int get_num_off_bits() const;
+  int get_next_higher_different_bit(int low_bit) const;
+
   INLINE int get_num_words() const;
   INLINE MaskType get_word(int n) const;
   INLINE void set_word(int n, MaskType value);

+ 86 - 0
panda/src/putil/bitMask.I

@@ -440,6 +440,73 @@ clear() {
   _word = 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BitMask::get_num_on_bits
+//       Access: Published
+//  Description: Returns the number of bits that are set to 1 in the
+//               mask.
+////////////////////////////////////////////////////////////////////
+template<class WType, int nbits>
+INLINE int BitMask<WType, nbits>::
+get_num_on_bits() const {
+  return count_bits_in_word(_word);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitMask::get_num_off_bits
+//       Access: Published
+//  Description: Returns the number of bits that are set to 0 in the
+//               mask.
+////////////////////////////////////////////////////////////////////
+template<class WType, int nbits>
+INLINE int BitMask<WType, nbits>::
+get_num_off_bits() const {
+  return count_bits_in_word(~_word);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitMask::get_next_higher_different_bit
+//       Access: Published
+//  Description: Returns the index of the next bit in the mask, above
+//               low_bit, whose value is different that the value of
+//               low_bit.  Returns low_bit again if all bits higher
+//               than low_bit have the same value.
+//
+//               This can be used to quickly iterate through all of
+//               the bits in the mask.
+////////////////////////////////////////////////////////////////////
+template<class WType, int nbits>
+INLINE int BitMask<WType, nbits>::
+get_next_higher_different_bit(int low_bit) const {
+  nassertr(low_bit >= 0 && low_bit < num_bits, low_bit);
+
+  WordType w;
+  if (_word & ((WordType)1 << low_bit)) {
+    // low_bit is 1.  Get the next higher 0 bit.  To do this, invert
+    // the word and the get the next higher 1 bit.
+    w = ~_word;
+  } else {
+    // low_bit is 0.  Get the next higher 1 bit.
+    w = _word;
+  }
+
+  // Shift out all of the low bits.
+  w >>= (low_bit + 1);
+
+  if (w == 0) {
+    // No more bits.
+    return low_bit;
+
+  } else {
+    // Now determine the lowest 1 bit in the remaining word.  This
+    // operation will clear out all bits except for the lowest 1 bit.
+    w = (w & -w);
+    
+    // And the answer is the number of bits in (w - 1).
+    return count_bits_in_word(w - 1) + low_bit + 1;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BitMask::output
 //       Access: Published
@@ -734,3 +801,22 @@ init_type() {
   str << "BitMask" << num_bits;
   register_type(_type_handle, str.str());
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: count_bits_in_word
+//  Description: Returns the number of 1 bits in the indicated word.
+////////////////////////////////////////////////////////////////////
+INLINE int
+count_bits_in_word(PN_uint32 x) {
+  return (int)num_bits_on[x & 0xffff] + (int)num_bits_on[(x >> 16) & 0xffff];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: count_bits_in_word
+//  Description: Returns the number of 1 bits in the indicated word.
+////////////////////////////////////////////////////////////////////
+INLINE int
+count_bits_in_word(PN_uint64 x) {
+  return count_bits_in_word((PN_uint32)x) + count_bits_in_word((PN_uint32)(x >> 32));
+}
+

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

@@ -23,3 +23,4 @@
 #pragma implementation
 #endif
 
+unsigned char num_bits_on[65536];

+ 10 - 0
panda/src/putil/bitMask.h

@@ -76,6 +76,10 @@ PUBLISHED:
   INLINE WordType get_word() const;
   INLINE void set_word(WordType value);
 
+  INLINE int get_num_on_bits() const;
+  INLINE int get_num_off_bits() const;
+  INLINE int get_next_higher_different_bit(int low_bit) const;
+
   INLINE void invert_in_place();
   INLINE bool has_bits_in_common(const BitMask<WType, nbits> &other) const;
   INLINE void clear();
@@ -132,6 +136,12 @@ private:
   static TypeHandle _type_handle;
 };
 
+INLINE int count_bits_in_word(PN_uint32 x);
+INLINE int count_bits_in_word(PN_uint64 x);
+
+// This table precomputes the number of on bits in each 16-bit word.
+extern EXPCL_PANDA unsigned char num_bits_on[65536];
+
 #include "bitMask.I"
 
 template<class WType, int nbits>

+ 66 - 39
panda/src/putil/config_util.cxx

@@ -85,47 +85,9 @@ ConfigVariableSearchPath sound_path
  PRC_DESC("The directories to search for sound and music files to be loaded."));
 
 ConfigureFn(config_util) {
-  AnimInterface::init_type();
-  BamCacheIndex::init_type();
-  BamCacheRecord::init_type();
-  BamReaderParam::init_type();
-  BitArray::init_type();
-  BitMask32::init_type();
-  BitMask64::init_type();
-  ButtonHandle::init_type();
-  CachedTypedWritableReferenceCount::init_type();
-  ClockObject::init_type();
-  Configurable::init_type();
-  CopyOnWriteObject::init_type();
-  Datagram::init_type();
-  DoubleBitMaskNative::init_type();
-  QuadBitMaskNative::init_type();
-  FactoryParam::init_type();
-  Namable::init_type();
-  NodeCachedReferenceCount::init_type();
-  ReferenceCount::init_type();
-  SparseArray::init_type();
-  TypedObject::init_type();
-  TypedReferenceCount::init_type();
-  TypedWritable::init_type();
-  TypedWritableReferenceCount::init_type();
-  WritableConfigurable::init_type();
-  WritableParam::init_type();
-
-  KeyboardButton::init_keyboard_buttons();
-  MouseButton::init_mouse_buttons();
-
-  DeferredDeletor::register_deletor();
-  NonDeletor::register_deletor();
-  SpamDeletor::register_deletor();
-
-  register_type(BamReader::_remove_flag, "remove");
-
-  BamCacheIndex::register_with_read_factory();
-  BamCacheRecord::register_with_read_factory();
+  init_libputil();
 }
 
-
 // Set this true to enable tracking of ReferenceCount pointer
 // allocation/deallcation via the MemoryUsage object.  This is
 // primarily useful for detecting memory leaks.  It has no effect when
@@ -170,3 +132,68 @@ ConfigVariableDouble sleep_precision
 
 ConfigVariableDouble average_frame_rate_interval
 ("average-frame-rate-interval", 1.0);
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libputil
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libputil() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+
+  AnimInterface::init_type();
+  BamCacheIndex::init_type();
+  BamCacheRecord::init_type();
+  BamReaderParam::init_type();
+  BitArray::init_type();
+  BitMask32::init_type();
+  BitMask64::init_type();
+  ButtonHandle::init_type();
+  CachedTypedWritableReferenceCount::init_type();
+  ClockObject::init_type();
+  Configurable::init_type();
+  CopyOnWriteObject::init_type();
+  Datagram::init_type();
+  DoubleBitMaskNative::init_type();
+  QuadBitMaskNative::init_type();
+  FactoryParam::init_type();
+  Namable::init_type();
+  NodeCachedReferenceCount::init_type();
+  ReferenceCount::init_type();
+  SparseArray::init_type();
+  TypedObject::init_type();
+  TypedReferenceCount::init_type();
+  TypedWritable::init_type();
+  TypedWritableReferenceCount::init_type();
+  WritableConfigurable::init_type();
+  WritableParam::init_type();
+
+  KeyboardButton::init_keyboard_buttons();
+  MouseButton::init_mouse_buttons();
+
+  DeferredDeletor::register_deletor();
+  NonDeletor::register_deletor();
+  SpamDeletor::register_deletor();
+
+  register_type(BamReader::_remove_flag, "remove");
+
+  BamCacheIndex::register_with_read_factory();
+  BamCacheRecord::register_with_read_factory();
+
+  // Initialize the num_bits_on table, for BitMask::get_num_on_bits().
+  for (int bit = 0; bit < 16; ++bit) {
+    int w = (1 << bit);
+    for (int i = 0; i < w; ++i) {
+      num_bits_on[i + w] = num_bits_on[i] + 1;
+    }
+  }
+}
+

+ 2 - 0
panda/src/putil/config_util.h

@@ -61,4 +61,6 @@ extern ConfigVariableDouble max_dt;
 extern ConfigVariableDouble sleep_precision;
 extern ConfigVariableDouble average_frame_rate_interval;
 
+extern EXPCL_PANDA void init_libputil();
+
 #endif /* __CONFIG_UTIL_H__ */

+ 80 - 0
panda/src/putil/sparseArray.cxx

@@ -54,6 +54,86 @@ SparseArray(const BitArray &from) {
   nassertv(current_state == empty_bit);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: SparseArray::get_num_on_bits
+//       Access: Published
+//  Description: Returns the number of bits that are set to 1 in the
+//               array.  Returns -1 if there are an infinite number of
+//               1 bits.
+////////////////////////////////////////////////////////////////////
+int SparseArray::
+get_num_on_bits() const {
+  if (_inverse) {
+    return -1;
+  }
+
+  int result = 0;
+  Subranges::const_iterator si;
+  for (si = _subranges.begin(); si != _subranges.end(); ++si) {
+    result += (*si)._end - (*si)._begin;
+  }
+
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SparseArray::get_num_off_bits
+//       Access: Published
+//  Description: Returns the number of bits that are set to 0 in the
+//               array.  Returns -1 if there are an infinite number of
+//               0 bits.
+////////////////////////////////////////////////////////////////////
+int SparseArray::
+get_num_off_bits() const {
+  if (!_inverse) {
+    return -1;
+  }
+
+  int result = 0;
+  Subranges::const_iterator si;
+  for (si = _subranges.begin(); si != _subranges.end(); ++si) {
+    result += (*si)._end - (*si)._begin;
+  }
+
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SparseArray::get_next_higher_different_bit
+//       Access: Published
+//  Description: Returns the index of the next bit in the array, above
+//               low_bit, whose value is different that the value of
+//               low_bit.  Returns low_bit again if all bits higher
+//               than low_bit have the same value.
+//
+//               This can be used to quickly iterate through all of
+//               the bits in the array.
+////////////////////////////////////////////////////////////////////
+int SparseArray::
+get_next_higher_different_bit(int low_bit) const {
+  Subrange range(low_bit, low_bit + 1);
+  Subranges::const_iterator si = _subranges.lower_bound(range);
+  if (si == _subranges.end()) {
+    // That was the end of the array.
+    return low_bit;
+  }
+
+  if (low_bit >= (*si)._begin) {
+    return (*si)._end;
+  }
+
+  int next = (*si)._begin;
+
+  if (si != _subranges.begin()) {
+    --si;
+    if (low_bit < (*si)._end) {
+      return (*si)._end;
+    }
+  }
+
+  return next;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: SparseArray::has_bits_in_common
 //       Access: Published

+ 4 - 0
panda/src/putil/sparseArray.h

@@ -83,6 +83,10 @@ PUBLISHED:
   INLINE void clear_range(int low_bit, int size);
   INLINE void set_range_to(bool value, int low_bit, int size);
 
+  int get_num_on_bits() const;
+  int get_num_off_bits() const;
+  int get_next_higher_different_bit(int low_bit) const;
+
   INLINE void invert_in_place();
   bool has_bits_in_common(const SparseArray &other) const;
   INLINE void clear();