| 1 | // tBitArray.cpp  |
| 2 | //  |
| 3 | // A tBitArray is a holder for an arbitrary number of bits and allows individual access to each bit, the ability to  |
| 4 | // clear or set all bits, and some simple binary bitwise operators such as 'and', 'xor', and 'or'. It currently does  |
| 5 | // not support dynamic growing or shrinking. If the number of bits you need is known at compile time, consider using a  |
| 6 | // tBitField instead as it is more feature-complete.  |
| 7 | //  |
| 8 | // Copyright (c) 2004-2006, 2015, 2017, 2019 Tristan Grimmer.  |
| 9 | // Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby  |
| 10 | // granted, provided that the above copyright notice and this permission notice appear in all copies.  |
| 11 | //  |
| 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL  |
| 13 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,  |
| 14 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  |
| 15 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR  |
| 16 | // PERFORMANCE OF THIS SOFTWARE.  |
| 17 |   |
| 18 | #include "Foundation/tBitArray.h"  |
| 19 | #include "Foundation/tStandard.h"  |
| 20 |   |
| 21 |   |
| 22 | void tBitArray::Set(int numBits)  |
| 23 | {  |
| 24 | Clear();  |
| 25 | tAssert(numBits > 0);  |
| 26 |   |
| 27 | NumBits = numBits;  |
| 28 | int numFields = GetNumFields();  |
| 29 | BitFields = new uint32[numFields];  |
| 30 | tStd::tMemset(BitFields, 0, numFields*sizeof(uint32));  |
| 31 | }  |
| 32 |   |
| 33 |   |
| 34 | void tBitArray::Set(const uint32* data, int numBits)  |
| 35 | {  |
| 36 | Clear();  |
| 37 | tAssert(data && numBits);  |
| 38 |   |
| 39 | NumBits = numBits;  |
| 40 | int n = GetNumFields();  |
| 41 | BitFields = new uint32[n];  |
| 42 | tStd::tMemcpy(BitFields, data, n*sizeof(uint32));  |
| 43 | ClearPadBits();  |
| 44 | }  |
| 45 |   |
| 46 |   |
| 47 | void tBitArray::Set(const tBitArray& src)  |
| 48 | {  |
| 49 | if (&src == this)  |
| 50 | return;  |
| 51 |   |
| 52 | Clear();  |
| 53 | if (!src.IsValid())  |
| 54 | return;  |
| 55 |   |
| 56 | NumBits = src.NumBits;  |
| 57 | int n = src.GetNumFields();  |
| 58 | BitFields = new uint32[n];  |
| 59 | tStd::tMemcpy(BitFields, src.BitFields, n*sizeof(uint32));  |
| 60 | }  |
| 61 |   |
| 62 |   |
| 63 | void tBitArray::InvertAll()  |
| 64 | {  |
| 65 | int n = GetNumFields();  |
| 66 | for (int i = 0; i < n; i++)  |
| 67 | BitFields[i] = ~BitFields[i];  |
| 68 |   |
| 69 | ClearPadBits();  |
| 70 | }  |
| 71 |   |
| 72 |   |
| 73 | bool tBitArray::AreAll(bool v) const  |
| 74 | {  |
| 75 | tAssert(BitFields);  |
| 76 | int n = GetNumFields();  |
| 77 | uint32 fullField = v ? 0xFFFFFFFF : 0x00000000;  |
| 78 | for (int i = 0; i < n-1; i++)  |
| 79 | {  |
| 80 | if (BitFields[i] != fullField)  |
| 81 | return false;  |
| 82 | }  |
| 83 |   |
| 84 | // Deal with the bits in the last field.  |
| 85 | int last = NumBits & 0x1F;  |
| 86 | uint32 maxFull = (last ? (1 << last) : 0) - 1;  |
| 87 | fullField = v ? maxFull : 0x00000000;  |
| 88 | return (BitFields[n-1] & maxFull) == fullField;  |
| 89 | }  |
| 90 |   |
| 91 |   |
| 92 | int tBitArray::CountBits(bool val) const  |
| 93 | {  |
| 94 | // Uses technique described here "http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan".  |
| 95 | // This is one reason the pad bits must always be cleared.  |
| 96 | tAssert(BitFields);  |
| 97 | int numFields = GetNumFields();  |
| 98 |   |
| 99 | int count = 0;  |
| 100 | for (int n = 0; n < numFields; n++)  |
| 101 | {  |
| 102 | uint32 v = BitFields[n]; // Count the number of bits set in v.  |
| 103 | uint32 c; // c accumulates the total bits set in v.  |
| 104 | for (c = 0; v; c++)  |
| 105 | v &= v - 1; // Clear the least significant bit set.  |
| 106 | count += c;  |
| 107 | }  |
| 108 |   |
| 109 | return val ? count : (NumBits - count);  |
| 110 | }  |
| 111 |   |
| 112 |   |
| 113 | int tBitArray::GetClearedBit(int index) const  |
| 114 | {  |
| 115 | tAssert(BitFields);  |
| 116 |   |
| 117 | // Find the first zero bit. The operation we do is log2((a xor (a+1)) +1)  |
| 118 | uint32 field = BitFields[index];  |
| 119 |   |
| 120 | // This is guaranteed to be a power of two.  |
| 121 | uint32 freeBit = (field ^ (field+1)) + 1;  |
| 122 |   |
| 123 | // Wraps around on the last bit.  |
| 124 | if (!freeBit)  |
| 125 | return 31;  |
| 126 |   |
| 127 | // Now get the log in base 2 of freeBit. See "http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog".  |
| 128 | const uint32 b[] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 };  |
| 129 | uint32 c = (freeBit & b[0]) != 0;  |
| 130 |   |
| 131 | c |= ((freeBit & b[4]) != 0) << 4;  |
| 132 | c |= ((freeBit & b[3]) != 0) << 3;  |
| 133 | c |= ((freeBit & b[2]) != 0) << 2;  |
| 134 | c |= ((freeBit & b[1]) != 0) << 1;  |
| 135 |   |
| 136 | // This is the first cleared index in the bit array.  |
| 137 | return c-1;  |
| 138 | }  |
| 139 |   |
| 140 |   |
| 141 | int tBitArray::GetClearedBitPos() const  |
| 142 | {  |
| 143 | int n = GetNumFields();  |
| 144 |   |
| 145 | for (int i = 0; i < n-1; i++)  |
| 146 | {  |
| 147 | if (BitFields[i] < 0xFFFFFFFF)  |
| 148 | return 32*i + GetClearedBit(i);  |
| 149 | }  |
| 150 |   |
| 151 | int last = NumBits & 0x1F;  |
| 152 | uint32 maxFull = (last ? (1 << last) : 0) - 1;  |
| 153 |   |
| 154 | if (BitFields[n-1] < maxFull)  |
| 155 | return 32*(n-1) + GetClearedBit(n-1);  |
| 156 |   |
| 157 | // There are no free bits available.  |
| 158 | return -1;  |
| 159 | }  |
| 160 |   |
| 161 |   |
| 162 | tBitArray& tBitArray::operator&=(const tBitArray& s)  |
| 163 | {  |
| 164 | tAssert(NumBits == s.NumBits);  |
| 165 | int n = GetNumFields();  |
| 166 | for (int i = 0; i < n; i++)  |
| 167 | BitFields[i] &= s.BitFields[i];  |
| 168 |   |
| 169 | return *this; // No need to ensure pad bits are cleared because 0 & 0 = 0.  |
| 170 | }  |
| 171 |   |
| 172 |   |
| 173 | tBitArray& tBitArray::operator|=(const tBitArray& s)  |
| 174 | {  |
| 175 | tAssert(NumBits == s.NumBits);  |
| 176 | int n = GetNumFields();  |
| 177 | for (int i = 0; i < n; i++)  |
| 178 | BitFields[i] |= s.BitFields[i];  |
| 179 |   |
| 180 | return *this; // No need to ensure pad bits are cleared because 0 | 0 = 0.  |
| 181 | }  |
| 182 |   |
| 183 |   |
| 184 | tBitArray& tBitArray::operator^=(const tBitArray& s)  |
| 185 | {  |
| 186 | tAssert(NumBits == s.NumBits);  |
| 187 | int n = GetNumFields();  |
| 188 | for (int i = 0; i < n; i++)  |
| 189 | BitFields[i] ^= s.BitFields[i];  |
| 190 |   |
| 191 | return *this; // No need to ensure pad bits are cleared because 0 ^ 0 = 0.  |
| 192 | }  |
| 193 | |