blob: 1c1cc61e385f4103a480008b6886b41cb5ae8660 [file] [log] [blame]
Werner Lemberg8728f292000-08-23 17:32:42 +00001/***************************************************************************/
2/* */
3/* ftlru.c */
4/* */
5/* XXX */
6/* */
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 Turnerb466a762000-08-23 11:22:30 +000019#include <cache/ftlru.h>
20#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;
31
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;
48
Werner Lemberg8728f292000-08-23 17:32:42 +000049
David Turnerb466a762000-08-23 11:22:30 +000050 *alru = 0;
Werner Lemberg8728f292000-08-23 17:32:42 +000051 if ( !ALLOC( lru, sizeof ( *lru ) ) )
David Turnerb466a762000-08-23 11:22:30 +000052 {
Werner Lemberg8728f292000-08-23 17:32:42 +000053 if ( pre_alloc )
David Turnerb466a762000-08-23 11:22:30 +000054 {
55 /* allocate static array of lru list nodes */
56 if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) )
57 {
58 FREE( lru );
59 goto Exit;
60 }
61
Werner Lemberg8728f292000-08-23 17:32:42 +000062 /* build the `free_nodes' list from the array */
David Turnerb466a762000-08-23 11:22:30 +000063 lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes );
64 }
65
66 /* initialize common fields */
67 lru->clazz = (FT_Lru_Class*)clazz;
68 lru->max_elements = max_elements;
69 lru->memory = memory;
David Turner3b2c50e2000-08-23 21:11:13 +000070 lru->user_data = user_data;
Werner Lemberg8728f292000-08-23 17:32:42 +000071
David Turnerb466a762000-08-23 11:22:30 +000072 *alru = lru;
73 }
Werner Lemberg8728f292000-08-23 17:32:42 +000074
David Turnerb466a762000-08-23 11:22:30 +000075 Exit:
76 return error;
77 }
78
79
80
Werner Lemberg8728f292000-08-23 17:32:42 +000081 FT_EXPORT_DEF( void ) FT_Lru_Reset( FT_Lru lru )
David Turnerb466a762000-08-23 11:22:30 +000082 {
83 FT_ListNode node = lru->elements.head;
84 FT_Lru_Class* clazz = lru->clazz;
85 FT_Memory memory = lru->memory;
86
Werner Lemberg8728f292000-08-23 17:32:42 +000087
88 while ( node )
David Turnerb466a762000-08-23 11:22:30 +000089 {
90 FT_ListNode next = node->next;
91
Werner Lemberg8728f292000-08-23 17:32:42 +000092
David Turnerb466a762000-08-23 11:22:30 +000093 clazz->done_element( lru, (FT_LruNode)node );
Werner Lemberg8728f292000-08-23 17:32:42 +000094 if ( !lru->nodes )
95 FREE( node );
David Turnerb466a762000-08-23 11:22:30 +000096
97 node = next;
98 }
99
100 /* rebuild free list if necessary */
Werner Lemberg8728f292000-08-23 17:32:42 +0000101 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000102 lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes );
Werner Lemberg8728f292000-08-23 17:32:42 +0000103
104 lru->elements.head = lru->elements.tail = 0;
David Turnerb466a762000-08-23 11:22:30 +0000105 lru->num_elements = 0;
106 }
107
108
Werner Lemberg8728f292000-08-23 17:32:42 +0000109 FT_EXPORT_DEF( void ) FT_Lru_Done( FT_Lru lru )
David Turnerb466a762000-08-23 11:22:30 +0000110 {
111 FT_Memory memory = lru->memory;
112
Werner Lemberg8728f292000-08-23 17:32:42 +0000113
114 FT_Lru_Reset( lru );
115 FREE( lru );
David Turnerb466a762000-08-23 11:22:30 +0000116 }
117
118
Werner Lemberg8728f292000-08-23 17:32:42 +0000119 FT_EXPORT_DEF( FT_Error ) FT_Lru_Lookup_Node( FT_Lru lru,
120 FT_LruKey key,
121 FT_LruNode* anode )
David Turnerb466a762000-08-23 11:22:30 +0000122 {
123 FT_Error error = 0;
124 FT_ListNode node = lru->elements.head;
125 FT_Lru_Class* clazz = lru->clazz;
126 FT_LruNode found = 0;
127 FT_Memory memory = lru->memory;
128
Werner Lemberg8728f292000-08-23 17:32:42 +0000129
130 if ( clazz->compare_element )
David Turnerb466a762000-08-23 11:22:30 +0000131 {
132 for ( ; node; node = node->next )
Werner Lemberg8728f292000-08-23 17:32:42 +0000133 if ( clazz->compare_element( (FT_LruNode)node, key ) )
David Turnerb466a762000-08-23 11:22:30 +0000134 {
135 found = (FT_LruNode)node;
136 break;
137 }
138 }
139 else
140 {
141 for ( ; node; node = node->next )
Werner Lemberg8728f292000-08-23 17:32:42 +0000142 if ( ((FT_LruNode)node)->key == key )
David Turnerb466a762000-08-23 11:22:30 +0000143 {
144 found = (FT_LruNode)node;
145 break;
146 }
147 }
148
Werner Lemberg8728f292000-08-23 17:32:42 +0000149 if ( !found )
David Turnerb466a762000-08-23 11:22:30 +0000150 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000151 /* we haven't found the relevant element. We will now try */
152 /* to create a new one. */
David Turnerb466a762000-08-23 11:22:30 +0000153 if ( lru->num_elements >= lru->max_elements )
154 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000155 /* this lru list is full; we will now flush */
David Turnerb466a762000-08-23 11:22:30 +0000156 /* the oldest node */
157 FT_LruNode lru_node;
158
159
160 node = lru->elements.tail;
161 lru_node = (FT_LruNode)node;
David Turner98d27012000-08-24 11:53:35 +0000162 found = lru_node;
David Turnerb466a762000-08-23 11:22:30 +0000163
Werner Lemberg8728f292000-08-23 17:32:42 +0000164 if ( clazz->flush_element )
David Turnerb466a762000-08-23 11:22:30 +0000165 error = clazz->flush_element( lru, lru_node, key );
166 else
167 {
168 clazz->done_element( lru, lru_node );
169 lru_node->key = key;
170 node->data = 0;
171 error = clazz->init_element( lru, lru_node );
172 }
173
Werner Lemberg8728f292000-08-23 17:32:42 +0000174 if ( !error )
David Turnerb466a762000-08-23 11:22:30 +0000175 {
176 /* now, move element to top of list */
177 FT_List_Up( &lru->elements, node );
178 }
179 else
180 {
181 /* in case of error, the node must be discarded */
182 FT_List_Remove( &lru->elements, node );
183 lru->num_elements--;
184
Werner Lemberg8728f292000-08-23 17:32:42 +0000185 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000186 FT_List_Insert( &lru->free_nodes, node );
187 else
188 FREE( lru_node );
David Turner98d27012000-08-24 11:53:35 +0000189
190 found = 0;
David Turnerb466a762000-08-23 11:22:30 +0000191 }
192 }
193 else
194 {
195 FT_LruNode lru_node;
196
Werner Lemberg8728f292000-08-23 17:32:42 +0000197
David Turnerb466a762000-08-23 11:22:30 +0000198 /* create a new lru list node, then the element for it */
Werner Lemberg8728f292000-08-23 17:32:42 +0000199 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000200 {
201 node = lru->free_nodes.head;
202 lru_node = (FT_LruNode)node;
203 lru_node->key = key;
204
205 error = clazz->init_element( lru, lru_node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000206 if ( error )
David Turnerb466a762000-08-23 11:22:30 +0000207 goto Exit;
208
209 FT_List_Remove( &lru->free_nodes, node );
210 }
211 else
212 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000213 if ( ALLOC( lru_node, sizeof ( *lru_node ) ) )
David Turnerb466a762000-08-23 11:22:30 +0000214 goto Exit;
215
216 lru_node->key = key;
217 error = clazz->init_element( lru, lru_node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000218 if ( error )
David Turnerb466a762000-08-23 11:22:30 +0000219 {
220 FREE( lru_node );
221 goto Exit;
222 }
223 }
224
225 found = lru_node;
226 node = (FT_ListNode)lru_node;
227 FT_List_Insert( &lru->elements, node );
228 lru->num_elements++;
229 }
230 }
231
232 Exit:
233 *anode = found;
234 return error;
235 }
236
237
Werner Lemberg8728f292000-08-23 17:32:42 +0000238 FT_EXPORT_DEF( FT_Error ) FT_Lru_Lookup( FT_Lru lru,
239 FT_LruKey key,
240 FT_Pointer* aobject )
David Turnerb466a762000-08-23 11:22:30 +0000241 {
242 FT_Error error;
243 FT_LruNode node;
244
Werner Lemberg8728f292000-08-23 17:32:42 +0000245
David Turnerb466a762000-08-23 11:22:30 +0000246 *aobject = 0;
247 error = FT_Lru_Lookup_Node( lru, key, &node );
Werner Lemberg8728f292000-08-23 17:32:42 +0000248 if ( !error )
David Turnerb466a762000-08-23 11:22:30 +0000249 *aobject = node->root.data;
250
251 return error;
252 }
253
254
Werner Lemberg8728f292000-08-23 17:32:42 +0000255 FT_EXPORT_FUNC( void ) FT_Lru_Remove_Node( FT_Lru lru,
256 FT_LruNode node )
David Turnerb466a762000-08-23 11:22:30 +0000257 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000258 if ( lru->num_elements > 0 )
David Turnerb466a762000-08-23 11:22:30 +0000259 {
260 FT_List_Remove( &lru->elements, (FT_ListNode)node );
261 lru->clazz->done_element( lru, node );
262
Werner Lemberg8728f292000-08-23 17:32:42 +0000263 if ( lru->nodes )
David Turnerb466a762000-08-23 11:22:30 +0000264 FT_List_Insert( &lru->free_nodes, (FT_ListNode)node );
265 else
266 {
267 FT_Memory memory = lru->memory;
Werner Lemberg8728f292000-08-23 17:32:42 +0000268
269
270 FREE( node );
David Turnerb466a762000-08-23 11:22:30 +0000271 }
Werner Lemberg8728f292000-08-23 17:32:42 +0000272
David Turnerb466a762000-08-23 11:22:30 +0000273 lru->num_elements--;
274 }
275 }
276
277
Werner Lemberg8728f292000-08-23 17:32:42 +0000278 FT_EXPORT_FUNC( void ) FT_Lru_Remove_Selection( FT_Lru lru,
279 FT_Lru_Selector selector,
280 FT_Pointer data )
David Turnerb466a762000-08-23 11:22:30 +0000281 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000282 if ( lru->num_elements > 0 )
David Turnerb466a762000-08-23 11:22:30 +0000283 {
Werner Lemberg8728f292000-08-23 17:32:42 +0000284 FT_ListNode node = lru->elements.head;
285 FT_ListNode next;
286
David Turnerb466a762000-08-23 11:22:30 +0000287
Werner Lemberg8728f292000-08-23 17:32:42 +0000288 while ( node )
David Turnerb466a762000-08-23 11:22:30 +0000289 {
290 next = node->next;
291 if ( selector( lru, (FT_LruNode)node, data ) )
292 {
293 /* remove this element from the list, and destroy it */
294 FT_Lru_Remove_Node( lru, (FT_LruNode)node );
295 }
296 node = next;
297 }
298 }
299 }
300
Werner Lemberg8728f292000-08-23 17:32:42 +0000301
302/* END */