raze-gles/source/blood/src/qheap.cpp

223 lines
5.6 KiB
C++

//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "ns.h" // Must come before everything else!
#ifdef USE_QHEAP
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "common_game.h"
#include "qheap.h"
void InstallFenceposts(HEAPNODE *n)
{
char *address = (char*)n;
memset(address + 0x20, 0xcc, 0x10);
memset(address + n->size - 0x10, 0xcc, 0x10);
}
void CheckFenceposts(HEAPNODE *n)
{
char *data = (char*)n + 0x20;
for (int i = 0; i < 0x10; i++)
{
if (data[i] != 0xcc)
{
ThrowError("Block underwritten");
}
}
data = (char*)n + n->size - 0x10;
for (int i = 0; i < 0x10; i++)
{
if (data[i] != 0xcc)
{
ThrowError("Block overwritten");
}
}
}
QHeap::QHeap(int heapSize)
{
dassert(heapSize > 0);
size = heapSize;
while (size > 0 && (heapPtr = malloc(size)) == NULL)
{
size -= 0x1000;
}
if (!heapPtr)
{
ThrowError("Allocation failure\n");
}
heap.isFree = false;
freeHeap.isFree = false;
HEAPNODE *node = (HEAPNODE*)(((intptr_t)heapPtr + 0xf) & ~0xf);
heap.next = heap.prev = node;
node->next = node->prev = &heap;
freeHeap.freeNext = freeHeap.freePrev = node;
node->freeNext = node->freePrev = &freeHeap;
node->isFree = true;
node->size = size & ~0xf;
}
QHeap::~QHeap(void)
{
Check();
free(heapPtr);
heapPtr = NULL;
}
void QHeap::Check(void)
{
HEAPNODE *node = heap.next;
while (node != &heap)
{
if (!node->isFree)
{
CheckFenceposts(node);
}
node = node->next;
}
}
void QHeap::Debug(void)
{
#if 0
char s[4];
FILE *f = fopen("MEMFRAG.TXT", "wt");
if (!f)
{
return;
}
HEAPNODE *node = heap.next;
while (node != &heap)
{
if (node->isFree)
{
fprintf(f, "%P %10d FREE", node, node->size);
}
else
{
char *data = (char*)node + 0x20;
for (int i = 0; i < 4; i++)
{
if (isalpha(data[i]))
{
s[i] = data[i];
}
else
{
s[i] = '_';
}
}
fprintf(f, "%P %10d %4s", node, node->size, s);
}
}
fclose(f);
#endif
}
void *QHeap::Alloc(int blockSize)
{
dassert(blockSize > 0);
dassert(heapPtr != NULL);
if (blockSize > 0)
{
blockSize = ((blockSize + 0xf) & ~0xf) + 0x40;
HEAPNODE *freeNode = freeHeap.freeNext;
while (freeNode != &freeHeap)
{
dassert(freeNode->isFree);
if (blockSize <= freeNode->size)
{
if (blockSize + 0x30 <= freeNode->size)
{
freeNode->size -= blockSize;
HEAPNODE *nextNode = (HEAPNODE *)((char*)freeNode + freeNode->size);
nextNode->size = blockSize;
nextNode->prev = freeNode;
nextNode->next = freeNode->next;
nextNode->prev->next = nextNode;
nextNode->next->prev = nextNode;
nextNode->isFree = false;
InstallFenceposts(nextNode);
return (void*)((char*)nextNode + 0x30);
}
else
{
freeNode->freePrev->freeNext = freeNode->freeNext;
freeNode->freeNext->freePrev = freeNode->freePrev;
freeNode->isFree = false;
InstallFenceposts(freeNode);
return (void*)((char*)freeNode + 0x30);
}
}
freeNode = freeNode->freeNext;
}
}
return NULL;
}
int QHeap::Free(void *p)
{
if (!p)
{
return 0;
}
dassert(heapPtr != NULL);
HEAPNODE *node = (HEAPNODE*)((char*)p - 0x30);
if (node->isFree)
{
ThrowError("Free on bad or freed block");
}
CheckFenceposts(node);
if (node->prev->isFree)
{
node->prev->size += node->size;
node->prev->next = node->next;
node->next->prev = node->prev;
node = node->prev;
}
else
{
node->freeNext = freeHeap.freeNext;
node->freePrev = &freeHeap;
node->freePrev->freeNext = node;
node->freeNext->freePrev = node;
node->isFree = true;
}
HEAPNODE *nextNode = node->next;
if (nextNode->isFree)
{
node->size += nextNode->size;
nextNode->freePrev->freeNext = nextNode->freeNext;
nextNode->freeNext->freePrev = nextNode->freePrev;
nextNode->prev->next = nextNode->next;
nextNode->next->prev = nextNode->prev;
}
return node->size - 0x40;
}
#endif