Program Listing for File RangeAllocator.cpp

Return to documentation for file (Source\Common\Src\Memory\RangeAllocator.cpp)

#include "Memory/RangeAllocator.h"
#include "Memory/MemoryBuffer.h"

namespace Azura {
namespace Memory {

namespace {
U32 AlignAhead(U32 size, U32 alignment) {
  return (size + (alignment - 1)) & ~(alignment - 1);
}
}  // namespace

RangeAllocator::RangeAllocator(MemoryBuffer& buffer, U32 size)
    : Allocator(buffer.Allocate(size), size), m_sourceBuffer(buffer) {}

RangeAllocator::~RangeAllocator() {
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
  m_sourceBuffer.Deallocate(reinterpret_cast<void*>(BasePtr()));
}

void* RangeAllocator::Allocate(U32 size, U32 alignment) {
  auto finalRangeItr     = m_freeRanges.end();
  U32 finalOffsetInRange = 0;

  const U32 expectedSize = AlignAhead(size, alignment);

  for (auto itr = m_freeRanges.begin(); itr != m_freeRanges.end(); ++itr) {
    const auto& range          = *itr;
    const AddressPtr rangeBase = BasePtr() + range.m_offset;

    const U32 mask          = alignment - 1;
    const UPTR misalignment = (rangeBase & mask);

    // TODO(vasumahesh1): Check Logic
    const U32 requiredSize = U32(misalignment) + expectedSize;

    if (range.m_size >= requiredSize) {
      finalRangeItr      = itr;
      finalOffsetInRange = U32(misalignment);
      break;
    }
  }

  if (finalRangeItr == m_freeRanges.end()) {
    // TODO(vasumahesh1): Must GC
    return nullptr;
  }

  // Take Copy
  const MemoryRange targetRange = *finalRangeItr;

  // Remove Free Range
  m_freeRanges.erase(finalRangeItr);

  // TODO(vasumahesh1): Should Sort or Place as sorted?

  if (finalOffsetInRange > 0) {
    m_freeRanges.emplace_back(targetRange.m_offset, finalOffsetInRange);
  }

  const U32 remainingRangeSize = targetRange.m_size - finalOffsetInRange - expectedSize;

  if (remainingRangeSize > 0) {
    m_freeRanges.emplace_back(targetRange.m_offset + finalOffsetInRange + expectedSize, remainingRangeSize);
  }

  const auto targetOffset = targetRange.m_offset + finalOffsetInRange;
  m_occupiedRanges.emplace_back(targetOffset, expectedSize);

  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
  return reinterpret_cast<void*>(static_cast<AddressPtr>(BasePtr() + targetOffset));
}

void RangeAllocator::Deallocate(void* address) {
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
  const auto addressPtr = reinterpret_cast<AddressPtr>(address);
  auto finalRangeItr    = m_occupiedRanges.end();

  for (auto itr = m_occupiedRanges.begin(); itr != m_occupiedRanges.end(); ++itr) {
    const auto& range          = *itr;
    const AddressPtr rangeBase = BasePtr() + range.m_offset;

    if (rangeBase == addressPtr) {
      finalRangeItr = itr;
      break;
    }
  }

  if (finalRangeItr == m_occupiedRanges.end()) {
    // TODO(vasumahesh1): Must Throw here?
    return;
  }

  // Take Copy
  const MemoryRange targetRange = *finalRangeItr;

  // Remove Free Range
  m_occupiedRanges.erase(finalRangeItr);

  // Release to free ranges
  m_freeRanges.emplace_back(targetRange.m_offset, targetRange.m_size);

  // TODO(vasumahesh1): Should Amalgamate Free Ranges?
}
}  // namespace Memory
}  // namespace Azura