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