hostile-takeover/game/cachemgr.cpp
2016-08-31 23:55:30 -04:00

229 lines
4.4 KiB
C++

#include "ht.h"
namespace wi {
CacheMgr gcam;
CacheMgr::CacheMgr()
{
m_pceList = NULL;
m_pceFirst = NULL;
m_pceFree = NULL;
m_cbTotalSize = 0;
m_cbLimit = 0;
}
CacheMgr::~CacheMgr()
{
Assert(m_pceList == NULL);
}
void CacheMgr::Exit()
{
// Free cache entries
while (m_pceFirst != NULL)
Discard(m_pceFirst);
m_pceFirst = NULL;
// Free CacheEntry list
delete[] m_pceList;
m_pceList = NULL;
m_pceFree = NULL;
}
bool CacheMgr::Init()
{
// Alloc cache entries
m_pceList = new CacheEntry[kcCacheEntries];
Assert(m_pceList != NULL, "out of memory!");
if (m_pceList == NULL)
return false;
memset(m_pceList, 0, sizeof(CacheEntry) * kcCacheEntries);
// Add all entries to free list
for (CacheEntry *pce = m_pceList; pce < &m_pceList[kcCacheEntries]; pce++) {
pce->wUniqueLock = kwIncUnique;
AddToFreeList(pce);
}
return true;
}
dword CacheMgr::GetLimit()
{
return m_cbLimit;
}
void CacheMgr::SetLimit(dword cbLimit)
{
if (cbLimit == 0) {
m_cbLimit = 0;
return;
}
gcam.MakeSpace((dword)-1);
dword cbMin = m_cbTotalSize + ((dword)32 * 1024);
if (cbLimit < cbMin)
cbLimit = cbMin;
m_cbLimit = cbLimit;
}
dword CacheMgr::GetTotalSize()
{
return m_cbTotalSize;
}
void *CacheMgr::GetPtr(CacheHandle hc)
{
CacheEntry *pce = ValidateHandle(hc);
if (pce == NULL)
return NULL;
Assert(pce->hmem != NULL);
Remove(pce);
Add(pce);
return gmmgr.GetPtr(pce->hmem);
}
void *CacheMgr::Lock(CacheHandle hc)
{
CacheEntry *pce = ValidateHandle(hc);
if (pce == NULL)
return NULL;
Assert(pce->hmem != NULL);
Remove(pce);
Add(pce);
Assert(((pce->wUniqueLock + kwIncLock) & kwLockMask) != 0);
pce->wUniqueLock += kwIncLock;
if ((pce->wUniqueLock & kwLockMask) == kwIncLock)
gmmgr.SetLocked(pce->hmem);
return gmmgr.GetPtr(pce->hmem);
}
void CacheMgr::Unlock(CacheHandle hc)
{
CacheEntry *pce = ValidateHandle(hc);
if (pce == NULL)
return;
Assert(pce->hmem != NULL);
Assert((pce->wUniqueLock & kwLockMask) != 0);
pce->wUniqueLock -= kwIncLock;
if ((pce->wUniqueLock & kwLockMask) == 0)
gmmgr.ClearLocked(pce->hmem);
}
bool CacheMgr::IsValid(CacheHandle hc)
{
CacheEntry *pce = ValidateHandle(hc);
return pce != NULL;
}
CacheHandle CacheMgr::NewObject(void *pv, word cb, word wfHints)
{
// Apply limits if asked
if (m_cbLimit != 0) {
while (m_cbTotalSize + cb > m_cbLimit) {
if (!MakeSpace(m_cbTotalSize + cb - m_cbLimit))
return NULL;
}
}
// Free up an entry if we need to
if (m_pceFree == NULL) {
// No free slots available. Discard the oldest entry for reuse.
for (CacheEntry *pceT = m_pceFirst->pcePrev; pceT != NULL; pceT = pceT->pcePrev) {
// If we loop back to m_pceFirst, then all CacheEntries are locked. No way!
Assert(pceT != m_pceFirst);
if ((pceT->wUniqueLock & kwLockMask) == 0) {
Discard(pceT);
break;
}
}
}
CacheEntry *pce = m_pceFree->pcePrev;
Assert(pce != NULL);
if (pce == NULL)
return NULL;
// Alloc the object
pce->hmem = gmmgr.AllocHandle(cb, wfHints);
Assert(pce->hmem != NULL);
if (pce->hmem == NULL)
return NULL;
pce->cbSize = cb;
// Write in data
if (pv != NULL)
gmmgr.WriteHandle(pce->hmem, 0, pv, cb);
// Take off free list, put at start of the alloced list
RemoveFromFreeList(pce);
Add(pce);
m_cbTotalSize += cb;
return MakeHandle(pce);
}
void CacheMgr::Write(CacheHandle hc, word ib, void *pvSrc, word cb)
{
CacheEntry *pce = ValidateHandle(hc);
Assert(pce != NULL);
if (pce == NULL)
return;
gmmgr.WriteHandle(pce->hmem, ib, pvSrc, cb);
}
word CacheMgr::GetSize(CacheHandle hc)
{
CacheEntry *pce = ValidateHandle(hc);
Assert(pce != NULL);
if (pce == NULL)
return 0;
return pce->cbSize;
}
void CacheMgr::Discard(CacheEntry *pce)
{
Assert((pce->wUniqueLock & kwLockMask) == 0);
Assert(pce->hmem != NULL);
Remove(pce);
AddToFreeList(pce);
gmmgr.FreeHandle(pce->hmem);
pce->hmem = NULL;
pce->wUniqueLock += kwIncUnique;
if ((pce->wUniqueLock & kwUniqueMask) == 0)
pce->wUniqueLock += kwIncUnique;
m_cbTotalSize -= pce->cbSize;
}
bool CacheMgr::MakeSpace(dword cb)
{
if (m_pceFirst == NULL)
return false;
CacheEntry *pceT = m_pceFirst->pcePrev;
while (pceT != m_pceFirst) {
if ((pceT->wUniqueLock & kwLockMask) != 0) {
pceT = pceT->pcePrev;
continue;
}
CacheEntry *pcePrev = pceT->pcePrev;
Discard(pceT);
word cbLargestFree;
gmmgr.GetFreeSize(&cbLargestFree);
if (cbLargestFree >= cb)
return true;
pceT = pcePrev;
}
return false;
}
} // namespace wi