440 lines
9.2 KiB
Text
440 lines
9.2 KiB
Text
|
/**
|
||
|
* PANDA 3D SOFTWARE
|
||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||
|
*
|
||
|
* All use of this software is subject to the terms of the revised BSD
|
||
|
* license. You should have received a copy of this license along
|
||
|
* with this source code in a file named "LICENSE."
|
||
|
*
|
||
|
* @file sparseArray.I
|
||
|
* @author drose
|
||
|
* @date 2007-02-14
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE SparseArray::
|
||
|
SparseArray() : _inverse(false) {
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a SparseArray with an infinite array of bits, all on.
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
all_on() {
|
||
|
SparseArray result;
|
||
|
result._inverse = true;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a SparseArray whose bits are all off.
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
all_off() {
|
||
|
return SparseArray();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a SparseArray whose lower on_bits bits are on.
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
lower_on(int on_bits) {
|
||
|
SparseArray result;
|
||
|
if (on_bits > 0) {
|
||
|
result._subranges.push_back(Subrange(0, on_bits));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a SparseArray with only the indicated bit on.
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
bit(int index) {
|
||
|
SparseArray result;
|
||
|
result.set_bit(index);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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() {
|
||
|
nassert_raise("SparseArray has no maximum bit count");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the entire bitmask is zero, false otherwise.
|
||
|
*/
|
||
|
INLINE bool SparseArray::
|
||
|
is_zero() const {
|
||
|
if (_inverse) {
|
||
|
return false;
|
||
|
} else {
|
||
|
return _subranges.empty();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the entire bitmask is one, false otherwise.
|
||
|
*/
|
||
|
bool SparseArray::
|
||
|
is_all_on() const {
|
||
|
if (_inverse) {
|
||
|
return _subranges.empty();
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Inverts all the bits in the SparseArray. This is equivalent to array =
|
||
|
* ~array.
|
||
|
*/
|
||
|
void SparseArray::
|
||
|
invert_in_place() {
|
||
|
_inverse = !_inverse;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets all the bits in the SparseArray off.
|
||
|
*/
|
||
|
void SparseArray::
|
||
|
clear() {
|
||
|
_subranges.clear();
|
||
|
_inverse = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE bool SparseArray::
|
||
|
operator == (const SparseArray &other) const {
|
||
|
return compare_to(other) == 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE bool SparseArray::
|
||
|
operator != (const SparseArray &other) const {
|
||
|
return compare_to(other) != 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
operator & (const SparseArray &other) const {
|
||
|
SparseArray result(*this);
|
||
|
result &= other;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
operator | (const SparseArray &other) const {
|
||
|
SparseArray result(*this);
|
||
|
result |= other;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
operator ^ (const SparseArray &other) const {
|
||
|
SparseArray result(*this);
|
||
|
result ^= other;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
operator ~ () const {
|
||
|
SparseArray result(*this);
|
||
|
result.invert_in_place();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
operator << (int shift) const {
|
||
|
SparseArray result(*this);
|
||
|
result <<= shift;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE SparseArray SparseArray::
|
||
|
operator >> (int shift) const {
|
||
|
SparseArray result(*this);
|
||
|
result >>= shift;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 size_t SparseArray::
|
||
|
get_num_subranges() const {
|
||
|
return _subranges.size();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the first numeric element in the nth subrange.
|
||
|
*
|
||
|
* Also see is_inverse().
|
||
|
*/
|
||
|
INLINE int SparseArray::
|
||
|
get_subrange_begin(size_t n) const {
|
||
|
nassertr(n < _subranges.size(), 0);
|
||
|
return _subranges[n]._begin;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the last numeric element, plus one, in the nth subrange.
|
||
|
*
|
||
|
* Also see is_inverse().
|
||
|
*/
|
||
|
INLINE int SparseArray::
|
||
|
get_subrange_end(size_t n) const {
|
||
|
nassertr(n < _subranges.size(), 0);
|
||
|
return _subranges[n]._end;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
INLINE SparseArray::Subrange::
|
||
|
Subrange(int begin, int end) :
|
||
|
_begin(begin),
|
||
|
_end(end)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
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;
|
||
|
}
|