blob: 4a580893068d57c5b6be067c1678aa72ff9b5f8d [file] [log] [blame]
Werner Lemberg8728f292000-08-23 17:32:42 +00001/***************************************************************************/
2/* */
3/* ftlru.c */
4/* */
Werner Lembergd1b74752000-08-24 16:29:15 +00005/* Simple LRU list-cache (body). */
Werner Lemberg8728f292000-08-23 17:32:42 +00006/* */
7/* Copyright 2000 by */
8/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
10/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
12/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13/* this file you indicate that you have read the license and */
14/* understand and accept it fully. */
15/* */
16/***************************************************************************/
17
18
David Turnerebdce832000-09-19 01:11:11 +000019#include <freetype/cache/ftlru.h>
David Turnerb466a762000-08-23 11:22:30 +000020#include <freetype/internal/ftobjs.h>
21#include <freetype/internal/ftlist.h>
22
Werner Lemberg8728f292000-08-23 17:32:42 +000023
David Turnerb466a762000-08-23 11:22:30 +000024 static
25 void lru_build_free_list( FT_LruNode nodes,
26 FT_UInt count,
27 FT_List free_list )
28 {
29 FT_LruNode node = nodes;
30 FT_LruNode limit = node + count;
Werner Lemberge4b32a52000-10-31 20:42:18 +000031
Werner Lemberg8728f292000-08-23 17:32:42 +000032
David Turnerb466a762000-08-23 11:22:30 +000033 free_list->head = free_list->tail = 0;
34 for ( ; node < limit; node++ )
35 FT_List_Add( free_list, (FT_ListNode)node );
36 }
37
38
Werner Lemberg8728f292000-08-23 17:32:42 +000039 FT_EXPORT_FUNC( FT_Error ) FT_Lru_New( const FT_Lru_Class* clazz,
40 FT_UInt max_elements,
David Turner3b2c50e2000-08-23 21:11:13 +000041 FT_Pointer user_data,
Werner Lemberg8728f292000-08-23 17:32:42 +000042 FT_Memory memory,
43 FT_Bool pre_alloc,
44 FT_Lru* alru )
David Turnerb466a762000-08-23 11:22:30 +000045 {
46 FT_Error error;
47 FT_Lru lru;
Werner Lemberge4b32a52000-10-31 20:42:18 +000048
Werner Lemberg8728f292000-08-23 17:32:42 +000049
Werner Lembergd1b74752000-08-24 16:29:15 +000050 if ( !alru )
51 return FT_Err_Invalid_Argument;
52
David Turnerb466a762000-08-23 11:22:30 +000053 *alru = 0;
Werner Lemberg8728f292000-08-23 17:32:42 +000054 if ( !ALLOC( lru, sizeof ( *lru ) ) )
David Turnerb466a762000-08-23 11:22:30 +000055 {
Werner Lemberg8728f292000-08-23 17:32:42 +000056 if ( pre_alloc )
David Turnerb466a762000-08-23 11:22:30 +000057 {
58 /* allocate static array of lru list nodes */
59 if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) )
60 {
61 FREE( lru );
62 goto Exit;
63 }
Werner Lemberge4b32a52000-10-31 20:42:18 +000064
Werner Lemberg8728f292000-08-23 17:32:42 +000065 /* build the `free_nodes' list from the array */
David Turnerb466a762000-08-23 11:22:30 +000066 lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes );
67 }
Werner Lemberge4b32a52000-10-31 20:42:18 +000068
David Turnerb466a762000-08-23 11:22:30 +000069 /* initialize common fields */
70 lru->clazz = (FT_Lru_Class*)clazz;
71 lru->max_elements = max_elements;
72 lru->memory = memory;
David Turner3b2c50e2000-08-23 21:11:13 +000073 lru->user_data = user_data;
Werner Lemberg8728f292000-08-23 17:32:42 +000074
David Turnerb466a762000-08-23 11:22:30 +000075 *alru = lru;
76 }
Werner Lemberg8728f292000-08-23 17:32:42 +000077
David Turnerb466a762000-08-23 11:22:30 +000078 Exit:
79 return error;
80 }
81
82
Werner Lemberg8728f292000-08-23 17:32:42 +000083 FT_EXPORT_DEF( void ) FT_Lru_Reset( FT_Lru lru )
David Turnerb466a762000-08-23 11:22:30 +000084 {
Werner Lembergd1b74752000-08-24 16:29:15 +000085 FT_ListNode node;
86 FT_Lru_Class* clazz;
87 FT_Memory memory;
Werner Lemberge4b32a52000-10-31 20:42:18 +000088
Werner Lemberg8728f292000-08-23 17:32:42 +000089
Werner Lembergd1b74752000-08-24 16:29:15 +000090 if ( !lru )
91 return;
92
93 node = lru->elements.head;
94 clazz = lru->clazz;
95 memory = lru->memory;
96
Werner Lemberg8728f292000-08-23 17:32:42 +000097 while ( node )
David Turnerb466a762000-08-23 11:22:30 +000098 {
99 FT_ListNode next = node->next;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000100
Werner Lemberg8728f292000-08-23 17:32:42 +0000101
David Turnerb466a762000-08-23 11:22:30 +0000102 clazz->done_element( lru, (FT_LruNode)node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000103 if ( !lru->nodes )
104 FREE( node );
Werner Lemberge4b32a52000-10-31 20:42:18 +0000105
David Turnerb466a762000-08-23 11:22:30 +0000106 node = next;
107 }
Werner Lemberge4b32a52000-10-31 20:42:18 +0000108
David Turnerb466a762000-08-23 11:22:30 +0000109 /* rebuild free list if necessary */
Werner Lemberg8728f292000-08-23 17:32:42 +0000110 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000111 lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes );
Werner Lemberg8728f292000-08-23 17:32:42 +0000112
113 lru->elements.head = lru->elements.tail = 0;
David Turnerb466a762000-08-23 11:22:30 +0000114 lru->num_elements = 0;
115 }
116
117
Werner Lemberg8728f292000-08-23 17:32:42 +0000118 FT_EXPORT_DEF( void ) FT_Lru_Done( FT_Lru lru )
David Turnerb466a762000-08-23 11:22:30 +0000119 {
Werner Lembergd1b74752000-08-24 16:29:15 +0000120 FT_Memory memory;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000121
Werner Lemberg8728f292000-08-23 17:32:42 +0000122
Werner Lembergd1b74752000-08-24 16:29:15 +0000123 if ( !lru )
124 return;
125
126 memory = lru->memory;
127
Werner Lemberg8728f292000-08-23 17:32:42 +0000128 FT_Lru_Reset( lru );
129 FREE( lru );
David Turnerb466a762000-08-23 11:22:30 +0000130 }
131
132
Werner Lemberg8728f292000-08-23 17:32:42 +0000133 FT_EXPORT_DEF( FT_Error ) FT_Lru_Lookup_Node( FT_Lru lru,
134 FT_LruKey key,
135 FT_LruNode* anode )
David Turnerb466a762000-08-23 11:22:30 +0000136 {
Werner Lembergd1b74752000-08-24 16:29:15 +0000137 FT_Error error = 0;
138 FT_ListNode node;
139 FT_Lru_Class* clazz;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000140 FT_LruNode found = 0;
Werner Lembergd1b74752000-08-24 16:29:15 +0000141 FT_Memory memory;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000142
Werner Lemberg8728f292000-08-23 17:32:42 +0000143
Werner Lembergd1b74752000-08-24 16:29:15 +0000144 if ( !lru || !key || !anode )
145 return FT_Err_Invalid_Argument;
146
147 node = lru->elements.head;
148 clazz = lru->clazz;
149 memory = lru->memory;
150
Werner Lemberg8728f292000-08-23 17:32:42 +0000151 if ( clazz->compare_element )
David Turnerb466a762000-08-23 11:22:30 +0000152 {
153 for ( ; node; node = node->next )
Werner Lemberg8728f292000-08-23 17:32:42 +0000154 if ( clazz->compare_element( (FT_LruNode)node, key ) )
David Turnerb466a762000-08-23 11:22:30 +0000155 {
156 found = (FT_LruNode)node;
157 break;
158 }
159 }
160 else
161 {
162 for ( ; node; node = node->next )
Werner Lemberg8728f292000-08-23 17:32:42 +0000163 if ( ((FT_LruNode)node)->key == key )
David Turnerb466a762000-08-23 11:22:30 +0000164 {
165 found = (FT_LruNode)node;
166 break;
167 }
168 }
Werner Lemberge4b32a52000-10-31 20:42:18 +0000169
Werner Lemberg8728f292000-08-23 17:32:42 +0000170 if ( !found )
David Turnerb466a762000-08-23 11:22:30 +0000171 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000172 /* we haven't found the relevant element. We will now try */
173 /* to create a new one. */
David Turnerb466a762000-08-23 11:22:30 +0000174 if ( lru->num_elements >= lru->max_elements )
175 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000176 /* this lru list is full; we will now flush */
David Turnerb466a762000-08-23 11:22:30 +0000177 /* the oldest node */
178 FT_LruNode lru_node;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000179
180
David Turnerb466a762000-08-23 11:22:30 +0000181 node = lru->elements.tail;
182 lru_node = (FT_LruNode)node;
David Turner98d27012000-08-24 11:53:35 +0000183 found = lru_node;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000184
Werner Lemberg8728f292000-08-23 17:32:42 +0000185 if ( clazz->flush_element )
David Turnerb466a762000-08-23 11:22:30 +0000186 error = clazz->flush_element( lru, lru_node, key );
187 else
188 {
189 clazz->done_element( lru, lru_node );
190 lru_node->key = key;
191 node->data = 0;
192 error = clazz->init_element( lru, lru_node );
193 }
194
Werner Lemberg8728f292000-08-23 17:32:42 +0000195 if ( !error )
David Turnerb466a762000-08-23 11:22:30 +0000196 {
197 /* now, move element to top of list */
198 FT_List_Up( &lru->elements, node );
199 }
200 else
201 {
202 /* in case of error, the node must be discarded */
203 FT_List_Remove( &lru->elements, node );
204 lru->num_elements--;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000205
Werner Lemberg8728f292000-08-23 17:32:42 +0000206 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000207 FT_List_Insert( &lru->free_nodes, node );
208 else
209 FREE( lru_node );
Werner Lemberge4b32a52000-10-31 20:42:18 +0000210
David Turner98d27012000-08-24 11:53:35 +0000211 found = 0;
David Turnerb466a762000-08-23 11:22:30 +0000212 }
213 }
214 else
Werner Lemberge4b32a52000-10-31 20:42:18 +0000215 {
David Turnerb466a762000-08-23 11:22:30 +0000216 FT_LruNode lru_node;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000217
Werner Lemberg8728f292000-08-23 17:32:42 +0000218
David Turnerb466a762000-08-23 11:22:30 +0000219 /* create a new lru list node, then the element for it */
Werner Lemberg8728f292000-08-23 17:32:42 +0000220 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000221 {
Werner Lembergab855232000-10-31 22:13:54 +0000222 node = lru->free_nodes.head;
223 lru_node = (FT_LruNode)node;
David Turnerb466a762000-08-23 11:22:30 +0000224 lru_node->key = key;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000225
David Turnerb466a762000-08-23 11:22:30 +0000226 error = clazz->init_element( lru, lru_node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000227 if ( error )
David Turnerb466a762000-08-23 11:22:30 +0000228 goto Exit;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000229
David Turnerb466a762000-08-23 11:22:30 +0000230 FT_List_Remove( &lru->free_nodes, node );
231 }
232 else
233 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000234 if ( ALLOC( lru_node, sizeof ( *lru_node ) ) )
David Turnerb466a762000-08-23 11:22:30 +0000235 goto Exit;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000236
David Turnerb466a762000-08-23 11:22:30 +0000237 lru_node->key = key;
238 error = clazz->init_element( lru, lru_node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000239 if ( error )
David Turnerb466a762000-08-23 11:22:30 +0000240 {
241 FREE( lru_node );
242 goto Exit;
243 }
244 }
Werner Lemberge4b32a52000-10-31 20:42:18 +0000245
246 found = lru_node;
David Turnerb466a762000-08-23 11:22:30 +0000247 node = (FT_ListNode)lru_node;
248 FT_List_Insert( &lru->elements, node );
249 lru->num_elements++;
250 }
251 }
Werner Lemberge4b32a52000-10-31 20:42:18 +0000252
253 Exit:
David Turnerb466a762000-08-23 11:22:30 +0000254 *anode = found;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000255 return error;
David Turnerb466a762000-08-23 11:22:30 +0000256 }
257
258
Werner Lemberg8728f292000-08-23 17:32:42 +0000259 FT_EXPORT_DEF( FT_Error ) FT_Lru_Lookup( FT_Lru lru,
260 FT_LruKey key,
261 FT_Pointer* aobject )
David Turnerb466a762000-08-23 11:22:30 +0000262 {
263 FT_Error error;
264 FT_LruNode node;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000265
Werner Lemberg8728f292000-08-23 17:32:42 +0000266
Werner Lembergd1b74752000-08-24 16:29:15 +0000267 /* check for valid `lru' and `key' delayed to FT_Lru_Lookup_Node() */
268
269 if ( !aobject )
270 return FT_Err_Invalid_Argument;
271
David Turnerb466a762000-08-23 11:22:30 +0000272 *aobject = 0;
273 error = FT_Lru_Lookup_Node( lru, key, &node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000274 if ( !error )
David Turnerb466a762000-08-23 11:22:30 +0000275 *aobject = node->root.data;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000276
David Turnerb466a762000-08-23 11:22:30 +0000277 return error;
278 }
279
280
Werner Lemberg8728f292000-08-23 17:32:42 +0000281 FT_EXPORT_FUNC( void ) FT_Lru_Remove_Node( FT_Lru lru,
282 FT_LruNode node )
David Turnerb466a762000-08-23 11:22:30 +0000283 {
Werner Lembergd1b74752000-08-24 16:29:15 +0000284 if ( !lru || !node )
285 return;
286
Werner Lemberg8728f292000-08-23 17:32:42 +0000287 if ( lru->num_elements > 0 )
David Turnerb466a762000-08-23 11:22:30 +0000288 {
289 FT_List_Remove( &lru->elements, (FT_ListNode)node );
290 lru->clazz->done_element( lru, node );
Werner Lemberge4b32a52000-10-31 20:42:18 +0000291
Werner Lemberg8728f292000-08-23 17:32:42 +0000292 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000293 FT_List_Insert( &lru->free_nodes, (FT_ListNode)node );
294 else
295 {
296 FT_Memory memory = lru->memory;
Werner Lemberg8728f292000-08-23 17:32:42 +0000297
298
299 FREE( node );
David Turnerb466a762000-08-23 11:22:30 +0000300 }
Werner Lemberg8728f292000-08-23 17:32:42 +0000301
David Turnerb466a762000-08-23 11:22:30 +0000302 lru->num_elements--;
303 }
304 }
305
306
Werner Lemberg8728f292000-08-23 17:32:42 +0000307 FT_EXPORT_FUNC( void ) FT_Lru_Remove_Selection( FT_Lru lru,
308 FT_Lru_Selector selector,
309 FT_Pointer data )
David Turnerb466a762000-08-23 11:22:30 +0000310 {
Werner Lembergd1b74752000-08-24 16:29:15 +0000311 if ( !lru || !selector )
312 return;
313
Werner Lemberg8728f292000-08-23 17:32:42 +0000314 if ( lru->num_elements > 0 )
David Turnerb466a762000-08-23 11:22:30 +0000315 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000316 FT_ListNode node = lru->elements.head;
317 FT_ListNode next;
318
Werner Lemberge4b32a52000-10-31 20:42:18 +0000319
Werner Lemberg8728f292000-08-23 17:32:42 +0000320 while ( node )
David Turnerb466a762000-08-23 11:22:30 +0000321 {
322 next = node->next;
323 if ( selector( lru, (FT_LruNode)node, data ) )
324 {
325 /* remove this element from the list, and destroy it */
326 FT_Lru_Remove_Node( lru, (FT_LruNode)node );
327 }
328 node = next;
329 }
330 }
331 }
332
Werner Lemberg8728f292000-08-23 17:32:42 +0000333
334/* END */