diff --git a/panda/src/putil/bitArray.cxx b/panda/src/putil/bitArray.cxx index 89bafca5d4..d79ebc1da9 100755 --- a/panda/src/putil/bitArray.cxx +++ b/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 diff --git a/panda/src/putil/bitArray.h b/panda/src/putil/bitArray.h index 7529e9c760..76b410a239 100755 --- a/panda/src/putil/bitArray.h +++ b/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); diff --git a/panda/src/putil/bitMask.I b/panda/src/putil/bitMask.I index a947c2752c..97943af5b5 100644 --- a/panda/src/putil/bitMask.I +++ b/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 +INLINE int BitMask:: +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 +INLINE int BitMask:: +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 +INLINE int BitMask:: +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)); +} + diff --git a/panda/src/putil/bitMask.cxx b/panda/src/putil/bitMask.cxx index d450d7cc05..5c47ba29fc 100644 --- a/panda/src/putil/bitMask.cxx +++ b/panda/src/putil/bitMask.cxx @@ -23,3 +23,4 @@ #pragma implementation #endif +unsigned char num_bits_on[65536]; diff --git a/panda/src/putil/bitMask.h b/panda/src/putil/bitMask.h index 7de06039f1..e1a500e341 100644 --- a/panda/src/putil/bitMask.h +++ b/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 &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 diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index 0b4b4ece34..02001beefb 100644 --- a/panda/src/putil/config_util.cxx +++ b/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; + } + } +} + diff --git a/panda/src/putil/config_util.h b/panda/src/putil/config_util.h index 68242eeda1..cbc7e81f1d 100644 --- a/panda/src/putil/config_util.h +++ b/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__ */ diff --git a/panda/src/putil/sparseArray.cxx b/panda/src/putil/sparseArray.cxx index f2e7497972..31fb7611e2 100644 --- a/panda/src/putil/sparseArray.cxx +++ b/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 diff --git a/panda/src/putil/sparseArray.h b/panda/src/putil/sparseArray.h index 5f091be484..9de63f753f 100644 --- a/panda/src/putil/sparseArray.h +++ b/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();