add SparseArray

This commit is contained in:
David Rose 2007-02-15 20:59:08 +00:00
parent 1b76d5a31c
commit 9f198514ce
10 changed files with 1474 additions and 2 deletions

View File

@ -53,6 +53,7 @@
nonDeletor.h \
pta_double.h \
pta_float.h pta_int.h \
sparseArray.I sparseArray.h \
string_utils.I string_utils.N string_utils.h \
timedCycle.I timedCycle.h typedWritable.I \
typedWritable.h typedWritableReferenceCount.I \
@ -94,6 +95,7 @@
nonDeletor.cxx \
pta_double.cxx pta_float.cxx \
pta_int.cxx pta_ushort.cxx \
sparseArray.cxx \
string_utils.cxx timedCycle.cxx typedWritable.cxx \
typedWritableReferenceCount.cxx updateSeq.cxx \
uniqueIdAllocator.cxx \
@ -145,6 +147,7 @@
nonDeletor.h \
pta_double.h \
pta_float.h pta_int.h pta_ushort.h \
sparseArray.I sparseArray.h \
string_utils.I \
string_utils.h timedCycle.I timedCycle.h typedWritable.I \
typedWritable.h typedWritableReferenceCount.I \

View File

@ -17,9 +17,31 @@
////////////////////////////////////////////////////////////////////
#include "bitArray.h"
#include "sparseArray.h"
TypeHandle BitArray::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: BitArray::Constructor (from SparseArray)
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
BitArray::
BitArray(const SparseArray &from) {
_highest_bits = 0;
int num_subranges = from.get_num_subranges();
for (int i = 0; i < num_subranges; ++i) {
int begin = from.get_subrange_begin(i);
int end = from.get_subrange_end(i);
set_range(begin, end - begin);
}
if (from.is_inverse()) {
invert_in_place();
}
}
////////////////////////////////////////////////////////////////////
// Function: BitArray::is_zero
// Access: Published
@ -37,13 +59,148 @@ is_zero() const {
// Start from the high end, since that's more likely to be nonzero.
Array::reverse_iterator ai;
for (ai = _array.rbegin(); ai != _array.rend(); ++ai) {
if ((*ai) != 0) {
if (!(*ai).is_zero()) {
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BitArray::is_all_on
// Access: Published
// Description: Returns true if the entire bitmask is one, false
// otherwise.
////////////////////////////////////////////////////////////////////
bool BitArray::
is_all_on() const {
if (!_highest_bits) {
// If all the infinite highest bits are not set, certainly the
// bitmask is not all on.
return false;
}
Array::reverse_iterator ai;
for (ai = _array.rbegin(); ai != _array.rend(); ++ai) {
if (!(*ai).is_all_on()) {
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BitArray::has_any_of
// Access: Published
// Description: Returns true if any bit in the indicated range is
// set, false otherwise.
////////////////////////////////////////////////////////////////////
bool BitArray::
has_any_of(int low_bit, int size) const {
if ((low_bit + size - 1) / num_bits_per_word >= get_num_words()) {
// This range touches the highest bits.
if (_highest_bits) {
return true;
}
}
int w = low_bit / num_bits_per_word;
int b = low_bit % num_bits_per_word;
if (w >= get_num_words()) {
// This range is entirely among the highest bits.
return _highest_bits;
}
if (b + size <= num_bits_per_word) {
// The whole thing fits within one word of the array.
return get_word(w).has_any_of(b, size);
}
int num_high_bits = num_bits_per_word - b;
if (_array[w].has_any_of(b, num_high_bits)) {
return true;
}
size -= num_high_bits;
++w;
while (size > 0) {
if (size <= num_bits_per_word) {
// The remainder fits within one word of the array.
return _array[w].has_any_of(0, size);
}
// Keep going.
if (!_array[w].is_zero()) {
return true;
}
size -= num_bits_per_word;
++w;
if (w >= get_num_words()) {
// Now we're up to the highest bits.
return _highest_bits;
}
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BitArray::has_all_of
// Access: Published
// Description: Returns true if all bits in the indicated range are
// set, false otherwise.
////////////////////////////////////////////////////////////////////
bool BitArray::
has_all_of(int low_bit, int size) const {
if ((low_bit + size - 1) / num_bits_per_word >= get_num_words()) {
// This range touches the highest bits.
if (!_highest_bits) {
return false;
}
}
int w = low_bit / num_bits_per_word;
int b = low_bit % num_bits_per_word;
if (w >= get_num_words()) {
// This range is entirely among the highest bits.
return _highest_bits;
}
if (b + size <= num_bits_per_word) {
// The whole thing fits within one word of the array.
return get_word(w).has_all_of(b, size);
}
int num_high_bits = num_bits_per_word - b;
if (!_array[w].has_all_of(b, num_high_bits)) {
return false;
}
size -= num_high_bits;
++w;
while (size > 0) {
if (size <= num_bits_per_word) {
// The remainder fits within one word of the array.
return _array[w].has_all_of(0, size);
}
// Keep going.
if (!_array[w].is_all_on()) {
return false;
}
size -= num_bits_per_word;
++w;
if (w >= get_num_words()) {
// Now we're up to the highest bits.
return _highest_bits;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BitArray::set_range
// Access: Published

View File

@ -29,6 +29,8 @@
#include "checksumHashGenerator.h"
class SparseArray;
////////////////////////////////////////////////////////////////////
// Class : BitArray
// Description : A dynamic array with an unlimited number of bits.
@ -44,11 +46,11 @@ public:
enum { num_bits_per_word = MaskType::num_bits };
PUBLISHED:
INLINE BitArray();
INLINE BitArray(WordType init_value);
INLINE BitArray(const BitArray &copy);
INLINE BitArray &operator = (const BitArray &copy);
BitArray(const SparseArray &from);
INLINE static BitArray all_on();
INLINE static BitArray all_off();
@ -69,9 +71,12 @@ PUBLISHED:
INLINE void set_bit_to(int index, bool value);
INLINE bool get_highest_bits() const;
bool is_zero() const;
bool is_all_on() const;
INLINE WordType extract(int low_bit, int size) const;
INLINE void store(WordType value, int low_bit, int size);
bool has_any_of(int low_bit, int size) const;
bool has_all_of(int low_bit, int size) const;
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);

View File

@ -273,6 +273,18 @@ is_zero() const {
return (_word == 0);
}
////////////////////////////////////////////////////////////////////
// Function: BitMask::is_all_on
// Access: Published
// Description: Returns true if the entire bitmask is one, false
// otherwise.
////////////////////////////////////////////////////////////////////
template<class WType, int nbits>
INLINE bool BitMask<WType, nbits>::
is_all_on() const {
return (~_word == 0);
}
////////////////////////////////////////////////////////////////////
// Function: BitMask::extract
// Access: Published
@ -300,6 +312,32 @@ store(WordType value, int low_bit, int size) {
_word = (_word & ~mask) | ((value << low_bit) & mask);
}
////////////////////////////////////////////////////////////////////
// Function: BitMask::has_any_of
// Access: Published
// Description: Returns true if any bit in the indicated range is
// set, false otherwise.
////////////////////////////////////////////////////////////////////
template<class WType, int nbits>
INLINE bool BitMask<WType, nbits>::
has_any_of(int low_bit, int size) const {
WordType mask = BitMask<WType, nbits>::range(low_bit, size)._word;
return (_word & mask) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: BitMask::has_all_of
// Access: Published
// Description: Returns true if all bits in the indicated range are
// set, false otherwise.
////////////////////////////////////////////////////////////////////
template<class WType, int nbits>
INLINE bool BitMask<WType, nbits>::
has_all_of(int low_bit, int size) const {
WordType mask = BitMask<WType, nbits>::range(low_bit, size)._word;
return (_word & mask) == mask;
}
////////////////////////////////////////////////////////////////////
// Function: BitMask::set_range
// Access: Published

View File

@ -64,9 +64,12 @@ PUBLISHED:
INLINE void clear_bit(int index);
INLINE void set_bit_to(int index, bool value);
INLINE bool is_zero() const;
INLINE bool is_all_on() const;
INLINE WordType extract(int low_bit, int size) const;
INLINE void store(WordType value, int low_bit, int size);
INLINE bool has_any_of(int low_bit, int size) const;
INLINE bool has_all_of(int low_bit, int size) const;
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);

View File

@ -32,6 +32,7 @@
#include "namable.h"
#include "nodeCachedReferenceCount.h"
#include "referenceCount.h"
#include "sparseArray.h"
#include "typedObject.h"
#include "typedReferenceCount.h"
#include "typedWritable.h"
@ -94,6 +95,7 @@ ConfigureFn(config_util) {
Namable::init_type();
NodeCachedReferenceCount::init_type();
ReferenceCount::init_type();
SparseArray::init_type();
TypedObject::init_type();
TypedReferenceCount::init_type();
TypedWritable::init_type();

View File

@ -13,6 +13,7 @@
#include "pta_float.cxx"
#include "pta_int.cxx"
#include "pta_ushort.cxx"
#include "sparseArray.cxx"
#include "string_utils.cxx"
#include "timedCycle.cxx"
#include "typedWritable.cxx"

View File

@ -0,0 +1,578 @@
// Filename: sparseArray.I
// Created by: drose (14Feb07)
//
////////////////////////////////////////////////////////////////////
//
// 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
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray::
SparseArray() : _inverse(false) {
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray::
SparseArray(const SparseArray &copy) :
_subranges(copy._subranges),
_inverse(copy._inverse)
{
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray &SparseArray::
operator = (const SparseArray &copy) {
_subranges = copy._subranges;
_inverse = copy._inverse;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Named all_on constructor
// Access: Published, Static
// Description: Returns a SparseArray with an infinite array of bits,
// all on.
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
all_on() {
SparseArray result;
result._inverse = true;
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Named all_on constructor
// Access: Published, Static
// Description: Returns a SparseArray whose bits are all off.
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
all_off() {
return SparseArray();
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Named lower_on constructor
// Access: Published, Static
// Description: Returns a SparseArray whose lower on_bits bits are on.
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
lower_on(int on_bits) {
SparseArray result;
result.set_range(0, on_bits);
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Named bit constructor
// Access: Published, Static
// Description: Returns a SparseArray with only the indicated bit on.
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
bit(int index) {
SparseArray result;
result.set_bit(index);
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Named range constructor
// Access: Published, Static
// Description: Returns a SparseArray whose size bits, beginning at
// low_bit, are on.
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
range(int low_bit, int size) {
SparseArray result;
result.set_range(low_bit, size);
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray::
~SparseArray() {
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::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 SparseArray has
// no maximum number of bits. This method is defined so
// generic programming algorithms can use BitMask or
// SparseArray interchangeably.
////////////////////////////////////////////////////////////////////
INLINE bool SparseArray::
has_max_num_bits() {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::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
// SparseArray has no maximum number of bits. This method
// is defined so generic programming algorithms can use
// BitMask or SparseArray interchangeably.
////////////////////////////////////////////////////////////////////
INLINE int SparseArray::
get_max_num_bits() {
nassertr(false, 0);
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::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 SparseArray::
get_num_bits() const {
if (_subranges.empty()) {
return 0;
} else {
Subranges::const_iterator si = _subranges.begin() + _subranges.size() - 1;
return (*si)._end;
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::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 SparseArray::
get_bit(int index) const {
return has_any_of(index, 1);
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::set_bit
// Access: Published
// Description: Sets the nth bit on. If n >= get_num_bits(), this
// automatically extends the array.
////////////////////////////////////////////////////////////////////
INLINE void SparseArray::
set_bit(int index) {
set_range(index, 1);
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::clear_bit
// Access: Published
// Description: Sets the nth bit off. If n >= get_num_bits(), this
// automatically extends the array.
////////////////////////////////////////////////////////////////////
INLINE void SparseArray::
clear_bit(int index) {
clear_range(index, 1);
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::set_bit_to
// Access: Published
// Description: Sets the nth bit either on or off, according to the
// indicated bool value.
////////////////////////////////////////////////////////////////////
INLINE void SparseArray::
set_bit_to(int index, bool value) {
if (value) {
set_bit(index);
} else {
clear_bit(index);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::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 SparseArray::
get_highest_bits() const {
return _inverse;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::is_zero
// Access: Published
// Description: Returns true if the entire bitmask is zero, false
// otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool SparseArray::
is_zero() const {
if (_inverse) {
return false;
} else {
return _subranges.empty();
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::is_all_on
// Access: Published
// Description: Returns true if the entire bitmask is one, false
// otherwise.
////////////////////////////////////////////////////////////////////
bool SparseArray::
is_all_on() const {
if (_inverse) {
return _subranges.empty();
} else {
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::has_any_of
// Access: Published
// Description: Returns true if any bit in the indicated range is
// set, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool SparseArray::
has_any_of(int low_bit, int size) const {
if (_inverse) {
return !do_has_all(low_bit, low_bit + size);
} else {
return do_has_any(low_bit, low_bit + size);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::has_all_of
// Access: Published
// Description: Returns true if all bits in the indicated range are
// set, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool SparseArray::
has_all_of(int low_bit, int size) const {
if (_inverse) {
return !do_has_any(low_bit, low_bit + size);
} else {
return do_has_all(low_bit, low_bit + size);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::set_range
// Access: Published
// Description: Sets the indicated range of bits on.
////////////////////////////////////////////////////////////////////
INLINE void SparseArray::
set_range(int low_bit, int size) {
if (_inverse) {
return do_remove_range(low_bit, low_bit + size);
} else {
return do_add_range(low_bit, low_bit + size);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::clear_range
// Access: Published
// Description: Sets the indicated range of bits off.
////////////////////////////////////////////////////////////////////
INLINE void SparseArray::
clear_range(int low_bit, int size) {
if (_inverse) {
return do_add_range(low_bit, low_bit + size);
} else {
return do_remove_range(low_bit, low_bit + size);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::set_range_to
// Access: Published
// Description: Sets the indicated range of bits to either on or off.
////////////////////////////////////////////////////////////////////
INLINE void SparseArray::
set_range_to(bool value, int low_bit, int size) {
if (value) {
set_range(low_bit, size);
} else {
clear_range(low_bit, size);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::invert_in_place
// Access: Published
// Description: Inverts all the bits in the SparseArray. This is
// equivalent to array = ~array.
////////////////////////////////////////////////////////////////////
void SparseArray::
invert_in_place() {
_inverse = !_inverse;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::clear
// Access: Published
// Description: Sets all the bits in the SparseArray off.
////////////////////////////////////////////////////////////////////
void SparseArray::
clear() {
_subranges.clear();
_inverse = false;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator ==
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool SparseArray::
operator == (const SparseArray &other) const {
return compare_to(other) == 0;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator !=
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool SparseArray::
operator != (const SparseArray &other) const {
return compare_to(other) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator <
// Access: Published
// Description: Returns true if the unsigned integer which is
// represented by this SparseArray is less than that of the
// other one, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool SparseArray::
operator < (const SparseArray &other) const {
return compare_to(other) < 0;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator &
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
operator & (const SparseArray &other) const {
SparseArray result(*this);
result &= other;
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator |
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
operator | (const SparseArray &other) const {
SparseArray result(*this);
result |= other;
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator ^
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
operator ^ (const SparseArray &other) const {
SparseArray result(*this);
result ^= other;
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator ~
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
operator ~ () const {
SparseArray result(*this);
result.invert_in_place();
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator <<
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
operator << (int shift) const {
SparseArray result(*this);
result <<= shift;
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator >>
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray SparseArray::
operator >> (int shift) const {
SparseArray result(*this);
result >>= shift;
return result;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator <<=
// Access: Published
// Description: Logical left shift. Since negative bit positions
// have meaning in a SparseArray, real bit values are
// rotated in on the left (not necessarily zero).
////////////////////////////////////////////////////////////////////
void SparseArray::
operator <<= (int shift) {
do_shift(shift);
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator >>=
// Access: Published
// Description: Logical right shift. The rightmost bits become
// negative, but are not lost; they will reappear into
// the zero position if the array is later left-shifted.
////////////////////////////////////////////////////////////////////
void SparseArray::
operator >>= (int shift) {
do_shift(-shift);
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::is_inverse
// Access: Published
// Description: If this is true, the SparseArray is actually defined
// as a list of subranges of integers that are *not* in
// the set. If this is false (the default), then the
// subranges define the integers that *are* in the set.
// This affects the interpretation of the values
// returned by iterating through get_num_subranges().
////////////////////////////////////////////////////////////////////
INLINE bool SparseArray::
is_inverse() const {
return _inverse;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::get_num_subranges
// Access: Published
// Description: Returns the number of separate subranges stored in
// the SparseArray. You can use this limit to iterate
// through the subranges, calling get_subrange_begin()
// and get_subrange_end() for each one.
//
// Also see is_inverse().
////////////////////////////////////////////////////////////////////
INLINE int SparseArray::
get_num_subranges() const {
return _subranges.size();
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::get_subrange_begin
// Access: Published
// Description: Returns the first numeric element in the nth
// subrange.
//
// Also see is_inverse().
////////////////////////////////////////////////////////////////////
INLINE int SparseArray::
get_subrange_begin(int n) const {
nassertr(n >= 0 && n < (int)_subranges.size(), 0);
return _subranges[n]._begin;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::get_subrange_end
// Access: Published
// Description: Returns the last numeric element, plus one, in the
// nth subrange.
//
// Also see is_inverse().
////////////////////////////////////////////////////////////////////
INLINE int SparseArray::
get_subrange_end(int n) const {
nassertr(n >= 0 && n < (int)_subranges.size(), 0);
return _subranges[n]._end;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Subrange::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE SparseArray::Subrange::
Subrange(int begin, int end) :
_begin(begin),
_end(end)
{
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Subrange::operator <
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool SparseArray::Subrange::
operator < (const SparseArray::Subrange &other) const {
// We compare the end values, rather than the begin values, to make
// lower_bound() sensibly return a possible intersection with the
// indicated Subrange.
return _end < other._end;
}

View File

@ -0,0 +1,517 @@
// Filename: sparseArray.cxx
// Created by: drose (14Feb07)
//
////////////////////////////////////////////////////////////////////
//
// 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
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "sparseArray.h"
#include "bitArray.h"
TypeHandle SparseArray::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: SparseArray::Constructor (from BitArray)
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
SparseArray::
SparseArray(const BitArray &from) {
bool empty_bit = from.get_highest_bits();
_inverse = empty_bit;
int begin = 0;
bool current_state = from.get_bit(0);
int i = 0;
// By including get_num_bits()--one more than the last bit--in this
// traversal, we guarantee that we will end on the empty_bit state
// (because the last bit we visit will be one of the highest_bits).
while (i <= from.get_num_bits()) {
if (from.get_bit(i) != current_state) {
// End of a run.
if (current_state != empty_bit) {
Subrange range(begin, i);
_subranges.push_back(range);
}
begin = i;
current_state = !current_state;
}
++i;
}
nassertv(current_state == empty_bit);
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::has_bits_in_common
// Access: Published
// Description: Returns true if this SparseArray has any "one" bits in
// common with the other one, false otherwise.
//
// This is equivalent to (array & other) != 0, but may
// be faster.
////////////////////////////////////////////////////////////////////
bool SparseArray::
has_bits_in_common(const SparseArray &other) const {
if (_inverse && other._inverse) {
// Yup, in fact we have an infinite number of bits in common.
return true;
}
if (_inverse != other._inverse) {
// We'll handle this tricky case the lazy way.
return !(*this & other).is_zero();
}
// Actually, we'll handle this easy case the lazy way too. Maybe
// later we'll do this smarter.
return !(*this & other).is_zero();
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::output
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void SparseArray::
output(ostream &out) const {
out << "[ ";
if (_inverse) {
out << "all except: ";
}
Subranges::const_iterator si;
for (si = _subranges.begin(); si != _subranges.end(); ++si) {
if ((*si)._end == (*si)._begin + 1) {
// A single element.
out << (*si)._begin << ", ";
} else {
// A range of elements.
out << (*si)._begin << "-" << ((*si)._end - 1) << ", ";
}
}
out << "]";
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::compare_to
// Access: Published
// Description: Returns a number less than zero if this SparseArray
// sorts before the indicated other SparseArray, greater
// than zero if it sorts after, or 0 if they are
// equivalent. This is based on the same ordering
// defined by operator <.
////////////////////////////////////////////////////////////////////
int SparseArray::
compare_to(const SparseArray &other) const {
if (_inverse != other._inverse) {
return _inverse ? 1 : -1;
}
Subranges::const_reverse_iterator ai = _subranges.rbegin();
Subranges::const_reverse_iterator bi = other._subranges.rbegin();
while (ai != _subranges.rend() && bi != other._subranges.rend()) {
if ((*ai)._end < (*bi)._end) {
// B is higher.
return -1;
} else if ((*bi)._end < (*ai)._end) {
// A is higher.
return 1;
} else if ((*ai)._begin < (*bi)._begin) {
// A is higher.
return 1;
} else if ((*bi)._begin < (*ai)._begin) {
// B is higher.
return -1;
}
--ai;
--bi;
}
if (ai != _subranges.rend()) {
// A is higher.
return 1;
}
if (bi != other._subranges.rend()) {
// B is higher.
return -1;
}
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator &=
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void SparseArray::
operator &= (const SparseArray &other) {
// We do this the slow and stupid way. This could be done much
// better with a little effort, but I'm not at all sure it's worth
// the effort. If you need fast boolean operations, you should
// probably be using a BitArray.
if (_inverse && other._inverse) {
do_union(other);
} else if (!_inverse && !other._inverse) {
do_intersection(other);
} else if (_inverse && !other._inverse) {
// a & b == b & a
(*this) = other & (*this);
} else if (!_inverse && other._inverse) {
do_intersection_neg(other);
} else {
// TODO.
nassertv(false);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator |=
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void SparseArray::
operator |= (const SparseArray &other) {
// We do this the slow and stupid way. This could be done much
// better with a little effort, but I'm not at all sure it's worth
// the effort. If you need fast boolean operations, you should
// probably be using a BitArray.
if (_inverse && other._inverse) {
do_intersection(other);
} else if (!_inverse && !other._inverse) {
do_union(other);
} else if (_inverse && !other._inverse) {
do_intersection_neg(other);
} else if (!_inverse && other._inverse) {
// a | b == b | a
(*this) = other | (*this);
} else {
nassertv(false);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::operator ^=
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void SparseArray::
operator ^= (const SparseArray &other) {
// We do this the slow and stupid way. This could be done much
// better with a little effort, but I'm not at all sure it's worth
// the effort. If you need fast boolean operations, you should
// probably be using a BitArray.
(*this) = ((*this) | other) & ~((*this) & other);
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::do_add_range
// Access: Private
// Description: Adds the consecutive range of integers beginning at
// begin, but not including end, to the array. If this
// range overlaps with another range already in the
// array, the result is the union.
////////////////////////////////////////////////////////////////////
void SparseArray::
do_add_range(int begin, int end) {
if (begin >= end) {
// Empty range.
return;
}
Subrange range(begin, end);
Subranges::iterator si = _subranges.lower_bound(range);
if (si == _subranges.end()) {
if (!_subranges.empty()) {
si = _subranges.begin() + _subranges.size() - 1;
if ((*si)._end >= begin) {
// The new range expands the last element of the array to the right.
(*si)._end = end;
// It might also expand it to the left; fall through.
} else {
// The new range is completely after the last element of the array.
_subranges.push_back(range);
return;
}
} else {
// The new range is completely after the last element of the array.
_subranges.push_back(range);
return;
}
}
nassertv((*si)._end >= end);
if ((*si)._begin > end) {
if (si != _subranges.begin()) {
Subranges::iterator si2 = si;
--si2;
if ((*si2)._end >= begin) {
// The new range expands an element within the array to the
// right (but does not intersect the next element).
(*si2)._end = end;
// It might also expand it to the left; fall through.
si = si2;
} else {
// The new range does not intersect any elements in the array.
_subranges.insert_unverified(si, range);
return;
}
} else {
// The new range does not intersect any elements in the array.
_subranges.insert_unverified(si, range);
return;
}
}
// Check if the new range overlaps with any elements to the left.
while (si != _subranges.begin()) {
Subranges::iterator si2 = si;
--si2;
if ((*si2)._end >= begin) {
// The new range straddles two elements, so they get combined.
(*si2)._end = (*si)._end;
_subranges.erase(si);
}
si = si2;
}
if ((*si)._begin > begin) {
// The new range expands an element to the left.
(*si)._begin = begin;
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::do_remove_range
// Access: Private
// Description: Removes the consecutive range of integers beginning
// at begin, but not including end, from the array.
////////////////////////////////////////////////////////////////////
void SparseArray::
do_remove_range(int begin, int end) {
if (begin >= end) {
// Empty range.
return;
}
Subrange range(begin, end);
Subranges::iterator si = _subranges.lower_bound(range);
if (si == _subranges.end()) {
if (!_subranges.empty()) {
si = _subranges.begin() + _subranges.size() - 1;
if ((*si)._end >= begin) {
// The new range shortens the last element of the array on the right.
end = min(end, (*si)._begin);
(*si)._end = end;
// It might also shorten it on the left; fall through.
} else {
// The new range is completely after the last element of the array.
return;
}
} else {
// The new range is completely after the last element of the array.
return;
}
}
nassertv((*si)._end >= end);
if ((*si)._begin > end) {
if (si != _subranges.begin()) {
Subranges::iterator si2 = si;
--si2;
if ((*si2)._end >= begin) {
// The new range shortens an element within the array on the
// right (but does not intersect the next element).
end = min(end, (*si2)._begin);
(*si2)._end = end;
// It might also shorten it on the left; fall through.
si = si2;
} else {
// The new range does not intersect any elements in the array.
return;
}
} else {
// The new range does not intersect any elements in the array.
return;
}
}
if (end < (*si)._end) {
// We must split an element into two.
Subrange left_range((*si)._begin, begin);
(*si)._begin = end;
si = _subranges.insert_unverified(si, left_range);
}
// Check if the new range removes any elements to the left.
while (begin <= (*si)._begin) {
if (si == _subranges.begin()) {
_subranges.erase(si);
return;
}
Subranges::iterator si2 = si;
--si2;
_subranges.erase(si);
si = si2;
}
(*si)._end = min((*si)._end, begin);
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::do_has_any
// Access: Private
// Description: Returns true if any of the consecutive range of
// integers beginning at begin, but not including end,
// appear in the array. Note that this will return
// false for an empty range.
////////////////////////////////////////////////////////////////////
bool SparseArray::
do_has_any(int begin, int end) const {
if (begin >= end) {
// Empty range.
return false;
}
Subrange range(begin, end);
Subranges::const_iterator si = _subranges.lower_bound(range);
if (si != _subranges.end() && end > (*si)._begin) {
return true;
}
if (si != _subranges.begin()) {
--si;
if (begin < (*si)._end) {
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::do_has_all
// Access: Private
// Description: Returns true if all of the consecutive range of
// integers beginning at begin, but not including end,
// appear in the array. Note that this will return
// true for an empty range.
////////////////////////////////////////////////////////////////////
bool SparseArray::
do_has_all(int begin, int end) const {
if (begin >= end) {
// Empty range.
return true;
}
Subrange range(begin, end);
Subranges::const_iterator si = _subranges.lower_bound(range);
if (si != _subranges.end() && begin >= (*si)._begin) {
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::do_intersection
// Access: Private
// Description: Removes from this array all of the elements that do
// not appear in the other one.
////////////////////////////////////////////////////////////////////
void SparseArray::
do_intersection(const SparseArray &other) {
if (_subranges.empty()) {
return;
}
if (other._subranges.empty()) {
_subranges.clear();
return;
}
int my_begin = (*_subranges.begin())._begin;
int other_begin = (*other._subranges.begin())._begin;
do_remove_range(my_begin, other_begin);
for (size_t i = 0; i < other._subranges.size() - 1; ++i) {
do_remove_range(other._subranges[i]._end, other._subranges[i + 1]._begin);
}
int my_end = (*(_subranges.begin() + _subranges.size() - 1))._end;
int other_end = (*(other._subranges.begin() + other._subranges.size() - 1))._end;
do_remove_range(other_end, my_end);
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::do_union
// Access: Private
// Description: Adds to this array all of the elements that also
// appear in the other one.
////////////////////////////////////////////////////////////////////
void SparseArray::
do_union(const SparseArray &other) {
Subranges::const_iterator si;
for (si = other._subranges.begin(); si != other._subranges.end(); ++si) {
do_add_range((*si)._begin, (*si)._end);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::do_intersection_neg
// Access: Private
// Description: Removes from this array all of the elements that also
// appear in the other one.
////////////////////////////////////////////////////////////////////
void SparseArray::
do_intersection_neg(const SparseArray &other) {
Subranges::const_iterator si;
for (si = other._subranges.begin(); si != other._subranges.end(); ++si) {
do_remove_range((*si)._begin, (*si)._end);
}
}
////////////////////////////////////////////////////////////////////
// Function: SparseArray::do_shift
// Access: Private
// Description: Shifts all the elements in the array by the indicated
// amount.
////////////////////////////////////////////////////////////////////
void SparseArray::
do_shift(int offset) {
if (offset != 0) {
Subranges::iterator si;
for (si = _subranges.begin(); si != _subranges.end(); ++si) {
(*si)._begin += offset;
(*si)._end += offset;
}
}
}

View File

@ -0,0 +1,168 @@
// Filename: sparseArray.h
// Created by: drose (14Feb07)
//
////////////////////////////////////////////////////////////////////
//
// 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
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef SPARSEARRAY_H
#define SPARSEARRAY_H
#include "pandabase.h"
#include "ordered_vector.h"
class BitArray;
////////////////////////////////////////////////////////////////////
// Class : SparseArray
// Description : This class records a set of integers, where each
// integer is either present or not present in the set.
//
// It is similar in principle and in interface to a
// BitArray (which can be thought of as a set of
// integers, one integer corresponding to each different
// bit position), but the SparseArray is implemented as
// a list of min/max subrange lists, rather than as a
// bitmask.
//
// This makes it particularly efficient for storing sets
// which consist of large sections of consecutively
// included or consecutively excluded elements, with
// arbitrarily large integers, but particularly
// inefficient for doing boolean operations such as & or
// |.
//
// Also, unlike BitArray, the SparseArray can store
// negative integers.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA SparseArray {
PUBLISHED:
INLINE SparseArray();
INLINE SparseArray(const SparseArray &copy);
INLINE SparseArray &operator = (const SparseArray &copy);
SparseArray(const BitArray &from);
INLINE static SparseArray all_on();
INLINE static SparseArray all_off();
INLINE static SparseArray lower_on(int on_bits);
INLINE static SparseArray bit(int index);
INLINE static SparseArray range(int low_bit, int size);
INLINE ~SparseArray();
INLINE static bool has_max_num_bits();
INLINE static int get_max_num_bits();
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;
INLINE bool is_zero() const;
INLINE bool is_all_on() const;
INLINE bool has_any_of(int low_bit, int size) const;
INLINE bool has_all_of(int low_bit, int size) const;
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 void invert_in_place();
bool has_bits_in_common(const SparseArray &other) const;
INLINE void clear();
void output(ostream &out) const;
INLINE bool operator == (const SparseArray &other) const;
INLINE bool operator != (const SparseArray &other) const;
INLINE bool operator < (const SparseArray &other) const;
int compare_to(const SparseArray &other) const;
INLINE SparseArray
operator & (const SparseArray &other) const;
INLINE SparseArray
operator | (const SparseArray &other) const;
INLINE SparseArray
operator ^ (const SparseArray &other) const;
INLINE SparseArray
operator ~ () const;
INLINE SparseArray
operator << (int shift) const;
INLINE SparseArray
operator >> (int shift) const;
void operator &= (const SparseArray &other);
void operator |= (const SparseArray &other);
void operator ^= (const SparseArray &other);
INLINE void operator <<= (int shift);
INLINE void operator >>= (int shift);
INLINE bool is_inverse() const;
INLINE int get_num_subranges() const;
INLINE int get_subrange_begin(int n) const;
INLINE int get_subrange_end(int n) const;
private:
void do_add_range(int begin, int end);
void do_remove_range(int begin, int end);
bool do_has_any(int begin, int end) const;
bool do_has_all(int begin, int end) const;
void do_intersection(const SparseArray &other);
void do_union(const SparseArray &other);
void do_intersection_neg(const SparseArray &other);
void do_shift(int offset);
// The SparseArray is implemented as a set of non-overlapping
// Subranges.
class Subrange {
public:
INLINE Subrange(int begin, int end);
INLINE bool operator < (const Subrange &other) const;
int _begin, _end;
};
typedef ov_set<Subrange> Subranges;
Subranges _subranges;
bool _inverse;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
register_type(_type_handle, "SparseArray");
}
private:
static TypeHandle _type_handle;
};
#include "sparseArray.I"
INLINE ostream &
operator << (ostream &out, const SparseArray &array) {
array.output(out);
return out;
}
#endif