mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-23 01:58:00 +02:00
CTFE updates, including heap support
This commit is contained in:
parent
792d92d014
commit
6bb363fb4b
29 changed files with 3050 additions and 595 deletions
335
BeefySysLib/util/Heap.cpp
Normal file
335
BeefySysLib/util/Heap.cpp
Normal file
|
@ -0,0 +1,335 @@
|
|||
#include "Heap.h"
|
||||
#include "DLIList.h"
|
||||
|
||||
USING_NS_BF;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define CH_REL_TO_ABS(VAL) ((ChBlock*)((uint8*)mMetadata + (VAL)))
|
||||
#define CH_REL_TO_ABS(VAL) ((ChBlock*)((uint8*)mMetadata + (VAL)))
|
||||
#define CH_ABS_TO_REL(VAL) (int)((uint8*)(VAL) - (uint8*)mMetadata)
|
||||
|
||||
enum ChBlockKind
|
||||
{
|
||||
ChBlockKind_Bad = 0xBEEF0BAD,
|
||||
ChBlockKind_Unused = 0xBEEF1212,
|
||||
ChBlockKind_Used = 0xBEEF2323,
|
||||
ChBlockKind_Merged = 0xBEEF3434,
|
||||
};
|
||||
|
||||
struct ChBlock
|
||||
{
|
||||
ContiguousHeap::AllocRef mPrev;
|
||||
ContiguousHeap::AllocRef mNext;
|
||||
int mSize;
|
||||
ChBlockKind mKind;
|
||||
|
||||
ChBlock()
|
||||
{
|
||||
mPrev = -1;
|
||||
mNext = -1;
|
||||
mSize = 0;
|
||||
mKind = ChBlockKind_Bad;
|
||||
}
|
||||
};
|
||||
|
||||
class ChList
|
||||
{
|
||||
public:
|
||||
void* mMetadata;
|
||||
int32 mHead;
|
||||
int32 mTail;
|
||||
|
||||
public:
|
||||
ChList()
|
||||
{
|
||||
mHead = -1;
|
||||
mTail = -1;
|
||||
}
|
||||
|
||||
void Size()
|
||||
{
|
||||
int size = 0;
|
||||
int checkNode = mHead;
|
||||
while (checkNode != NULL)
|
||||
{
|
||||
size++;
|
||||
checkNode = CH_REL_TO_ABS(checkNode)->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
void PushBack(int node)
|
||||
{
|
||||
BF_ASSERT(CH_REL_TO_ABS(node)->mNext == -1);
|
||||
|
||||
if (mHead == -1)
|
||||
mHead = node;
|
||||
else
|
||||
{
|
||||
CH_REL_TO_ABS(mTail)->mNext = node;
|
||||
CH_REL_TO_ABS(node)->mPrev = mTail;
|
||||
}
|
||||
mTail = node;
|
||||
}
|
||||
|
||||
void AddAfter(int refNode, int newNode)
|
||||
{
|
||||
int32 prevNext = CH_REL_TO_ABS(refNode)->mNext;
|
||||
CH_REL_TO_ABS(refNode)->mNext = newNode;
|
||||
CH_REL_TO_ABS(newNode)->mPrev = refNode;
|
||||
CH_REL_TO_ABS(newNode)->mNext = prevNext;
|
||||
if (prevNext != -1)
|
||||
CH_REL_TO_ABS(prevNext)->mPrev = newNode;
|
||||
if (refNode == mTail)
|
||||
mTail = newNode;
|
||||
}
|
||||
|
||||
void Remove(int node)
|
||||
{
|
||||
if (CH_REL_TO_ABS(node)->mPrev == -1)
|
||||
{
|
||||
mHead = CH_REL_TO_ABS(node)->mNext;
|
||||
if (mHead != -1)
|
||||
CH_REL_TO_ABS(mHead)->mPrev = -1;
|
||||
}
|
||||
else
|
||||
CH_REL_TO_ABS(CH_REL_TO_ABS(node)->mPrev)->mNext = CH_REL_TO_ABS(node)->mNext;
|
||||
|
||||
if (CH_REL_TO_ABS(node)->mNext == -1)
|
||||
{
|
||||
mTail = CH_REL_TO_ABS(node)->mPrev;
|
||||
if (mTail != -1)
|
||||
CH_REL_TO_ABS(mTail)->mNext = -1;
|
||||
}
|
||||
else
|
||||
CH_REL_TO_ABS(CH_REL_TO_ABS(node)->mNext)->mPrev = CH_REL_TO_ABS(node)->mPrev;
|
||||
|
||||
CH_REL_TO_ABS(node)->mPrev = -1;
|
||||
CH_REL_TO_ABS(node)->mNext = -1;
|
||||
}
|
||||
|
||||
bool IsEmpty()
|
||||
{
|
||||
return mHead == -1;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ContiguousHeap::ContiguousHeap()
|
||||
{
|
||||
mMetadata = NULL;
|
||||
mMemorySize = 0;
|
||||
mBlockDataOfs = 0;
|
||||
mFreeIdx = 0;
|
||||
}
|
||||
|
||||
ContiguousHeap::~ContiguousHeap()
|
||||
{
|
||||
free(mMetadata);
|
||||
}
|
||||
|
||||
void ContiguousHeap::Clear(int maxAllocSize)
|
||||
{
|
||||
if (mBlockDataOfs == 0)
|
||||
return;
|
||||
|
||||
mBlockDataOfs = 0;
|
||||
mFreeList.Clear();
|
||||
if ((mMemorySize != -1) && (mMemorySize > maxAllocSize))
|
||||
{
|
||||
free(mMetadata);
|
||||
mMetadata = NULL;
|
||||
mMemorySize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
auto blockList = (ChList*)mMetadata;
|
||||
if (blockList->mHead != -1)
|
||||
{
|
||||
auto block = CH_REL_TO_ABS(blockList->mHead);
|
||||
while (block != NULL)
|
||||
{
|
||||
block->mKind = ChBlockKind_Bad;
|
||||
block = CH_REL_TO_ABS(block->mNext);
|
||||
}
|
||||
}
|
||||
blockList->mHead = -1;
|
||||
blockList->mTail = -1;
|
||||
}
|
||||
|
||||
ContiguousHeap::AllocRef ContiguousHeap::Alloc(int size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
size = BF_ALIGN(size, 16);
|
||||
|
||||
auto blockList = (ChList*)mMetadata;
|
||||
|
||||
while (true)
|
||||
{
|
||||
for (int itr = 0; itr < (int)mFreeList.size(); itr++)
|
||||
{
|
||||
auto block = (ChBlock*)((uint8*)mMetadata + mFreeList[mFreeIdx]);
|
||||
|
||||
if (block->mKind == ChBlockKind_Merged)
|
||||
{
|
||||
itr--;
|
||||
if (mFreeIdx >= mFreeList.mSize)
|
||||
mFreeIdx = 0;
|
||||
block->mKind = (ChBlockKind)0;
|
||||
mFreeList.RemoveAtFast(mFreeIdx);
|
||||
continue;
|
||||
}
|
||||
|
||||
BF_ASSERT(block->mKind == ChBlockKind_Unused);
|
||||
|
||||
if (block->mSize >= size)
|
||||
{
|
||||
mFreeList.RemoveAtFast(mFreeIdx);
|
||||
if (block->mSize >= size + 64)
|
||||
{
|
||||
// Split block
|
||||
auto newBlock = new ((uint8*)block + size) ChBlock();
|
||||
newBlock->mSize = block->mSize - size;
|
||||
newBlock->mKind = ChBlockKind_Unused;
|
||||
blockList->AddAfter(CH_ABS_TO_REL(block), CH_ABS_TO_REL(newBlock));
|
||||
block->mSize = size;
|
||||
|
||||
mFreeList.Add(CH_ABS_TO_REL(newBlock));
|
||||
}
|
||||
|
||||
block->mKind = ChBlockKind_Used;
|
||||
return CH_ABS_TO_REL(block);
|
||||
}
|
||||
|
||||
mFreeIdx = (mFreeIdx + 1) % mFreeList.mSize;
|
||||
}
|
||||
|
||||
int wantSize = BF_MAX(mMemorySize + mMemorySize / 2, mMemorySize + BF_MAX(size, 64 * 1024));
|
||||
mMetadata = realloc(mMetadata, wantSize);
|
||||
|
||||
memset((uint8*)mMetadata + mMemorySize, 0, wantSize - mMemorySize);
|
||||
|
||||
blockList = (ChList*)mMetadata;
|
||||
mMemorySize = wantSize;
|
||||
|
||||
if (mBlockDataOfs == 0)
|
||||
{
|
||||
blockList = new (mMetadata) ChList();
|
||||
mBlockDataOfs = sizeof(ChList);
|
||||
}
|
||||
blockList->mMetadata = mMetadata;
|
||||
|
||||
auto block = new ((uint8*)mMetadata + mBlockDataOfs) ChBlock();
|
||||
block->mSize = mMemorySize - mBlockDataOfs;
|
||||
block->mKind = ChBlockKind_Unused;
|
||||
mBlockDataOfs += block->mSize;
|
||||
blockList->PushBack(CH_ABS_TO_REL(block));
|
||||
|
||||
mFreeList.Add(CH_ABS_TO_REL(block));
|
||||
}
|
||||
}
|
||||
|
||||
bool ContiguousHeap::Free(AllocRef ref)
|
||||
{
|
||||
if ((ref < 0) || (ref > mMemorySize - sizeof(ChBlock)))
|
||||
return false;
|
||||
|
||||
auto blockList = (ChList*)mMetadata;
|
||||
auto block = CH_REL_TO_ABS(ref);
|
||||
|
||||
if (block->mKind != ChBlockKind_Used)
|
||||
return false;
|
||||
|
||||
int headAccSize = 0;
|
||||
auto mergeHead = block;
|
||||
while (mergeHead->mPrev != -1)
|
||||
{
|
||||
auto checkBlock = CH_REL_TO_ABS(mergeHead->mPrev);
|
||||
if (checkBlock->mKind != ChBlockKind_Unused)
|
||||
break;
|
||||
headAccSize += mergeHead->mSize;
|
||||
// Mark PREVIOUS as merged, only leave the current alive
|
||||
mergeHead->mKind = ChBlockKind_Merged;
|
||||
blockList->Remove(CH_ABS_TO_REL(mergeHead));
|
||||
mergeHead = checkBlock;
|
||||
}
|
||||
|
||||
int tailAccSize = 0;
|
||||
if (mergeHead->mNext != -1)
|
||||
{
|
||||
auto mergeTail = CH_REL_TO_ABS(mergeHead->mNext);
|
||||
while (mergeTail->mKind == ChBlockKind_Unused)
|
||||
{
|
||||
ChBlock* nextBlock = NULL;
|
||||
if (mergeTail->mNext != -1)
|
||||
nextBlock = CH_REL_TO_ABS(mergeTail->mNext);
|
||||
tailAccSize += mergeTail->mSize;
|
||||
mergeTail->mKind = ChBlockKind_Merged;
|
||||
blockList->Remove(CH_ABS_TO_REL(mergeTail));
|
||||
if (nextBlock == NULL)
|
||||
break;
|
||||
mergeTail = nextBlock;
|
||||
}
|
||||
}
|
||||
|
||||
mergeHead->mSize += tailAccSize + headAccSize;
|
||||
if ((mergeHead->mKind != ChBlockKind_Unused) && (mergeHead->mKind != ChBlockKind_Merged))
|
||||
{
|
||||
// If it were MERGED that means it's still in the free list
|
||||
mFreeList.Add(CH_ABS_TO_REL(mergeHead));
|
||||
}
|
||||
mergeHead->mKind = ChBlockKind_Unused;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContiguousHeap::DebugDump()
|
||||
{
|
||||
String str = "Heap Dump:\n";
|
||||
|
||||
auto blockList = (ChList*)mMetadata;
|
||||
|
||||
if (blockList->mHead != -1)
|
||||
{
|
||||
int totalSize = 0;
|
||||
|
||||
auto block = CH_REL_TO_ABS(blockList->mHead);
|
||||
while (block != NULL)
|
||||
{
|
||||
str += StrFormat("@%d: %d ", CH_ABS_TO_REL(block), block->mSize);
|
||||
switch (block->mKind)
|
||||
{
|
||||
case ChBlockKind_Unused:
|
||||
str += "Unused";
|
||||
break;
|
||||
case ChBlockKind_Used:
|
||||
str += "Used";
|
||||
break;
|
||||
case ChBlockKind_Merged:
|
||||
str += "Merged";
|
||||
break;
|
||||
default:
|
||||
str += "??????";
|
||||
}
|
||||
|
||||
str += "\n";
|
||||
|
||||
totalSize += block->mSize;
|
||||
|
||||
if (block->mNext == -1)
|
||||
break;
|
||||
block = CH_REL_TO_ABS(block->mNext);
|
||||
}
|
||||
|
||||
str += StrFormat("Sum: %d Allocated: %d\n", totalSize, mMemorySize);
|
||||
}
|
||||
|
||||
str += "\nFree List:\n";
|
||||
for (auto val : mFreeList)
|
||||
str += StrFormat("@%d\n", val);
|
||||
str += "\n";
|
||||
|
||||
OutputDebugStrF(str.c_str());
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue