/***************************************************************************/ /* */ /* 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 #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 */