ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ftccache.c
Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftccache.c                                                             */
00004 /*                                                                         */
00005 /*    The FreeType internal cache interface (body).                        */
00006 /*                                                                         */
00007 /*  Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 by */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
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 /* this one _must_ be a power of 2! */
00036 #define FTC_HASH_INITIAL_SIZE  8
00037 
00038 
00039   /*************************************************************************/
00040   /*************************************************************************/
00041   /*****                                                               *****/
00042   /*****                   CACHE NODE DEFINITIONS                      *****/
00043   /*****                                                               *****/
00044   /*************************************************************************/
00045   /*************************************************************************/
00046 
00047   /* add a new node to the head of the manager's circular MRU list */
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   /* remove a node from the manager's MRU list */
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   /* move a node to the head of the manager's MRU list */
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 /* !FTC_INLINE */
00087 
00088 
00089   /* Note that this function cannot fail.  If we cannot re-size the
00090    * buckets array appropriately, we simply degrade the hash table's
00091    * performance!
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;    /* number of buckets */
00102 
00103 
00104       /* do we need to shrink the buckets array? */
00105       if ( cache->slack < 0 )
00106       {
00107         FTC_Node  new_list = NULL;
00108 
00109 
00110         /* try to expand the buckets array _before_ splitting
00111          * the bucket lists
00112          */
00113         if ( p >= mask )
00114         {
00115           FT_Memory  memory = cache->memory;
00116           FT_Error   error;
00117 
00118 
00119           /* if we can't expand the array, leave immediately */
00120           if ( FT_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) )
00121             break;
00122         }
00123 
00124         /* split a single bucket */
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       /* do we need to expand the buckets array? */
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           /* if we can't shrink the array, leave immediately */
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 /* the hash table is balanced */
00195         break;
00196     }
00197   }
00198 
00199 
00200   /* remove a node from its cache's hash table */
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   /* add a node to the `top' of its cache's hash table */
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   /* remove a node from the cache manager */
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     /* find node's cache */
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     /* remove node from mru list */
00297     ftc_node_mru_unlink( node, manager );
00298 
00299     /* remove node from cache's hash table */
00300     ftc_node_hash_unlink( node, cache );
00301 
00302     /* now finalize it */
00303     cache->clazz.node_free( node, cache );
00304 
00305 #if 0
00306     /* check, just in case of general corruption :-) */
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   /*****                    ABSTRACT CACHE CLASS                       *****/
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 && cache->buckets )
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           /* remove node from mru list */
00369           ftc_node_mru_unlink( node, manager );
00370 
00371           /* now finalize it */
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_PtrDist 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_PtrDist  hash,
00442                      FT_Pointer  query,
00443                      FTC_Node   *anode )
00444   {
00445     FT_Error  error;
00446     FTC_Node  node;
00447 
00448 
00449     /*
00450      * We use the FTC_CACHE_TRYLOOP macros to support out-of-memory
00451      * errors (OOM) correctly, i.e., by flushing the cache progressively
00452      * in order to make more room.
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      /* don't assume that the cache has the same number of buckets, since
00466       * our allocation request might have triggered global cache flushing
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_PtrDist  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 = FTC_Err_Ok;
00489 
00490     FTC_Node_CompareFunc  compare = cache->clazz.node_compare;
00491 
00492 
00493     if ( cache == NULL || anode == NULL )
00494       return FTC_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     /* move to head of MRU list */
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 /* !FTC_INLINE */
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     /* remove all nodes in the free list */
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 /* END */

Generated on Sat May 26 2012 04:32:39 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.