Edit

kc3-lang/freetype/src/cache/ftlru.c

Branch :

  • Show log

    Commit

  • Author : David Turner
    Date : 2000-09-19 01:11:11
    Hash : ebdce834
    Message : updated the cache sub-system. Major internal rewrite please be aware that major bug persist..

  • src/cache/ftlru.c
  • /***************************************************************************/
    /*                                                                         */
    /*  ftlru.c                                                                */
    /*                                                                         */
    /*    Simple LRU list-cache (body).                                        */
    /*                                                                         */
    /*  Copyright 2000 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/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_Pointer           user_data,
                                              FT_Memory            memory,
                                              FT_Bool              pre_alloc,
                                              FT_Lru*              alru )
      {
        FT_Error  error;
        FT_Lru    lru;
        
    
        if ( !alru )
          return FT_Err_Invalid_Argument;
    
        *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;
          lru->user_data    = user_data;
    
          *alru = lru;
        }
    
      Exit:
        return error;
      }
    
    
                                             
      FT_EXPORT_DEF( void )  FT_Lru_Reset( FT_Lru  lru )
      {
        FT_ListNode    node;
        FT_Lru_Class*  clazz;
        FT_Memory      memory;
        
    
        if ( !lru )
          return;
    
        node   = lru->elements.head;
        clazz  = lru->clazz;
        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;
        
    
        if ( !lru )
          return;
    
        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;
        FT_Lru_Class*  clazz;
        FT_LruNode     found = 0; 
        FT_Memory      memory;
        
    
        if ( !lru || !key || !anode )
          return FT_Err_Invalid_Argument;
    
        node   = lru->elements.head;
        clazz  = lru->clazz;
        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 haven't found 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;
            found    = lru_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 );
                
              found = 0;
            }
          }
          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;
        
    
        /* check for valid `lru' and `key' delayed to FT_Lru_Lookup_Node() */
    
        if ( !aobject )
          return FT_Err_Invalid_Argument;
    
        *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 || !node )
          return;
    
        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 || !selector )
          return;
    
        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;
          }
        }
      }
    
    
    /* END */