fthash.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #include <ft2build.h>
  2. #include FT_TYPES_H
  3. #include FT_INTERNAL_HASH_H
  4. #include FT_INTERNAL_MEMORY_H
  5. #include FT_INTERNAL_DEBUG_H
  6. #define FT_HASH_MAX_LOAD 2
  7. #define FT_HASH_MIN_LOAD 1
  8. #define FT_HASH_SUB_LOAD (FT_HASH_MAX_LOAD-FT_HASH_MIN_LOAD)
  9. /* this one _must_ be a power of 2 !! */
  10. #define FT_HASH_INITIAL_SIZE 8
  11. FT_BASE_DEF( void )
  12. ft_hash_done( FT_Hash table,
  13. FT_Hash_ForeachFunc node_func,
  14. const FT_Pointer node_data )
  15. {
  16. if ( table )
  17. {
  18. FT_Memory memory = table->memory;
  19. if ( node_func )
  20. ft_hash_foreach( table, node_func, node_data );
  21. FT_FREE( table->buckets );
  22. table->p = 0;
  23. table->mask = 0;
  24. table->slack = 0;
  25. table->node_equal = NULL;
  26. }
  27. }
  28. FT_BASE_DEF( FT_UInt )
  29. ft_hash_get_size( FT_Hash table )
  30. {
  31. FT_UInt result = 0;
  32. if ( table )
  33. result = (table->p + table->mask + 1)*FT_HASH_MAX_LOAD - table->slack;
  34. return result;
  35. }
  36. FT_BASE_DEF( FT_Error )
  37. ft_hash_init( FT_Hash table,
  38. FT_Hash_EqualFunc equal,
  39. FT_Memory memory )
  40. {
  41. FT_Error error;
  42. table->memory = memory;
  43. table->p = 0;
  44. table->mask = FT_HASH_INITIAL_SIZE-1;
  45. table->slack = FT_HASH_INITIAL_SIZE*FT_HASH_MAX_LOAD;
  46. table->node_equal = equal;
  47. (void)FT_NEW_ARRAY( table->buckets, FT_HASH_INITIAL_SIZE*2 );
  48. return error;
  49. }
  50. FT_BASE_DEF( void )
  51. ft_hash_foreach( FT_Hash table,
  52. FT_Hash_ForeachFunc foreach_func,
  53. const FT_Pointer foreach_data )
  54. {
  55. FT_UInt count = table->p + table->mask + 1;
  56. FT_HashNode* pnode = table->buckets;
  57. FT_HashNode node, next;
  58. for ( ; count > 0; count--, pnode++ )
  59. {
  60. node = *pnode;
  61. while ( node )
  62. {
  63. next = node->link;
  64. foreach_func( node, foreach_data );
  65. node = next;
  66. }
  67. }
  68. }
  69. FT_BASE_DEF( FT_HashLookup )
  70. ft_hash_lookup( FT_Hash table,
  71. FT_HashNode keynode )
  72. {
  73. FT_UInt index;
  74. FT_UInt32 hash = keynode->hash;
  75. FT_HashNode node, *pnode;
  76. index = (FT_UInt)(hash & table->mask);
  77. if ( index < table->p )
  78. index = (FT_UInt)(hash & (2*table->mask+1));
  79. pnode = &table->buckets[index];
  80. for (;;)
  81. {
  82. node = *pnode;
  83. if ( node == NULL )
  84. break;
  85. if ( node->hash == hash && table->node_equal( node, keynode ) )
  86. break;
  87. pnode = &node->link;
  88. }
  89. return pnode;
  90. }
  91. FT_BASE_DEF( FT_Error )
  92. ft_hash_add( FT_Hash table,
  93. FT_HashLookup lookup,
  94. FT_HashNode new_node )
  95. {
  96. FT_Error error = 0;
  97. /* add it to the hash table */
  98. new_node->link = *lookup;
  99. *lookup = new_node;
  100. if ( --table->slack < 0 )
  101. {
  102. FT_UInt p = table->p;
  103. FT_UInt mask = table->mask;
  104. FT_HashNode new_list, node, *pnode;
  105. /* split a single bucket */
  106. new_list = NULL;
  107. pnode = table->buckets + p;
  108. for (;;)
  109. {
  110. node = *pnode;
  111. if ( node == NULL )
  112. break;
  113. if ( node->hash & mask )
  114. {
  115. *pnode = node->link;
  116. node->link = new_list;
  117. new_list = node;
  118. }
  119. else
  120. pnode = &node->link;
  121. }
  122. table->buckets[ p + mask + 1 ] = new_list;
  123. table->slack += FT_HASH_MAX_LOAD;
  124. if ( p >= mask )
  125. {
  126. FT_Memory memory = table->memory;
  127. if (FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1)*4 ))
  128. goto Exit;
  129. table->mask = 2*mask + 1;
  130. table->p = 0;
  131. }
  132. else
  133. table->p = p + 1;
  134. }
  135. Exit:
  136. return error;
  137. }
  138. FT_BASE_DEF( FT_Error )
  139. ft_hash_remove( FT_Hash table,
  140. FT_HashLookup lookup )
  141. {
  142. FT_HashNode node;
  143. FT_UInt num_buckets;
  144. FT_Error error = 0;
  145. FT_ASSERT( pnode != NULL && node != NULL );
  146. node = *lookup;
  147. *lookup = node->link;
  148. node->link = NULL;
  149. num_buckets = ( table->p + table->mask + 1) ;
  150. if ( ++ table->slack > (FT_Long)num_buckets*FT_HASH_SUB_LOAD )
  151. {
  152. FT_UInt p = table->p;
  153. FT_UInt mask = table->mask;
  154. FT_UInt old_index = p + mask;
  155. FT_HashNode* pnode;
  156. FT_HashNode* pold;
  157. if ( old_index < FT_HASH_INITIAL_SIZE )
  158. goto Exit;
  159. if ( p == 0 )
  160. {
  161. FT_Memory memory = table->memory;
  162. table->mask >>= 1;
  163. p = table->mask;
  164. if ( FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1) ) )
  165. {
  166. /* this should never happen normally, but who knows :-) */
  167. /* we need to re-inject the node in the hash table before */
  168. /* returning there, since it's safer */
  169. pnode = table->buckets;
  170. node->link = *pnode;
  171. *pnode = node;
  172. goto Exit;
  173. }
  174. }
  175. else
  176. p--;
  177. pnode = table->buckets + p;
  178. while ( *pnode )
  179. pnode = &(*pnode)->link;
  180. pold = table->buckets + old_index;
  181. *pnode = *pold;
  182. *pold = NULL;
  183. table->slack -= FT_HASH_MAX_LOAD;
  184. table->p = p;
  185. }
  186. Exit:
  187. return error;
  188. }