#ifndef CACHE_H
#define CACHE_H
**
** Copyright 2001 pinc Software. All Rights Reserved.
** Released under the terms of the MIT license.
*/
#include <SupportDefs.h>
#include <stdio.h>
template<class T> class Cache
{
public:
class Cacheable
{
public:
Cacheable()
:
prev(NULL),
next(NULL),
locked(0L),
isDirty(false)
{
}
virtual ~Cacheable()
{
}
virtual bool Equals(T) = 0;
Cacheable *prev,*next;
int32 locked;
bool isDirty;
};
public:
Cache(int32 max = 20)
:
fMaxInQueue(max),
fCount(0),
fHoldChanges(false),
fMostRecentlyUsed(NULL),
fLeastRecentlyUsed(NULL)
{
}
virtual ~Cache()
{
Clear(0,true);
}
void Clear(int32 targetCount = 0,bool force = false)
{
Cacheable *entry = fLeastRecentlyUsed;
while (entry)
{
Cacheable *prev = entry->prev;
if (entry->locked <= 0 || force)
{
if (entry->next)
entry->next->prev = prev;
if (prev)
prev->next = entry->next;
if (fLeastRecentlyUsed == entry)
fLeastRecentlyUsed = prev;
if (fMostRecentlyUsed == entry)
fMostRecentlyUsed = prev;
delete entry;
if (--fCount <= targetCount)
break;
}
entry = prev;
}
}
void SetHoldChanges(bool hold)
{
fHoldChanges = hold;
if (!hold)
Clear(fMaxInQueue);
}
status_t SetDirty(T data,bool dirty)
{
Cacheable *entry = Get(data);
if (!entry)
return B_ENTRY_NOT_FOUND;
entry->isDirty = dirty;
return B_OK;
}
status_t Lock(T data)
{
Cacheable *entry = Get(data);
if (!entry)
return B_ENTRY_NOT_FOUND;
entry->locked++;
return B_OK;
}
status_t Unlock(T data)
{
Cacheable *entry = Get(data);
if (!entry)
return B_ENTRY_NOT_FOUND;
entry->locked--;
return B_OK;
}
Cacheable *Get(T data)
{
Cacheable *entry = GetFromCache(data);
if (entry)
{
if (fMostRecentlyUsed == entry)
return entry;
if (entry->prev)
entry->prev->next = entry->next;
if (!entry->next)
{
if (fLeastRecentlyUsed == entry)
fLeastRecentlyUsed = entry->prev;
else
fprintf(stderr,"Cache: fatal error, fLeastRecentlyUsed != entry\n");
}
else
entry->next->prev = entry->prev;
}
else
{
entry = NewCacheable(data);
if (entry)
fCount++;
}
if (entry)
{
entry->next = fMostRecentlyUsed;
entry->prev = NULL;
if (fMostRecentlyUsed)
fMostRecentlyUsed->prev = entry;
else if (fLeastRecentlyUsed == NULL)
fLeastRecentlyUsed = entry;
else
fprintf(stderr,"Cache: fatal error, fLeastRecently != NULL!\n");
fMostRecentlyUsed = entry;
if (!fHoldChanges
&& fCount > fMaxInQueue
&& fLeastRecentlyUsed)
Clear(fMaxInQueue);
}
return entry;
}
protected:
Cacheable *GetFromCache(T data)
{
Cacheable *entry = fMostRecentlyUsed;
while (entry)
{
if (entry->Equals(data))
return entry;
entry = entry->next;
}
return NULL;
}
virtual Cacheable *NewCacheable(T data) = 0;
int32 fMaxInQueue, fCount;
bool fHoldChanges;
Cacheable *fMostRecentlyUsed;
Cacheable *fLeastRecentlyUsed;
};
#endif