add get_num_on_bits(), etc.

This commit is contained in:
David Rose 2007-06-26 19:04:37 +00:00
parent 4ae6be208c
commit a71cd2a689
9 changed files with 337 additions and 39 deletions

View File

@ -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

View File

@ -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);

View File

@ -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));
}

View File

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

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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__ */

View File

@ -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

View File

@ -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();