Program Listing for File FixedSizeAllocator.cpp#
↰ Return to documentation for file (FixedSizeAllocator.cpp)
#include "FixedSizeAllocator.h"
#include <cstdio>
#include "MemoryAlignmentHelper.h"
#include "BitArray.h"
FixedSizeAllocator* FixedSizeAllocator::Create(void* i_pBaseAddressOfAvailableMemory, size_t i_sizeOfAvailableMemoryMemory, size_t i_sizeOfBlock, size_t i_numberOfBlocks)
{
assert(i_numberOfBlocks);
size_t requiredSizeForMemoryBlocks = GetRequiredSizeForFixedSizeMemoryBlocks(i_sizeOfBlock, i_numberOfBlocks);
uintptr_t startAddressOfAvailableMemory = reinterpret_cast<uintptr_t>(i_pBaseAddressOfAvailableMemory);
uintptr_t endAddressOfAvailableMemory = startAddressOfAvailableMemory + i_sizeOfAvailableMemoryMemory;
uintptr_t baseAddressOfFixedSizeMemoryBlocks = endAddressOfAvailableMemory - requiredSizeForMemoryBlocks;
uintptr_t alignedBaseAddressOfFixedSizeMemoryBlocks = MemoryAlignmentHelper::AlignDown(baseAddressOfFixedSizeMemoryBlocks);
size_t remainingAvailableSize = alignedBaseAddressOfFixedSizeMemoryBlocks - startAddressOfAvailableMemory;
uintptr_t requiredSizeForBitArrayObject = BitArray::GetRequiredSizeForObject(i_pBaseAddressOfAvailableMemory, remainingAvailableSize, i_numberOfBlocks);
uintptr_t rootAddress = alignedBaseAddressOfFixedSizeMemoryBlocks - requiredSizeForBitArrayObject - sizeof(FixedSizeAllocator);
//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 && "If assert fails increase the available memory for Heap");
FixedSizeAllocator* fixedSizeAllocator = reinterpret_cast<FixedSizeAllocator*>(rootAddress);
assert(fixedSizeAllocator);
size_t totalSize = endAddressOfAvailableMemory - rootAddress;
uintptr_t baseAddressOfBitArrayObject = alignedBaseAddressOfFixedSizeMemoryBlocks - requiredSizeForBitArrayObject;
//return fixedSizeAllocator->Initialize(rootAddress, totalSize, i_sizeOfBlock, i_numberOfBlocks, i_pBaseAddressOfAvailableMemory, remainingAvailableSize, alignedBaseAddressOfFixedSizeMemoryBlocks);
return fixedSizeAllocator->Initialize(rootAddress, totalSize, i_sizeOfBlock, i_numberOfBlocks, baseAddressOfBitArrayObject, requiredSizeForBitArrayObject, alignedBaseAddressOfFixedSizeMemoryBlocks);
}
FixedSizeAllocator* FixedSizeAllocator::Initialize(uintptr_t i_rootAddress, size_t i_totalSize,
size_t i_sizeOfBlock, size_t i_numberOfBlocks, uintptr_t i_pBaseAddressOfAvailableMemory, size_t i_remainingAvailableSize, uintptr_t i_alignedBaseAddressOfFixedSizeMemoryBlocks)
{
pRoot = i_rootAddress;
totalSize = i_totalSize;
FSAInfoData.sizeOfBlock = i_sizeOfBlock;
FSAInfoData.numberOfBlocks = i_numberOfBlocks;
pFSABitArray = BitArray::Create(reinterpret_cast<void*>(i_pBaseAddressOfAvailableMemory), i_remainingAvailableSize, i_numberOfBlocks, true);
pBaseAddressOfFixedSizeMemoryBlocks = i_alignedBaseAddressOfFixedSizeMemoryBlocks;
return reinterpret_cast<FixedSizeAllocator*>(pRoot);
}
void FixedSizeAllocator::Destroy()
{
#ifdef _DEBUG
ShowOutstandingAllocations();
#endif
}
void* FixedSizeAllocator::Alloc()
{
size_t i_firstAvailable;
if(pFSABitArray->GetFirstClearBit(i_firstAvailable))
{
pFSABitArray->SetBit(i_firstAvailable);
uintptr_t baseAddressOfUserMemory = pBaseAddressOfFixedSizeMemoryBlocks + (i_firstAvailable * FSAInfoData.sizeOfBlock);
return reinterpret_cast<void*>(baseAddressOfUserMemory);
}
return nullptr;
}
bool FixedSizeAllocator::Free(void* i_pMemory)
{
assert(Contains(i_pMemory));
uintptr_t memoryAddressToCheck = reinterpret_cast<uintptr_t>(i_pMemory);
size_t bitIndex = (memoryAddressToCheck - pBaseAddressOfFixedSizeMemoryBlocks) / FSAInfoData.sizeOfBlock;
assert(bitIndex < FSAInfoData.numberOfBlocks);
if(pFSABitArray->IsBitSet(bitIndex))
{
pFSABitArray->ClearBit(bitIndex);
return true;
}
return false;
}
bool FixedSizeAllocator::Contains(void* i_pMemory) const
{
if(i_pMemory == nullptr)
{
return false;
}
uintptr_t memoryAddressToCheck = reinterpret_cast<uintptr_t>(i_pMemory);
uintptr_t endAddressOfFixedSizeMemoryBlocks = pBaseAddressOfFixedSizeMemoryBlocks + (FSAInfoData.numberOfBlocks * FSAInfoData.sizeOfBlock);
bool isAddressWithinValidMemoryRange = (memoryAddressToCheck >= pBaseAddressOfFixedSizeMemoryBlocks && memoryAddressToCheck < endAddressOfFixedSizeMemoryBlocks);
if(isAddressWithinValidMemoryRange)
{
//Check memoryAddressToCheck is a valid base address
uintptr_t differenceInMemoryAddress = (memoryAddressToCheck - pBaseAddressOfFixedSizeMemoryBlocks);
if(differenceInMemoryAddress % FSAInfoData.sizeOfBlock == 0)
{
return true;
}
}
return false;
}
FSAData FixedSizeAllocator::GetFSAData() const
{
return FSAInfoData;
}
size_t FixedSizeAllocator::GetRequiredSizeForFixedSizeMemoryBlocks(size_t i_sizeOfBlock, size_t i_numberOfBlocks)
{
return i_sizeOfBlock * i_numberOfBlocks;
}
void FixedSizeAllocator::ShowFreeBlocks() const
{
printf("FreeBlock BitArray Data for FSA of Size: %zu\n", FSAInfoData.sizeOfBlock);
if(!pFSABitArray->AreAllBitsClear())
{
pFSABitArray->Display();
}
else
{
printf("All Blocks are free");
}
}
void FixedSizeAllocator::ShowOutstandingAllocations() const
{
if (!pFSABitArray->AreAllBitsClear())
{
printf("Outstanding Allocations for FSA of Size: %zu\n", FSAInfoData.sizeOfBlock);
pFSABitArray->Display();
}
}