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