shithub: freetype+ttf2subf

ref: b466a7650ce97d3843bcbb4b145bda323a201022
dir: /src/cache/ftlru.c/

View raw version
#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;
      }
    }
  }