00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <ft2build.h>
00020 #include "ftcmanag.h"
00021 #include FT_INTERNAL_OBJECTS_H
00022 #include FT_INTERNAL_DEBUG_H
00023
00024 #include "ftccback.h"
00025 #include "ftcerror.h"
00026
00027 #undef FT_COMPONENT
00028 #define FT_COMPONENT trace_cache
00029
00030
00031 #define FTC_HASH_MAX_LOAD 2
00032 #define FTC_HASH_MIN_LOAD 1
00033 #define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD )
00034
00035
00036 #define FTC_HASH_INITIAL_SIZE 8
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 static void
00049 ftc_node_mru_link( FTC_Node node,
00050 FTC_Manager manager )
00051 {
00052 void *nl = &manager->nodes_list;
00053
00054
00055 FTC_MruNode_Prepend( (FTC_MruNode*)nl,
00056 (FTC_MruNode)node );
00057 manager->num_nodes++;
00058 }
00059
00060
00061
00062 static void
00063 ftc_node_mru_unlink( FTC_Node node,
00064 FTC_Manager manager )
00065 {
00066 void *nl = &manager->nodes_list;
00067
00068
00069 FTC_MruNode_Remove( (FTC_MruNode*)nl,
00070 (FTC_MruNode)node );
00071 manager->num_nodes--;
00072 }
00073
00074
00075 #ifndef FTC_INLINE
00076
00077
00078 static void
00079 ftc_node_mru_up( FTC_Node node,
00080 FTC_Manager manager )
00081 {
00082 FTC_MruNode_Up( (FTC_MruNode*)&manager->nodes_list,
00083 (FTC_MruNode)node );
00084 }
00085
00086 #endif
00087
00088
00089
00090
00091
00092
00093 static void
00094 ftc_cache_resize( FTC_Cache cache )
00095 {
00096 for (;;)
00097 {
00098 FTC_Node node, *pnode;
00099 FT_UFast p = cache->p;
00100 FT_UFast mask = cache->mask;
00101 FT_UFast count = mask + p + 1;
00102
00103
00104
00105 if ( cache->slack < 0 )
00106 {
00107 FTC_Node new_list = NULL;
00108
00109
00110
00111
00112
00113 if ( p >= mask )
00114 {
00115 FT_Memory memory = cache->memory;
00116 FT_Error error;
00117
00118
00119
00120 if ( FT_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) )
00121 break;
00122 }
00123
00124
00125 pnode = cache->buckets + p;
00126
00127 for (;;)
00128 {
00129 node = *pnode;
00130 if ( node == NULL )
00131 break;
00132
00133 if ( node->hash & ( mask + 1 ) )
00134 {
00135 *pnode = node->link;
00136 node->link = new_list;
00137 new_list = node;
00138 }
00139 else
00140 pnode = &node->link;
00141 }
00142
00143 cache->buckets[p + mask + 1] = new_list;
00144
00145 cache->slack += FTC_HASH_MAX_LOAD;
00146
00147 if ( p >= mask )
00148 {
00149 cache->mask = 2 * mask + 1;
00150 cache->p = 0;
00151 }
00152 else
00153 cache->p = p + 1;
00154 }
00155
00156
00157 else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD )
00158 {
00159 FT_UFast old_index = p + mask;
00160 FTC_Node* pold;
00161
00162
00163 if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE )
00164 break;
00165
00166 if ( p == 0 )
00167 {
00168 FT_Memory memory = cache->memory;
00169 FT_Error error;
00170
00171
00172
00173 if ( FT_RENEW_ARRAY( cache->buckets,
00174 ( mask + 1 ) * 2, mask + 1 ) )
00175 break;
00176
00177 cache->mask >>= 1;
00178 p = cache->mask;
00179 }
00180 else
00181 p--;
00182
00183 pnode = cache->buckets + p;
00184 while ( *pnode )
00185 pnode = &(*pnode)->link;
00186
00187 pold = cache->buckets + old_index;
00188 *pnode = *pold;
00189 *pold = NULL;
00190
00191 cache->slack -= FTC_HASH_MAX_LOAD;
00192 cache->p = p;
00193 }
00194 else
00195 break;
00196 }
00197 }
00198
00199
00200
00201 static void
00202 ftc_node_hash_unlink( FTC_Node node0,
00203 FTC_Cache cache )
00204 {
00205 FTC_Node *pnode;
00206 FT_UInt idx;
00207
00208
00209 idx = (FT_UInt)( node0->hash & cache->mask );
00210 if ( idx < cache->p )
00211 idx = (FT_UInt)( node0->hash & ( 2 * cache->mask + 1 ) );
00212
00213 pnode = cache->buckets + idx;
00214
00215 for (;;)
00216 {
00217 FTC_Node node = *pnode;
00218
00219
00220 if ( node == NULL )
00221 {
00222 FT_TRACE0(( "ftc_node_hash_unlink: unknown node\n" ));
00223 return;
00224 }
00225
00226 if ( node == node0 )
00227 break;
00228
00229 pnode = &(*pnode)->link;
00230 }
00231
00232 *pnode = node0->link;
00233 node0->link = NULL;
00234
00235 cache->slack++;
00236 ftc_cache_resize( cache );
00237 }
00238
00239
00240
00241 static void
00242 ftc_node_hash_link( FTC_Node node,
00243 FTC_Cache cache )
00244 {
00245 FTC_Node *pnode;
00246 FT_UInt idx;
00247
00248
00249 idx = (FT_UInt)( node->hash & cache->mask );
00250 if ( idx < cache->p )
00251 idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) );
00252
00253 pnode = cache->buckets + idx;
00254
00255 node->link = *pnode;
00256 *pnode = node;
00257
00258 cache->slack--;
00259 ftc_cache_resize( cache );
00260 }
00261
00262
00263
00264 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
00265 FT_BASE_DEF( void )
00266 #else
00267 FT_LOCAL_DEF( void )
00268 #endif
00269 ftc_node_destroy( FTC_Node node,
00270 FTC_Manager manager )
00271 {
00272 FTC_Cache cache;
00273
00274
00275 #ifdef FT_DEBUG_ERROR
00276
00277 if ( node->cache_index >= manager->num_caches )
00278 {
00279 FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" ));
00280 return;
00281 }
00282 #endif
00283
00284 cache = manager->caches[node->cache_index];
00285
00286 #ifdef FT_DEBUG_ERROR
00287 if ( cache == NULL )
00288 {
00289 FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" ));
00290 return;
00291 }
00292 #endif
00293
00294 manager->cur_weight -= cache->clazz.node_weight( node, cache );
00295
00296
00297 ftc_node_mru_unlink( node, manager );
00298
00299
00300 ftc_node_hash_unlink( node, cache );
00301
00302
00303 cache->clazz.node_free( node, cache );
00304
00305 #if 0
00306
00307 if ( manager->num_nodes == 0 )
00308 FT_TRACE0(( "ftc_node_destroy: invalid cache node count (%d)\n",
00309 manager->num_nodes ));
00310 #endif
00311 }
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 FT_LOCAL_DEF( FT_Error )
00324 FTC_Cache_Init( FTC_Cache cache )
00325 {
00326 return ftc_cache_init( cache );
00327 }
00328
00329
00330 FT_LOCAL_DEF( FT_Error )
00331 ftc_cache_init( FTC_Cache cache )
00332 {
00333 FT_Memory memory = cache->memory;
00334 FT_Error error;
00335
00336
00337 cache->p = 0;
00338 cache->mask = FTC_HASH_INITIAL_SIZE - 1;
00339 cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
00340
00341 (void)FT_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 );
00342 return error;
00343 }
00344
00345
00346 static void
00347 FTC_Cache_Clear( FTC_Cache cache )
00348 {
00349 if ( cache )
00350 {
00351 FTC_Manager manager = cache->manager;
00352 FT_UFast i;
00353 FT_UFast count;
00354
00355
00356 count = cache->p + cache->mask + 1;
00357
00358 for ( i = 0; i < count; i++ )
00359 {
00360 FTC_Node *pnode = cache->buckets + i, next, node = *pnode;
00361
00362
00363 while ( node )
00364 {
00365 next = node->link;
00366 node->link = NULL;
00367
00368
00369 ftc_node_mru_unlink( node, manager );
00370
00371
00372 manager->cur_weight -= cache->clazz.node_weight( node, cache );
00373
00374 cache->clazz.node_free( node, cache );
00375 node = next;
00376 }
00377 cache->buckets[i] = NULL;
00378 }
00379 ftc_cache_resize( cache );
00380 }
00381 }
00382
00383
00384 FT_LOCAL_DEF( void )
00385 ftc_cache_done( FTC_Cache cache )
00386 {
00387 if ( cache->memory )
00388 {
00389 FT_Memory memory = cache->memory;
00390
00391
00392 FTC_Cache_Clear( cache );
00393
00394 FT_FREE( cache->buckets );
00395 cache->mask = 0;
00396 cache->p = 0;
00397 cache->slack = 0;
00398
00399 cache->memory = NULL;
00400 }
00401 }
00402
00403
00404 FT_LOCAL_DEF( void )
00405 FTC_Cache_Done( FTC_Cache cache )
00406 {
00407 ftc_cache_done( cache );
00408 }
00409
00410
00411 static void
00412 ftc_cache_add( FTC_Cache cache,
00413 FT_UInt32 hash,
00414 FTC_Node node )
00415 {
00416 node->hash = hash;
00417 node->cache_index = (FT_UInt16) cache->index;
00418 node->ref_count = 0;
00419
00420 ftc_node_hash_link( node, cache );
00421 ftc_node_mru_link( node, cache->manager );
00422
00423 {
00424 FTC_Manager manager = cache->manager;
00425
00426
00427 manager->cur_weight += cache->clazz.node_weight( node, cache );
00428
00429 if ( manager->cur_weight >= manager->max_weight )
00430 {
00431 node->ref_count++;
00432 FTC_Manager_Compress( manager );
00433 node->ref_count--;
00434 }
00435 }
00436 }
00437
00438
00439 FT_LOCAL_DEF( FT_Error )
00440 FTC_Cache_NewNode( FTC_Cache cache,
00441 FT_UInt32 hash,
00442 FT_Pointer query,
00443 FTC_Node *anode )
00444 {
00445 FT_Error error;
00446 FTC_Node node;
00447
00448
00449
00450
00451
00452
00453
00454
00455 FTC_CACHE_TRYLOOP( cache )
00456 {
00457 error = cache->clazz.node_new( &node, query, cache );
00458 }
00459 FTC_CACHE_TRYLOOP_END();
00460
00461 if ( error )
00462 node = NULL;
00463 else
00464 {
00465
00466
00467
00468 ftc_cache_add( cache, hash, node );
00469 }
00470
00471 *anode = node;
00472 return error;
00473 }
00474
00475
00476 #ifndef FTC_INLINE
00477
00478 FT_LOCAL_DEF( FT_Error )
00479 FTC_Cache_Lookup( FTC_Cache cache,
00480 FT_UInt32 hash,
00481 FT_Pointer query,
00482 FTC_Node *anode )
00483 {
00484 FT_UFast idx;
00485 FTC_Node* bucket;
00486 FTC_Node* pnode;
00487 FTC_Node node;
00488 FT_Error error = 0;
00489
00490 FTC_Node_CompareFunc compare = cache->clazz.node_compare;
00491
00492
00493 if ( cache == NULL || anode == NULL )
00494 return FT_Err_Invalid_Argument;
00495
00496 idx = hash & cache->mask;
00497 if ( idx < cache->p )
00498 idx = hash & ( cache->mask * 2 + 1 );
00499
00500 bucket = cache->buckets + idx;
00501 pnode = bucket;
00502 for (;;)
00503 {
00504 node = *pnode;
00505 if ( node == NULL )
00506 goto NewNode;
00507
00508 if ( node->hash == hash && compare( node, query, cache ) )
00509 break;
00510
00511 pnode = &node->link;
00512 }
00513
00514 if ( node != *bucket )
00515 {
00516 *pnode = node->link;
00517 node->link = *bucket;
00518 *bucket = node;
00519 }
00520
00521
00522 {
00523 FTC_Manager manager = cache->manager;
00524
00525
00526 if ( node != manager->nodes_list )
00527 ftc_node_mru_up( node, manager );
00528 }
00529 *anode = node;
00530 return error;
00531
00532 NewNode:
00533 return FTC_Cache_NewNode( cache, hash, query, anode );
00534 }
00535
00536 #endif
00537
00538
00539 FT_LOCAL_DEF( void )
00540 FTC_Cache_RemoveFaceID( FTC_Cache cache,
00541 FTC_FaceID face_id )
00542 {
00543 FT_UFast i, count;
00544 FTC_Manager manager = cache->manager;
00545 FTC_Node frees = NULL;
00546
00547
00548 count = cache->p + cache->mask;
00549 for ( i = 0; i < count; i++ )
00550 {
00551 FTC_Node* bucket = cache->buckets + i;
00552 FTC_Node* pnode = bucket;
00553
00554
00555 for ( ;; )
00556 {
00557 FTC_Node node = *pnode;
00558
00559
00560 if ( node == NULL )
00561 break;
00562
00563 if ( cache->clazz.node_remove_faceid( node, face_id, cache ) )
00564 {
00565 *pnode = node->link;
00566 node->link = frees;
00567 frees = node;
00568 }
00569 else
00570 pnode = &node->link;
00571 }
00572 }
00573
00574
00575 while ( frees )
00576 {
00577 FTC_Node node;
00578
00579
00580 node = frees;
00581 frees = node->link;
00582
00583 manager->cur_weight -= cache->clazz.node_weight( node, cache );
00584 ftc_node_mru_unlink( node, manager );
00585
00586 cache->clazz.node_free( node, cache );
00587
00588 cache->slack++;
00589 }
00590
00591 ftc_cache_resize( cache );
00592 }
00593
00594
00595