1 #ifndef CACHE_H 2 #define CACHE_H 3 /* Cache - a template cache class 4 ** 5 ** Copyright 2001 pinc Software. All Rights Reserved. 6 */ 7 8 9 #include <SupportDefs.h> 10 11 12 template<class T> class Cache 13 { 14 public: 15 class Cacheable 16 { 17 public: 18 Cacheable() 19 : 20 prev(NULL), 21 next(NULL), 22 locked(0L), 23 isDirty(false) 24 { 25 } 26 27 virtual ~Cacheable() 28 { 29 // perform your "undirty" work here 30 } 31 32 virtual bool Equals(T) = 0; 33 34 Cacheable *prev,*next; 35 int32 locked; 36 bool isDirty; 37 }; 38 39 public: 40 Cache(int32 max = 20) 41 : 42 fMaxInQueue(max), 43 fCount(0), 44 fHoldChanges(false), 45 fMostRecentlyUsed(NULL), 46 fLeastRecentlyUsed(NULL) 47 { 48 } 49 50 virtual ~Cache() 51 { 52 Clear(0,true); 53 } 54 55 void Clear(int32 targetCount = 0,bool force = false) 56 { 57 Cacheable *entry = fLeastRecentlyUsed; 58 while (entry) 59 { 60 Cacheable *prev = entry->prev; 61 if (entry->locked <= 0 || force) 62 { 63 if (entry->next) 64 entry->next->prev = prev; 65 if (prev) 66 prev->next = entry->next; 67 68 if (fLeastRecentlyUsed == entry) 69 fLeastRecentlyUsed = prev; 70 if (fMostRecentlyUsed == entry) 71 fMostRecentlyUsed = prev; 72 73 delete entry; 74 75 if (--fCount <= targetCount) 76 break; 77 } 78 79 entry = prev; 80 } 81 } 82 83 void SetHoldChanges(bool hold) 84 { 85 fHoldChanges = hold; 86 if (!hold) 87 Clear(fMaxInQueue); 88 } 89 90 status_t SetDirty(T data,bool dirty) 91 { 92 Cacheable *entry = Get(data); 93 if (!entry) 94 return B_ENTRY_NOT_FOUND; 95 96 entry->isDirty = dirty; 97 return B_OK; 98 } 99 100 status_t Lock(T data) 101 { 102 Cacheable *entry = Get(data); 103 if (!entry) 104 return B_ENTRY_NOT_FOUND; 105 106 entry->locked++; 107 return B_OK; 108 } 109 110 status_t Unlock(T data) 111 { 112 Cacheable *entry = Get(data); 113 if (!entry) 114 return B_ENTRY_NOT_FOUND; 115 116 entry->locked--; 117 return B_OK; 118 } 119 120 Cacheable *Get(T data) 121 { 122 Cacheable *entry = GetFromCache(data); 123 if (entry) 124 { 125 if (fMostRecentlyUsed == entry) 126 return entry; 127 128 // remove entry from cache (to insert it at top of the MRU list) 129 if (entry->prev) 130 entry->prev->next = entry->next; 131 if (!entry->next) 132 { 133 if (fLeastRecentlyUsed == entry) 134 fLeastRecentlyUsed = entry->prev; 135 else 136 fprintf(stderr,"Cache: fatal error, fLeastRecentlyUsed != entry\n"); 137 } 138 else 139 entry->next->prev = entry->prev; 140 } 141 else 142 { 143 entry = NewCacheable(data); 144 if (entry) 145 fCount++; 146 } 147 148 if (entry) 149 { 150 // insert entry at the top of the MRU list 151 entry->next = fMostRecentlyUsed; 152 entry->prev = NULL; 153 154 if (fMostRecentlyUsed) 155 fMostRecentlyUsed->prev = entry; 156 else if (fLeastRecentlyUsed == NULL) 157 fLeastRecentlyUsed = entry; 158 else 159 fprintf(stderr,"Cache: fatal error, fLeastRecently != NULL!\n"); 160 fMostRecentlyUsed = entry; 161 162 // remove old nodes from of the cache (if possible and necessary) 163 if (!fHoldChanges 164 && fCount > fMaxInQueue 165 && fLeastRecentlyUsed) 166 Clear(fMaxInQueue); 167 } 168 return entry; 169 } 170 171 protected: 172 Cacheable *GetFromCache(T data) 173 { 174 Cacheable *entry = fMostRecentlyUsed; 175 while (entry) 176 { 177 if (entry->Equals(data)) 178 return entry; 179 entry = entry->next; 180 } 181 return NULL; 182 } 183 184 virtual Cacheable *NewCacheable(T data) = 0; 185 186 int32 fMaxInQueue, fCount; 187 bool fHoldChanges; 188 Cacheable *fMostRecentlyUsed; 189 Cacheable *fLeastRecentlyUsed; 190 }; 191 192 #endif /* CACHE_H */ 193