Program Listing for File HeapManager.cpp#

Return to documentation for file (HeapManager.cpp)

//#define DEBUG_CLEAR_MEMORY_ON_DESTROY

#include "HeapManager.h"

#include <cassert>

#include "LinkedListAllocator.h"
#include "FixedSizeAllocator.h"

uintptr_t HeapManager::sBaseAddressOfHeapManager = 0;

HeapManager* HeapManager::Get()
{
    return reinterpret_cast<HeapManager*>(sBaseAddressOfHeapManager);
}

HeapManager* HeapManager::Create(void* i_pMemory, size_t i_bytes, unsigned int i_numDescriptors, FSAData* i_FSAData/* = nullptr*/, size_t i_numFSAs/* = 0*/)
{
    //Default Fixed-Size Allocators
    FSAData iFSAData[] = { {16, 10}, {32, 20}, {96,40} };
    i_numFSAs = 3;

    assert(i_bytes > sizeof(HeapManager));

    HeapManager* pHeapManager = static_cast<HeapManager*>(i_pMemory);
    assert(pHeapManager);

    if(i_numFSAs == 0 || i_FSAData == nullptr)
    {
        //Use Default Fixed-Size Allocators Data
        return pHeapManager->Initialize(i_pMemory, i_bytes, i_numDescriptors, iFSAData, i_numFSAs);
    }
    return pHeapManager->Initialize(i_pMemory, i_bytes, i_numDescriptors, i_FSAData, i_numFSAs);
}

HeapManager* HeapManager::Initialize(void* i_pMemory, size_t i_bytes, unsigned i_numDescriptors, const FSAData* i_FSAData, const size_t i_numFSAs)
{
    pRoot = reinterpret_cast<uintptr_t>(i_pMemory);
    sBaseAddressOfHeapManager = pRoot;
    totalSizeOfHeapManager = i_bytes;
    sizeOfFixedSizeAllocatorAddressArray = i_numFSAs;

    uintptr_t startAddressOfHeapManager = reinterpret_cast<uintptr_t>(i_pMemory);
    uintptr_t endAddressOfHeapManager = startAddressOfHeapManager + i_bytes;

    uintptr_t startAddressOfAllocators = pRoot + sizeof(HeapManager) + ((sizeOfFixedSizeAllocatorAddressArray - 1) * sizeof(uintptr_t));
    size_t availableSizeForAllocators = endAddressOfHeapManager - startAddressOfAllocators;

    for(size_t index = 0; index < sizeOfFixedSizeAllocatorAddressArray; index++)
    {
        FSAData FSAInfoData = i_FSAData[index];
        FixedSizeAllocator* FSA = FixedSizeAllocator::Create(reinterpret_cast<void*>(startAddressOfAllocators), availableSizeForAllocators, FSAInfoData.sizeOfBlock, FSAInfoData.numberOfBlocks);
        uintptr_t addressOfFSA = reinterpret_cast<uintptr_t>(FSA);
        //Make sure the rootAddress is within the available memory range
        //If assert fails increase the available memory
        assert(IsAddressWithinAvailableMemoryRange(i_pMemory, i_bytes, reinterpret_cast<void*>(addressOfFSA)) && "If assert fails increase the available memory for Heap");
        uintptr_t* pFixedSizeAllocatorBaseAddressArrayPointer = reinterpret_cast<uintptr_t*>(&pFixedSizeAllocatorBaseAddressArray + index);
        *(pFixedSizeAllocatorBaseAddressArrayPointer) = reinterpret_cast<uintptr_t>(FSA);
        availableSizeForAllocators = addressOfFSA - startAddressOfAllocators;
    }

    LinkedListAllocator* pLinkedListAllocator = LinkedListAllocator::Create(reinterpret_cast<void*>(startAddressOfAllocators), availableSizeForAllocators, i_numDescriptors);
    pLinkedListAllocatorBaseAddress = reinterpret_cast<uintptr_t>(pLinkedListAllocator);
    //Make sure the rootAddress is within the available memory range
    //If assert fails increase the available memory
    assert(IsAddressWithinAvailableMemoryRange(i_pMemory, i_bytes, reinterpret_cast<void*>(pLinkedListAllocator)) && "If assert fails increase the available memory for Heap");

    return reinterpret_cast<HeapManager*>(pRoot);
}

void HeapManager::Destroy()
{
    if (pFixedSizeAllocatorBaseAddressArray != nullptr)
    {
        for (size_t index = 0; index < sizeOfFixedSizeAllocatorAddressArray; index++)
        {
            FixedSizeAllocator* pFSA = reinterpret_cast<FixedSizeAllocator*>(*(&pFixedSizeAllocatorBaseAddressArray + index));
            pFSA->Destroy();
        }
    }
    LinkedListAllocator* pLinkedListAllocator = reinterpret_cast<LinkedListAllocator*>(pLinkedListAllocatorBaseAddress);
    pLinkedListAllocator->Destroy();

#ifdef DEBUG_CLEAR_MEMORY_ON_DESTROY
    void* pMemoryAddressStart = reinterpret_cast<void*>(pRoot);
    const size_t totalSize = totalSizeOfHeapManager;
    const size_t arraySize = totalSize / sizeof(uintptr_t);
    for (size_t index = 0; index < arraySize; index++)
    {
        *static_cast<uintptr_t*>(pMemoryAddressStart) = 0;
        pMemoryAddressStart = static_cast<uintptr_t*>(pMemoryAddressStart) + 1;
    }
#endif

    sBaseAddressOfHeapManager = 0;
}

void* HeapManager::Alloc(size_t i_size)
{
    void* pAllocatedMemoryAddress = nullptr;
    FixedSizeAllocator* pFSA = FindFixedSizeAllocator(i_size);

    if(pFSA)
    {
        pAllocatedMemoryAddress = pFSA->Alloc();
    }

    if(pAllocatedMemoryAddress == nullptr)
    {
        LinkedListAllocator* pLinkedListAllocator = reinterpret_cast<LinkedListAllocator*>(pLinkedListAllocatorBaseAddress);
        pAllocatedMemoryAddress = pLinkedListAllocator->Alloc(i_size);
    }

    return pAllocatedMemoryAddress;
}

void* HeapManager::Alloc(size_t i_size, size_t i_align)
{
    LinkedListAllocator* pLinkedListAllocator = reinterpret_cast<LinkedListAllocator*>(pLinkedListAllocatorBaseAddress);
    return pLinkedListAllocator->Alloc(i_size, i_align);
}

void HeapManager::Free(void* i_pMemory)
{
    if (i_pMemory == nullptr)
    {
        return;
    }
    assert(Contains(i_pMemory));

    if (pFixedSizeAllocatorBaseAddressArray != nullptr)
    {
        for (size_t index = 0; index < sizeOfFixedSizeAllocatorAddressArray; index++)
        {
            FixedSizeAllocator* pFSA = reinterpret_cast<FixedSizeAllocator*>(*(&pFixedSizeAllocatorBaseAddressArray + index));
            if (pFSA->Contains(i_pMemory))
            {
                pFSA->Free(i_pMemory);
                return;
            }
        }
    }

    LinkedListAllocator* pLinkedListAllocator = reinterpret_cast<LinkedListAllocator*>(pLinkedListAllocatorBaseAddress);
    pLinkedListAllocator->Free(i_pMemory);
}

void HeapManager::Collect()
{
    LinkedListAllocator* pLinkedListAllocator = reinterpret_cast<LinkedListAllocator*>(pLinkedListAllocatorBaseAddress);
    pLinkedListAllocator->Collect();
}

bool HeapManager::Contains(void* i_pMemory) const
{
    if (pFixedSizeAllocatorBaseAddressArray != nullptr)
    {
        for (size_t index = 0; index < sizeOfFixedSizeAllocatorAddressArray; index++)
        {
            FixedSizeAllocator* pFSA = reinterpret_cast<FixedSizeAllocator*>(*(&pFixedSizeAllocatorBaseAddressArray + index));
            if (pFSA->Contains(i_pMemory))
            {
                return true;
            }
        }
    }

    LinkedListAllocator* pLinkedListAllocator = reinterpret_cast<LinkedListAllocator*>(pLinkedListAllocatorBaseAddress);
    return pLinkedListAllocator->Contains(i_pMemory);
}

void HeapManager::ShowFreeBlocks() const
{
    for (size_t index = 0; index < sizeOfFixedSizeAllocatorAddressArray; index++)
    {
        FixedSizeAllocator* pFSA = reinterpret_cast<FixedSizeAllocator*>(*(&pFixedSizeAllocatorBaseAddressArray + index));
        pFSA->ShowFreeBlocks();
    }
    LinkedListAllocator* pLinkedListAllocator = reinterpret_cast<LinkedListAllocator*>(pLinkedListAllocatorBaseAddress);
    pLinkedListAllocator->ShowFreeBlocks();
}

void HeapManager::ShowOutstandingAllocations() const
{
    for (size_t index = 0; index < sizeOfFixedSizeAllocatorAddressArray; index++)
    {
        FixedSizeAllocator* pFSA = reinterpret_cast<FixedSizeAllocator*>(*(&pFixedSizeAllocatorBaseAddressArray + index));
        pFSA->ShowOutstandingAllocations();
    }
    LinkedListAllocator* pLinkedListAllocator = reinterpret_cast<LinkedListAllocator*>(pLinkedListAllocatorBaseAddress);
    pLinkedListAllocator->ShowOutstandingAllocations();
}


FixedSizeAllocator* HeapManager::FindFixedSizeAllocator(size_t i_size)
{
    if(pFixedSizeAllocatorBaseAddressArray == nullptr)
    {
        return nullptr;
    }

    for (size_t index = 0; index < sizeOfFixedSizeAllocatorAddressArray; index++)
    {
        FixedSizeAllocator* pFSA = reinterpret_cast<FixedSizeAllocator*>(*(&pFixedSizeAllocatorBaseAddressArray + index));
        FSAData FSAInfoData = pFSA->GetFSAData();
        if(i_size <= FSAInfoData.sizeOfBlock)
        {
            return reinterpret_cast<FixedSizeAllocator*>(*((&pFixedSizeAllocatorBaseAddressArray) + index));
        }
    }
    return nullptr;
}

bool HeapManager::IsAddressWithinAvailableMemoryRange(void* i_pMemory, size_t i_bytes, void* i_AddressToCheck)
{
    assert(i_pMemory);
    assert(i_bytes);
    assert(i_AddressToCheck);
    uintptr_t startAddressOfAvailableMemory = reinterpret_cast<uintptr_t>(i_pMemory);
    uintptr_t endAddressOfAvailableMemory = reinterpret_cast<uintptr_t>(i_pMemory) + i_bytes;
    uintptr_t addressToCheck = reinterpret_cast<uintptr_t>(i_AddressToCheck);
    bool IsAddressWithinMemory = ((addressToCheck >= startAddressOfAvailableMemory) && (addressToCheck < endAddressOfAvailableMemory));
    return IsAddressWithinMemory;
}