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