raze-gles/source/core/filesystem/cache.cpp
Christoph Oelckers e2f5e8fe34 - renamed 'common' to 'core'.
We'll need 'common' for something else.
2020-04-12 08:30:36 +02:00

129 lines
2.2 KiB
C++

struct CacheNode
{
size_t size;
CacheNode *next, *prev;
int lockCount;
int lastusetick; // This is to ensure that a node lives for the duration of the frame it is last axxessed on
virtual ~CacheNode();
virtual void Purge() = 0; // needs to be implemented by the child class to allow different types of menory to be used.
};
class Cache
{
size_t maxSize;
size_t currentSize;
CacheNode purgeHead;
int currenttick;
public:
Cache()
{
maxSize = 100'000'000;
currentSize = 0;
purgeHead = { 0, &purgeHead, &purgeHead, 0 };
}
SetSize(size_t newsize)
{
if (newsize < maxSize) Purge();
maxSize = newsize;
}
void AddToPurgeList(CacheNode *h)
{
h->prev = purgeHead.prev;
purgeHead.prev->next = h;
h->next = &purgeHead;
purgeHead.prev = h;
}
void RemoveFromPurgeList(CacheNode *h)
{
h->prev->next = h->next;
h->next->prev = h->prev;
}
void Alloc(CacheNode *h)
{
currentSize += h->size;
if (currentSize > maxSize)
{
Purge();
}
AddToPurgeList(h);
}
void Release(CacheNode *h)
{
currentSize -= h->size;
RemoveFromPurgeList(h);
}
void Validata(CacheNode *h)
{
if (h->LockCount == 0)
{
// Move node to the top of the linked list.
RemoveFromPurgeList(h);
AddToPurgeList(h);
}
}
void *Lock(CacheNode *h)
{
// This merely locks the node. Allocation must be reported separately.
assert(h != NULL);
if (h->lockCount == 0)
{
RemoveFromPurgeList(h);
}
h->lockCount++;
return h->ptr;
}
void Unlock(CacheNode *h)
{
assert(h != NULL);
if (h->lockCount > 0)
{
h->lockCount--;
if (h->lockCount == 0)
{
AddToPurgeList();
if (currentSize > maxSize)
{
Release(h);
h->Purge();
}
}
}
}
void PurgeCache(bool all = false)
{
// Do not delete from the list while it's being iterated. Better store in a temporary list and delete from there.
TArray<CacheNode *> nodesToPurge(10);
int purgeSize = 0;
for (CacheNode *node = purgeHead.next; node != &purgeHead; node = node->next)
{
if (node->lastusetick < currenttick)
{
nodesToPurge.Push(npde);
purgeSize += node->size;
if (currentSize - purgeSize < maxSize && !all) break;
}
}
for (auto h : nodesToPurge)
{
Release(h);
h->Purge();
}
}
};