1647cff2eSAxel Dörfler #ifndef CACHE_H 2647cff2eSAxel Dörfler #define CACHE_H 3647cff2eSAxel Dörfler /* Cache - a template cache class 4647cff2eSAxel Dörfler ** 5647cff2eSAxel Dörfler ** Copyright 2001 pinc Software. All Rights Reserved. 6*8f087d87SAlexander von Gluck IV ** Released under the terms of the MIT license. 7647cff2eSAxel Dörfler */ 8647cff2eSAxel Dörfler 9647cff2eSAxel Dörfler 10647cff2eSAxel Dörfler #include <SupportDefs.h> 11647cff2eSAxel Dörfler 12a59d56faSFrançois Revol #include <stdio.h> 13a59d56faSFrançois Revol 14647cff2eSAxel Dörfler 15647cff2eSAxel Dörfler template<class T> class Cache 16647cff2eSAxel Dörfler { 17647cff2eSAxel Dörfler public: 18647cff2eSAxel Dörfler class Cacheable 19647cff2eSAxel Dörfler { 20647cff2eSAxel Dörfler public: Cacheable()21647cff2eSAxel Dörfler Cacheable() 22647cff2eSAxel Dörfler : 23647cff2eSAxel Dörfler prev(NULL), 24647cff2eSAxel Dörfler next(NULL), 25647cff2eSAxel Dörfler locked(0L), 26647cff2eSAxel Dörfler isDirty(false) 27647cff2eSAxel Dörfler { 28647cff2eSAxel Dörfler } 29647cff2eSAxel Dörfler ~Cacheable()30647cff2eSAxel Dörfler virtual ~Cacheable() 31647cff2eSAxel Dörfler { 32647cff2eSAxel Dörfler // perform your "undirty" work here 33647cff2eSAxel Dörfler } 34647cff2eSAxel Dörfler 35647cff2eSAxel Dörfler virtual bool Equals(T) = 0; 36647cff2eSAxel Dörfler 37647cff2eSAxel Dörfler Cacheable *prev,*next; 38647cff2eSAxel Dörfler int32 locked; 39647cff2eSAxel Dörfler bool isDirty; 40647cff2eSAxel Dörfler }; 41647cff2eSAxel Dörfler 42647cff2eSAxel Dörfler public: 43647cff2eSAxel Dörfler Cache(int32 max = 20) 44647cff2eSAxel Dörfler : fMaxInQueue(max)45647cff2eSAxel Dörfler fMaxInQueue(max), 46647cff2eSAxel Dörfler fCount(0), 47647cff2eSAxel Dörfler fHoldChanges(false), 48647cff2eSAxel Dörfler fMostRecentlyUsed(NULL), 49647cff2eSAxel Dörfler fLeastRecentlyUsed(NULL) 50647cff2eSAxel Dörfler { 51647cff2eSAxel Dörfler } 52647cff2eSAxel Dörfler ~Cache()53647cff2eSAxel Dörfler virtual ~Cache() 54647cff2eSAxel Dörfler { 55647cff2eSAxel Dörfler Clear(0,true); 56647cff2eSAxel Dörfler } 57647cff2eSAxel Dörfler 58647cff2eSAxel Dörfler void Clear(int32 targetCount = 0,bool force = false) 59647cff2eSAxel Dörfler { 60647cff2eSAxel Dörfler Cacheable *entry = fLeastRecentlyUsed; 61647cff2eSAxel Dörfler while (entry) 62647cff2eSAxel Dörfler { 63647cff2eSAxel Dörfler Cacheable *prev = entry->prev; 64647cff2eSAxel Dörfler if (entry->locked <= 0 || force) 65647cff2eSAxel Dörfler { 66647cff2eSAxel Dörfler if (entry->next) 67647cff2eSAxel Dörfler entry->next->prev = prev; 68647cff2eSAxel Dörfler if (prev) 69647cff2eSAxel Dörfler prev->next = entry->next; 70647cff2eSAxel Dörfler 71647cff2eSAxel Dörfler if (fLeastRecentlyUsed == entry) 72647cff2eSAxel Dörfler fLeastRecentlyUsed = prev; 73647cff2eSAxel Dörfler if (fMostRecentlyUsed == entry) 74647cff2eSAxel Dörfler fMostRecentlyUsed = prev; 75647cff2eSAxel Dörfler 76647cff2eSAxel Dörfler delete entry; 77647cff2eSAxel Dörfler 78647cff2eSAxel Dörfler if (--fCount <= targetCount) 79647cff2eSAxel Dörfler break; 80647cff2eSAxel Dörfler } 81647cff2eSAxel Dörfler 82647cff2eSAxel Dörfler entry = prev; 83647cff2eSAxel Dörfler } 84647cff2eSAxel Dörfler } 85647cff2eSAxel Dörfler SetHoldChanges(bool hold)86647cff2eSAxel Dörfler void SetHoldChanges(bool hold) 87647cff2eSAxel Dörfler { 88647cff2eSAxel Dörfler fHoldChanges = hold; 89647cff2eSAxel Dörfler if (!hold) 90647cff2eSAxel Dörfler Clear(fMaxInQueue); 91647cff2eSAxel Dörfler } 92647cff2eSAxel Dörfler SetDirty(T data,bool dirty)93647cff2eSAxel Dörfler status_t SetDirty(T data,bool dirty) 94647cff2eSAxel Dörfler { 95647cff2eSAxel Dörfler Cacheable *entry = Get(data); 96647cff2eSAxel Dörfler if (!entry) 97647cff2eSAxel Dörfler return B_ENTRY_NOT_FOUND; 98647cff2eSAxel Dörfler 99647cff2eSAxel Dörfler entry->isDirty = dirty; 100647cff2eSAxel Dörfler return B_OK; 101647cff2eSAxel Dörfler } 102647cff2eSAxel Dörfler Lock(T data)103647cff2eSAxel Dörfler status_t Lock(T data) 104647cff2eSAxel Dörfler { 105647cff2eSAxel Dörfler Cacheable *entry = Get(data); 106647cff2eSAxel Dörfler if (!entry) 107647cff2eSAxel Dörfler return B_ENTRY_NOT_FOUND; 108647cff2eSAxel Dörfler 109647cff2eSAxel Dörfler entry->locked++; 110647cff2eSAxel Dörfler return B_OK; 111647cff2eSAxel Dörfler } 112647cff2eSAxel Dörfler Unlock(T data)113647cff2eSAxel Dörfler status_t Unlock(T data) 114647cff2eSAxel Dörfler { 115647cff2eSAxel Dörfler Cacheable *entry = Get(data); 116647cff2eSAxel Dörfler if (!entry) 117647cff2eSAxel Dörfler return B_ENTRY_NOT_FOUND; 118647cff2eSAxel Dörfler 119647cff2eSAxel Dörfler entry->locked--; 120647cff2eSAxel Dörfler return B_OK; 121647cff2eSAxel Dörfler } 122647cff2eSAxel Dörfler Get(T data)123647cff2eSAxel Dörfler Cacheable *Get(T data) 124647cff2eSAxel Dörfler { 125647cff2eSAxel Dörfler Cacheable *entry = GetFromCache(data); 126647cff2eSAxel Dörfler if (entry) 127647cff2eSAxel Dörfler { 128647cff2eSAxel Dörfler if (fMostRecentlyUsed == entry) 129647cff2eSAxel Dörfler return entry; 130647cff2eSAxel Dörfler 131647cff2eSAxel Dörfler // remove entry from cache (to insert it at top of the MRU list) 132647cff2eSAxel Dörfler if (entry->prev) 133647cff2eSAxel Dörfler entry->prev->next = entry->next; 134647cff2eSAxel Dörfler if (!entry->next) 135647cff2eSAxel Dörfler { 136647cff2eSAxel Dörfler if (fLeastRecentlyUsed == entry) 137647cff2eSAxel Dörfler fLeastRecentlyUsed = entry->prev; 138647cff2eSAxel Dörfler else 139647cff2eSAxel Dörfler fprintf(stderr,"Cache: fatal error, fLeastRecentlyUsed != entry\n"); 140647cff2eSAxel Dörfler } 141647cff2eSAxel Dörfler else 142647cff2eSAxel Dörfler entry->next->prev = entry->prev; 143647cff2eSAxel Dörfler } 144647cff2eSAxel Dörfler else 145647cff2eSAxel Dörfler { 146647cff2eSAxel Dörfler entry = NewCacheable(data); 147647cff2eSAxel Dörfler if (entry) 148647cff2eSAxel Dörfler fCount++; 149647cff2eSAxel Dörfler } 150647cff2eSAxel Dörfler 151647cff2eSAxel Dörfler if (entry) 152647cff2eSAxel Dörfler { 153647cff2eSAxel Dörfler // insert entry at the top of the MRU list 154647cff2eSAxel Dörfler entry->next = fMostRecentlyUsed; 155647cff2eSAxel Dörfler entry->prev = NULL; 156647cff2eSAxel Dörfler 157647cff2eSAxel Dörfler if (fMostRecentlyUsed) 158647cff2eSAxel Dörfler fMostRecentlyUsed->prev = entry; 159647cff2eSAxel Dörfler else if (fLeastRecentlyUsed == NULL) 160647cff2eSAxel Dörfler fLeastRecentlyUsed = entry; 161647cff2eSAxel Dörfler else 162647cff2eSAxel Dörfler fprintf(stderr,"Cache: fatal error, fLeastRecently != NULL!\n"); 163647cff2eSAxel Dörfler fMostRecentlyUsed = entry; 164647cff2eSAxel Dörfler 165647cff2eSAxel Dörfler // remove old nodes from of the cache (if possible and necessary) 166647cff2eSAxel Dörfler if (!fHoldChanges 167647cff2eSAxel Dörfler && fCount > fMaxInQueue 168647cff2eSAxel Dörfler && fLeastRecentlyUsed) 169647cff2eSAxel Dörfler Clear(fMaxInQueue); 170647cff2eSAxel Dörfler } 171647cff2eSAxel Dörfler return entry; 172647cff2eSAxel Dörfler } 173647cff2eSAxel Dörfler 174647cff2eSAxel Dörfler protected: GetFromCache(T data)175647cff2eSAxel Dörfler Cacheable *GetFromCache(T data) 176647cff2eSAxel Dörfler { 177647cff2eSAxel Dörfler Cacheable *entry = fMostRecentlyUsed; 178647cff2eSAxel Dörfler while (entry) 179647cff2eSAxel Dörfler { 180647cff2eSAxel Dörfler if (entry->Equals(data)) 181647cff2eSAxel Dörfler return entry; 182647cff2eSAxel Dörfler entry = entry->next; 183647cff2eSAxel Dörfler } 184647cff2eSAxel Dörfler return NULL; 185647cff2eSAxel Dörfler } 186647cff2eSAxel Dörfler 187647cff2eSAxel Dörfler virtual Cacheable *NewCacheable(T data) = 0; 188647cff2eSAxel Dörfler 189647cff2eSAxel Dörfler int32 fMaxInQueue, fCount; 190647cff2eSAxel Dörfler bool fHoldChanges; 191647cff2eSAxel Dörfler Cacheable *fMostRecentlyUsed; 192647cff2eSAxel Dörfler Cacheable *fLeastRecentlyUsed; 193647cff2eSAxel Dörfler }; 194647cff2eSAxel Dörfler 195647cff2eSAxel Dörfler #endif /* CACHE_H */ 196