All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
compressedBits.h
1//
2// Copyright 2024 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_BASE_TF_COMPRESSED_BITS_H
8#define PXR_BASE_TF_COMPRESSED_BITS_H
9
10#include "pxr/base/arch/align.h"
11#include "pxr/base/tf/api.h"
13#include "pxr/base/tf/hash.h"
16
17#include <algorithm>
18#include <cstdint>
19#include <string>
20#include <type_traits>
21#include <vector>
22
23PXR_NAMESPACE_OPEN_SCOPE
24
27class TfBits;
28
61{
62private:
63 // Type of one word stored in the word array
64 typedef uint32_t _WordType;
65
66 // Lightweight, re-allocating array type optimized for native, word data.
67 //
68 // Note, this is not a std::vector, because we really want a container,
69 // which is optimized for native types, allowing fast memcpy capabilities,
70 // and providing local storage optimizations.
71 class _WordArray
72 {
73 public:
74 static const uint32_t LOCAL_SIZE = 6;
75
76 _WordArray() :
77 _data(_local),
78 _numAllocated(LOCAL_SIZE),
79 _num(0) {}
80
81 _WordArray(const _WordArray &rhs) :
82 _data(_local),
83 _numAllocated(LOCAL_SIZE),
84 _num(rhs._num) {
85 _Duplicate(rhs);
86 }
87
88 ~_WordArray() {
89 _Deallocate();
90 }
91
92 _WordArray& operator=(const _WordArray &rhs) {
93 if (this == &rhs) {
94 return *this;
95 }
96
97 _Duplicate(rhs);
98 return *this;
99 }
100
101 // Clear all words
102 void Clear() {
103 _num = 0;
104 }
105
106 // Add a word (may cause re-allocation)
107 void PushBack(_WordType value) {
108 // Reallocate?
109 if (_num >= _numAllocated) {
110 _Reallocate();
111 }
112
113 // PushBack
114 _data[_num] = value;
115 ++_num;
116 }
117
118 // Remove a word
119 void PopBack() {
120 --_num;
121 }
122
123 // Remove multiple words
124 void PopBackNum(uint32_t popNum) {
125 _num -= popNum;
126 }
127
128 // Move this representation into rhs. This representation will be
129 // invalid after this operation.
130 void MoveInto(_WordArray &rhs) {
131 rhs._numAllocated = _numAllocated;
132 rhs._num = _num;
133
134 rhs._Deallocate();
135
136 // If the data is stored locally, copy it
137 if (_IsStoredLocally()) {
138 // The compiler will unroll this loop, making this faster
139 // than memcpy!
140 for (size_t i = 0; i < LOCAL_SIZE; ++i) {
141 rhs._data[i] = _data[i];
142 }
143 }
144
145 // Otherwise, just assign pointers
146 else {
147 rhs._data = _data;
148
149 // Set our pointer back to local, so we won't deallocate the
150 // storage, which is now owned by rhs.
151 _data = _local;
152 _numAllocated = LOCAL_SIZE;
153 }
154 }
155
156 // Swap two representations
157 void Swap(_WordArray &rhs) {
158 if (!_IsStoredLocally() && !rhs._IsStoredLocally()) {
159 std::swap(_data, rhs._data);
160 std::swap(_numAllocated, rhs._numAllocated);
161 std::swap(_num, rhs._num);
162 } else {
163 // Fall back to a copy. This could be optimized.
164 std::swap(*this, rhs);
165 }
166 }
167
168 // Index operator
169 _WordType &operator[](size_t index) {
170 return _data[index];
171 }
172
173 const _WordType &operator[](size_t index) const {
174 return _data[index];
175 }
176
177 // Returns the number of words stored (not allocated)
178 uint32_t GetNum() const {
179 return _num;
180 }
181
182 // Return the number of allocated words
183 uint32_t GetNumAllocated() const {
184 return _numAllocated;
185 }
186
187 // Return a pointer to the first word
188 const _WordType *Begin() const {
189 return _data;
190 }
191
192 // Return a pointer one past the end of the array.
193 const _WordType *End() const {
194 return _data + _num;
195 }
196
197 // Returns the first word
198 _WordType &Front() {
199 return _data[0];
200 }
201
202 const _WordType &Front() const {
203 return _data[0];
204 }
205
206 // Returns the last word
207 _WordType &Back() {
208 return _data[_num - 1];
209 }
210
211 const _WordType &Back() const {
212 return _data[_num - 1];
213 }
214
215 private:
216 bool _IsStoredLocally() const {
217 return _data == _local;
218 }
219
220 void _Deallocate() {
221 if (!_IsStoredLocally()) {
222 delete[] _data;
223 _data = _local;
224 }
225 }
226
227 void _Duplicate(const _WordArray &rhs) {
228 if (rhs._num > 0) {
229 if (_numAllocated < rhs._num) {
230 _Deallocate();
231 _data = new _WordType[rhs._numAllocated];
232 _numAllocated = rhs._numAllocated;
233 }
234
235 if (rhs._IsStoredLocally()) {
236 // The compiler will unroll this loop, making this faster
237 // than memcpy!
238 for (size_t i = 0; i < LOCAL_SIZE; ++i) {
239 _data[i] = rhs._data[i];
240 }
241 } else {
242 memcpy(_data, rhs._data, sizeof(_WordType) * rhs._num);
243 }
244 }
245
246 _num = rhs._num;
247 }
248
249 void _Reallocate() {
250 _numAllocated <<= 1;
251 _WordType *newData = new _WordType[_numAllocated];
252 memcpy(newData, _data, sizeof(_WordType) * _num);
253 _Deallocate();
254 _data = newData;
255 }
256
257 // Pointer to the data
258 _WordType *_data;
259
260 // Local storage optimization
261 _WordType _local[LOCAL_SIZE];
262
263 // Number of words allocated
264 uint32_t _numAllocated;
265
266 // Number of words stored
267 uint32_t _num;
268 };
269
270public:
271
272 // View and iterator modes: All bits, all set bits, all unset bits,
273 // platforms (iterator provides platform size and value)
274 enum class Mode { All, AllSet, AllUnset, Platforms };
275
282 struct Hash {
283 size_t operator()(const TfCompressedBits &bits) const {
284 return bits.GetHash();
285 }
286 };
287
294 struct FastHash {
295 size_t operator()(const TfCompressedBits &bits) const {
296 if (bits.GetSize() == 0) {
297 return 0;
298 }
299
300 // Hash the running bit and number of platforms.
301 size_t hash = TfHash::Combine(
302 bits.GetSize(),
303 bits._runningBit,
304 bits._platforms.GetNum());
305
306 // Hash a single cache line of platform data.
307 const uint32_t n = std::min<uint32_t>(
308 bits._platforms.GetNum(),
309 ARCH_CACHE_LINE_SIZE / sizeof(uint32_t));
310 for (uint32_t i = 0; i < n; ++i) {
311 hash = TfHash::Combine(hash, bits._platforms[i]);
312 }
313
314 return hash;
315 }
316 };
317
320 explicit TfCompressedBits(size_t num = 0) :
321 _num(num),
322 _runningBit(0) {
323 _platforms.PushBack(num);
324 }
325
328 explicit TfCompressedBits(size_t num, size_t first, size_t last) :
329 _num(num),
330 _runningBit(0) {
331
332 // Empty bitset
333 if (num == 0) {
334 _platforms.PushBack(0);
335 return;
336 }
337
338 // Range error (clear the whole bitset):
339 if (!TF_VERIFY(first < num && last < num && first <= last)) {
340 _platforms.PushBack(num);
341 return;
342 }
343
344 size_t trailingZeroes = 0;
345 const size_t range = last - first + 1;
346 if (first == 0) {
347 _runningBit = 1;
348 _platforms.PushBack(range);
349 trailingZeroes = num - range;
350 } else {
351 _platforms.PushBack(first);
352 _platforms.PushBack(range);
353 trailingZeroes = num - last - 1;
354 }
355
356 // Only push trailing zeroes, if there are any. Otherwise the
357 // _platforms array will be in an inconsistent state (containing
358 // platforms of size 0, when _num != 0).
359 if (trailingZeroes != 0) {
360 _platforms.PushBack(trailingZeroes);
361 }
362 }
363
367 _platforms(rhs._platforms),
368 _num(rhs._num),
369 _runningBit(rhs._runningBit) {}
370
374 enum ComplementTagType { ComplementTag };
376 _platforms(rhs._platforms),
377 _num(rhs._num),
378 _runningBit(1 - rhs._runningBit) {
379 if (_num == 0) {
380 _runningBit = 0;
381 }
382 }
383
386 TF_API
387 explicit TfCompressedBits(const TfBits &bits);
388
392 _num(rhs._num),
393 _runningBit(rhs._runningBit) {
394 rhs._platforms.MoveInto(_platforms);
395 rhs._platforms.Clear();
396 rhs._num = 0;
397 rhs._runningBit = 0;
398 }
399
403
407 if (this == &rhs) {
408 return *this;
409 }
410
411 _platforms = rhs._platforms;
412 _num = rhs._num;
413 _runningBit = rhs._runningBit;
414
415 return *this;
416 }
417
421 if (this == &rhs) {
422 return *this;
423 }
424
425 _num = rhs._num;
426 _runningBit = rhs._runningBit;
427 rhs._platforms.MoveInto(_platforms);
428 rhs._platforms.Clear();
429 rhs._num = 0;
430 rhs._runningBit = 0;
431
432 return *this;
433 }
434
437 void ResizeKeepContents(size_t num) {
438 if (_num == num) {
439 return;
440 }
441
442 // Reduce size to 0
443 if (num == 0) {
444 _platforms.Clear();
445 _platforms.PushBack(0);
446 _runningBit = 0;
447 _num = 0;
448 return;
449 }
450
451 // Grow
452 if (_num < num) {
453 if ((UINT32_C(1) - _runningBit) ==
454 (_platforms.GetNum() & UINT32_C(1))) {
455 _platforms.Back() += (num - _num);
456 } else {
457 _platforms.PushBack(num - _num);
458 }
459 }
460
461 // Shrink
462 else if (_num > num) {
463 uint32_t diff = _num - num;
464 while (_platforms.Back() <= diff) {
465 diff -= _platforms.Back();
466 _platforms.PopBack();
467 }
468 _platforms.Back() -= diff;
469 }
470
471 _num = num;
472 }
473
477 std::swap(_num, rhs._num);
478 std::swap(_runningBit, rhs._runningBit);
479 _platforms.Swap(rhs._platforms);
480 }
481
484 void ClearAll() {
485 if (_num <= 0 || (_runningBit == 0 && _platforms.GetNum() == 1)) {
486 return;
487 }
488
489 _runningBit = 0;
490 _platforms.Clear();
491 _platforms.PushBack(_num);
492 }
493
496 void SetAll() {
497 if (_num <= 0 || (_runningBit == 1 && _platforms.GetNum() == 1)) {
498 return;
499 }
500
501 _runningBit = 1;
502 _platforms.Clear();
503 _platforms.PushBack(_num);
504 }
505
510 void Clear(size_t index) {
511 if (!TF_VERIFY(index < _num)) {
512 return;
513 }
514
515 TfCompressedBits tmp(_num, index, index);
516 tmp.Complement();
517 *this &= tmp;
518 }
519
524 void Set(size_t index) {
525 if (!TF_VERIFY(index < _num)) {
526 return;
527 }
528
529 TfCompressedBits tmp(_num, index, index);
530 *this |= tmp;
531 }
532
537 void SetRange(size_t first, size_t last) {
538 // Range constructor does error checking
539 TfCompressedBits tmp(_num, first, last);
540 *this |= tmp;
541 }
542
546 void Append(size_t num, bool value) {
547 if (num == 0) {
548 return;
549 }
550
551 if (_num == 0) {
552 _platforms[0] = num;
553 _runningBit = value;
554 _num = num;
555 return;
556 }
557
558 const bool lastValue = _runningBit == (_platforms.GetNum() & 1);
559 if (value == lastValue) {
560 _platforms.Back() += num;
561 } else {
562 _platforms.PushBack(num);
563 }
564
565 _num += num;
566 }
567
570 void Assign(size_t index, bool value) {
571 if (value) {
572 Set(index);
573 } else {
574 Clear(index);
575 }
576 }
577
581 void ShiftRight(size_t bits) {
582 if (_num == 0 || bits == 0) {
583 return;
584 }
585
586 // If the running bit is 0, just increment the first word (num zeroes)
587 if (_runningBit == 0) {
588 _platforms.Front() += bits;
589 }
590
591 // If the running bit is 1, shift all the _platforms to the right and
592 // flip the running bit. Set the first platform (num zeroes) to the
593 // number of bits shifted.
594 else {
595 _runningBit = 0;
596 _platforms.PushBack(0);
597 for (size_t i = _platforms.GetNum() - 1; i > 0; --i) {
598 _platforms[i] = _platforms[i - 1];
599 }
600 _platforms[0] = bits;
601 }
602
603 // Now trim the _platforms on the right
604 while (_platforms.Back() <= bits) {
605 bits -= _platforms.Back();
606 _platforms.PopBack();
607 }
608 _platforms.Back() -= bits;
609 }
610
614 void ShiftLeft(size_t bits) {
615 if (_num == 0 || bits == 0) {
616 return;
617 }
618
619 // How many platforms to trim on the left?
620 size_t trimBits = bits;
621 size_t platformIndex = 0;
622 while (platformIndex < _platforms.GetNum() &&
623 _platforms[platformIndex] <= trimBits) {
624 trimBits -= _platforms[platformIndex];
625 ++platformIndex;
626 }
627
628 // Reduce the size of the first platform or, if the shift clears the
629 // whole bitset, remove all platforms.
630 if (platformIndex < _platforms.GetNum()) {
631 _platforms[platformIndex] -= trimBits;
632 } else {
633 _platforms.Clear();
634 _runningBit = 0;
635 platformIndex = 0;
636 }
637
638 // Are there any platforms to be trimmed on the left?
639 if (platformIndex > 0) {
640 // Shift the platforms to the left, by the number of
641 // platforms trimmed
642 const size_t last = _platforms.GetNum() - platformIndex;
643 for (size_t i = 0; i < last; ++i) {
644 _platforms[i] = _platforms[i + platformIndex];
645 }
646 _platforms.PopBackNum(platformIndex);
647
648 // Flip the running bit, if necessary
649 if (platformIndex & 1) {
650 _runningBit = 1 - _runningBit;
651 }
652 }
653
654 // Extend on the right, by adding zeros, if the last platform
655 // is zeros ...
656 if ((UINT32_C(1) - _runningBit) ==
657 (_platforms.GetNum() & UINT32_C(1))) {
658 _platforms.Back() += bits;
659 return;
660 }
661
662 // ... or adding a new platform with zeros, if the last platform
663 // is ones
664 _platforms.PushBack(std::min<_WordType>(_num, bits));
665 }
666
672 bool IsSet(size_t index) const {
673 if (!TF_VERIFY(index < _num)) {
674 return false;
675 }
676
677 size_t platformIndex, bitCount;
678 return _LinearSearch(index, &platformIndex, &bitCount) == 1;
679 }
680
690 size_t FindNthSet(size_t nth) const {
691 size_t index = 0;
692 size_t count = 0;
693 uint8_t bit = _runningBit;
694
695 // Iterate over all platforms to find the nth set bit using a running
696 // count of set bits, and an up-to-date index into the bitset.
697 for (size_t i = 0; i < _platforms.GetNum(); ++i) {
698 const _WordType platform = _platforms[i];
699
700 // Since bit toggles between 1 and 0 for every iteration of the
701 // loop, using it in a conditional guarantees a misprediction every
702 // time. Doing the multiplication instead is cheap and doesn't
703 // change the result of the conditional until we find the right
704 // index.
705 if (((count + platform) * bit) > nth) {
706 return index + (nth - count);
707 }
708
709 index += platform;
710 count += (platform * bit);
711 bit = 1 - bit;
712 }
713
714 // Less than nth bits are set, so return the size.
715 return _num;
716 }
717
724 size_t FindNextSet(size_t index) const
725 {
726 if (index >= _num) {
727 return _num;
728 }
729
730 size_t platformIndex, bitCount;
731 const uint8_t bit = _LinearSearch(index, &platformIndex, &bitCount);
732
733 if (bit == 1) {
734 return index;
735 }
736
737 return bitCount;
738 }
739
746 size_t FindPrevSet(size_t index) const
747 {
748 if (index >= _num) {
749 return _num;
750 }
751
752 size_t platformIndex, bitCount;
753 const uint8_t bit = _LinearSearch(index, &platformIndex, &bitCount);
754
755 if (bit == 1) {
756 return index;
757 }
758
759 const size_t first = bitCount - _platforms[platformIndex];
760 if (first > 0) {
761 return first - 1;
762 }
763
764 return _num;
765 }
766
773 size_t FindNextUnset(size_t index) const
774 {
775 if (index >= _num) {
776 return _num;
777 }
778
779 size_t platformIndex, bitCount;
780 const uint8_t bit = _LinearSearch(index, &platformIndex, &bitCount);
781
782 if (bit == 0) {
783 return index;
784 }
785
786 return bitCount;
787 }
788
791 void Count(size_t *numSet, size_t *maxGap) const {
792 const uint32_t lastIndex = _platforms.GetNum() - 1;
793 uint32_t num = 0;
794 uint32_t max = 0;
795 uint8_t bit = _runningBit;
796 for (size_t i = 0; i < _platforms.GetNum(); ++i) {
797 // Accumulate set bits.
798 if (bit == 1) {
799 num += _platforms[i];
800 }
801 // Don't account the leading and trailing zeros as gaps.
802 else if (i > 0 && i < lastIndex) {
803 max = std::max(max, _platforms[i]);
804 }
805 bit = 1 - bit;
806 }
807 *numSet = num;
808 *maxGap = max;
809 }
810
813 size_t GetSize() const {
814 return _num;
815 }
816
819 bool IsEmpty() const {
820 return _num == 0;
821 }
822
826 size_t GetFirstSet() const {
827 if (_num == 0 || _runningBit == 1) {
828 return 0;
829 }
830
831 return _platforms.Front();
832 }
833
837 size_t GetLastSet() const {
838 // Zero size or all zeros case
839 if (_num == 0 || (_runningBit == 0 && _platforms.GetNum() == 1)) {
840 return _num;
841 }
842
843 // If _runningBit == 1 and number of words is odd or
844 // _runningBit == 0 and number of words is even
845 if (_runningBit == (_platforms.GetNum() & 1)) {
846 return _num - 1;
847 }
848
849 return _num - 1 - _platforms.Back();
850 }
851
854 size_t GetNumSet() const {
855 size_t numSet = 0;
856 for (size_t i = 1 - _runningBit; i < _platforms.GetNum(); i += 2) {
857 numSet += _platforms[i];
858 }
859 return numSet;
860 }
861
864 size_t GetNumPlatforms() const {
865 if (_num == 0) {
866 return 0;
867 }
868
869 return _platforms.GetNum();
870 }
871
874 size_t GetNumSetPlatforms() const {
875 if (_num == 0) {
876 return 0;
877 }
878
879 const uint32_t numP = _platforms.GetNum();
880 return (numP / 2) + (numP & _runningBit);
881 }
882
885 size_t GetNumUnsetPlatforms() const {
886 if (_num == 0) {
887 return 0;
888 }
889
890 const uint32_t numP = _platforms.GetNum();
891 return (numP / 2) + (numP & (1 - _runningBit));
892 }
893
896 bool AreAllSet() const {
897 return _num == 0 || (_runningBit == 1 && _platforms.GetNum() == 1);
898 }
899
902 bool AreAllUnset() const {
903 return !IsAnySet();
904 }
905
908 bool IsAnySet() const {
909 return _num > 0 && (_runningBit == 1 || _platforms.GetNum() > 1);
910 }
911
914 bool IsAnyUnset() const {
915 return _num > 0 && (_runningBit == 0 || _platforms.GetNum() > 1);
916 }
917
922 bool AreContiguouslySet() const {
923 const uint32_t numP = _platforms.GetNum();
924 return
925 _num > 0 && numP <= 3 &&
926 (numP == 2 ||
927 (_runningBit == 1 && numP == 1) ||
928 (_runningBit == 0 && numP == 3));
929 }
930
933 size_t GetAllocatedSize() const
934 {
935 size_t size = sizeof(TfCompressedBits);
936 if (_platforms.GetNumAllocated() > _WordArray::LOCAL_SIZE) {
937 size += sizeof(_WordType) * _platforms.GetNumAllocated();
938 }
939 return size;
940 }
941
944 TF_API
945 size_t GetHash() const;
946
950 TF_API
951 std::string GetAsStringLeftToRight() const;
952
956 TF_API
957 std::string GetAsStringRightToLeft() const;
958
962 TF_API
963 std::string GetAsRLEString() const;
964
978 TF_API
979 static TfCompressedBits FromString(const std::string &source);
980
983
986 bool operator==(const TfCompressedBits &rhs) const {
987 if (this == &rhs || (_num == 0 && rhs._num == 0)) {
988 return true;
989 }
990
991 // Fast comparisons, first
992 if (_num == rhs._num &&
993 _runningBit == rhs._runningBit &&
994 _platforms.GetNum() == rhs._platforms.GetNum()) {
995
996 // Worst case, scenario: Must compare every word
997 for (size_t i = 0; i < _platforms.GetNum(); ++i) {
998 // Early bailout, if two words don't match
999 if (_platforms[i] != rhs._platforms[i]) {
1000 return false;
1001 }
1002 }
1003
1004 // All words match
1005 return true;
1006 }
1007
1008 // Early comparison failed
1009 return false;
1010 }
1011
1014 bool operator!=(const TfCompressedBits &rhs) const {
1015 return !(*this == rhs);
1016 }
1017
1023 if (!TF_VERIFY(_num == rhs._num) ||
1024 _num == 0 || rhs._num == 0) {
1025 return *this;
1026 }
1027
1028 const uint32_t numA = _platforms.GetNum();
1029 const uint32_t numB = rhs._platforms.GetNum();
1030 const uint8_t bitA = _runningBit;
1031 const uint8_t bitB = rhs._runningBit;
1032
1033 // Early bailout: This is all zeroes or all ones
1034 if (numA == 1) {
1035 if (bitA == 0) {
1036 return *this;
1037 }
1038
1039 _runningBit = bitB;
1040 _platforms = rhs._platforms;
1041 return *this;
1042 }
1043
1044 // Early bailout: Rhs is all zeroes or all ones
1045 if (numB == 1) {
1046 if (bitB == 1) {
1047 return *this;
1048 }
1049
1050 ClearAll();
1051 return *this;
1052 }
1053
1054 // Early bailout: No bits will overlap, if sets are disjoint
1055 if (_AreBoundsDisjoint(rhs)) {
1056 ClearAll();
1057 return *this;
1058 }
1059
1060 return _Logical<_And>(bitB, rhs._platforms);
1061 }
1062
1066 TfCompressedBits r(*this);
1067 r &= rhs;
1068 return r;
1069 }
1070
1076 if (!TF_VERIFY(_num == rhs._num) ||
1077 _num == 0 || rhs._num == 0) {
1078 return *this;
1079 }
1080
1081 const uint32_t numA = _platforms.GetNum();
1082 const uint32_t numB = rhs._platforms.GetNum();
1083 const uint8_t bitA = _runningBit;
1084 const uint8_t bitB = rhs._runningBit;
1085
1086 // Early bailout: This is all zeroes or all ones
1087 if (numA == 1) {
1088 if (bitA == 1) {
1089 return *this;
1090 }
1091
1092 _runningBit = bitB;
1093 _platforms = rhs._platforms;
1094 return *this;
1095 }
1096
1097 // Early bailout: Rhs is all zeroes or all ones
1098 if (numB == 1) {
1099 if (bitB == 0) {
1100 return *this;
1101 }
1102
1103 SetAll();
1104 return *this;
1105 }
1106
1107 // If this set already contains all the bits in rhs, there is no
1108 // point in proceeding with the full logical OR. Note, that although
1109 // this operation needs to look at all the platforms, it only performs
1110 // reads from memory, which makes it faster than the logical OR. If
1111 // this check fails, the data is already prefetched and ready to be
1112 // consumed by the logical OR.
1113 if (Contains(rhs)) {
1114 return *this;
1115 }
1116
1117 return _Logical<_Or>(bitB, rhs._platforms);
1118 }
1119
1123 TfCompressedBits r(*this);
1124 r |= rhs;
1125 return r;
1126 }
1127
1134 if (!TF_VERIFY(_num == rhs._num) ||
1135 _num == 0 || rhs._num == 0) {
1136 return *this;
1137 }
1138
1139 // Early bailout: This is all zeroes
1140 if (AreAllUnset()) {
1141 *this = rhs;
1142 return *this;
1143 }
1144
1145 // Early bailout: Rhs is all zeroes
1146 if (rhs.AreAllUnset()) {
1147 return *this;
1148 }
1149
1150 return _Logical<_Xor>(rhs._runningBit, rhs._platforms);
1151 }
1152
1156 TfCompressedBits r(*this);
1157 r ^= rhs;
1158 return r;
1159 }
1160
1167 if (!TF_VERIFY(_num == rhs._num) ||
1168 _num == 0 || rhs._num == 0) {
1169 return *this;
1170 }
1171
1172 const uint32_t numA = _platforms.GetNum();
1173 const uint32_t numB = rhs._platforms.GetNum();
1174 const uint8_t bitA = _runningBit;
1175 const uint8_t bitB = rhs._runningBit;
1176
1177 // Early bailout: This is all zeroes or all ones
1178 if (numA == 1) {
1179 if (bitA == 0) {
1180 return *this;
1181 }
1182
1183 _runningBit = 1 - bitB;
1184 _platforms = rhs._platforms;
1185 return *this;
1186 }
1187
1188 // Early bailout: Rhs is all zeroes or all ones
1189 if (numB == 1) {
1190 if (bitB == 0) {
1191 return *this;
1192 }
1193
1194 ClearAll();
1195 return *this;
1196 }
1197
1198 // Early bailout: No bits will be subtracted, if sets are disjoint.
1199 // Note, that although this operation needs to look at all the
1200 // platforms, it only performs reads from memory, which makes it faster
1201 // than the logical AND. If this check fails, the data is already
1202 // prefetched and ready to be consumed by the logical AND.
1203 if (_AreBoundsDisjoint(rhs) || !HasNonEmptyIntersection(rhs)) {
1204 return *this;
1205 }
1206
1207 return _Logical<_And>(1 - bitB, rhs._platforms);
1208 }
1209
1213 TfCompressedBits r(*this);
1214 r -= rhs;
1215 return r;
1216 }
1217
1223 if (_num != 0) {
1224 _runningBit = 1 - _runningBit;
1225 }
1226 return *this;
1227 }
1228
1233 bool operator[](size_t index) const {
1234 return IsSet(index);
1235 }
1236
1240 ShiftRight(bits);
1241 return *this;
1242 }
1243
1246 TfCompressedBits operator>>(size_t bits) const {
1247 TfCompressedBits r(*this);
1248 r >>= bits;
1249 return r;
1250 }
1251
1255 ShiftLeft(bits);
1256 return *this;
1257 }
1258
1261 TfCompressedBits operator<<(size_t bits) const {
1262 TfCompressedBits r(*this);
1263 r <<= bits;
1264 return r;
1265 }
1266
1268
1269
1277 if (!TF_VERIFY(_num == rhs._num) ||
1278 _num == 0 || rhs._num == 0) {
1279 return false;
1280 }
1281
1282 uint8_t bitA = _runningBit;
1283 uint8_t bitB = rhs._runningBit;
1284 if (bitA & bitB) {
1285 return true;
1286 }
1287
1288 const uint32_t numA = _platforms.GetNum();
1289 const uint32_t numB = rhs._platforms.GetNum();
1290 if (numA == 1) {
1291 if (bitA == 0) {
1292 return false;
1293 }
1294
1295 return rhs.IsAnySet();
1296 }
1297
1298 if (numB == 1) {
1299 if (bitB == 0) {
1300 return false;
1301 }
1302
1303 return IsAnySet();
1304 }
1305
1306 // We can bail out early if the ranges of set bits do not overlap
1307 if (_AreBoundsDisjoint(rhs)) {
1308 return false;
1309 }
1310
1311 return _HasLogical<_And>(bitB, rhs._platforms);
1312 }
1313
1320 if (!TF_VERIFY(_num == rhs._num) ||
1321 _num == 0 || rhs._num == 0) {
1322 return false;
1323 }
1324
1325 uint8_t bitA = _runningBit;
1326 uint8_t bitB = rhs._runningBit;
1327 if (bitA && !bitB) {
1328 return true;
1329 }
1330
1331 const uint32_t numA = _platforms.GetNum();
1332 const uint32_t numB = rhs._platforms.GetNum();
1333 if (numA == 1) {
1334 if (bitA == 0) {
1335 return false;
1336 }
1337
1338 return rhs.IsAnyUnset();
1339 }
1340
1341 if (numB == 1) {
1342 if (bitB == 0) {
1343 return IsAnySet();
1344 }
1345
1346 return false;
1347 }
1348
1349 // We can bail out early, if the ranges of set bits do not overlap.
1350 // Check the first set bits first, because checking for the last set
1351 // bit is more expensive.
1352 const size_t firstSet = GetFirstSet();
1353 const size_t rhsFirstSet = rhs.GetFirstSet();
1354 if (firstSet < rhsFirstSet) {
1355 return true;
1356 }
1357
1358 // If we still haven't bailed out yet, check the last set bit.
1359 const size_t lastSet = GetLastSet();
1360 const size_t rhsLastSet = rhs.GetLastSet();
1361 if (lastSet > rhsLastSet ||
1362 firstSet > rhsLastSet ||
1363 lastSet < rhsFirstSet) {
1364 return true;
1365 }
1366
1367 return _HasLogical<_And>(1 - bitB, rhs._platforms);
1368 }
1369
1375 bool Contains(const TfCompressedBits &rhs) const {
1376 return !rhs.HasNonEmptyDifference(*this);
1377 }
1378
1381 static const TfCompressedBits &GetEmpty() {
1382 static TfStaticData<TfCompressedBits> emptyBits;
1383 return *emptyBits;
1384 }
1385
1388 TF_API
1389 void Decompress(TfBits *bits) const;
1390
1393 template <Mode mode>
1394 class View;
1395
1399 inline AllView GetAllView() const;
1400
1404 inline AllSetView GetAllSetView() const;
1405
1409 inline AllUnsetView GetAllUnsetView() const;
1410
1414 inline PlatformsView GetPlatformsView() const;
1415
1416private:
1417 // Functor for logical operation: AND
1418 struct _And {
1419 inline uint8_t operator() (uint8_t a, uint8_t b) {
1420 return a & b;
1421 }
1422 };
1423
1424 // Functor for logical operation: OR
1425 struct _Or {
1426 inline uint8_t operator() (uint8_t a, uint8_t b) {
1427 return a | b;
1428 }
1429 };
1430
1431 // Functor for logical operation: XOR
1432 struct _Xor {
1433 inline uint8_t operator() (uint8_t a, uint8_t b) {
1434 return a ^ b;
1435 }
1436 };
1437
1438 // This method performs a logical operation on the passed in running bit
1439 // and word array. OP denotes a functor implementing the logical operation.
1440 // The idea is that the compiler will be smart enough to inline the
1441 // operation, without actually having to call the function.
1442 template < class OP > TfCompressedBits &
1443 _Logical(uint8_t rhsRunningBit, const _WordArray &rhsPlatforms) {
1444 OP op;
1445
1446 const uint32_t numA = _platforms.GetNum();
1447 const uint32_t numB = rhsPlatforms.GetNum();
1448 uint8_t bitA = _runningBit;
1449 uint8_t bitB = rhsRunningBit;
1450
1451 uint8_t b = op(bitA, bitB);
1452 _WordArray result;
1453 _runningBit = b;
1454
1455 size_t indexA = 0;
1456 size_t indexB = 0;
1457 _WordType platformA = _platforms[indexA];
1458 _WordType platformB = rhsPlatforms[indexB];
1459
1460 uint32_t newTotal = 0;
1461 _WordType newPlatform = 0;
1462
1463 while (true) {
1464 if (platformA < platformB) {
1465 newTotal += platformA;
1466 newPlatform += platformA;
1467 bitA = 1 - bitA;
1468
1469 // Commit the new platform
1470 const uint8_t newBit = op(bitA, bitB);
1471 if (newBit != b) {
1472 result.PushBack(newPlatform);
1473 newPlatform = 0;
1474 b = newBit;
1475 }
1476
1477 // Move on to the next platform
1478 ++indexA;
1479 platformB = platformB - platformA;
1480 if (indexA == numA) {
1481 platformA = _num - newTotal;
1482 } else if (indexA < numA) {
1483 platformA = _platforms[indexA];
1484 }
1485
1486 } else if (platformA > platformB) {
1487 newTotal += platformB;
1488 newPlatform += platformB;
1489 bitB = 1 - bitB;
1490
1491 // Commit the new platform
1492 const uint8_t newBit = op(bitA, bitB);
1493 if (newBit != b) {
1494 result.PushBack(newPlatform);
1495 newPlatform = 0;
1496 b = newBit;
1497 }
1498
1499 // Move on to the next platform
1500 ++indexB;
1501 platformA = platformA - platformB;
1502 if (indexB == numB) {
1503 platformB = _num - newTotal;
1504 } else if(indexB < numB) {
1505 platformB = rhsPlatforms[indexB];
1506 }
1507
1508 } else {
1509 newTotal += platformA;
1510 newPlatform += platformA;
1511 bitA = 1 - bitA;
1512 bitB = 1 - bitB;
1513
1514 // Commit the new platform
1515 const uint8_t newBit = op(bitA, bitB);
1516 if (newBit != b || newTotal >= _num) {
1517 result.PushBack(newPlatform);
1518 newPlatform = 0;
1519 b = newBit;
1520 }
1521
1522 if (newTotal >= _num)
1523 break;
1524
1525 // Move on to the next platforms
1526 ++indexA;
1527 if (indexA == numA) {
1528 platformA = _num - newTotal;
1529 } else if (indexA < numA) {
1530 platformA = _platforms[indexA];
1531 }
1532
1533 ++indexB;
1534 if (indexB == numB) {
1535 platformB = _num - newTotal;
1536 } else if (indexB < numB) {
1537 platformB = rhsPlatforms[indexB];
1538 }
1539 }
1540 }
1541
1542 result.MoveInto(_platforms);
1543 return *this;
1544 }
1545
1546 // Performs a logical operation, but breaks out and returns true, as soon
1547 // as the logical operation returns true. If the logical operation never
1548 // returns true, false is returned.
1549 template < class OP > bool
1550 _HasLogical(uint8_t rhsRunningBit, const _WordArray &rhsPlatforms) const {
1551 OP op;
1552
1553 uint8_t bitA = _runningBit;
1554 uint8_t bitB = rhsRunningBit;
1555 const uint32_t numA = _platforms.GetNum();
1556 const uint32_t numB = rhsPlatforms.GetNum();
1557
1558 size_t indexA = 0;
1559 size_t indexB = 0;
1560 _WordType sumPlatformA = _platforms[indexA];
1561 _WordType sumPlatformB = rhsPlatforms[indexB];
1562 while (indexA < numA && indexB < numB) {
1563 if (op(bitA, bitB)) {
1564 return true;
1565 }
1566
1567 if (sumPlatformA < sumPlatformB) {
1568 bitA = 1 - bitA;
1569 ++indexA;
1570 sumPlatformA += _platforms[indexA];
1571
1572 } else if (sumPlatformA > sumPlatformB) {
1573 bitB = 1 - bitB;
1574 ++indexB;
1575 sumPlatformB += rhsPlatforms[indexB];
1576
1577 } else {
1578 bitA = 1 - bitA;
1579 bitB = 1 - bitB;
1580 ++indexA;
1581 ++indexB;
1582
1583 if (indexA >= numA || indexB >= numB) {
1584 return false;
1585 }
1586
1587 sumPlatformA += _platforms[indexA];
1588 sumPlatformB += rhsPlatforms[indexB];
1589 }
1590 }
1591
1592 return false;
1593 }
1594
1595 // Do a liner search for the bit index, returning its bit value.
1596 // Also returns the index of that bit in the word array, as well as the
1597 // bitCount denoting the number of bits counted up until the range that
1598 // terminates the current word, the index is found in.
1599 uint8_t _LinearSearch(
1600 size_t index, size_t *platformIndex, size_t *bitCount) const {
1601 uint8_t bit = _runningBit;
1602 size_t count = 0;
1603 size_t i;
1604
1605 for (i = 0; i < _platforms.GetNum(); ++i) {
1606 count += _platforms[i];
1607 if (count > index) {
1608 break;
1609 }
1610 bit = 1 - bit;
1611 }
1612
1613 *platformIndex = i;
1614 *bitCount = count;
1615 return bit;
1616 }
1617
1618 // Returns true if this bit array's bounds are disjoint from the bounds
1619 // of the rhs bit array. The two are considered disjoint if the last bit
1620 // set of array A is at a lower index than the first bit set on array B
1621 // (or vice versa).
1622 // Note, that the bit arrays may still be disjoint, even if this method
1623 // returns false, but if this method returns true, the bit arrays are
1624 // guaranteed to be disjoint. This is basically a very cheap early out for
1625 // the Overlaps() method.
1626 bool _AreBoundsDisjoint(const TfCompressedBits &rhs) const {
1627 return
1628 GetLastSet() < rhs.GetFirstSet() ||
1629 GetFirstSet() > rhs.GetLastSet();
1630 }
1631
1632 // The word array, storing the bit platforms.
1633 _WordArray _platforms;
1634
1635 // The size of this bit array in number of bits.
1636 uint32_t _num;
1637
1638 // The value of the running bit, indicating what the bit value of the first
1639 // word is.
1640 uint8_t _runningBit;
1641
1642};
1643
1644template <TfCompressedBits::Mode mode>
1646{
1647public:
1648 class const_iterator
1649 {
1650 public:
1651 using iterator_category = std::forward_iterator_tag;
1652 using value_type = const uint32_t;
1653 using reference = const uint32_t &;
1654 using pointer = const uint32_t *;
1655 using difference_type = const uint32_t;
1656
1657 const_iterator() :
1658 _bits(nullptr),
1659 _platformIndex(0),
1660 _bitIndex(0),
1661 _bitCounter(0),
1662 _value(0)
1663 {}
1664
1665 reference operator*() const { return dereference(); }
1666 pointer operator->() const { return &(dereference()); }
1667
1668 const_iterator& operator++() {
1669 increment();
1670 return *this;
1671 }
1672
1673 const_iterator operator++(int) {
1674 const_iterator r(*this);
1675 increment();
1676 return r;
1677 }
1678
1679 bool operator==(const const_iterator& rhs) const {
1680 return equal(rhs);
1681 }
1682
1683 bool operator!=(const const_iterator& rhs) const {
1684 return !equal(rhs);
1685 }
1686
1687 bool IsSet() const {
1688 return _value == 1;
1689 }
1690
1691 bool IsAtEnd() const {
1692 if (!_bits) {
1693 return true;
1694 }
1695 return _bitIndex >= _bits->GetSize();
1696 }
1697
1698 private:
1699 friend class View;
1700
1701 const_iterator(
1702 const TfCompressedBits *bits,
1703 uint32_t platformIndex,
1704 uint32_t bitIndex,
1705 uint8_t value) :
1706 _bits(bits),
1707 _platformIndex(platformIndex),
1708 _bitIndex(bitIndex),
1709 _bitCounter(0),
1710 _value(value)
1711 {}
1712
1713 bool equal(const const_iterator &rhs) const {
1714 return _bits == rhs._bits && _bitIndex == rhs._bitIndex;
1715 }
1716
1717 void increment() {
1718 // Note, this looks like quite a bit of logic, but mode is a
1719 // compile time constant. The compiler to the rescue!
1720 if (!_bits) {
1721 return;
1722 }
1723
1724 // Increment bit index
1725 ++_bitIndex;
1726
1727 // Increment bit counter (counting the current word)
1728 ++_bitCounter;
1729
1730 // If the bit counter surpasses the current word,
1731 // skip ahead to the next word
1732 if (_bitCounter >= _bits->_platforms[_platformIndex]) {
1733
1734 // If the iterator mode is not All, look at
1735 // every other word
1736 const uint32_t numP =
1737 _bits->_platforms.GetNum();
1738 if ((mode == Mode::AllSet || mode == Mode::AllUnset) &&
1739 (_platformIndex + 1) < numP) {
1740 _bitIndex += _bits->_platforms[_platformIndex + 1];
1741 _platformIndex += 2;
1742 }
1743
1744 // Otherwise, look at every word and toggle
1745 // the value bit
1746 else {
1747 ++_platformIndex;
1748 _value = 1 - _value;
1749 }
1750
1751 // Reset the bit counter
1752 _bitCounter = 0;
1753 }
1754 }
1755
1756 const uint32_t &dereference() const {
1757 return _bitIndex;
1758 }
1759
1760 const TfCompressedBits *_bits;
1761 uint32_t _platformIndex;
1762 uint32_t _bitIndex;
1763 uint32_t _bitCounter;
1764 uint8_t _value;
1765 };
1766
1767 // Support for TF_FOR_ALL.
1768 typedef const_iterator iterator;
1769
1770 const_iterator begin() const {
1771 const uint8_t bit = _bits->_runningBit;
1772
1773 // Skip ahead one word, if looking at AllSet/AllUnset and the
1774 // first word describes an unset/set platform of bits
1775 if ((mode == Mode::AllSet && bit == 0) ||
1776 (mode == Mode::AllUnset && bit == 1)) {
1777 return const_iterator(_bits, 1, _bits->_platforms[0], 1 - bit);
1778 }
1779
1780 return const_iterator(_bits, 0, 0, bit);
1781 }
1782
1783 const_iterator end() const {
1784 return const_iterator(_bits, 0, _bits->GetSize(), 0);
1785 }
1786
1789 bool IsEmpty() const {
1790 return begin() == end();
1791 }
1792
1793private:
1794
1795 // The TfCompressedBits can create new views.
1796 friend class TfCompressedBits;
1797
1798 // Ctor.
1799 View(const TfCompressedBits *bits) :
1800 _bits(bits)
1801 {}
1802
1803 const TfCompressedBits *_bits;
1804};
1805
1806// Specialize the platform view because its iterators are much simpler than
1807// the per-bit views.
1808template <>
1809class TfCompressedBits::View<TfCompressedBits::Mode::Platforms>
1810{
1811public:
1812 class const_iterator
1813 {
1814 public:
1815 using iterator_category = std::forward_iterator_tag;
1816 using value_type = const uint32_t;
1817 using reference = const uint32_t &;
1818 using pointer = const uint32_t *;
1819 using difference_type = const uint32_t;
1820
1821 const_iterator() :
1822 _platform(nullptr),
1823 _bitIndex(0),
1824 _value(0)
1825 {}
1826
1827 reference operator*() const { return dereference(); }
1828 pointer operator->() const { return &(dereference()); }
1829
1830 const_iterator& operator++() {
1831 increment();
1832 return *this;
1833 }
1834
1835 const_iterator operator++(int) {
1836 const_iterator r(*this);
1837 increment();
1838 return r;
1839 }
1840
1841 bool operator==(const const_iterator& rhs) const {
1842 return equal(rhs);
1843 }
1844
1845 bool operator!=(const const_iterator& rhs) const {
1846 return !equal(rhs);
1847 }
1848
1849 bool IsSet() const {
1850 return _value == 1;
1851 }
1852
1853 uint32_t GetPlatformSize() const {
1854 return *_platform;
1855 }
1856
1857 private:
1858 friend class View;
1859
1860 const_iterator(
1861 const uint32_t *platform,
1862 uint8_t value)
1863 : _platform(platform)
1864 , _bitIndex(0)
1865 , _value(value)
1866 {}
1867
1868 bool equal(const const_iterator &rhs) const {
1869 return _platform == rhs._platform;
1870 }
1871
1872 void increment() {
1873 _bitIndex += *_platform;
1874 ++_platform;
1875 _value = 1 - _value;
1876 }
1877
1878 const uint32_t &dereference() const {
1879 return _bitIndex;
1880 }
1881
1882 const uint32_t *_platform;
1883 uint32_t _bitIndex;
1884 uint8_t _value;
1885 };
1886
1887 const_iterator begin() const {
1888 return const_iterator(_bits->_platforms.Begin(), _bits->_runningBit);
1889 }
1890
1891 const_iterator end() const {
1892 return const_iterator(_bits->_platforms.End(), 0);
1893 }
1894
1897 bool IsEmpty() const {
1898 return begin() == end();
1899 }
1900
1901private:
1902
1903 // The TfCompressedBits can create new views.
1904 friend class TfCompressedBits;
1905
1906 // Ctor.
1907 View(const TfCompressedBits *bits) :
1908 _bits(bits)
1909 {}
1910
1911 const TfCompressedBits *_bits;
1912};
1913
1915TfCompressedBits::GetAllView() const
1916{
1917 return View<Mode::All>(this);
1918}
1919
1921TfCompressedBits::GetAllSetView() const
1922{
1923 return View<Mode::AllSet>(this);
1924}
1925
1927TfCompressedBits::GetAllUnsetView() const
1928{
1929 return View<Mode::AllUnset>(this);
1930}
1931
1933TfCompressedBits::GetPlatformsView() const
1934{
1935 return View<Mode::Platforms>(this);
1936}
1937
1938// Specializing, so TfIterator knows to retain a copy when iterating.
1939template<>
1940struct Tf_ShouldIterateOverCopy<TfCompressedBits::AllView> :
1941 std::true_type
1942{};
1943
1944template<>
1945struct Tf_ShouldIterateOverCopy<TfCompressedBits::AllSetView> :
1946 std::true_type
1947{};
1948
1949template<>
1950struct Tf_ShouldIterateOverCopy<TfCompressedBits::AllUnsetView> :
1951 std::true_type
1952{};
1953
1955// \ingroup group_tf_DebuggingOutput
1956inline std::ostream&
1957operator<<(std::ostream &out, const TfCompressedBits &bits) {
1958 out << bits.GetAsStringLeftToRight();
1959 return out;
1960}
1961
1962PXR_NAMESPACE_CLOSE_SCOPE
1963
1964#endif
Provide architecture-specific memory-alignment information.
Low-level utilities for informing users of various internal and external diagnostic conditions.
A simple iterator adapter for STL containers.
Fast bit array that keeps track of the number of bits set and can find the next set in a timely manne...
Definition: bits.h:49
Iterator support.
bool IsEmpty() const
Return true, if the view is empty.
Fast, compressed bit array which is capable of performing logical operations without first decompress...
void ShiftLeft(size_t bits)
Shift this bitset a given number of bits to the left, and extend the right with zeroes.
TfCompressedBits operator<<(size_t bits) const
Returns bits shifted to the left.
void SetAll()
Sets all bits to one.
size_t GetSize() const
Returns the size of the bit array, ie.
size_t FindNextUnset(size_t index) const
Finds the next unset bit that has a higher or equal index than index.
bool Contains(const TfCompressedBits &rhs) const
Returns true if this bit array contains rhs by computing: (rhs - this).GetNumSet() == 0.
bool AreAllSet() const
Returns true, if all the bits in this bit array are set.
size_t GetNumSetPlatforms() const
Returns the number of set (ones) platforms in this bitset.
TfCompressedBits operator&(const TfCompressedBits &rhs) const
Returns these bits and'ed with rhs.
TF_API std::string GetAsStringRightToLeft() const
Returns a string representing the bits for debugging with bits ordered from right to left with increa...
void SetRange(size_t first, size_t last)
Sets the bit within the range of first and last.
bool IsAnySet() const
Returns true, if there is at least a single set bit.
View< Mode::AllSet > AllSetView
Returns an iteratable view for the bits that steps over all set bits.
bool operator==(const TfCompressedBits &rhs) const
Returns true if this == rhs.
TfCompressedBits & operator-=(const TfCompressedBits &rhs)
Removes all bits in the rhs bits from these bits.
size_t FindNthSet(size_t nth) const
Returns the index of the n-th bit set in this bit set.
View< Mode::AllUnset > AllUnsetView
Returns an iteratable view for the bits that steps over all unset bits.
TfCompressedBits(const TfCompressedBits &rhs)
Copy-constructs a fixed size bit array.
void ResizeKeepContents(size_t num)
Resize the bitset, while keeping the contents, unless trimmed.
void Clear(size_t index)
Clears bit # index to zero.
TfCompressedBits operator>>(size_t bits) const
Returns bits shifted to the right.
TfCompressedBits operator-(const TfCompressedBits &rhs) const
Returns bits with all the bits in rhs removed from these bits.
bool AreContiguouslySet() const
Returns true if the set bits in this bit array are contiguous.
void Append(size_t num, bool value)
Append a number of bits with the given value to this bitset.
TfCompressedBits & operator=(const TfCompressedBits &rhs)
Assignment operator.
size_t GetLastSet() const
Returns the index of the last bit set in the bit array.
void Count(size_t *numSet, size_t *maxGap) const
Count the bits set, and also return the largest gap between bits.
void Set(size_t index)
Sets bit # index to zero.
void Assign(size_t index, bool value)
Assigns val to bit # index.
TF_API std::string GetAsStringLeftToRight() const
Returns a string representing the bits for debugging with bits ordered from left to right with increa...
void ShiftRight(size_t bits)
Shift this bitset a given number of bits to the right, and extend to the left with zeroes.
bool IsSet(size_t index) const
Returns true, if bit # index is set.
TfCompressedBits(size_t num=0)
Constructs a fixed size bit array, clears all bits.
TfCompressedBits & operator=(TfCompressedBits &&rhs)
Move assignment operator.
size_t GetNumUnsetPlatforms() const
Returns the number of unset (zeros) platforms in this bitset.
bool IsEmpty() const
Returns true if this bit array is empty, i.e.
TfCompressedBits & operator>>=(size_t bits)
Shifts to the right (see ShiftRight)
size_t GetFirstSet() const
Returns the index of the first bit set in the bit array.
TfCompressedBits & operator^=(const TfCompressedBits &rhs)
Xors these bits with the rhs bits.
void Swap(TfCompressedBits &rhs)
Provides a fast swap.
void ClearAll()
Clears all bits to zero.
bool IsAnyUnset() const
Returns true, if there is at least a single unset bit.
TF_API std::string GetAsRLEString() const
Returns a string representing the bits for debugging with bits represented in run-length encoding for...
TF_API size_t GetHash() const
Returns a hash for this instance.
size_t GetNumPlatforms() const
Returns the number of platforms (zeros or ones) in this bitset.
TfCompressedBits & Complement()
Flips all bits.
TF_API void Decompress(TfBits *bits) const
Decompress the bits into a TfBits array.
size_t GetAllocatedSize() const
Returns the amount of memory this object holds on to.
bool operator!=(const TfCompressedBits &rhs) const
Returns true if this != rhs.
TfCompressedBits & operator|=(const TfCompressedBits &rhs)
Ors these bits with the rhs bits.
TfCompressedBits(TfCompressedBits &&rhs)
Move Constructor.
size_t FindPrevSet(size_t index) const
Finds the next unset bit that has a higher or equal index than index.
TfCompressedBits operator^(const TfCompressedBits &rhs) const
Returns these bits xor'ed with rhs.
bool HasNonEmptyDifference(const TfCompressedBits &rhs) const
Returns true if the result of an asymmetric set different is non-zero.
~TfCompressedBits()
Destructor.
TF_API TfCompressedBits(const TfBits &bits)
Construct a TfCompressedBits array from a TfBits array.
TfCompressedBits & operator&=(const TfCompressedBits &rhs)
Ands these bits with the rhs bits.
TfCompressedBits & operator<<=(size_t bits)
Shifts to the left (see ShiftLeft)
static TF_API TfCompressedBits FromString(const std::string &source)
Returns a bitset constructed from the supplied string representation.
View< Mode::All > AllView
Returns an iteratable view for the bits that steps over all bits.
TfCompressedBits(size_t num, size_t first, size_t last)
Constructs a fixed size bit array, with a range of bits set.
static const TfCompressedBits & GetEmpty()
Returns an empty TfBits.
bool AreAllUnset() const
Returns true, if all the bits in this bit array are unset.
bool HasNonEmptyIntersection(const TfCompressedBits &rhs) const
Returns true if the result of the intersection with rhs would be non-zero.
size_t FindNextSet(size_t index) const
Find the next bit set that is higher or equal to index.
bool operator[](size_t index) const
Returns bit at index.
TfCompressedBits operator|(const TfCompressedBits &rhs) const
Returns these bits or'ed with the rhs.
size_t GetNumSet() const
Returns the number of bits currently set in this array.
ComplementTagType
Copy-construct a fixed sized bit array, from the complement of the rhs bitset.
View< Mode::Platforms > PlatformsView
Returns an iteratable view for the bits that steps over all platforms.
static size_t Combine(Args &&... args)
Produce a hash code by combining the hash codes of several objects.
Definition: hash.h:475
Create or return a previously created object instance of global data.
Definition: staticData.h:96
#define ARCH_CACHE_LINE_SIZE
The size of a CPU cache line on the current processor architecture in bytes.
Definition: align.h:67
GF_API std::ostream & operator<<(std::ostream &, const GfBBox3d &)
Output a GfBBox3d using the format [(range) matrix zeroArea].
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition: diagnostic.h:266
A hash functor for TfCompressedBits that is faster than Hash.
Hash for TfCompressedBits.