/***************************************************************************/ | |
/* */ | |
/* ftcmru.c */ | |
/* */ | |
/* FreeType MRU support (body). */ | |
/* */ | |
/* Copyright 2003-2015 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 "ftcmru.h" | |
#include FT_INTERNAL_OBJECTS_H | |
#include FT_INTERNAL_DEBUG_H | |
#include "ftcerror.h" | |
FT_LOCAL_DEF( void ) | |
FTC_MruNode_Prepend( FTC_MruNode *plist, | |
FTC_MruNode node ) | |
{ | |
FTC_MruNode first = *plist; | |
if ( first ) | |
{ | |
FTC_MruNode last = first->prev; | |
#ifdef FT_DEBUG_ERROR | |
{ | |
FTC_MruNode cnode = first; | |
do | |
{ | |
if ( cnode == node ) | |
{ | |
fprintf( stderr, "FTC_MruNode_Prepend: invalid action\n" ); | |
exit( 2 ); | |
} | |
cnode = cnode->next; | |
} while ( cnode != first ); | |
} | |
#endif | |
first->prev = node; | |
last->next = node; | |
node->next = first; | |
node->prev = last; | |
} | |
else | |
{ | |
node->next = node; | |
node->prev = node; | |
} | |
*plist = node; | |
} | |
FT_LOCAL_DEF( void ) | |
FTC_MruNode_Up( FTC_MruNode *plist, | |
FTC_MruNode node ) | |
{ | |
FTC_MruNode first = *plist; | |
FT_ASSERT( first != NULL ); | |
if ( first != node ) | |
{ | |
FTC_MruNode prev, next, last; | |
#ifdef FT_DEBUG_ERROR | |
{ | |
FTC_MruNode cnode = first; | |
do | |
{ | |
if ( cnode == node ) | |
goto Ok; | |
cnode = cnode->next; | |
} while ( cnode != first ); | |
fprintf( stderr, "FTC_MruNode_Up: invalid action\n" ); | |
exit( 2 ); | |
Ok: | |
} | |
#endif | |
prev = node->prev; | |
next = node->next; | |
prev->next = next; | |
next->prev = prev; | |
last = first->prev; | |
last->next = node; | |
first->prev = node; | |
node->next = first; | |
node->prev = last; | |
*plist = node; | |
} | |
} | |
FT_LOCAL_DEF( void ) | |
FTC_MruNode_Remove( FTC_MruNode *plist, | |
FTC_MruNode node ) | |
{ | |
FTC_MruNode first = *plist; | |
FTC_MruNode prev, next; | |
FT_ASSERT( first != NULL ); | |
#ifdef FT_DEBUG_ERROR | |
{ | |
FTC_MruNode cnode = first; | |
do | |
{ | |
if ( cnode == node ) | |
goto Ok; | |
cnode = cnode->next; | |
} while ( cnode != first ); | |
fprintf( stderr, "FTC_MruNode_Remove: invalid action\n" ); | |
exit( 2 ); | |
Ok: | |
} | |
#endif | |
prev = node->prev; | |
next = node->next; | |
prev->next = next; | |
next->prev = prev; | |
if ( node == next ) | |
{ | |
FT_ASSERT( first == node ); | |
FT_ASSERT( prev == node ); | |
*plist = NULL; | |
} | |
else if ( node == first ) | |
*plist = next; | |
} | |
FT_LOCAL_DEF( void ) | |
FTC_MruList_Init( FTC_MruList list, | |
FTC_MruListClass clazz, | |
FT_UInt max_nodes, | |
FT_Pointer data, | |
FT_Memory memory ) | |
{ | |
list->num_nodes = 0; | |
list->max_nodes = max_nodes; | |
list->nodes = NULL; | |
list->clazz = *clazz; | |
list->data = data; | |
list->memory = memory; | |
} | |
FT_LOCAL_DEF( void ) | |
FTC_MruList_Reset( FTC_MruList list ) | |
{ | |
while ( list->nodes ) | |
FTC_MruList_Remove( list, list->nodes ); | |
FT_ASSERT( list->num_nodes == 0 ); | |
} | |
FT_LOCAL_DEF( void ) | |
FTC_MruList_Done( FTC_MruList list ) | |
{ | |
FTC_MruList_Reset( list ); | |
} | |
#ifndef FTC_INLINE | |
FT_LOCAL_DEF( FTC_MruNode ) | |
FTC_MruList_Find( FTC_MruList list, | |
FT_Pointer key ) | |
{ | |
FTC_MruNode_CompareFunc compare = list->clazz.node_compare; | |
FTC_MruNode first, node; | |
first = list->nodes; | |
node = NULL; | |
if ( first ) | |
{ | |
node = first; | |
do | |
{ | |
if ( compare( node, key ) ) | |
{ | |
if ( node != first ) | |
FTC_MruNode_Up( &list->nodes, node ); | |
return node; | |
} | |
node = node->next; | |
} while ( node != first); | |
} | |
return NULL; | |
} | |
#endif | |
FT_LOCAL_DEF( FT_Error ) | |
FTC_MruList_New( FTC_MruList list, | |
FT_Pointer key, | |
FTC_MruNode *anode ) | |
{ | |
FT_Error error; | |
FTC_MruNode node = NULL; | |
FT_Memory memory = list->memory; | |
if ( list->num_nodes >= list->max_nodes && list->max_nodes > 0 ) | |
{ | |
node = list->nodes->prev; | |
FT_ASSERT( node ); | |
if ( list->clazz.node_reset ) | |
{ | |
FTC_MruNode_Up( &list->nodes, node ); | |
error = list->clazz.node_reset( node, key, list->data ); | |
if ( !error ) | |
goto Exit; | |
} | |
FTC_MruNode_Remove( &list->nodes, node ); | |
list->num_nodes--; | |
if ( list->clazz.node_done ) | |
list->clazz.node_done( node, list->data ); | |
} | |
else if ( FT_ALLOC( node, list->clazz.node_size ) ) | |
goto Exit; | |
error = list->clazz.node_init( node, key, list->data ); | |
if ( error ) | |
goto Fail; | |
FTC_MruNode_Prepend( &list->nodes, node ); | |
list->num_nodes++; | |
Exit: | |
*anode = node; | |
return error; | |
Fail: | |
if ( list->clazz.node_done ) | |
list->clazz.node_done( node, list->data ); | |
FT_FREE( node ); | |
goto Exit; | |
} | |
#ifndef FTC_INLINE | |
FT_LOCAL_DEF( FT_Error ) | |
FTC_MruList_Lookup( FTC_MruList list, | |
FT_Pointer key, | |
FTC_MruNode *anode ) | |
{ | |
FTC_MruNode node; | |
node = FTC_MruList_Find( list, key ); | |
if ( node == NULL ) | |
return FTC_MruList_New( list, key, anode ); | |
*anode = node; | |
return 0; | |
} | |
#endif /* FTC_INLINE */ | |
FT_LOCAL_DEF( void ) | |
FTC_MruList_Remove( FTC_MruList list, | |
FTC_MruNode node ) | |
{ | |
FTC_MruNode_Remove( &list->nodes, node ); | |
list->num_nodes--; | |
{ | |
FT_Memory memory = list->memory; | |
if ( list->clazz.node_done ) | |
list->clazz.node_done( node, list->data ); | |
FT_FREE( node ); | |
} | |
} | |
FT_LOCAL_DEF( void ) | |
FTC_MruList_RemoveSelection( FTC_MruList list, | |
FTC_MruNode_CompareFunc selection, | |
FT_Pointer key ) | |
{ | |
FTC_MruNode first, node, next; | |
first = list->nodes; | |
while ( first && ( selection == NULL || selection( first, key ) ) ) | |
{ | |
FTC_MruList_Remove( list, first ); | |
first = list->nodes; | |
} | |
if ( first ) | |
{ | |
node = first->next; | |
while ( node != first ) | |
{ | |
next = node->next; | |
if ( selection( node, key ) ) | |
FTC_MruList_Remove( list, node ); | |
node = next; | |
} | |
} | |
} | |
/* END */ |