mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
add SparseArray
This commit is contained in:
parent
1b76d5a31c
commit
9f198514ce
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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 ©);
|
||||
INLINE BitArray &operator = (const BitArray ©);
|
||||
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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
578
panda/src/putil/sparseArray.I
Normal file
578
panda/src/putil/sparseArray.I
Normal 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 ©) :
|
||||
_subranges(copy._subranges),
|
||||
_inverse(copy._inverse)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SparseArray::Copy Assignment Operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE SparseArray &SparseArray::
|
||||
operator = (const SparseArray ©) {
|
||||
_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;
|
||||
}
|
||||
|
517
panda/src/putil/sparseArray.cxx
Normal file
517
panda/src/putil/sparseArray.cxx
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
168
panda/src/putil/sparseArray.h
Normal file
168
panda/src/putil/sparseArray.h
Normal 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 ©);
|
||||
INLINE SparseArray &operator = (const SparseArray ©);
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user