1139825Simp#ifndef CACHE_H 2251709Sjeff#define CACHE_H 3148078Srwatson/* Cache - a template cache class 4148078Srwatson** 592654Sjeff** Copyright 2001 pinc Software. All Rights Reserved. 692654Sjeff** Released under the terms of the MIT license. 792654Sjeff*/ 892654Sjeff 992654Sjeff 1092654Sjeff#include <SupportDefs.h> 1192654Sjeff 1292654Sjeff#include <stdio.h> 1392654Sjeff 1492654Sjeff 1592654Sjefftemplate<class T> class Cache 1692654Sjeff{ 1792654Sjeff public: 1892654Sjeff class Cacheable 1992654Sjeff { 2092654Sjeff public: 2192654Sjeff Cacheable() 2292654Sjeff : 2392654Sjeff prev(NULL), 2492654Sjeff next(NULL), 2592654Sjeff locked(0L), 2692654Sjeff isDirty(false) 2792654Sjeff { 2892654Sjeff } 2992654Sjeff 3092654Sjeff virtual ~Cacheable() 3192654Sjeff { 3292654Sjeff // perform your "undirty" work here 3392654Sjeff } 3492654Sjeff 3592654Sjeff virtual bool Equals(T) = 0; 3692654Sjeff 3792654Sjeff Cacheable *prev,*next; 3892654Sjeff int32 locked; 39129906Sbmilekic bool isDirty; 4092654Sjeff }; 4192654Sjeff 42129906Sbmilekic public: 4392654Sjeff Cache(int32 max = 20) 4492654Sjeff : 4592654Sjeff fMaxInQueue(max), 4692654Sjeff fCount(0), 4792654Sjeff fHoldChanges(false), 48251709Sjeff fMostRecentlyUsed(NULL), 49251709Sjeff fLeastRecentlyUsed(NULL) 50251709Sjeff { 5192654Sjeff } 5292654Sjeff 5392654Sjeff virtual ~Cache() 5492654Sjeff { 5592654Sjeff Clear(0,true); 5692654Sjeff } 5792654Sjeff 5892654Sjeff void Clear(int32 targetCount = 0,bool force = false) 5992654Sjeff { 60129906Sbmilekic Cacheable *entry = fLeastRecentlyUsed; 61129906Sbmilekic while (entry) 62129906Sbmilekic { 63129906Sbmilekic Cacheable *prev = entry->prev; 64129906Sbmilekic if (entry->locked <= 0 || force) 65129906Sbmilekic { 66129906Sbmilekic if (entry->next) 67169431Srwatson entry->next->prev = prev; 68169431Srwatson if (prev) 69169431Srwatson prev->next = entry->next; 70169431Srwatson 71169431Srwatson if (fLeastRecentlyUsed == entry) 72169431Srwatson fLeastRecentlyUsed = prev; 73169431Srwatson if (fMostRecentlyUsed == entry) 7492654Sjeff fMostRecentlyUsed = prev; 7592654Sjeff 7692654Sjeff delete entry; 7792654Sjeff 7892654Sjeff if (--fCount <= targetCount) 7992654Sjeff break; 8092654Sjeff } 8192654Sjeff 8292654Sjeff entry = prev; 8392654Sjeff } 8492654Sjeff } 8592654Sjeff 8692654Sjeff void SetHoldChanges(bool hold) 8792654Sjeff { 8892654Sjeff fHoldChanges = hold; 8992654Sjeff if (!hold) 9092654Sjeff Clear(fMaxInQueue); 9192654Sjeff } 9292654Sjeff 9392654Sjeff status_t SetDirty(T data,bool dirty) 9492654Sjeff { 9592654Sjeff Cacheable *entry = Get(data); 9692654Sjeff if (!entry) 9792654Sjeff return B_ENTRY_NOT_FOUND; 9892654Sjeff 9992654Sjeff entry->isDirty = dirty; 10092654Sjeff return B_OK; 10192654Sjeff } 10292654Sjeff 10392654Sjeff status_t Lock(T data) 10492654Sjeff { 10592654Sjeff Cacheable *entry = Get(data); 10692654Sjeff if (!entry) 10792654Sjeff return B_ENTRY_NOT_FOUND; 10892654Sjeff 10992654Sjeff entry->locked++; 110222163Salc return B_OK; 11192654Sjeff } 112249264Sglebius 113249264Sglebius status_t Unlock(T data) 11492654Sjeff { 11592654Sjeff Cacheable *entry = Get(data); 11692654Sjeff if (!entry) 11792654Sjeff return B_ENTRY_NOT_FOUND; 11892654Sjeff 11992654Sjeff entry->locked--; 12092654Sjeff return B_OK; 12192654Sjeff } 12292654Sjeff 12392654Sjeff Cacheable *Get(T data) 12492654Sjeff { 12592654Sjeff Cacheable *entry = GetFromCache(data); 12692654Sjeff if (entry) 127251709Sjeff { 12892654Sjeff if (fMostRecentlyUsed == entry) 12992654Sjeff return entry; 13092654Sjeff 131200129Santoine // remove entry from cache (to insert it at top of the MRU list) 13292654Sjeff if (entry->prev) 13392654Sjeff entry->prev->next = entry->next; 134200129Santoine if (!entry->next) 13592654Sjeff { 13692654Sjeff if (fLeastRecentlyUsed == entry) 13792654Sjeff fLeastRecentlyUsed = entry->prev; 13892654Sjeff else 13992654Sjeff fprintf(stderr,"Cache: fatal error, fLeastRecentlyUsed != entry\n"); 14092654Sjeff } 14192654Sjeff else 14292654Sjeff entry->next->prev = entry->prev; 14392654Sjeff } 14492654Sjeff else 14592654Sjeff { 14692654Sjeff entry = NewCacheable(data); 147205266Skmacy if (entry) 148205266Skmacy fCount++; 149205487Skmacy } 150205487Skmacy 151205487Skmacy if (entry) 152205298Skmacy { 153205487Skmacy // insert entry at the top of the MRU list 154205266Skmacy entry->next = fMostRecentlyUsed; 155205266Skmacy entry->prev = NULL; 15692654Sjeff 15792654Sjeff if (fMostRecentlyUsed) 15892654Sjeff fMostRecentlyUsed->prev = entry; 15992654Sjeff else if (fLeastRecentlyUsed == NULL) 16092654Sjeff fLeastRecentlyUsed = entry; 161120218Sjeff else 162120218Sjeff fprintf(stderr,"Cache: fatal error, fLeastRecently != NULL!\n"); 163120218Sjeff fMostRecentlyUsed = entry; 164205487Skmacy 16592654Sjeff // remove old nodes from of the cache (if possible and necessary) 16692654Sjeff if (!fHoldChanges 16792654Sjeff && fCount > fMaxInQueue 16892654Sjeff && fLeastRecentlyUsed) 16992654Sjeff Clear(fMaxInQueue); 17092654Sjeff } 171249313Sglebius return entry; 172249313Sglebius } 173205266Skmacy 17492654Sjeff protected: 17592654Sjeff Cacheable *GetFromCache(T data) 17692654Sjeff { 17792654Sjeff Cacheable *entry = fMostRecentlyUsed; 178129906Sbmilekic while (entry) 179129906Sbmilekic { 180129906Sbmilekic if (entry->Equals(data)) 181129906Sbmilekic return entry; 182129906Sbmilekic entry = entry->next; 183129906Sbmilekic } 184252040Sjeff return NULL; 185129906Sbmilekic } 186129906Sbmilekic 187129906Sbmilekic virtual Cacheable *NewCacheable(T data) = 0; 188129906Sbmilekic 189129906Sbmilekic int32 fMaxInQueue, fCount; 190129906Sbmilekic bool fHoldChanges; 191129906Sbmilekic Cacheable *fMostRecentlyUsed; 192249313Sglebius Cacheable *fLeastRecentlyUsed; 193249313Sglebius}; 194249313Sglebius 195252226Sjeff#endif /* CACHE_H */ 196249313Sglebius