ref: b466a7650ce97d3843bcbb4b145bda323a201022
dir: /src/cache/ftlru.c/
#include <cache/ftlru.h> #include <freetype/internal/ftobjs.h> #include <freetype/internal/ftlist.h> static void lru_build_free_list( FT_LruNode nodes, FT_UInt count, FT_List free_list ) { FT_LruNode node = nodes; FT_LruNode limit = node + count; free_list->head = free_list->tail = 0; for ( ; node < limit; node++ ) FT_List_Add( free_list, (FT_ListNode)node ); } FT_EXPORT_FUNC(FT_Error) FT_Lru_New ( const FT_Lru_Class* clazz, FT_UInt max_elements, FT_Memory memory, FT_Bool pre_alloc, FT_Lru *alru ) { FT_Error error; FT_Lru lru; *alru = 0; if ( !ALLOC( lru, sizeof(*lru) ) ) { if (pre_alloc) { /* allocate static array of lru list nodes */ if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) ) { FREE( lru ); goto Exit; } /* build the 'free_nodes' list from the array */ lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes ); } /* initialize common fields */ lru->clazz = (FT_Lru_Class*)clazz; lru->max_elements = max_elements; lru->memory = memory; *alru = lru; } Exit: return error; } FT_EXPORT_DEF(void) FT_Lru_Reset ( FT_Lru lru ) { FT_ListNode node = lru->elements.head; FT_Lru_Class* clazz = lru->clazz; FT_Memory memory = lru->memory; while (node) { FT_ListNode next = node->next; clazz->done_element( lru, (FT_LruNode)node ); if (!lru->nodes) FREE(node); node = next; } /* rebuild free list if necessary */ if (lru->nodes) lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes ); lru->elements.head = lru->elements.tail = 0; lru->num_elements = 0; } FT_EXPORT_DEF(void) FT_Lru_Done ( FT_Lru lru ) { FT_Memory memory = lru->memory; FT_Lru_Reset(lru); FREE(lru); } FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup_Node( FT_Lru lru, FT_LruKey key, FT_LruNode* anode ) { FT_Error error = 0; FT_ListNode node = lru->elements.head; FT_Lru_Class* clazz = lru->clazz; FT_LruNode found = 0; FT_Memory memory = lru->memory; if (clazz->compare_element) { for ( ; node; node = node->next ) if (clazz->compare_element( (FT_LruNode)node, key )) { found = (FT_LruNode)node; break; } } else { for ( ; node; node = node->next ) if (((FT_LruNode)node)->key == key) { found = (FT_LruNode)node; break; } } if (!found) { /* we didn't find the relevant element. We will now try */ /* to create a new one.. */ if ( lru->num_elements >= lru->max_elements ) { /* this lru list is full, we will now flush */ /* the oldest node */ FT_LruNode lru_node; node = lru->elements.tail; lru_node = (FT_LruNode)node; if (clazz->flush_element) error = clazz->flush_element( lru, lru_node, key ); else { clazz->done_element( lru, lru_node ); lru_node->key = key; node->data = 0; error = clazz->init_element( lru, lru_node ); } if (!error) { /* now, move element to top of list */ FT_List_Up( &lru->elements, node ); } else { /* in case of error, the node must be discarded */ FT_List_Remove( &lru->elements, node ); lru->num_elements--; if (lru->nodes) FT_List_Insert( &lru->free_nodes, node ); else FREE( lru_node ); } } else { FT_LruNode lru_node; /* create a new lru list node, then the element for it */ if (lru->nodes) { node = lru->free_nodes.head; lru_node = (FT_LruNode)node; lru_node->key = key; error = clazz->init_element( lru, lru_node ); if (error) goto Exit; FT_List_Remove( &lru->free_nodes, node ); } else { if ( ALLOC( lru_node, sizeof(*lru_node) ) ) goto Exit; lru_node->key = key; error = clazz->init_element( lru, lru_node ); if (error) { FREE( lru_node ); goto Exit; } } found = lru_node; node = (FT_ListNode)lru_node; FT_List_Insert( &lru->elements, node ); lru->num_elements++; } } Exit: *anode = found; return error; } FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup( FT_Lru lru, FT_LruKey key, FT_Pointer *aobject ) { FT_Error error; FT_LruNode node; *aobject = 0; error = FT_Lru_Lookup_Node( lru, key, &node ); if (!error) *aobject = node->root.data; return error; } FT_EXPORT_FUNC(void) FT_Lru_Remove_Node( FT_Lru lru, FT_LruNode node ) { if (lru->num_elements > 0) { FT_List_Remove( &lru->elements, (FT_ListNode)node ); lru->clazz->done_element( lru, node ); if (lru->nodes) FT_List_Insert( &lru->free_nodes, (FT_ListNode)node ); else { FT_Memory memory = lru->memory; FREE(node); } lru->num_elements--; } } FT_EXPORT_FUNC(void) FT_Lru_Remove_Selection( FT_Lru lru, FT_Lru_Selector selector, FT_Pointer data ) { if (lru->num_elements > 0) { FT_ListNode node = lru->elements.head; FT_ListNode next; while (node) { next = node->next; if ( selector( lru, (FT_LruNode)node, data ) ) { /* remove this element from the list, and destroy it */ FT_Lru_Remove_Node( lru, (FT_LruNode)node ); } node = next; } } }