forsyth20121205-174063a80cc13 years agoHistory
246 lines · 5.3 KB · C
RawDownload
#include <ft2build.h>#include FT_TYPES_H#include FT_INTERNAL_HASH_H#include FT_INTERNAL_MEMORY_H#include FT_INTERNAL_DEBUG_H #define  FT_HASH_MAX_LOAD  2#define  FT_HASH_MIN_LOAD  1#define  FT_HASH_SUB_LOAD  (FT_HASH_MAX_LOAD-FT_HASH_MIN_LOAD) /* this one _must_ be a power of 2 !! */#define  FT_HASH_INITIAL_SIZE  8    FT_BASE_DEF( void )  ft_hash_done( FT_Hash              table,                FT_Hash_ForeachFunc  node_func,                const FT_Pointer     node_data )  {    if ( table )    {      FT_Memory  memory = table->memory;       if ( node_func )        ft_hash_foreach( table, node_func, node_data );       FT_FREE( table->buckets );      table->p     = 0;      table->mask  = 0;      table->slack = 0;       table->node_equal = NULL;    }  }    FT_BASE_DEF( FT_UInt )  ft_hash_get_size( FT_Hash  table )  {    FT_UInt  result = 0;     if ( table )      result = (table->p + table->mask + 1)*FT_HASH_MAX_LOAD - table->slack;     return result;  }     FT_BASE_DEF( FT_Error )  ft_hash_init( FT_Hash            table,                FT_Hash_EqualFunc  equal,                FT_Memory          memory )  {    FT_Error  error;     table->memory     = memory;    table->p          = 0;    table->mask       = FT_HASH_INITIAL_SIZE-1;    table->slack      = FT_HASH_INITIAL_SIZE*FT_HASH_MAX_LOAD;    table->node_equal = equal;     (void)FT_NEW_ARRAY( table->buckets, FT_HASH_INITIAL_SIZE*2 );     return error;  }     FT_BASE_DEF( void )  ft_hash_foreach( FT_Hash              table,                   FT_Hash_ForeachFunc  foreach_func,                   const FT_Pointer     foreach_data )  {    FT_UInt       count = table->p + table->mask + 1;    FT_HashNode*  pnode = table->buckets;    FT_HashNode   node, next;     for ( ; count > 0; count--, pnode++ )    {      node = *pnode;      while ( node )      {        next = node->link;        foreach_func( node, foreach_data );        node = next;      }    }  }     FT_BASE_DEF( FT_HashLookup )  ft_hash_lookup( FT_Hash      table,                  FT_HashNode  keynode )  {    FT_UInt       index;    FT_UInt32     hash = keynode->hash;    FT_HashNode   node, *pnode;     index = (FT_UInt)(hash & table->mask);    if ( index < table->p )      index = (FT_UInt)(hash & (2*table->mask+1));     pnode = &table->buckets[index];    for (;;)    {      node = *pnode;      if ( node == NULL )        break;       if ( node->hash == hash && table->node_equal( node, keynode ) )        break;       pnode = &node->link;    }     return pnode;  }      FT_BASE_DEF( FT_Error )  ft_hash_add( FT_Hash        table,               FT_HashLookup  lookup,               FT_HashNode    new_node )  {    FT_Error     error = 0;     /* add it to the hash table */    new_node->link = *lookup;    *lookup        = new_node;     if ( --table->slack < 0 )    {      FT_UInt       p     = table->p;      FT_UInt       mask  = table->mask;      FT_HashNode   new_list, node, *pnode;       /* split a single bucket */      new_list = NULL;      pnode    = table->buckets + p;      for (;;)      {        node = *pnode;        if ( node == NULL )          break;         if ( node->hash & mask )        {          *pnode     = node->link;          node->link = new_list;          new_list   = node;        }        else          pnode = &node->link;      }       table->buckets[ p + mask + 1 ] = new_list;       table->slack += FT_HASH_MAX_LOAD;       if ( p >= mask )      {        FT_Memory  memory = table->memory;          if (FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1)*4 ))          goto Exit;         table->mask = 2*mask + 1;        table->p    = 0;      }      else        table->p = p + 1;    }  Exit:    return error;  }     FT_BASE_DEF( FT_Error )  ft_hash_remove( FT_Hash        table,                  FT_HashLookup  lookup )  {    FT_HashNode  node;    FT_UInt      num_buckets;    FT_Error     error = 0;     FT_ASSERT( pnode != NULL && node != NULL );     node       = *lookup;    *lookup    = node->link;    node->link = NULL;     num_buckets = ( table->p + table->mask + 1) ;     if ( ++ table->slack > (FT_Long)num_buckets*FT_HASH_SUB_LOAD )    {      FT_UInt       p         = table->p;      FT_UInt       mask      = table->mask;      FT_UInt       old_index = p + mask;      FT_HashNode*  pnode;      FT_HashNode*  pold;       if ( old_index < FT_HASH_INITIAL_SIZE )        goto Exit;       if ( p == 0 )      {        FT_Memory  memory = table->memory;         table->mask >>= 1;        p             = table->mask;         if ( FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1) ) )        {          /* this should never happen normally, but who knows :-)   */          /* we need to re-inject the node in the hash table before */          /* returning there, since it's safer                      */          pnode      = table->buckets;          node->link = *pnode;          *pnode     = node;           goto Exit;        }      }      else        p--;       pnode = table->buckets + p;      while ( *pnode )        pnode = &(*pnode)->link;       pold   = table->buckets + old_index;      *pnode = *pold;      *pold  = NULL;       table->slack -= FT_HASH_MAX_LOAD;      table->p      = p;    }  Exit:    return error;  }