1 /***************************************************************************/
5 /* Simple LRU list-cache (body). */
7 /* Copyright 2000-2001, 2002 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
21 #include FT_CACHE_INTERNAL_LRU_H
23 #include FT_INTERNAL_OBJECTS_H
24 #include FT_INTERNAL_DEBUG_H
29 FT_EXPORT_DEF( FT_Error )
30 FT_LruList_New( FT_LruList_Class clazz,
40 if ( !alist || !clazz )
41 return FTC_Err_Invalid_Argument;
44 if ( !FT_ALLOC( list, clazz->list_size ) )
46 /* initialize common fields */
48 list->memory = memory;
49 list->max_nodes = max_nodes;
50 list->data = user_data;
52 if ( clazz->list_init )
54 error = clazz->list_init( list );
57 if ( clazz->list_done )
58 clazz->list_done( list );
72 FT_LruList_Destroy( FT_LruList list )
75 FT_LruList_Class clazz;
81 memory = list->memory;
84 FT_LruList_Reset( list );
86 if ( clazz->list_done )
87 clazz->list_done( list );
94 FT_LruList_Reset( FT_LruList list )
97 FT_LruList_Class clazz;
106 memory = list->memory;
110 FT_LruNode next = node->next;
113 if ( clazz->node_done )
114 clazz->node_done( node, list->data );
125 FT_EXPORT_DEF( FT_Error )
126 FT_LruList_Lookup( FT_LruList list,
131 FT_LruNode node, *pnode;
132 FT_LruList_Class clazz;
134 FT_LruNode result = NULL;
138 if ( !list || !key || !anode )
139 return FTC_Err_Invalid_Argument;
141 pnode = &list->nodes;
145 memory = list->memory;
147 if ( clazz->node_compare )
155 if ( clazz->node_compare( node, key, list->data ) )
159 pnode = &(*pnode)->next;
170 if ( node->key == key )
174 pnode = &(*pnode)->next;
180 /* move element to top of list */
181 if ( list->nodes != node )
184 node->next = list->nodes;
191 /* since we haven't found the relevant element in our LRU list,
192 * we're going to "create" a new one.
194 * the following code is a bit special, because it tries to handle
195 * out-of-memory conditions (OOM) in an intelligent way.
197 * more precisely, if not enough memory is available to create a
198 * new node or "flush" an old one, we need to remove the oldest
199 * elements from our list, and try again. since several tries may
200 * be necessary, a loop is needed
202 * this loop will only exit when:
204 * - a new node was succesfully created, or an old node flushed
205 * - an error other than FT_Err_Out_Of_Memory is detected
206 * - the list of nodes is empty, and it isn't possible to create
209 * on each unsucesful attempt, one node will be removed from the list
214 FT_Int drop_last = ( list->max_nodes > 0 &&
215 list->num_nodes >= list->max_nodes );
221 /* when "drop_last" is true, we should free the last node in
222 * the list to make room for a new one. note that we re-use
223 * its memory block to save allocation calls.
227 /* find the last node in the list
229 pnode = &list->nodes;
234 FT_ASSERT( list->nodes == 0 );
235 error = FT_Err_Out_Of_Memory;
239 FT_ASSERT( list->num_nodes > 0 );
247 /* remove it from the list, and try to "flush" it. doing this will
248 * save a significant number of dynamic allocations compared to
249 * a classic destroy/create cycle
252 list->num_nodes -= 1;
254 if ( clazz->node_flush )
256 error = clazz->node_flush( node, key, list->data );
260 /* note that if an error occured during the flush, we need to
261 * finalize it since it is potentially in incomplete state.
265 /* we finalize, but do not destroy the last node, we
266 * simply re-use its memory block !
268 if ( clazz->node_done )
269 clazz->node_done( node, list->data );
271 FT_MEM_ZERO( node, clazz->node_size );
275 /* try to allocate a new node when "drop_last" is not TRUE
276 * this usually happens on the first pass, when the LRU list
277 * is not already full.
279 if ( FT_ALLOC( node, clazz->node_size ) )
283 FT_ASSERT( node != NULL );
286 error = clazz->node_init( node, key, list->data );
289 if ( clazz->node_done )
290 clazz->node_done( node, list->data );
299 node->next = list->nodes;
305 if ( error != FT_Err_Out_Of_Memory )
320 FT_EXPORT_DEF( void )
321 FT_LruList_Remove( FT_LruList list,
327 if ( !list || !node )
330 pnode = &list->nodes;
333 if ( *pnode == node )
335 FT_Memory memory = list->memory;
336 FT_LruList_Class clazz = list->clazz;
342 if ( clazz->node_done )
343 clazz->node_done( node, list->data );
350 pnode = &(*pnode)->next;
355 FT_EXPORT_DEF( void )
356 FT_LruList_Remove_Selection( FT_LruList list,
357 FT_LruNode_SelectFunc select_func,
358 FT_Pointer select_data )
360 FT_LruNode *pnode, node;
361 FT_LruList_Class clazz;
365 if ( !list || !select_func )
368 memory = list->memory;
370 pnode = &list->nodes;
378 if ( select_func( node, select_data, list->data ) )
383 if ( clazz->node_done )
384 clazz->node_done( node, list );
389 pnode = &(*pnode)->next;