5 FReservation(
Parameters::HEAP_RESERVATION_SIZE),
15 const auto MinimumInitialCommit(
sizeof(
LargeBlock) + 1);
16 return AInitialCommitSize >= MinimumInitialCommit ? AInitialCommitSize : MinimumInitialCommit;
20 return *
static_cast<Block*
>(FReservation());
24 return *
static_cast<Block*
>(FReservation());
28 if (APreviousEntry ==
nullptr) {
29 ABlock.FNextFree = FFreeList;
33 ABlock.FNextFree = APreviousEntry->FNextFree;
34 APreviousEntry->FNextFree = &ABlock;
39 if (APreviousEntry ==
nullptr)
40 FFreeList = FFreeList->FNextFree;
42 APreviousEntry->FNextFree = ABlock.FNextFree;
48 if (FLargeBlock->Size() <= ARequiredNumBytes) {
49 const auto SizeDifference(ARequiredNumBytes - FLargeBlock->Size());
50 const auto NewCommitSize(FReservation.CommitSize() + SizeDifference + 1000);
53 FReservation.Commit(NewCommitSize);
60 FLargeBlock->SetSize(FLargeBlock->Size() + SizeDifference + 1000);
67 if (ABlock->LeftBlock() !=
nullptr && ABlock->LeftBlock()->IsFree()) {
68 auto LeftBlock(ABlock->LeftBlock());
69 const auto NewSize(ABlock->Size() + LeftBlock->Size() +
sizeof(
Block));
71 if (NewSize <= static_cast<unsigned long long>(std::numeric_limits<int>::max())) {
72 RemoveFromFreeList(*ABlock, ALastFreeListEntry);
73 ABlock = &ABlock->EatLeftBlock();
80 static_cast<void>(ALock);
82 ANumBytes = ANumBytes + (
sizeof(
void*) - (ANumBytes %
sizeof(
void*)));
85 const auto MinimumBlockSize(16);
86 const auto MinimumBlockFootprint(MinimumBlockSize +
sizeof(
Block));
89 for (
Block* CurrentBlock(FFreeList), *LastFreeListEntry(
nullptr); CurrentBlock !=
nullptr; CurrentBlock = CurrentBlock->
FNextFree) {
93 if (CurrentBlock->Size() >= ANumBytes) {
96 RemoveFromFreeList(*CurrentBlock, LastFreeListEntry);
99 if ((CurrentBlock->Size() - ANumBytes) >= MinimumBlockFootprint) {
100 auto& NewBlock(CurrentBlock->Splice(ANumBytes));
102 AddToFreeList(NewBlock, LastFreeListEntry);
105 CurrentBlock->SetFree(
false);
106 return *CurrentBlock;
110 MergeBlockIfPossible(CurrentBlock, LastFreeListEntry);
111 LastFreeListEntry = CurrentBlock;
114 LargeBlockNeedsAtLeast(ANumBytes);
118 AllocatedBlock.SetFree(
false);
120 return AllocatedBlock;
123 ANumBytes = ANumBytes + (
sizeof(
void*) - (ANumBytes %
sizeof(
void*)));
126 if (!RightBlock.IsLargeBlock()) {
128 auto& NewData(AllocImpl(ANumBytes, ALock));
130 std::copy(static_cast<byte*>(ABlock.
GetData()), static_cast<byte*>(ABlock.
GetData()) + ABlock.
Size(),
static_cast<byte*
>(NewData.GetData()));
136 API::Assert::Equal<Block*>(&RightBlock, FLargeBlock);
137 const auto Required(ANumBytes - ABlock.
Size());
138 LargeBlockNeedsAtLeast(Required);
149 static_cast<void>(ALock);
150 if (ABlock.LeftBlock() !=
nullptr && ABlock.LeftBlock()->IsFree()) {
151 ABlock.EatLeftBlock().Validate();
154 AddToFreeList(ABlock,
nullptr);
155 ABlock.SetFree(
true);
161 static_cast<void>(ALock);
162 long long ExpectedFreeListSize(0);
163 for (
const Block* CurrentBlock(&FirstBlock()), *PreviousBlock(
nullptr); !CurrentBlock->
IsLargeBlock(); PreviousBlock = CurrentBlock, CurrentBlock = &CurrentBlock->RightBlock()) {
164 CurrentBlock->Validate();
165 API::Assert::Equal(static_cast<const Block*>(const_cast<Block*>(CurrentBlock)->LeftBlock()), PreviousBlock);
166 if (CurrentBlock->IsFree())
167 ++ExpectedFreeListSize;
169 FLargeBlock->Validate();
171 for (
auto CurrentBlock(FFreeList); CurrentBlock !=
nullptr; CurrentBlock = CurrentBlock->FNextFree, --ExpectedFreeListSize)
184 if (ANumBytes != 0) {
188 return AllocImpl(static_cast<unsigned int>(ANumBytes), Lock).GetData();
199 if (APreviousAllocation !=
nullptr) {
202 if (ANumBytes != 0) {
205 if (WorkingBlock.Size() >=
static_cast<unsigned int>(ANumBytes))
206 return APreviousAllocation;
209 return ReallocImpl(WorkingBlock, static_cast<unsigned int>(ANumBytes), Lock).GetData();
217 FreeImpl(WorkingBlock, Lock);
220 return Alloc(ANumBytes);
224 if (APreviousAllocation !=
nullptr) {
227 FreeImpl(WorkingBlock, Lock);
Block & AllocImpl(unsigned int ANumBytes, API::LockGuard &ALock)
Allocates a Block.
A RAII locking mechanism.
unsigned char byte
It's a byte, 8 bits, etc...
Block & EatLeftBlock(void) noexcept
Merge size and header into the size of the Block to the left. Does not modify free lists...
static void True(const bool AExpression) noexcept
Assertion function. AExpression should always be evaluated.
An allocation was attempted with a negative size value.
Block & RightBlock(void) noexcept
Get the block to the right of this Block.
Heap(const unsigned long long AInitialCommitSize)
Create a Heap.
void SetFree(const bool ANewFree) noexcept
Set the Block's free state.
Used to identify the end of a Heap.
void Walk(void) const
Walks the heap blocks and free list and HCFs if an error is detected.
static void LessThan(const AType &ALHS, const AType &ARHS) noexcept
Less than assertion function. May not be evaluated.
void FreeImpl(Block &ABlock, API::LockGuard &ALock) noexcept(!API::Platform::IsDebug())
Frees a Block.
void * GetData(void) noexcept
Get the data portion of the memory owned by this Block.
const unsigned int FErrorCode
The assigned error code.
void * Alloc(const int ASize) finaloverride
Allocate memory from the heap for use.
static Block & FromData(void *const AData)
Retrieves a reference to a Block given it's data pointer.
Exceptions caused by external call failures or invalid external data. Only classifies ones that can p...
An allocation was attempted with a size above 2047MB.
bool IsLargeBlock(void) const noexcept
Check if this Block is a LargeBlock.
void WalkImpl(API::LockGuard &ALock) const
Walks the heap blocks and free list and throws if an error is detected.
Compilation configuration variables.
static Block & AllocateBlock(LargeBlock *&ALargeBlock, const unsigned int ANewBlockSize) noexcept
Allocate a portion of the LargeBlock's owned data to create a regular block.
static void Equal(const AType &ALHS, const AType &ARHS) noexcept
Equivalence assertion function. May not be evaluated.
A heap has no block large enough for a requested allocation and expansion failed. ...
void Release(void) noexcept
Releases the lock on Mutex, this same LockGuard can never reaquire it.
static unsigned long long CalculateInitialCommitSize(const unsigned long long AInitialCommitSize) noexcept
A small max comparison of AInitialCommitSize and sizeof(Block) + 1.
Memory could not be commited from a reservation.
void MergeBlockIfPossible(Block *&ABlock, Block *const ALastFreeListEntry) noexcept
Coalesces Blocks to the left of ABlock and updates the free list.
Precompiled header for inter-engine operations.
Platform::System::VirtualMemory FReservation
The VirtualMemory mapping owned by the heap, also a pointer to the first block.
void Free(void *const APreviousAllocation) noexceptfinaloverride
Return memory to the heap. Data in allocated range will be lost.
void LargeBlockNeedsAtLeast(unsigned int ARequiredNumBytes)
Ensures that FLargeBlock has at least ARequiredNumBytes of Size by committing more memory if necessar...
Block & ReallocImpl(Block &ABlock, unsigned int ANumBytes, API::LockGuard &ALock)
Reallocates a Block.
void * Realloc(void *const APreviousAllocation, const int ANewSize) finaloverride
Allocate memory from the heap for use while preserving previous data. Passing a valid APreviousAlloca...
A unit of memory allocation.
LargeBlock * FLargeBlock
The block that extends to the end of the free list.
Exceptions that are thrown internally in the engine that the should never see, these are a superset o...
unsigned int Size(void) const noexcept
Get the size of the Block.
Exceptions indicating an API contract violation. Should not be anticipated.
void RemoveFromFreeList(Block &ABlock, Block *const APreviousEntry) noexcept
Removes a Block from the free list after APreviousEntry while performing all the checks and reassignm...
Block & FirstBlock(void) noexcept
Get a reference to the first block in the reservation.
void AddToFreeList(Block &ABlock, Block *const APreviousEntry) noexcept
Adds a Block to the free list after APreviousEntry while performing all the checks and reassignments...
static constexpr unsigned long long Megabytes(const unsigned long long AAmount)
Get the true byte value of some amount of megabytes.
Block * FNextFree
The next block in the free list.