MVKBitArray updates reuse pointer for data if
under 64 bits, and remove inline declarations.
diff --git a/MoltenVK/MoltenVK/Utility/MVKBitArray.h b/MoltenVK/MoltenVK/Utility/MVKBitArray.h
index 4aae743..719464e 100755
--- a/MoltenVK/MoltenVK/Utility/MVKBitArray.h
+++ b/MoltenVK/MoltenVK/Utility/MVKBitArray.h
@@ -28,7 +28,7 @@
class MVKBitArray {
static constexpr size_t SectionMaskSize = 6; // 64 bits
- static constexpr size_t SectionBitCount = 1U << SectionMaskSize;
+ static constexpr size_t SectionBitCount = (size_t)1U << SectionMaskSize;
static constexpr size_t SectionByteCount = SectionBitCount / 8;
static constexpr uint64_t SectionMask = SectionBitCount - 1;
@@ -38,33 +38,33 @@
* Returns the value of the bit, and optionally clears that bit if it was set.
* Returns false if the bitIndex is beyond the size of this array, returns false.
*/
- inline bool getBit(size_t bitIndex, bool shouldClear = false) {
+ bool getBit(size_t bitIndex, bool shouldClear = false) {
if (bitIndex >= _bitCount) { return false; }
- bool val = mvkIsAnyFlagEnabled(_pSections[getIndexOfSection(bitIndex)], getSectionSetMask(bitIndex));
+ bool val = mvkIsAnyFlagEnabled(getSection(getIndexOfSection(bitIndex)), getSectionSetMask(bitIndex));
if (shouldClear && val) { clearBit(bitIndex); }
return val;
}
/** Sets the value of the bit to the val (or to 1 by default). */
- inline void setBit(size_t bitIndex, bool val = true) {
+ void setBit(size_t bitIndex, bool val = true) {
size_t secIdx = getIndexOfSection(bitIndex);
if (val) {
- mvkEnableFlags(_pSections[secIdx], getSectionSetMask(bitIndex));
+ mvkEnableFlags(getSection(secIdx), getSectionSetMask(bitIndex));
if (secIdx < _minUnclearedSectionIndex) { _minUnclearedSectionIndex = secIdx; }
} else {
- mvkDisableFlags(_pSections[secIdx], getSectionSetMask(bitIndex));
- if (secIdx == _minUnclearedSectionIndex && !_pSections[secIdx]) { _minUnclearedSectionIndex++; }
+ mvkDisableFlags(getSection(secIdx), getSectionSetMask(bitIndex));
+ if (secIdx == _minUnclearedSectionIndex && !getSection(secIdx)) { _minUnclearedSectionIndex++; }
}
}
/** Sets the value of the bit to 0. */
- inline void clearBit(size_t bitIndex) { setBit(bitIndex, false); }
+ void clearBit(size_t bitIndex) { setBit(bitIndex, false); }
/** Sets all bits in the array to 1. */
- inline void setAllBits() { setAllSections(~0); }
+ void setAllBits() { setAllSections(~0); }
/** Clears all bits in the array to 0. */
- inline void clearAllBits() { setAllSections(0); }
+ void clearAllBits() { setAllSections(0); }
/**
* Returns the index of the first bit that is set, at or after the specified index,
@@ -75,10 +75,10 @@
size_t bitIdx = startSecIdx << SectionMaskSize;
size_t secCnt = getSectionCount();
for (size_t secIdx = startSecIdx; secIdx < secCnt; secIdx++) {
- size_t lclBitIdx = getIndexOfFirstSetBitInSection(_pSections[secIdx], getBitIndexInSection(startIndex));
+ size_t lclBitIdx = getIndexOfFirstSetBitInSection(getSection(secIdx), getBitIndexInSection(startIndex));
bitIdx += lclBitIdx;
if (lclBitIdx < SectionBitCount) {
- if (startSecIdx == _minUnclearedSectionIndex && !_pSections[startSecIdx]) { _minUnclearedSectionIndex = secIdx; }
+ if (startSecIdx == _minUnclearedSectionIndex && !getSection(startSecIdx)) { _minUnclearedSectionIndex = secIdx; }
if (shouldClear) { clearBit(bitIdx); }
return bitIdx;
}
@@ -90,7 +90,7 @@
* Returns the index of the first bit that is set, at or after the specified index.
* If no bits are set, returns the size() of this bit array.
*/
- inline size_t getIndexOfFirstSetBit(size_t startIndex) {
+ size_t getIndexOfFirstSetBit(size_t startIndex) {
return getIndexOfFirstSetBit(startIndex, false);
}
@@ -98,7 +98,7 @@
* Returns the index of the first bit that is set and optionally clears that bit.
* If no bits are set, returns the size() of this bit array.
*/
- inline size_t getIndexOfFirstSetBit(bool shouldClear) {
+ size_t getIndexOfFirstSetBit(bool shouldClear) {
return getIndexOfFirstSetBit(0, shouldClear);
}
@@ -106,7 +106,7 @@
* Returns the index of the first bit that is set.
* If no bits are set, returns the size() of this bit array.
*/
- inline size_t getIndexOfFirstSetBit() {
+ size_t getIndexOfFirstSetBit() {
return getIndexOfFirstSetBit(0, false);
}
@@ -133,47 +133,61 @@
}
/** Returns the number of bits in this array. */
- inline size_t size() { return _bitCount; }
+ size_t size() const { return _bitCount; }
/** Returns whether this array is empty. */
- inline bool empty() { return !_bitCount; }
+ bool empty() const { return !_bitCount; }
/**
- * Resize this array to the specified number of bits. The value of existing
- * bits that fit within the new size are retained, and any new bits that
- * are added to accommodate the new size are set to the given value.
- * Consumed memory is retained unless the size is set to zero.
+ * Resize this array to the specified number of bits.
+ *
+ * The value of existing bits that fit within the new size are retained, and any
+ * new bits that are added to accommodate the new size are set to the given value.
+ *
+ * If the new size is larger than the existing size, new memory may be allocated.
+ * If the new size is less than the existing size, consumed memory is retained
+ * unless the size is set to zero.
*/
- inline void resize(size_t size, bool val = false) {
+ void resize(size_t size, bool val = false) {
size_t oldBitCnt = _bitCount;
size_t oldSecCnt = getSectionCount();
+ size_t oldEndBitCnt = oldSecCnt << SectionMaskSize;
+
+ // Some magic here. If we need only one section, _data is used as that section,
+ // and it will be stomped on if we reallocate, so we cache it here.
+ uint64_t* oldData = _data;
+ uint64_t* pOldData = oldSecCnt > 1 ? oldData : (uint64_t*)&oldData;
_bitCount = size;
- size_t newSecCnt = getSectionCount();
- if (newSecCnt > oldSecCnt) {
- uint64_t* pOldSecs = _pSections;
+ size_t newSecCnt = getSectionCount();
+ if (newSecCnt == 0) {
+ // Clear out the existing data
+ if (oldSecCnt > 1) { free(pOldData); }
+ _data = 0;
+ _minUnclearedSectionIndex = 0;
+ } else if (newSecCnt == oldSecCnt) {
+ // Keep the existing data, but fill any bits in the last section
+ // that were beyond the old bit count with the new initial value.
+ for (size_t bitIdx = oldBitCnt; bitIdx < oldEndBitCnt; bitIdx++) { setBit(bitIdx, val); }
+ } else if (newSecCnt > oldSecCnt) {
size_t oldByteCnt = oldSecCnt * SectionByteCount;
size_t newByteCnt = newSecCnt * SectionByteCount;
- // Allocate new memory and fill it with the new initial value
- _pSections = _bitCount ? (uint64_t*)malloc(newByteCnt) : nullptr;
- if (_pSections) { memset(_pSections, val ? ~0 : 0, newByteCnt); }
+ // If needed, allocate new memory.
+ if (newSecCnt > 1) { _data = (uint64_t*)malloc(newByteCnt); }
- // Copy the old contents to the new memory, and fill any bits in the old
- // last section that were beyond the old bit count with the new initial value.
- if (_pSections && pOldSecs) { memcpy(_pSections, pOldSecs, oldByteCnt); }
- size_t oldEndBitCnt = oldSecCnt << SectionMaskSize;
+ // Fill the new memory with the new initial value, copy the old contents to
+ // the new memory, fill any bits in the old last section that were beyond
+ // the old bit count with the new initial value, and remove the old memory.
+ uint64_t* pNewData = getData();
+ memset(pNewData, val ? ~0 : 0, newByteCnt);
+ memcpy(pNewData, pOldData, oldByteCnt);
for (size_t bitIdx = oldBitCnt; bitIdx < oldEndBitCnt; bitIdx++) { setBit(bitIdx, val); }
+ if (oldSecCnt > 1) { free(pOldData); }
// If the entire old array and the new array are cleared, move the uncleared indicator to the new end.
if (_minUnclearedSectionIndex == oldSecCnt && !val) { _minUnclearedSectionIndex = newSecCnt; }
-
- free(pOldSecs);
- } else if (newSecCnt == 0) {
- free(_pSections);
- _pSections = nullptr;
- _minUnclearedSectionIndex = 0;
}
}
@@ -182,13 +196,13 @@
MVKBitArray(const MVKBitArray& other) {
resize(other._bitCount);
- memcpy(_pSections, other._pSections, getSectionCount() * SectionByteCount);
+ memcpy(getData(), other.getData(), getSectionCount() * SectionByteCount);
}
MVKBitArray& operator=(const MVKBitArray& other) {
resize(0);
resize(other._bitCount);
- memcpy(_pSections, other._pSections, getSectionCount() * SectionByteCount);
+ memcpy(getData(), other.getData(), getSectionCount() * SectionByteCount);
return *this;
}
@@ -196,24 +210,35 @@
protected:
+ // Returns a pointer do the data.
+ // Some magic here. If we need only one section, _data is used as that section.
+ uint64_t* getData() const {
+ return getSectionCount() > 1 ? _data : (uint64_t*)&_data;
+ }
+
+ // Returns a reference to the section.
+ uint64_t& getSection(size_t secIdx) {
+ return getData()[secIdx];
+ }
+
// Returns the number of sections.
- inline size_t getSectionCount() {
+ size_t getSectionCount() const {
return _bitCount ? getIndexOfSection(_bitCount - 1) + 1 : 0;
}
// Returns the index of the section that contains the specified bit.
- static inline size_t getIndexOfSection(size_t bitIndex) {
+ static size_t getIndexOfSection(size_t bitIndex) {
return bitIndex >> SectionMaskSize;
}
// Converts the bit index to a local bit index within a section, and returns that local bit index.
- static inline size_t getBitIndexInSection(size_t bitIndex) {
+ static size_t getBitIndexInSection(size_t bitIndex) {
return bitIndex & SectionMask;
}
// Returns a section mask containing a single 1 value in the bit in the section that
// corresponds to the specified global bit index, and 0 values in all other bits.
- static inline uint64_t getSectionSetMask(size_t bitIndex) {
+ static uint64_t getSectionSetMask(size_t bitIndex) {
return (uint64_t)1U << ((SectionBitCount - 1) - getBitIndexInSection(bitIndex));
}
@@ -231,12 +256,12 @@
void setAllSections(uint64_t sectionValue) {
size_t secCnt = getSectionCount();
for (size_t secIdx = 0; secIdx < secCnt; secIdx++) {
- _pSections[secIdx] = sectionValue;
+ getSection(secIdx) = sectionValue;
}
_minUnclearedSectionIndex = sectionValue ? 0 : secCnt;
}
- uint64_t* _pSections = nullptr;
+ uint64_t* _data = 0;
size_t _bitCount = 0;
size_t _minUnclearedSectionIndex = 0; // Tracks where to start looking for bits that are set
};