264 lines
6.7 KiB
C
264 lines
6.7 KiB
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|