diff options
Diffstat (limited to 'libfreetype/ftlru.c')
| -rw-r--r-- | libfreetype/ftlru.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/libfreetype/ftlru.c b/libfreetype/ftlru.c new file mode 100644 index 00000000..4a6f6035 --- /dev/null +++ b/libfreetype/ftlru.c @@ -0,0 +1,338 @@ +/***************************************************************************/ +/* */ +/* ftlru.c */ +/* */ +/* Simple LRU list-cache (body). */ +/* */ +/* Copyright 2000-2001, 2002 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_CACHE_H +#include FT_CACHE_INTERNAL_LRU_H +#include FT_LIST_H +#include FT_INTERNAL_OBJECTS_H + +#include "ftcerror.h" + + + FT_EXPORT_DEF( FT_Error ) + FT_LruList_New( FT_LruList_Class clazz, + FT_UInt max_nodes, + FT_Pointer user_data, + FT_Memory memory, + FT_LruList *alist ) + { + FT_Error error; + FT_LruList list; + + + if ( !alist || !clazz ) + return FTC_Err_Invalid_Argument; + + *alist = NULL; + if ( !FT_ALLOC( list, clazz->list_size ) ) + { + /* initialize common fields */ + list->clazz = clazz; + list->memory = memory; + list->max_nodes = max_nodes; + list->data = user_data; + + if ( clazz->list_init ) + { + error = clazz->list_init( list ); + if ( error ) + { + if ( clazz->list_done ) + clazz->list_done( list ); + + FT_FREE( list ); + } + } + + *alist = list; + } + + return error; + } + + + FT_EXPORT_DEF( void ) + FT_LruList_Destroy( FT_LruList list ) + { + FT_Memory memory; + FT_LruList_Class clazz; + + + if ( !list ) + return; + + memory = list->memory; + clazz = list->clazz; + + FT_LruList_Reset( list ); + + if ( clazz->list_done ) + clazz->list_done( list ); + + FT_FREE( list ); + } + + + FT_EXPORT_DEF( void ) + FT_LruList_Reset( FT_LruList list ) + { + FT_LruNode node; + FT_LruList_Class clazz; + FT_Memory memory; + + + if ( !list ) + return; + + node = list->nodes; + clazz = list->clazz; + memory = list->memory; + + while ( node ) + { + FT_LruNode next = node->next; + + + if ( clazz->node_done ) + clazz->node_done( node, list->data ); + + FT_FREE( node ); + node = next; + } + + list->nodes = NULL; + list->num_nodes = 0; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_LruList_Lookup( FT_LruList list, + FT_LruKey key, + FT_LruNode *anode ) + { + FT_Error error = 0; + FT_LruNode node, *pnode; + FT_LruList_Class clazz; + FT_LruNode* plast; + FT_LruNode result = NULL; + FT_Memory memory; + + + if ( !list || !key || !anode ) + return FTC_Err_Invalid_Argument; + + pnode = &list->nodes; + plast = pnode; + node = NULL; + clazz = list->clazz; + memory = list->memory; + + if ( clazz->node_compare ) + { + for (;;) + { + node = *pnode; + if ( node == NULL ) + break; + + if ( clazz->node_compare( node, key, list->data ) ) + break; + + plast = pnode; + pnode = &(*pnode)->next; + } + } + else + { + for (;;) + { + node = *pnode; + if ( node == NULL ) + break; + + if ( node->key == key ) + break; + + plast = pnode; + pnode = &(*pnode)->next; + } + } + + if ( node ) + { + /* move element to top of list */ + if ( list->nodes != node ) + { + *pnode = node->next; + node->next = list->nodes; + list->nodes = node; + } + result = node; + goto Exit; + } + + /* we haven't found the relevant element. We will now try */ + /* to create a new one. */ + /* */ + + /* first, check if our list if full, when appropriate */ + if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes ) + { + /* this list list is full; we will now flush */ + /* the oldest node, if there's one! */ + FT_LruNode last = *plast; + + + if ( last ) + { + if ( clazz->node_flush ) + { + error = clazz->node_flush( last, key, list->data ); + } + else + { + if ( clazz->node_done ) + clazz->node_done( last, list->data ); + + last->key = key; + error = clazz->node_init( last, key, list->data ); + } + + if ( !error ) + { + /* move it to the top of the list */ + *plast = NULL; + last->next = list->nodes; + list->nodes = last; + + result = last; + goto Exit; + } + + /* in case of error during the flush or done/init cycle, */ + /* we need to discard the node */ + if ( clazz->node_done ) + clazz->node_done( last, list->data ); + + *plast = NULL; + list->num_nodes--; + + FT_FREE( last ); + goto Exit; + } + } + + /* otherwise, simply allocate a new node */ + if ( FT_ALLOC( node, clazz->node_size ) ) + goto Exit; + + node->key = key; + error = clazz->node_init( node, key, list->data ); + if ( error ) + { + FT_FREE( node ); + goto Exit; + } + + result = node; + node->next = list->nodes; + list->nodes = node; + list->num_nodes++; + + Exit: + *anode = result; + return error; + } + + + FT_EXPORT_DEF( void ) + FT_LruList_Remove( FT_LruList list, + FT_LruNode node ) + { + FT_LruNode *pnode; + + + if ( !list || !node ) + return; + + pnode = &list->nodes; + for (;;) + { + if ( *pnode == node ) + { + FT_Memory memory = list->memory; + FT_LruList_Class clazz = list->clazz; + + + *pnode = node->next; + node->next = NULL; + + if ( clazz->node_done ) + clazz->node_done( node, list->data ); + + FT_FREE( node ); + list->num_nodes--; + break; + } + + pnode = &(*pnode)->next; + } + } + + + FT_EXPORT_DEF( void ) + FT_LruList_Remove_Selection( FT_LruList list, + FT_LruNode_SelectFunc select_func, + FT_Pointer select_data ) + { + FT_LruNode *pnode, node; + FT_LruList_Class clazz; + FT_Memory memory; + + + if ( !list || !select_func ) + return; + + memory = list->memory; + clazz = list->clazz; + pnode = &list->nodes; + + for (;;) + { + node = *pnode; + if ( node == NULL ) + break; + + if ( select_func( node, select_data, list->data ) ) + { + *pnode = node->next; + node->next = NULL; + + if ( clazz->node_done ) + clazz->node_done( node, list ); + + FT_FREE( node ); + } + else + pnode = &(*pnode)->next; + } + } + + +/* END */ |
