xref: /haiku/src/bin/bfs_tools/lib/Cache.h (revision 647cff2e5925f2a1483b94aaff5620647ddf11bd)
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