blob: 2838847a70deb0d9fd90805cfb2cbb52c9fbc3e1 [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/* */
Werner Lemberg415235d2001-06-28 17:49:10 +00007/* Copyright 2000-2001 by */
Werner Lemberg8728f292000-08-23 17:32:42 +00008/* 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
Werner Lembergcc069be2000-12-08 16:17:16 +000018
19#include <ft2build.h>
20#include FT_CACHE_H
21#include FT_CACHE_INTERNAL_LRU_H
22#include FT_LIST_H
23#include FT_INTERNAL_OBJECTS_H
David Turnerb466a762000-08-23 11:22:30 +000024
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000025#include "ftcerror.h"
26
Werner Lemberg8728f292000-08-23 17:32:42 +000027
Werner Lembergf814d0f2001-06-27 16:18:10 +000028 static void
29 lru_build_free_list( FT_LruNode nodes,
30 FT_UInt count,
31 FT_List free_list )
David Turnerb466a762000-08-23 11:22:30 +000032 {
33 FT_LruNode node = nodes;
34 FT_LruNode limit = node + count;
Werner Lemberge4b32a52000-10-31 20:42:18 +000035
Werner Lemberg8728f292000-08-23 17:32:42 +000036
David Turnerb466a762000-08-23 11:22:30 +000037 free_list->head = free_list->tail = 0;
38 for ( ; node < limit; node++ )
39 FT_List_Add( free_list, (FT_ListNode)node );
40 }
41
42
Werner Lembergf814d0f2001-06-27 16:18:10 +000043 FT_EXPORT_DEF( FT_Error )
44 FT_Lru_New( const FT_Lru_Class* clazz,
45 FT_UInt max_elements,
46 FT_Pointer user_data,
47 FT_Memory memory,
48 FT_Bool pre_alloc,
49 FT_Lru *anlru )
David Turnerb466a762000-08-23 11:22:30 +000050 {
51 FT_Error error;
52 FT_Lru lru;
Werner Lemberge4b32a52000-10-31 20:42:18 +000053
Werner Lemberg8728f292000-08-23 17:32:42 +000054
Werner Lemberg4b680072000-11-07 06:30:29 +000055 if ( !anlru )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000056 return FTC_Err_Invalid_Argument;
Werner Lembergd1b74752000-08-24 16:29:15 +000057
Werner Lemberg4b680072000-11-07 06:30:29 +000058 *anlru = 0;
Werner Lemberg8728f292000-08-23 17:32:42 +000059 if ( !ALLOC( lru, sizeof ( *lru ) ) )
David Turnerb466a762000-08-23 11:22:30 +000060 {
Werner Lemberg8728f292000-08-23 17:32:42 +000061 if ( pre_alloc )
David Turnerb466a762000-08-23 11:22:30 +000062 {
63 /* allocate static array of lru list nodes */
64 if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) )
65 {
66 FREE( lru );
67 goto Exit;
68 }
Werner Lemberge4b32a52000-10-31 20:42:18 +000069
Werner Lemberg8728f292000-08-23 17:32:42 +000070 /* build the `free_nodes' list from the array */
David Turnerb466a762000-08-23 11:22:30 +000071 lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes );
72 }
Werner Lemberge4b32a52000-10-31 20:42:18 +000073
David Turnerb466a762000-08-23 11:22:30 +000074 /* initialize common fields */
75 lru->clazz = (FT_Lru_Class*)clazz;
76 lru->max_elements = max_elements;
77 lru->memory = memory;
David Turner3b2c50e2000-08-23 21:11:13 +000078 lru->user_data = user_data;
Werner Lemberg8728f292000-08-23 17:32:42 +000079
Werner Lemberg4b680072000-11-07 06:30:29 +000080 *anlru = lru;
David Turnerb466a762000-08-23 11:22:30 +000081 }
Werner Lemberg8728f292000-08-23 17:32:42 +000082
David Turnerb466a762000-08-23 11:22:30 +000083 Exit:
84 return error;
85 }
86
87
Werner Lembergf814d0f2001-06-27 16:18:10 +000088 FT_EXPORT_DEF( void )
89 FT_Lru_Reset( FT_Lru lru )
David Turnerb466a762000-08-23 11:22:30 +000090 {
Werner Lembergd1b74752000-08-24 16:29:15 +000091 FT_ListNode node;
92 FT_Lru_Class* clazz;
93 FT_Memory memory;
Werner Lemberge4b32a52000-10-31 20:42:18 +000094
Werner Lemberg8728f292000-08-23 17:32:42 +000095
Werner Lembergd1b74752000-08-24 16:29:15 +000096 if ( !lru )
97 return;
98
99 node = lru->elements.head;
100 clazz = lru->clazz;
101 memory = lru->memory;
102
Werner Lemberg8728f292000-08-23 17:32:42 +0000103 while ( node )
David Turnerb466a762000-08-23 11:22:30 +0000104 {
105 FT_ListNode next = node->next;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000106
Werner Lemberg8728f292000-08-23 17:32:42 +0000107
David Turnerb466a762000-08-23 11:22:30 +0000108 clazz->done_element( lru, (FT_LruNode)node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000109 if ( !lru->nodes )
110 FREE( node );
Werner Lemberge4b32a52000-10-31 20:42:18 +0000111
David Turnerb466a762000-08-23 11:22:30 +0000112 node = next;
113 }
Werner Lemberge4b32a52000-10-31 20:42:18 +0000114
David Turnerb466a762000-08-23 11:22:30 +0000115 /* rebuild free list if necessary */
Werner Lemberg8728f292000-08-23 17:32:42 +0000116 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000117 lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes );
Werner Lemberg8728f292000-08-23 17:32:42 +0000118
119 lru->elements.head = lru->elements.tail = 0;
David Turnerb466a762000-08-23 11:22:30 +0000120 lru->num_elements = 0;
121 }
122
123
Werner Lembergf814d0f2001-06-27 16:18:10 +0000124 FT_EXPORT_DEF( void )
125 FT_Lru_Done( FT_Lru lru )
David Turnerb466a762000-08-23 11:22:30 +0000126 {
Werner Lembergd1b74752000-08-24 16:29:15 +0000127 FT_Memory memory;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000128
Werner Lemberg8728f292000-08-23 17:32:42 +0000129
Werner Lembergd1b74752000-08-24 16:29:15 +0000130 if ( !lru )
131 return;
132
133 memory = lru->memory;
134
Werner Lemberg8728f292000-08-23 17:32:42 +0000135 FT_Lru_Reset( lru );
David Turner50840942000-12-06 18:02:01 +0000136
137 FREE( lru->nodes );
Werner Lemberg8728f292000-08-23 17:32:42 +0000138 FREE( lru );
David Turnerb466a762000-08-23 11:22:30 +0000139 }
140
141
Werner Lembergf814d0f2001-06-27 16:18:10 +0000142 FT_EXPORT_DEF( FT_Error )
143 FT_Lru_Lookup_Node( FT_Lru lru,
144 FT_LruKey key,
145 FT_LruNode *anode )
David Turnerb466a762000-08-23 11:22:30 +0000146 {
Werner Lembergd1b74752000-08-24 16:29:15 +0000147 FT_Error error = 0;
148 FT_ListNode node;
149 FT_Lru_Class* clazz;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000150 FT_LruNode found = 0;
Werner Lembergd1b74752000-08-24 16:29:15 +0000151 FT_Memory memory;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000152
Werner Lemberg8728f292000-08-23 17:32:42 +0000153
Werner Lembergd1b74752000-08-24 16:29:15 +0000154 if ( !lru || !key || !anode )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000155 return FTC_Err_Invalid_Argument;
Werner Lembergd1b74752000-08-24 16:29:15 +0000156
157 node = lru->elements.head;
158 clazz = lru->clazz;
159 memory = lru->memory;
160
Werner Lemberg8728f292000-08-23 17:32:42 +0000161 if ( clazz->compare_element )
David Turnerb466a762000-08-23 11:22:30 +0000162 {
163 for ( ; node; node = node->next )
Werner Lemberg8728f292000-08-23 17:32:42 +0000164 if ( clazz->compare_element( (FT_LruNode)node, key ) )
David Turnerb466a762000-08-23 11:22:30 +0000165 {
166 found = (FT_LruNode)node;
167 break;
168 }
169 }
170 else
171 {
172 for ( ; node; node = node->next )
Werner Lemberg8728f292000-08-23 17:32:42 +0000173 if ( ((FT_LruNode)node)->key == key )
David Turnerb466a762000-08-23 11:22:30 +0000174 {
175 found = (FT_LruNode)node;
176 break;
177 }
178 }
Werner Lemberge4b32a52000-10-31 20:42:18 +0000179
David Turner5b1e8142001-10-07 11:06:07 +0000180 if ( found )
181 {
182 /* move element to top of list */
183 FT_List_Up( &lru->elements, node );
184 }
185 else
David Turnerb466a762000-08-23 11:22:30 +0000186 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000187 /* we haven't found the relevant element. We will now try */
188 /* to create a new one. */
David Turnerb466a762000-08-23 11:22:30 +0000189 if ( lru->num_elements >= lru->max_elements )
190 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000191 /* this lru list is full; we will now flush */
David Turnerb466a762000-08-23 11:22:30 +0000192 /* the oldest node */
193 FT_LruNode lru_node;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000194
195
David Turnerb466a762000-08-23 11:22:30 +0000196 node = lru->elements.tail;
197 lru_node = (FT_LruNode)node;
David Turner98d27012000-08-24 11:53:35 +0000198 found = lru_node;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000199
Werner Lemberg8728f292000-08-23 17:32:42 +0000200 if ( clazz->flush_element )
David Turnerb466a762000-08-23 11:22:30 +0000201 error = clazz->flush_element( lru, lru_node, key );
202 else
203 {
204 clazz->done_element( lru, lru_node );
205 lru_node->key = key;
206 node->data = 0;
207 error = clazz->init_element( lru, lru_node );
208 }
209
Werner Lemberg8728f292000-08-23 17:32:42 +0000210 if ( !error )
David Turnerb466a762000-08-23 11:22:30 +0000211 {
212 /* now, move element to top of list */
213 FT_List_Up( &lru->elements, node );
214 }
215 else
216 {
217 /* in case of error, the node must be discarded */
218 FT_List_Remove( &lru->elements, node );
219 lru->num_elements--;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000220
Werner Lemberg8728f292000-08-23 17:32:42 +0000221 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000222 FT_List_Insert( &lru->free_nodes, node );
223 else
224 FREE( lru_node );
Werner Lemberge4b32a52000-10-31 20:42:18 +0000225
David Turner98d27012000-08-24 11:53:35 +0000226 found = 0;
David Turnerb466a762000-08-23 11:22:30 +0000227 }
228 }
229 else
Werner Lemberge4b32a52000-10-31 20:42:18 +0000230 {
David Turnerb466a762000-08-23 11:22:30 +0000231 FT_LruNode lru_node;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000232
Werner Lemberg8728f292000-08-23 17:32:42 +0000233
David Turnerb466a762000-08-23 11:22:30 +0000234 /* create a new lru list node, then the element for it */
Werner Lemberg8728f292000-08-23 17:32:42 +0000235 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000236 {
Werner Lembergab855232000-10-31 22:13:54 +0000237 node = lru->free_nodes.head;
238 lru_node = (FT_LruNode)node;
David Turnerb466a762000-08-23 11:22:30 +0000239 lru_node->key = key;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000240
David Turnerb466a762000-08-23 11:22:30 +0000241 error = clazz->init_element( lru, lru_node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000242 if ( error )
David Turnerb466a762000-08-23 11:22:30 +0000243 goto Exit;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000244
David Turnerb466a762000-08-23 11:22:30 +0000245 FT_List_Remove( &lru->free_nodes, node );
246 }
247 else
248 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000249 if ( ALLOC( lru_node, sizeof ( *lru_node ) ) )
David Turnerb466a762000-08-23 11:22:30 +0000250 goto Exit;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000251
David Turnerb466a762000-08-23 11:22:30 +0000252 lru_node->key = key;
253 error = clazz->init_element( lru, lru_node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000254 if ( error )
David Turnerb466a762000-08-23 11:22:30 +0000255 {
256 FREE( lru_node );
257 goto Exit;
258 }
259 }
Werner Lemberge4b32a52000-10-31 20:42:18 +0000260
261 found = lru_node;
David Turnerb466a762000-08-23 11:22:30 +0000262 node = (FT_ListNode)lru_node;
263 FT_List_Insert( &lru->elements, node );
264 lru->num_elements++;
265 }
266 }
Werner Lemberge4b32a52000-10-31 20:42:18 +0000267
268 Exit:
David Turnerb466a762000-08-23 11:22:30 +0000269 *anode = found;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000270 return error;
David Turnerb466a762000-08-23 11:22:30 +0000271 }
272
273
Werner Lembergf814d0f2001-06-27 16:18:10 +0000274 FT_EXPORT_DEF( FT_Error )
275 FT_Lru_Lookup( FT_Lru lru,
276 FT_LruKey key,
277 FT_Pointer *anobject )
David Turnerb466a762000-08-23 11:22:30 +0000278 {
279 FT_Error error;
280 FT_LruNode node;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000281
Werner Lemberg8728f292000-08-23 17:32:42 +0000282
Werner Lembergd1b74752000-08-24 16:29:15 +0000283 /* check for valid `lru' and `key' delayed to FT_Lru_Lookup_Node() */
284
Werner Lemberg4b680072000-11-07 06:30:29 +0000285 if ( !anobject )
Werner Lemberg1f7f0e82001-06-06 17:30:41 +0000286 return FTC_Err_Invalid_Argument;
Werner Lembergd1b74752000-08-24 16:29:15 +0000287
Werner Lemberg4b680072000-11-07 06:30:29 +0000288 *anobject = 0;
David Turnerb466a762000-08-23 11:22:30 +0000289 error = FT_Lru_Lookup_Node( lru, key, &node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000290 if ( !error )
Werner Lemberg4b680072000-11-07 06:30:29 +0000291 *anobject = node->root.data;
Werner Lemberge4b32a52000-10-31 20:42:18 +0000292
David Turnerb466a762000-08-23 11:22:30 +0000293 return error;
294 }
295
296
Werner Lembergf814d0f2001-06-27 16:18:10 +0000297 FT_EXPORT_DEF( void )
298 FT_Lru_Remove_Node( FT_Lru lru,
299 FT_LruNode node )
David Turnerb466a762000-08-23 11:22:30 +0000300 {
Werner Lembergd1b74752000-08-24 16:29:15 +0000301 if ( !lru || !node )
302 return;
303
Werner Lemberg8728f292000-08-23 17:32:42 +0000304 if ( lru->num_elements > 0 )
David Turnerb466a762000-08-23 11:22:30 +0000305 {
306 FT_List_Remove( &lru->elements, (FT_ListNode)node );
307 lru->clazz->done_element( lru, node );
Werner Lemberge4b32a52000-10-31 20:42:18 +0000308
Werner Lemberg8728f292000-08-23 17:32:42 +0000309 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000310 FT_List_Insert( &lru->free_nodes, (FT_ListNode)node );
311 else
312 {
313 FT_Memory memory = lru->memory;
Werner Lemberg8728f292000-08-23 17:32:42 +0000314
315
316 FREE( node );
David Turnerb466a762000-08-23 11:22:30 +0000317 }
Werner Lemberg8728f292000-08-23 17:32:42 +0000318
David Turnerb466a762000-08-23 11:22:30 +0000319 lru->num_elements--;
320 }
321 }
322
323
Werner Lembergf814d0f2001-06-27 16:18:10 +0000324 FT_EXPORT_DEF( void )
325 FT_Lru_Remove_Selection( FT_Lru lru,
326 FT_Lru_Selector selector,
327 FT_Pointer data )
David Turnerb466a762000-08-23 11:22:30 +0000328 {
Werner Lembergd1b74752000-08-24 16:29:15 +0000329 if ( !lru || !selector )
330 return;
331
Werner Lemberg8728f292000-08-23 17:32:42 +0000332 if ( lru->num_elements > 0 )
David Turnerb466a762000-08-23 11:22:30 +0000333 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000334 FT_ListNode node = lru->elements.head;
335 FT_ListNode next;
336
Werner Lemberge4b32a52000-10-31 20:42:18 +0000337
Werner Lemberg8728f292000-08-23 17:32:42 +0000338 while ( node )
David Turnerb466a762000-08-23 11:22:30 +0000339 {
340 next = node->next;
341 if ( selector( lru, (FT_LruNode)node, data ) )
342 {
343 /* remove this element from the list, and destroy it */
344 FT_Lru_Remove_Node( lru, (FT_LruNode)node );
345 }
346 node = next;
347 }
348 }
349 }
350
Werner Lemberg8728f292000-08-23 17:32:42 +0000351
352/* END */