| /**************************************************************************** |
| * |
| * ftcmru.c |
| * |
| * FreeType MRU support (body). |
| * |
| * Copyright (C) 2003-2020 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 <freetype/ftcache.h> |
| #include "ftcmru.h" |
| #include <freetype/internal/ftobjs.h> |
| #include <freetype/internal/ftdebug.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 ); |
| |
| 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 ); |
| |
| #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 ) |
| 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 || 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 */ |