Panda3D
Loading...
Searching...
No Matches
sparseArray.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file sparseArray.cxx
10 * @author drose
11 * @date 2007-02-14
12 */
13
14#include "sparseArray.h"
15#include "bitArray.h"
16#include "datagram.h"
17#include "datagramIterator.h"
18
19TypeHandle SparseArray::_type_handle;
20
21/**
22 *
23 */
24SparseArray::
25SparseArray(const BitArray &from) {
26 bool empty_bit = from.get_highest_bits();
27 _inverse = empty_bit;
28
29 size_t begin = 0;
30 bool current_state = from.get_bit(0);
31 size_t i = 0;
32
33 // By including get_num_bits()--one more than the last bit--in this
34 // traversal, we guarantee that we will end on the empty_bit state (because
35 // the last bit we visit will be one of the highest_bits).
36 while (i <= from.get_num_bits()) {
37 if (from.get_bit(i) != current_state) {
38 // End of a run.
39 if (current_state != empty_bit) {
40 Subrange range(begin, i);
41 _subranges.push_back(range);
42 }
43 begin = i;
44 current_state = !current_state;
45 }
46 ++i;
47 }
48
49 nassertv(current_state == empty_bit);
50}
51
52/**
53 * Returns the number of bits that are set to 1 in the array. Returns -1 if
54 * there are an infinite number of 1 bits.
55 */
57get_num_on_bits() const {
58 if (_inverse) {
59 return -1;
60 }
61
62 int result = 0;
63 Subranges::const_iterator si;
64 for (si = _subranges.begin(); si != _subranges.end(); ++si) {
65 result += (*si)._end - (*si)._begin;
66 }
67
68 return result;
69}
70
71/**
72 * Returns the number of bits that are set to 0 in the array. Returns -1 if
73 * there are an infinite number of 0 bits.
74 */
76get_num_off_bits() const {
77 if (!_inverse) {
78 return -1;
79 }
80
81 int result = 0;
82 Subranges::const_iterator si;
83 for (si = _subranges.begin(); si != _subranges.end(); ++si) {
84 result += (*si)._end - (*si)._begin;
85 }
86
87 return result;
88}
89
90/**
91 * Returns the index of the lowest 1 bit in the array. Returns -1 if there
92 * are no 1 bits and 0 if there are an infinite number of 1 bits.
93 */
95get_lowest_on_bit() const {
96 if (_inverse) {
97 if (_subranges.empty() || _subranges[0]._begin > 0) {
98 return 0;
99 } else {
100 return _subranges[0]._end;
101 }
102 }
103
104 if (_subranges.empty()) {
105 return -1;
106 }
107
108 return _subranges[0]._begin;
109}
110
111/**
112 * Returns the index of the lowest 0 bit in the array. Returns -1 if there
113 * are no 0 bits or if there are an infinite number of 1 bits.
114 */
116get_lowest_off_bit() const {
117 if (!_inverse) {
118 if (_subranges.empty() || _subranges[0]._begin > 0) {
119 return 0;
120 } else {
121 return _subranges[0]._end;
122 }
123 }
124
125 if (_subranges.empty()) {
126 return -1;
127 }
128
129 return _subranges[0]._begin;
130}
131
132/**
133 * Returns the index of the highest 1 bit in the array. Returns -1 if there
134 * are no 1 bits or if there an infinite number of 1 bits.
135 */
137get_highest_on_bit() const {
138 if (_inverse) {
139 return -1;
140 }
141
142 if (_subranges.empty()) {
143 return -1;
144 }
145
146 return _subranges[_subranges.size() - 1]._end - 1;
147}
148
149/**
150 * Returns the index of the highest 0 bit in the array. Returns -1 if there
151 * are no 0 bits or if there an infinite number of 1 bits.
152 */
154get_highest_off_bit() const {
155 if (!_inverse) {
156 return -1;
157 }
158
159 if (_subranges.empty()) {
160 return -1;
161 }
162
163 return _subranges[_subranges.size() - 1]._end - 1;
164}
165
166/**
167 * Returns the index of the next bit in the array, above low_bit, whose value
168 * is different that the value of low_bit. Returns low_bit again if all bits
169 * higher than low_bit have the same value.
170 *
171 * This can be used to quickly iterate through all of the bits in the array.
172 */
174get_next_higher_different_bit(int low_bit) const {
175 Subrange range(low_bit, low_bit + 1);
176 Subranges::const_iterator si = _subranges.lower_bound(range);
177 if (si == _subranges.end()) {
178 // That was the end of the array.
179 return low_bit;
180 }
181
182 if (low_bit >= (*si)._begin) {
183 return (*si)._end;
184 }
185
186 int next = (*si)._begin;
187
188 if (si != _subranges.begin()) {
189 --si;
190 if (low_bit < (*si)._end) {
191 return (*si)._end;
192 }
193 }
194
195 return next;
196}
197
198/**
199 * Returns true if this SparseArray has any "one" bits in common with the
200 * other one, false otherwise.
201 *
202 * This is equivalent to (array & other) != 0, but may be faster.
203 */
205has_bits_in_common(const SparseArray &other) const {
206 if (_inverse && other._inverse) {
207 // Yup, in fact we have an infinite number of bits in common.
208 return true;
209 }
210
211 if (_inverse != other._inverse) {
212 // We'll handle this tricky case the lazy way.
213 return !(*this & other).is_zero();
214 }
215
216 // Actually, we'll handle this easy case the lazy way too. Maybe later
217 // we'll do this smarter.
218 return !(*this & other).is_zero();
219}
220
221/**
222 *
223 */
224void SparseArray::
225output(std::ostream &out) const {
226 out << "[ ";
227 if (_inverse) {
228 out << "all except: ";
229 }
230 Subranges::const_iterator si;
231 for (si = _subranges.begin(); si != _subranges.end(); ++si) {
232 if ((*si)._end == (*si)._begin + 1) {
233 // A single element.
234 out << (*si)._begin << ", ";
235 } else {
236 // A range of elements.
237 out << (*si)._begin << "-" << ((*si)._end - 1) << ", ";
238 }
239 }
240 out << "]";
241}
242
243/**
244 * Returns a number less than zero if this SparseArray sorts before the
245 * indicated other SparseArray, greater than zero if it sorts after, or 0 if
246 * they are equivalent. This is based on the same ordering defined by
247 * operator <.
248 */
250compare_to(const SparseArray &other) const {
251 if (_inverse != other._inverse) {
252 return _inverse ? 1 : -1;
253 }
254
255 Subranges::const_reverse_iterator ai = _subranges.rbegin();
256 Subranges::const_reverse_iterator bi = other._subranges.rbegin();
257
258 while (ai != _subranges.rend() && bi != other._subranges.rend()) {
259 if ((*ai)._end < (*bi)._end) {
260 // B is higher.
261 return -1;
262 } else if ((*bi)._end < (*ai)._end) {
263 // A is higher.
264 return 1;
265 } else if ((*ai)._begin < (*bi)._begin) {
266 // A is higher.
267 return 1;
268 } else if ((*bi)._begin < (*ai)._begin) {
269 // B is higher.
270 return -1;
271 }
272
273 ++ai;
274 ++bi;
275 }
276
277 if (ai != _subranges.rend()) {
278 // A is higher.
279 return 1;
280 }
281 if (bi != other._subranges.rend()) {
282 // B is higher.
283 return -1;
284 }
285
286 return 0;
287}
288
289/**
290 *
291 */
292void SparseArray::
293operator &= (const SparseArray &other) {
294 // We do this the slow and stupid way. This could be done much better with
295 // a little effort, but I'm not at all sure it's worth the effort. If you
296 // need fast boolean operations, you should probably be using a BitArray.
297
298 if (_inverse && other._inverse) {
299 do_union(other);
300
301 } else if (!_inverse && !other._inverse) {
302 do_intersection(other);
303
304 } else if (_inverse && !other._inverse) {
305 // a & b == b & a
306 (*this) = other & (*this);
307
308 } else if (!_inverse && other._inverse) {
309 do_intersection_neg(other);
310
311 } else {
312 // TODO.
313 nassertv(false);
314 }
315}
316
317/**
318 *
319 */
320void SparseArray::
321operator |= (const SparseArray &other) {
322 // We do this the slow and stupid way. This could be done much better with
323 // a little effort, but I'm not at all sure it's worth the effort. If you
324 // need fast boolean operations, you should probably be using a BitArray.
325
326 if (_inverse && other._inverse) {
327 do_intersection(other);
328
329 } else if (!_inverse && !other._inverse) {
330 do_union(other);
331
332 } else if (_inverse && !other._inverse) {
333 do_intersection_neg(other);
334
335 } else if (!_inverse && other._inverse) {
336 // a | b == b | a
337 (*this) = other | (*this);
338
339 } else {
340 nassertv(false);
341 }
342}
343
344/**
345 *
346 */
347void SparseArray::
348operator ^= (const SparseArray &other) {
349 // We do this the slow and stupid way. This could be done much better with
350 // a little effort, but I'm not at all sure it's worth the effort. If you
351 // need fast boolean operations, you should probably be using a BitArray.
352
353 (*this) = ((*this) | other) & ~((*this) & other);
354}
355
356/**
357 * Adds the consecutive range of integers beginning at begin, but not
358 * including end, to the array. If this range overlaps with another range
359 * already in the array, the result is the union.
360 */
361void SparseArray::
362do_add_range(int begin, int end) {
363 if (begin >= end) {
364 // Empty range.
365 return;
366 }
367
368 Subrange range(begin, end);
369 Subranges::iterator si = _subranges.lower_bound(range);
370 if (si == _subranges.end()) {
371 if (!_subranges.empty()) {
372 si = _subranges.begin() + _subranges.size() - 1;
373 if ((*si)._end >= begin) {
374 // The new range expands the last element of the array to the right.
375 (*si)._end = end;
376 // It might also expand it to the left; fall through.
377 } else {
378 // The new range is completely after the last element of the array.
379 _subranges.push_back(range);
380 return;
381 }
382
383 } else {
384 // The new range is completely after the last element of the array.
385 _subranges.push_back(range);
386 return;
387 }
388 }
389
390 nassertv((*si)._end >= end);
391
392 if ((*si)._begin > end) {
393 if (si != _subranges.begin()) {
394 Subranges::iterator si2 = si;
395 --si2;
396 if ((*si2)._end >= begin) {
397 // The new range expands an element within the array to the right (but
398 // does not intersect the next element).
399 (*si2)._end = end;
400 // It might also expand it to the left; fall through.
401 si = si2;
402 } else {
403 // The new range does not intersect any elements in the array.
404 _subranges.insert_unverified(si, range);
405 return;
406 }
407 } else {
408 // The new range does not intersect any elements in the array.
409 _subranges.insert_unverified(si, range);
410 return;
411 }
412 }
413
414 // Check if the new range overlaps with any elements to the left.
415 while (si != _subranges.begin()) {
416 Subranges::iterator si2 = si;
417 --si2;
418 if ((*si2)._end >= begin) {
419 // The new range straddles two elements, so they get combined.
420 (*si2)._end = (*si)._end;
421 _subranges.erase(si);
422 } else {
423 // Stop here.
424 break;
425 }
426 si = si2;
427 }
428
429 if ((*si)._begin > begin) {
430 // The new range expands an element to the left.
431 (*si)._begin = begin;
432 }
433}
434
435/**
436 * Removes the consecutive range of integers beginning at begin, but not
437 * including end, from the array.
438 */
439void SparseArray::
440do_remove_range(int begin, int end) {
441 if (begin >= end) {
442 // Empty range.
443 return;
444 }
445
446 Subrange range(begin, end);
447 Subranges::iterator si = _subranges.lower_bound(range);
448 if (si == _subranges.end()) {
449 if (!_subranges.empty()) {
450 si = _subranges.begin() + _subranges.size() - 1;
451 if ((*si)._end > begin) {
452 // The new range shortens the last element of the array on the right.
453 end = std::max(begin, (*si)._begin);
454 (*si)._end = end;
455 // It might also shorten it on the left; fall through.
456 } else {
457 // The new range is completely after the last element of the array.
458 return;
459 }
460
461 } else {
462 // The new range is completely after the last element of the array.
463 return;
464 }
465 }
466
467 nassertv((*si)._end >= end);
468
469 if ((*si)._begin > end) {
470 if (si != _subranges.begin()) {
471 Subranges::iterator si2 = si;
472 --si2;
473 if ((*si2)._end > begin) {
474 // The new range shortens an element within the array on the right
475 // (but does not intersect the next element).
476 end = std::max(begin, (*si2)._begin);
477 (*si2)._end = end;
478 // It might also shorten it on the left; fall through.
479 si = si2;
480 } else {
481 // The new range does not intersect any elements in the array.
482 return;
483 }
484 } else {
485 // The new range does not intersect any elements in the array.
486 return;
487 }
488 }
489
490
491 if (end < (*si)._end) {
492 // We must split an element into two.
493 Subrange left_range((*si)._begin, begin);
494 (*si)._begin = end;
495 si = _subranges.insert_unverified(si, left_range);
496 }
497
498 // Check if the new range removes any elements to the left.
499 while (begin <= (*si)._begin || (*si)._begin >= (*si)._end) {
500 if (si == _subranges.begin()) {
501 _subranges.erase(si);
502 return;
503 }
504 Subranges::iterator si2 = si;
505 --si2;
506 _subranges.erase(si);
507 si = si2;
508 }
509
510 (*si)._end = std::min((*si)._end, begin);
511 nassertv((*si)._end > (*si)._begin);
512}
513
514/**
515 * Returns true if any of the consecutive range of integers beginning at
516 * begin, but not including end, appear in the array. Note that this will
517 * return false for an empty range.
518 */
519bool SparseArray::
520do_has_any(int begin, int end) const {
521 if (begin >= end) {
522 // Empty range.
523 return false;
524 }
525
526 Subrange range(begin, end);
527 Subranges::const_iterator si = _subranges.lower_bound(range);
528 if (si != _subranges.end() && end > (*si)._begin) {
529 return true;
530 }
531 if (si != _subranges.begin()) {
532 --si;
533 if (begin < (*si)._end) {
534 return true;
535 }
536 }
537
538 return false;
539}
540
541/**
542 * Returns true if all of the consecutive range of integers beginning at
543 * begin, but not including end, appear in the array. Note that this will
544 * return true for an empty range.
545 */
546bool SparseArray::
547do_has_all(int begin, int end) const {
548 if (begin >= end) {
549 // Empty range.
550 return true;
551 }
552
553 Subrange range(begin, end);
554 Subranges::const_iterator si = _subranges.lower_bound(range);
555 if (si != _subranges.end() && begin >= (*si)._begin) {
556 return true;
557 }
558
559 return false;
560}
561
562/**
563 * Removes from this array all of the elements that do not appear in the other
564 * one.
565 */
566void SparseArray::
567do_intersection(const SparseArray &other) {
568 if (_subranges.empty()) {
569 return;
570 }
571 if (other._subranges.empty()) {
572 _subranges.clear();
573 return;
574 }
575
576 int my_begin = (*_subranges.begin())._begin;
577 int other_begin = (*other._subranges.begin())._begin;
578 do_remove_range(my_begin, other_begin);
579
580 for (size_t i = 0; i < other._subranges.size() - 1; ++i) {
581 do_remove_range(other._subranges[i]._end, other._subranges[i + 1]._begin);
582 }
583
584 int my_end = (*(_subranges.begin() + _subranges.size() - 1))._end;
585 int other_end = (*(other._subranges.begin() + other._subranges.size() - 1))._end;
586 do_remove_range(other_end, my_end);
587}
588
589/**
590 * Adds to this array all of the elements that also appear in the other one.
591 */
592void SparseArray::
593do_union(const SparseArray &other) {
594 Subranges::const_iterator si;
595 for (si = other._subranges.begin(); si != other._subranges.end(); ++si) {
596 do_add_range((*si)._begin, (*si)._end);
597 }
598}
599
600/**
601 * Removes from this array all of the elements that also appear in the other
602 * one.
603 */
604void SparseArray::
605do_intersection_neg(const SparseArray &other) {
606 Subranges::const_iterator si;
607 for (si = other._subranges.begin(); si != other._subranges.end(); ++si) {
608 do_remove_range((*si)._begin, (*si)._end);
609 }
610}
611
612/**
613 * Shifts all the elements in the array by the indicated amount.
614 */
615void SparseArray::
616do_shift(int offset) {
617 if (offset != 0) {
618 Subranges::iterator si;
619 for (si = _subranges.begin(); si != _subranges.end(); ++si) {
620 (*si)._begin += offset;
621 (*si)._end += offset;
622 }
623 }
624}
625
626/**
627 * Writes the contents of this object to the datagram for shipping out to a
628 * Bam file.
629 */
631write_datagram(BamWriter *manager, Datagram &dg) const {
632 dg.add_uint32(_subranges.size());
633 Subranges::const_iterator si;
634 for (si = _subranges.begin(); si != _subranges.end(); ++si) {
635 dg.add_int32((*si)._begin);
636 dg.add_int32((*si)._end);
637 }
638 dg.add_bool(_inverse);
639}
640
641/**
642 * Reads the object that was previously written to a Bam file.
643 */
646 size_t num_subranges = scan.get_uint32();
647 _subranges.reserve(num_subranges);
648 for (size_t i = 0; i < num_subranges; ++i) {
649 int begin = scan.get_int32();
650 int end = scan.get_int32();
651 _subranges.push_back(Subrange(begin, end));
652 }
653 _inverse = scan.get_bool();
654}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition bamWriter.h:63
A dynamic array with an unlimited number of bits.
Definition bitArray.h:40
bool get_highest_bits() const
Returns true if the infinite set of bits beyond get_num_bits() are all on, or false of they are all o...
Definition bitArray.I:163
size_t get_num_bits() const
Returns the current number of possibly different bits in this array.
Definition bitArray.I:89
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
Definition bitArray.I:99
A class to retrieve the individual data elements previously stored in a Datagram.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
bool get_bool()
Extracts a boolean value.
int32_t get_int32()
Extracts a signed 32-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition datagram.I:94
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
Definition datagram.I:67
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition datagram.I:34
This class records a set of integers, where each integer is either present or not present in the set.
Definition sparseArray.h:43
int get_highest_on_bit() const
Returns the index of the highest 1 bit in the array.
int get_num_off_bits() const
Returns the number of bits that are set to 0 in the array.
void write_datagram(BamWriter *manager, Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
void read_datagram(DatagramIterator &scan, BamReader *manager)
Reads the object that was previously written to a Bam file.
int get_lowest_on_bit() const
Returns the index of the lowest 1 bit in the array.
int get_lowest_off_bit() const
Returns the index of the lowest 0 bit in the array.
bool has_bits_in_common(const SparseArray &other) const
Returns true if this SparseArray has any "one" bits in common with the other one, false otherwise.
int compare_to(const SparseArray &other) const
Returns a number less than zero if this SparseArray sorts before the indicated other SparseArray,...
static SparseArray range(int low_bit, int size)
Returns a SparseArray whose size bits, beginning at low_bit, are on.
Definition sparseArray.I:65
int get_highest_off_bit() const
Returns the index of the highest 0 bit in the array.
bool is_zero() const
Returns true if the entire bitmask is zero, false otherwise.
int get_num_on_bits() const
Returns the number of bits that are set to 1 in the array.
int get_next_higher_different_bit(int low_bit) const
Returns the index of the next bit in the array, above low_bit, whose value is different that the valu...
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
reverse_iterator_0 rend()
Returns the iterator that marks the end of the ordered vector, when viewed in reverse order.
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
reverse_iterator_0 rbegin()
Returns the iterator that marks the first element in the ordered vector, when viewed in reverse order...
size_type_0 size() const
Returns the number of elements in the ordered vector.
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.