| 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.  |
| 6 | //  |
| 7 | // Comparisons  |
| 8 | // tBitArray - Use when you want to store a large number of bits and you don't know how many at compile-time.  |
| 9 | // This type os primatily for storage and access to a large number of bits. Not many bitwise or  |
| 10 | // mathematical operators.  |
| 11 | // tBitArray8 - Similar to a tBitArray but uses bytes as the elements. Slightly less efficient but the order of the  |
| 12 | // bits in memory exactly matches what is being represented in the array. Also less padding needed at end.  |
| 13 | // tBitField - Use when know how many bits at compile-time and you want bitwise logic opertors like and, or, xor,  |
| 14 | // shift, not, etc. Good for storing a fixed number of flags or channels etc.  |
| 15 | // tFixInt - Use when you want full mathematical operations like any built-in integral type. Size must be known at  |
| 16 | // compile time and must be a multiple of 32 bits. You get + - / * etc as well as all bitwise logic ops.  |
| 17 | //  |
| 18 | // Copyright (c) 2004-2006, 2015, 2017, 2019, 2021-2023 Tristan Grimmer.  |
| 19 | // Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby  |
| 20 | // granted, provided that the above copyright notice and this permission notice appear in all copies.  |
| 21 | //  |
| 22 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL  |
| 23 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,  |
| 24 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  |
| 25 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR  |
| 26 | // PERFORMANCE OF THIS SOFTWARE.  |
| 27 |   |
| 28 | #include "Foundation/tBitArray.h"  |
| 29 | #include "Foundation/tStandard.h"  |
| 30 | #include "Foundation/tFundamentals.h"  |
| 31 |   |
| 32 |   |
| 33 | void tBitArray::Set(int numBits)  |
| 34 | {  |
| 35 | Clear();  |
| 36 | tAssert(numBits > 0);  |
| 37 |   |
| 38 | NumBits = numBits;  |
| 39 | int n = GetNumElements();  |
| 40 | ElemData = new uint32[n];  |
| 41 | tStd::tMemset(dest: ElemData, val: 0, numBytes: n*sizeof(uint32));  |
| 42 | }  |
| 43 |   |
| 44 |   |
| 45 | void tBitArray::Set(uint32* data, int numBits, bool external)  |
| 46 | {  |
| 47 | Clear();  |
| 48 | tAssert(data && numBits);  |
| 49 |   |
| 50 | ExternalData = external;  |
| 51 | NumBits = numBits;  |
| 52 | int n = GetNumElements();  |
| 53 |   |
| 54 | if (external)  |
| 55 | {  |
| 56 | ElemData = data;  |
| 57 | }  |
| 58 | else  |
| 59 | {  |
| 60 | ElemData = new uint32[n];  |
| 61 | tStd::tMemcpy(dest: ElemData, src: data, numBytes: n*sizeof(uint32));  |
| 62 | }  |
| 63 | ClearPadBits();  |
| 64 | }  |
| 65 |   |
| 66 |   |
| 67 | void tBitArray::Set(const tBitArray& src)  |
| 68 | {  |
| 69 | if (&src == this)  |
| 70 | return;  |
| 71 |   |
| 72 | Clear();  |
| 73 | if (!src.IsValid())  |
| 74 | return;  |
| 75 |   |
| 76 | NumBits = src.NumBits;  |
| 77 | int n = src.GetNumElements();  |
| 78 | ElemData = new uint32[n];  |
| 79 | tStd::tMemcpy(dest: ElemData, src: src.ElemData, numBytes: n*sizeof(uint32));  |
| 80 | }  |
| 81 |   |
| 82 |   |
| 83 | bool tBitArray::AreAll(bool v) const  |
| 84 | {  |
| 85 | tAssert(ElemData);  |
| 86 | int n = GetNumElements();  |
| 87 | uint32 fullField = v ? 0xFFFFFFFF : 0x00000000;  |
| 88 | for (int i = 0; i < n-1; i++)  |
| 89 | if (ElemData[i] != fullField)  |
| 90 | return false;  |
| 91 |   |
| 92 | // Deal with the bits in the last field.  |
| 93 | int last = NumBits & 0x1F;  |
| 94 | uint32 maxFull = (last ? (1 << last) : 0) - 1;  |
| 95 | fullField = v ? maxFull : 0x00000000;  |
| 96 | return (ElemData[n-1] & maxFull) == fullField;  |
| 97 | }  |
| 98 |   |
| 99 |   |
| 100 | int tBitArray::CountBits(bool val) const  |
| 101 | {  |
| 102 | // Uses technique described here "http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan".  |
| 103 | // This is one reason the pad bits must always be cleared.  |
| 104 | tAssert(ElemData);  |
| 105 | int numFields = GetNumElements();  |
| 106 |   |
| 107 | int count = 0;  |
| 108 | for (int n = 0; n < numFields; n++)  |
| 109 | {  |
| 110 | uint32 v = ElemData[n]; // Count the number of bits set in v.  |
| 111 | uint32 c; // c accumulates the total bits set in v.  |
| 112 | for (c = 0; v; c++)  |
| 113 | v &= v - 1; // Clear the least significant bit set.  |
| 114 | count += c;  |
| 115 | }  |
| 116 |   |
| 117 | return val ? count : (NumBits - count);  |
| 118 | }  |
| 119 |   |
| 120 |   |
| 121 | int tBitArray::FindFirstClearBit() const  |
| 122 | {  |
| 123 | int n = GetNumElements();  |
| 124 | int index = -1;  |
| 125 | for (int i = 0; i < n; i++)  |
| 126 | {  |
| 127 | uint32 elem = ElemData[i];  |
| 128 | if (elem != 0xFFFFFFFF)  |
| 129 | {  |
| 130 | index = 32*i + tMath::tFindFirstClearBit(v: elem);  |
| 131 | break;  |
| 132 | }  |
| 133 | }  |
| 134 |   |
| 135 | // If the zero was found in the padding bits, it doesn't count.  |
| 136 | if (index >= NumBits)  |
| 137 | return -1;  |
| 138 |   |
| 139 | return index;  |
| 140 | }  |
| 141 |   |
| 142 |   |
| 143 | //  |
| 144 | // tBitArray8.  |
| 145 | //  |
| 146 | void tBitArray8::Set(int numBits)  |
| 147 | {  |
| 148 | Clear();  |
| 149 | tAssert(numBits > 0);  |
| 150 |   |
| 151 | NumBits = numBits;  |
| 152 | int n = GetNumElements();  |
| 153 | ElemData = new uint8[n];  |
| 154 | tStd::tMemset(dest: ElemData, val: 0, numBytes: n);  |
| 155 | }  |
| 156 |   |
| 157 |   |
| 158 | void tBitArray8::Set(uint8* data, int numBits, bool external)  |
| 159 | {  |
| 160 | Clear();  |
| 161 | tAssert(data && numBits);  |
| 162 | NumBits = numBits;  |
| 163 | ExternalData = external;  |
| 164 | int n = GetNumElements();  |
| 165 | if (external)  |
| 166 | {  |
| 167 | ElemData = data;  |
| 168 | }  |
| 169 | else  |
| 170 | {  |
| 171 | ElemData = new uint8[n];  |
| 172 | tStd::tMemcpy(dest: ElemData, src: data, numBytes: n);  |
| 173 | }  |
| 174 | ClearPadBits();  |
| 175 | }  |
| 176 |   |
| 177 |   |
| 178 | void tBitArray8::Set(const tBitArray8& src)  |
| 179 | {  |
| 180 | if (&src == this)  |
| 181 | return;  |
| 182 |   |
| 183 | Clear();  |
| 184 | if (!src.IsValid())  |
| 185 | return;  |
| 186 |   |
| 187 | NumBits = src.NumBits;  |
| 188 | int n = src.GetNumElements();  |
| 189 | ElemData = new uint8[n];  |
| 190 | tStd::tMemcpy(dest: ElemData, src: src.ElemData, numBytes: n);  |
| 191 | }  |
| 192 |   |
| 193 |   |
| 194 | bool tBitArray8::AreAll(bool v) const  |
| 195 | {  |
| 196 | tAssert(ElemData);  |
| 197 | int n = GetNumElements();  |
| 198 | uint8 fullField = v ? 0xFF : 0x00;  |
| 199 | for (int i = 0; i < n-1; i++)  |
| 200 | if (ElemData[i] != fullField)  |
| 201 | return false;  |
| 202 |   |
| 203 | // Deal with the bits in the last field.  |
| 204 | int last = NumBits & 0x07;  |
| 205 | if (!last)  |
| 206 | return true;  |
| 207 |   |
| 208 | uint8 maxFull = ((1 << last) - 1) << (8-last);  |
| 209 | fullField = v ? maxFull : 0x00;  |
| 210 | return (ElemData[n-1] & maxFull) == fullField;  |
| 211 | }  |
| 212 |   |
| 213 |   |
| 214 | int tBitArray8::CountBits(bool val) const  |
| 215 | {  |
| 216 | // Uses technique described here "http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan".  |
| 217 | // This is one reason the pad bits must always be cleared.  |
| 218 | tAssert(ElemData);  |
| 219 | int numFields = GetNumElements();  |
| 220 |   |
| 221 | int count = 0;  |
| 222 | for (int n = 0; n < numFields; n++)  |
| 223 | {  |
| 224 | uint8 v = ElemData[n]; // Count the number of bits set in v.  |
| 225 | uint8 c; // c accumulates the total bits set in v.  |
| 226 | for (c = 0; v; c++)  |
| 227 | v &= v - 1; // Clear the least significant bit set.  |
| 228 | count += c;  |
| 229 | }  |
| 230 |   |
| 231 | return val ? count : (NumBits - count);  |
| 232 | }  |
| 233 |   |
| 234 |   |
| 235 | int tBitArray8::FindFirstClearBit() const  |
| 236 | {  |
| 237 | int n = GetNumElements();  |
| 238 | int index = -1;  |
| 239 | for (int i = 0; i < n; i++)  |
| 240 | {  |
| 241 | uint8 elem = ElemData[i];  |
| 242 | if (elem != 0xFF)  |
| 243 | {  |
| 244 | tMath::tiReverseBits(v&: elem);  |
| 245 | index = 8*i + tMath::tFindFirstClearBit(v: elem);  |
| 246 | break;  |
| 247 | }  |
| 248 | }  |
| 249 |   |
| 250 | // If the zero was found in the padding bits, it doesn't count.  |
| 251 | if (index >= NumBits)  |
| 252 | return -1;  |
| 253 |   |
| 254 | return index;  |
| 255 | }  |
| 256 | |