Program Listing for File BitArray.cpp#
↰ Return to documentation for file (BitArray.cpp)
#include "BitArray.h"
#define DEBUG_BIT_ARRAY_BITS
#ifdef DEBUG_BIT_ARRAY_BITS
#include <cstdio>
#endif
#include <cassert>
#include <cstring>
#include <intrin.h>
#ifdef _WIN64
#pragma intrinsic(_BitScanForward64, _bittest64)
#else
#pragma intrinsic(_BitScanForward, _bittest)
#endif
#include "MemoryAlignmentHelper.h"
const size_t BitArray::sBitsPerElement = sizeof(uintptr_t) * 8; //8 bits per byte
BitArray* BitArray::Create(void* i_pBaseAddressOfAvailableMemory, size_t i_sizeOfAvailableMemory, size_t i_numBits, bool i_bInitToZero)
{
assert(i_numBits);
size_t requiredSizeInBytes = GetRequiredPlatformWordArraySizeForBits(i_numBits) * sizeof(uintptr_t);
uintptr_t startAddressOfAvailableMemory = reinterpret_cast<uintptr_t>(i_pBaseAddressOfAvailableMemory);
uintptr_t endAddressOfAvailableMemory = startAddressOfAvailableMemory + i_sizeOfAvailableMemory;
uintptr_t baseAddressOfBitData = endAddressOfAvailableMemory - requiredSizeInBytes;
uintptr_t alignedBaseAddressOfBitData = MemoryAlignmentHelper::AlignDown(baseAddressOfBitData);
uintptr_t rootAddress = alignedBaseAddressOfBitData - sizeof(BitArray);
//Make sure the rootAddress is within the available memory range
//If assert fails increase the available memory
bool isValidRootAddress = (rootAddress >= startAddressOfAvailableMemory) && (rootAddress < endAddressOfAvailableMemory);
assert(isValidRootAddress);
BitArray* bitArray = reinterpret_cast<BitArray*>(rootAddress);
assert(bitArray);
return bitArray->Initialize(rootAddress, alignedBaseAddressOfBitData, i_numBits, i_bInitToZero);
}
BitArray* BitArray::Initialize(uintptr_t i_rootAddress, uintptr_t i_alignedBaseAddressOfBitData, size_t i_numBits, bool i_bInitToZero)
{
pRoot = i_rootAddress;
pBaseAddressOfBitData = i_alignedBaseAddressOfBitData;
pBitData = reinterpret_cast<uintptr_t*>(i_alignedBaseAddressOfBitData);
//sBaseAddressOfBitArray = i_alignedBaseAddressOfBitData;
numBits = i_numBits;
arraySize = GetRequiredPlatformWordArraySizeForBits(numBits);
#ifdef _WIN64
const uintptr_t fillValue = (i_bInitToZero ? static_cast<uintptr_t>(0) : UINT64_MAX);
#else
const uintptr_t fillValue = (i_bInitToZero ? static_cast<uintptr_t>(0) : UINT32_MAX);
#endif
for (size_t sizeIndex = 0; sizeIndex < arraySize; sizeIndex++)
{
pBitData[sizeIndex] = fillValue;
}
return reinterpret_cast<BitArray*>(pRoot);
}
void BitArray::Destroy()
{
}
void BitArray::Display()
{
#ifdef DEBUG_BIT_ARRAY_BITS
printf_s("pBits: ");
for (size_t sizeIndex = 0; sizeIndex < arraySize; sizeIndex++)
{
uintptr_t Bits = pBitData[sizeIndex];
//for(size_t bitIndex = 0; bitIndex < sBitsPerElement; bitIndex++)
for (size_t bitIndex = (sBitsPerElement - 1); true; bitIndex--)
{
if (Bits & (static_cast<uintptr_t>(1) << bitIndex))
{
printf_s("1");
}
else
{
printf_s("0");
}
if (bitIndex == 0)
{
break;
}
}
printf_s(" ");
}
printf_s("\n");
#endif
}
void BitArray::InvertAllBits()
{
for (size_t sizeIndex = 0; sizeIndex < arraySize; sizeIndex++)
{
pBitData[sizeIndex] = ~(pBitData[sizeIndex]);
}
}
size_t BitArray::GetRequiredPlatformWordArraySizeForBits(size_t i_numBits)
{
size_t requiredArraySize = (i_numBits / sBitsPerElement);
const size_t extraBits = i_numBits % sBitsPerElement;
if (extraBits != 0)
{
requiredArraySize = (i_numBits / sBitsPerElement) + 1;
}
return requiredArraySize;
}
size_t BitArray::GetRequiredSizeForObject(void* i_pBaseAddressOfAvailableMemory, size_t i_sizeOfAvailableMemory, size_t i_numBits)
{
size_t requiredSizeInBytes = GetRequiredPlatformWordArraySizeForBits(i_numBits) * sizeof(uintptr_t);
uintptr_t endAddressOfAvailableMemory = reinterpret_cast<uintptr_t>(i_pBaseAddressOfAvailableMemory) + i_sizeOfAvailableMemory;
uintptr_t baseAddressOfBitData = endAddressOfAvailableMemory - requiredSizeInBytes;
uintptr_t alignedBaseAddressOfBitData = MemoryAlignmentHelper::AlignDown(baseAddressOfBitData);
uintptr_t rootAddress = alignedBaseAddressOfBitData - sizeof(BitArray);
//Make sure the rootAddress is within the available memory range
//If assert fails increase the available memory
bool isValidRootAddress = (rootAddress > reinterpret_cast<uintptr_t>(i_pBaseAddressOfAvailableMemory)) && (rootAddress < endAddressOfAvailableMemory);
assert(isValidRootAddress && "If assert fails increase the available memory for Heap");
return endAddressOfAvailableMemory - rootAddress;
}
size_t BitArray::GetBitArraySize() const
{
return numBits;
}
void BitArray::ClearAll()
{
const uintptr_t fillValue = static_cast<uintptr_t>(0);
for (size_t sizeIndex = 0; sizeIndex < arraySize; sizeIndex++)
{
pBitData[sizeIndex] = fillValue;
}
}
void BitArray::SetAll()
{
#ifdef _WIN64
const uintptr_t fillValue = UINT64_MAX;
#else
const uintptr_t fillValue = UINT32_MAX;
#endif
for (size_t sizeIndex = 0; sizeIndex < arraySize; sizeIndex++)
{
pBitData[sizeIndex] = fillValue;
}
}
bool BitArray::AreAllBitsClear() const
{
const uintptr_t fillValueToTest = static_cast<uintptr_t>(0);
for (size_t sizeIndex = 0; sizeIndex < arraySize; sizeIndex++)
{
if (pBitData[sizeIndex] != fillValueToTest)
{
return false;
}
}
return true;
}
bool BitArray::AreAllBitsSet() const
{
#ifdef _WIN64
const uintptr_t fillValueToTest = UINT64_MAX;
#else
const uintptr_t fillValueToTest = UINT32_MAX;
#endif
for (size_t sizeIndex = 0; sizeIndex < arraySize; sizeIndex++)
{
if (pBitData[sizeIndex] != fillValueToTest)
{
return false;
}
}
return true;
}
bool BitArray::IsBitSet(size_t i_bitNumber) const
{
return (*this)[i_bitNumber];
}
bool BitArray::IsBitClear(size_t i_bitNumber) const
{
return !IsBitSet(i_bitNumber);
}
void BitArray::SetBit(size_t i_bitNumber)
{
assert(i_bitNumber < numBits);
const size_t sizeIndex = i_bitNumber / sBitsPerElement;
const size_t bitIndex = i_bitNumber % sBitsPerElement;
pBitData[sizeIndex] |= (static_cast<uintptr_t>(1) << bitIndex);
}
void BitArray::ClearBit(size_t i_bitNumber)
{
assert(i_bitNumber < numBits);
const size_t sizeIndex = i_bitNumber / sBitsPerElement;
const size_t bitIndex = i_bitNumber % sBitsPerElement;
pBitData[sizeIndex] &= ~(static_cast<uintptr_t>(1) << bitIndex);
}
bool BitArray::GetFirstClearBit(size_t& o_firstClearBitIndex) const
{
unsigned long Index;
for (size_t sizeIndex = 0; sizeIndex < arraySize; sizeIndex++)
{
const uintptr_t bitsToTest = ~(pBitData[sizeIndex]);
#ifdef _WIN64
const unsigned char isNonZero = _BitScanForward64(&Index, bitsToTest);
#else
const unsigned char isNonZero = _BitScanForward(&Index, bitsToTest);
#endif
if (isNonZero)
{
const size_t bitIndex = (sizeIndex * sBitsPerElement) + Index;
if (bitIndex < numBits)
{
o_firstClearBitIndex = bitIndex;
return true;
}
}
}
return false;
}
bool BitArray::GetFirstSetBit(size_t& o_firstSetBitIndex) const
{
unsigned long Index;
for (size_t sizeIndex = 0; sizeIndex < arraySize; sizeIndex++)
{
#ifdef _WIN64
const unsigned char isNonZero = _BitScanForward64(&Index, pBitData[sizeIndex]);
#else
const unsigned char isNonZero = _BitScanForward(&Index, pBitData[sizeIndex]);
#endif
if (isNonZero)
{
const size_t bitIndex = (sizeIndex * sBitsPerElement) + Index;
if (bitIndex < numBits)
{
o_firstSetBitIndex = bitIndex;
return true;
}
}
}
return false;
}
bool BitArray::operator[](size_t i_index) const
{
assert(i_index < numBits);
#ifdef _WIN64
const __int64* MemoryBits = reinterpret_cast<__int64*>(pBitData);
const size_t int64ArrayIndex = i_index / sBitsPerElement;
const __int64 int64ArrayBitIndex = static_cast<__int64>(i_index) % sBitsPerElement;
const unsigned char isBitValueEqualToOne = _bittest64(&MemoryBits[int64ArrayIndex], int64ArrayBitIndex);
#else
const long* MemoryBits = reinterpret_cast<long*>(pBitData);
const size_t longArrayIndex = i_index / sBitsPerElement;
const long longArrayBitIndex = static_cast<long>(i_index) % sBitsPerElement;
const unsigned char isBitValueEqualToOne = _bittest(&MemoryBits[longArrayIndex], longArrayBitIndex);
#endif
if (isBitValueEqualToOne)
{
return true;
}
return false;
}