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