Home | History | Annotate | Download | only in base
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  fthash.c                                                               */
      4 /*                                                                         */
      5 /*    Hashing functions (body).                                            */
      6 /*                                                                         */
      7 /***************************************************************************/
      8 
      9 /*
     10  * Copyright 2000 Computing Research Labs, New Mexico State University
     11  * Copyright 2001-2015
     12  *   Francesco Zappa Nardelli
     13  *
     14  * Permission is hereby granted, free of charge, to any person obtaining a
     15  * copy of this software and associated documentation files (the "Software"),
     16  * to deal in the Software without restriction, including without limitation
     17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     18  * and/or sell copies of the Software, and to permit persons to whom the
     19  * Software is furnished to do so, subject to the following conditions:
     20  *
     21  * The above copyright notice and this permission notice shall be included in
     22  * all copies or substantial portions of the Software.
     23  *
     24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     27  * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
     28  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
     29  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
     30  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     31  */
     32 
     33   /*************************************************************************/
     34   /*                                                                       */
     35   /*  This file is based on code from bdf.c,v 1.22 2000/03/16 20:08:50     */
     36   /*                                                                       */
     37   /*  taken from Mark Leisher's xmbdfed package                            */
     38   /*                                                                       */
     39   /*************************************************************************/
     40 
     41 
     42 #include <ft2build.h>
     43 #include FT_INTERNAL_HASH_H
     44 #include FT_INTERNAL_MEMORY_H
     45 
     46 
     47 #define INITIAL_HT_SIZE  241
     48 
     49 
     50   static FT_ULong
     51   hash_str_lookup( FT_Hashkey*  key )
     52   {
     53     const char*  kp  = key->str;
     54     FT_ULong     res = 0;
     55 
     56 
     57     /* Mocklisp hash function. */
     58     while ( *kp )
     59       res = ( res << 5 ) - res + (FT_ULong)*kp++;
     60 
     61     return res;
     62   }
     63 
     64 
     65   static FT_ULong
     66   hash_num_lookup( FT_Hashkey*  key )
     67   {
     68     FT_ULong  num = (FT_ULong)key->num;
     69     FT_ULong  res;
     70 
     71 
     72     /* Mocklisp hash function. */
     73     res = num & 0xFF;
     74     res = ( res << 5 ) - res + ( ( num >>  8 ) & 0xFF );
     75     res = ( res << 5 ) - res + ( ( num >> 16 ) & 0xFF );
     76     res = ( res << 5 ) - res + ( ( num >> 24 ) & 0xFF );
     77 
     78     return res;
     79   }
     80 
     81 
     82   static FT_Bool
     83   hash_str_compare( FT_Hashkey*  a,
     84                     FT_Hashkey*  b )
     85   {
     86     if ( a->str[0] == b->str[0]           &&
     87          ft_strcmp( a->str, b->str ) == 0 )
     88       return 1;
     89 
     90     return 0;
     91   }
     92 
     93 
     94   static FT_Bool
     95   hash_num_compare( FT_Hashkey*  a,
     96                     FT_Hashkey*  b )
     97   {
     98     if ( a->num == b->num )
     99       return 1;
    100 
    101     return 0;
    102   }
    103 
    104 
    105   static FT_Hashnode*
    106   hash_bucket( FT_Hashkey  key,
    107                FT_Hash     hash )
    108   {
    109     FT_ULong      res = 0;
    110     FT_Hashnode*  bp  = hash->table;
    111     FT_Hashnode*  ndp;
    112 
    113 
    114     res = (hash->lookup)( &key );
    115 
    116     ndp = bp + ( res % hash->size );
    117     while ( *ndp )
    118     {
    119       if ( (hash->compare)( &(*ndp)->key, &key ) )
    120         break;
    121 
    122       ndp--;
    123       if ( ndp < bp )
    124         ndp = bp + ( hash->size - 1 );
    125     }
    126 
    127     return ndp;
    128   }
    129 
    130 
    131   static FT_Error
    132   hash_rehash( FT_Hash    hash,
    133                FT_Memory  memory )
    134   {
    135     FT_Hashnode*  obp = hash->table;
    136     FT_Hashnode*  bp;
    137     FT_Hashnode*  nbp;
    138 
    139     FT_UInt   i, sz = hash->size;
    140     FT_Error  error = FT_Err_Ok;
    141 
    142 
    143     hash->size <<= 1;
    144     hash->limit  = hash->size / 3;
    145 
    146     if ( FT_NEW_ARRAY( hash->table, hash->size ) )
    147       goto Exit;
    148 
    149     for ( i = 0, bp = obp; i < sz; i++, bp++ )
    150     {
    151       if ( *bp )
    152       {
    153         nbp = hash_bucket( (*bp)->key, hash );
    154         *nbp = *bp;
    155       }
    156     }
    157 
    158     FT_FREE( obp );
    159 
    160   Exit:
    161     return error;
    162   }
    163 
    164 
    165   static FT_Error
    166   hash_init( FT_Hash    hash,
    167              FT_Bool    is_num,
    168              FT_Memory  memory )
    169   {
    170     FT_UInt   sz = INITIAL_HT_SIZE;
    171     FT_Error  error;
    172 
    173 
    174     hash->size  = sz;
    175     hash->limit = sz / 3;
    176     hash->used  = 0;
    177 
    178     if ( is_num )
    179     {
    180       hash->lookup  = hash_num_lookup;
    181       hash->compare = hash_num_compare;
    182     }
    183     else
    184     {
    185       hash->lookup  = hash_str_lookup;
    186       hash->compare = hash_str_compare;
    187     }
    188 
    189     FT_MEM_NEW_ARRAY( hash->table, sz );
    190 
    191     return error;
    192   }
    193 
    194 
    195   FT_Error
    196   ft_hash_str_init( FT_Hash    hash,
    197                     FT_Memory  memory )
    198   {
    199     return hash_init( hash, 0, memory );
    200   }
    201 
    202 
    203   FT_Error
    204   ft_hash_num_init( FT_Hash    hash,
    205                     FT_Memory  memory )
    206   {
    207     return hash_init( hash, 1, memory );
    208   }
    209 
    210 
    211   void
    212   ft_hash_str_free( FT_Hash    hash,
    213                     FT_Memory  memory )
    214   {
    215     if ( hash )
    216     {
    217       FT_UInt       sz = hash->size;
    218       FT_Hashnode*  bp = hash->table;
    219       FT_UInt       i;
    220 
    221 
    222       for ( i = 0; i < sz; i++, bp++ )
    223         FT_FREE( *bp );
    224 
    225       FT_FREE( hash->table );
    226     }
    227   }
    228 
    229 
    230   /* `ft_hash_num_free' is the same as `ft_hash_str_free' */
    231 
    232 
    233   static FT_Error
    234   hash_insert( FT_Hashkey  key,
    235                size_t      data,
    236                FT_Hash     hash,
    237                FT_Memory   memory )
    238   {
    239     FT_Hashnode   nn;
    240     FT_Hashnode*  bp    = hash_bucket( key, hash );
    241     FT_Error      error = FT_Err_Ok;
    242 
    243 
    244     nn = *bp;
    245     if ( !nn )
    246     {
    247       if ( FT_NEW( nn ) )
    248         goto Exit;
    249       *bp = nn;
    250 
    251       nn->key  = key;
    252       nn->data = data;
    253 
    254       if ( hash->used >= hash->limit )
    255       {
    256         error = hash_rehash( hash, memory );
    257         if ( error )
    258           goto Exit;
    259       }
    260 
    261       hash->used++;
    262     }
    263     else
    264       nn->data = data;
    265 
    266   Exit:
    267     return error;
    268   }
    269 
    270 
    271   FT_Error
    272   ft_hash_str_insert( const char*  key,
    273                       size_t       data,
    274                       FT_Hash      hash,
    275                       FT_Memory    memory )
    276   {
    277     FT_Hashkey  hk;
    278 
    279 
    280     hk.str = key;
    281 
    282     return hash_insert( hk, data, hash, memory );
    283   }
    284 
    285 
    286   FT_Error
    287   ft_hash_num_insert( FT_Int     num,
    288                       size_t     data,
    289                       FT_Hash    hash,
    290                       FT_Memory  memory )
    291   {
    292     FT_Hashkey  hk;
    293 
    294 
    295     hk.num = num;
    296 
    297     return hash_insert( hk, data, hash, memory );
    298   }
    299 
    300 
    301   static size_t*
    302   hash_lookup( FT_Hashkey  key,
    303                FT_Hash     hash )
    304   {
    305     FT_Hashnode*  np = hash_bucket( key, hash );
    306 
    307 
    308     return (*np) ? &(*np)->data
    309                  : NULL;
    310   }
    311 
    312 
    313   size_t*
    314   ft_hash_str_lookup( const char*  key,
    315                       FT_Hash      hash )
    316   {
    317     FT_Hashkey  hk;
    318 
    319 
    320     hk.str = key;
    321 
    322     return hash_lookup( hk, hash );
    323   }
    324 
    325 
    326   size_t*
    327   ft_hash_num_lookup( FT_Int   num,
    328                       FT_Hash  hash )
    329   {
    330     FT_Hashkey  hk;
    331 
    332 
    333     hk.num = num;
    334 
    335     return hash_lookup( hk, hash );
    336   }
    337 
    338 
    339 /* END */
    340