7
#ifdef HAVE_LIBFREETYPE
17
* Caches of pointers to user structs in which the least-recently-used
18
* element is replaced in the event of a cache miss after the cache has
19
* reached a given size.
21
* John Ellson (ellson@lucent.com) Oct 31, 1997
24
* gcc -o gdcache -g -Wall -DTEST gdcache.c
26
* The cache is implemented by a singly-linked list of elements
27
* each containing a pointer to a user struct that is being managed by
30
* The head structure has a pointer to the most-recently-used
31
* element, and elements are moved to this position in the list each
32
* time they are used. The head also contains pointers to three
33
* user defined functions:
34
* - a function to test if a cached userdata matches some keydata
35
* - a function to provide a new userdata struct to the cache
36
* if there has been a cache miss.
37
* - a function to release a userdata struct when it is
38
* no longer being managed by the cache
40
* In the event of a cache miss the cache is allowed to grow up to
41
* a specified maximum size. After the maximum size is reached then
42
* the least-recently-used element is discarded to make room for the
43
* new. The most-recently-returned value is always left at the
44
* beginning of the list after retrieval.
46
* In the current implementation the cache is traversed by a linear
47
* search from most-recent to least-recent. This linear search
48
* probably limits the usefulness of this implementation to cache
49
* sizes of a few tens of elements.
54
/*********************************************************/
56
/*********************************************************/
59
/* create a new cache */
63
gdCacheTestFn_t gdCacheTest,
64
gdCacheFetchFn_t gdCacheFetch,
65
gdCacheReleaseFn_t gdCacheRelease)
69
head = (gdCache_head_t *) gdMalloc (sizeof (gdCache_head_t));
72
head->gdCacheTest = gdCacheTest;
73
head->gdCacheFetch = gdCacheFetch;
74
head->gdCacheRelease = gdCacheRelease;
79
gdCacheDelete (gdCache_head_t * head)
81
gdCache_element_t *elem, *prev;
86
(*(head->gdCacheRelease)) (elem->userdata);
89
gdFree ((char *) prev);
91
gdFree ((char *) head);
95
gdCacheGet (gdCache_head_t * head, void *keydata)
98
gdCache_element_t *elem, *prev = NULL, *prevprev = NULL;
104
if ((*(head->gdCacheTest)) (elem->userdata, keydata))
107
{ /* if not already most-recently-used */
108
/* relink to top of list */
109
prev->next = elem->next;
110
elem->next = head->mru;
113
return elem->userdata;
120
userdata = (*(head->gdCacheFetch)) (&(head->error), keydata);
123
/* if there was an error in the fetch then don't cache */
127
{ /* cache still growing - add new elem */
128
elem = (gdCache_element_t *) gdMalloc (sizeof (gdCache_element_t));
131
{ /* cache full - replace least-recently-used */
132
/* preveprev becomes new end of list */
133
prevprev->next = NULL;
135
(*(head->gdCacheRelease)) (elem->userdata);
137
/* relink to top of list */
138
elem->next = head->mru;
140
elem->userdata = userdata;
146
/*********************************************************/
148
/*********************************************************/
163
cacheTest (void *map, void *key)
165
return (((key_value_t *) map)->key == *(int *) key);
169
cacheFetch (char **error, void *key)
173
map = (key_value_t *) gdMalloc (sizeof (key_value_t));
174
map->key = *(int *) key;
182
cacheRelease (void *map)
184
gdFree ((char *) map);
188
main (char *argv[], int argc)
190
gdCache_head_t *cacheTable;
193
cacheTable = gdCacheCreate (3, cacheTest, cacheFetch, cacheRelease);
196
elem = *(int *) gdCacheGet (cacheTable, &key);
198
elem = *(int *) gdCacheGet (cacheTable, &key);
200
elem = *(int *) gdCacheGet (cacheTable, &key);
202
elem = *(int *) gdCacheGet (cacheTable, &key);
204
elem = *(int *) gdCacheGet (cacheTable, &key);
206
elem = *(int *) gdCacheGet (cacheTable, &key);
208
gdCacheDelete (cacheTable);
214
#endif /* HAVE_LIBTTF */