⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ttcache.c

📁 神龙卡开发原代码
💻 C
字号:
/******************************************************************* * *  ttcache.c                                                   1.1 * *    Generic object cache * *  Copyright 1996-1999 by *  David Turner, Robert Wilhelm, and Werner Lemberg. * *  This file is part of the FreeType project, and may only be used *  modified and distributed under the terms of the FreeType project *  license, LICENSE.TXT.  By continuing to use, modify, or distribute *  this file you indicate that you have read the license and *  understand and accept it fully. * * Changes between 1.1 and 1.0: * *  - introduced the refresher and finalizer in the cache class *    definition/implementation. * ******************************************************************/#include "ttengine.h"#include "ttmemory.h"#include "ttcache.h"#include "ttobjs.h"#include "ttdebug.h"/* required by the tracing mode */#undef  TT_COMPONENT#define TT_COMPONENT  trace_cache#define ZERO_List( list )  list = NULL/* The macro FREE_Elements aliases the current engine instance's *//* free list_elements recycle list.                              */#define FREE_Elements  ( engine->list_free_elements )/* Redefinition of LOCK and UNLOCK macros for New_Element and Done_Element *//* Note: The macros are redefined below for the cache functions            */#undef  LOCK#define LOCK()    MUTEX_Lock   ( engine->lock )#undef  UNLOCK#define UNLOCK()  MUTEX_Release( engine->lock )/******************************************************************* * *  Function    :  Element_New * *  Description :  Gets a new (either fresh or recycled) list *                 element.  The element is unlisted. * *  Input  :  None * *  Output :  List element address.  NULL if out of memory. * ******************************************************************/  static  PList_Element  Element_New( PEngine_Instance  engine )  {    PList_Element  element;    LOCK();    if ( FREE_Elements )    {      element       = (PList_Element)FREE_Elements;      FREE_Elements = element->next;    }    else    {      if ( !MEM_Alloc( element, sizeof ( TList_Element ) ) )      {        element->next = NULL;        element->data = NULL;      }    }    /* Note: in case of failure, Alloc sets the pointer to NULL */    UNLOCK();    return element;  }/******************************************************************* * *  Function    :  Element_Done * *  Description :  Recycles an unlinked list element. * *  Input  :  The list element to recycle.  It _must_ be unlisted. * *  Output :  none. * *  Note   :  This function doesn't check the element. * ******************************************************************/  static  void  Element_Done( PEngine_Instance  engine,                      PList_Element     element )  {    LOCK();    /* Simply add the list element to the recycle list */    element->next = (PList_Element)FREE_Elements;    FREE_Elements = element;    UNLOCK();  }/* Redefinition of LOCK and UNLOCK macros for the cache functions          *//* Note: The macros are defined above for the list element functions       */#undef  LOCK#define LOCK()    MUTEX_Lock( *cache->lock )#undef  UNLOCK#define UNLOCK()  MUTEX_Release( *cache->lock )/******************************************************************* * *  Function    :  Cache_Create * *  Description :  Creates a new cache that will be used to list *                 and recycle several objects of the same class. * *  Input  :  clazz       a pointer to the cache's class.  This is *                        a simple structure that describes the *                        the cache's object types and recycling *                        limits. * *            cache       address of cache to create * *            lock        address of the mutex to use for this *                        cache.  The mutex will be used to protect *                        the cache's lists.  Use NULL for unprotected *                        cache. * *  Output :  Error code. * ******************************************************************/  LOCAL_FUNC  TT_Error  Cache_Create( PEngine_Instance  engine,                          PCache_Class      clazz,                          TCache*           cache,                          TMutex*           lock )  {    cache->engine     = engine;    cache->clazz      = clazz;    cache->lock       = lock;    cache->idle_count = 0;    ZERO_List( cache->active );    ZERO_List( cache->idle );    return TT_Err_Ok;  }/******************************************************************* * *  Function    :  Cache_Destroy * *  Description :  Destroys a cache and all its idle and active *                 objects.  This will call each object's destructor *                 before freeing it. * *  Input  :  cache   address of cache to destroy * *  Output :  error code. * *  Note: This function is not MT-Safe, as we assume that a client *        isn't stupid enough to use an object while destroying it. * ******************************************************************/  LOCAL_FUNC  TT_Error  Cache_Destroy( TCache*  cache )  {    PDestructor    destroy;    PList_Element  current;    PList_Element  next;    /* now destroy all active and idle listed objects */    /* get the destructor function */    destroy = cache->clazz->done;    /* destroy all elements in active list */    current = cache->active;    while ( current )    {      next = current->next;      destroy( current->data );      FREE( current->data );      Element_Done( cache->engine, current );      current = next;    }    ZERO_List(cache->active);    /* destroy all elements in idle list */    current = cache->idle;    while ( current )    {      next = current->next;      destroy( current->data );      FREE( current->data );      Element_Done( cache->engine, current );      current = next;    }    ZERO_List(cache->idle);    cache->clazz      = NULL;    cache->idle_count = 0;    return TT_Err_Ok;  }/******************************************************************* * *  Function    :  Cache_New * *  Description :  Extracts a new object from a cache.  This will *                 try to recycle an idle object, if any is found. *                 Otherwise, a new object will be allocated and *                 built (by calling its constructor). * *  Input  :   cache          address of cache to use *             new_object     address of target pointer to the 'new' *                            object *             parent_object  this pointer is passed to a new object *                            constructor (unused if object is *                            recycled) * *  Output :   Error code. * *  Notes: This function is thread-safe, each cache list is protected *         through the cache's mutex, if there is one... * *         *new_object will be set to NULL in case of failure. * ******************************************************************/  LOCAL_FUNC  TT_Error  Cache_New( TCache*  cache,                       void**   new_object,                       void*    parent_object )  {    TT_Error       error;    PList_Element  current;    PConstructor   build;    PRefresher     reset;    void*          object;    LOCK();    current = cache->idle;    if ( current )    {      cache->idle = current->next;      cache->idle_count--;    }    UNLOCK();    if ( current )    {      object = current->data;      reset  = cache->clazz->reset;      if ( reset )      {        error = reset( object, parent_object );        if ( error )        {          LOCK();          current->next = cache->idle;          cache->idle   = current;          cache->idle_count++;          UNLOCK();          goto Exit;        }      }    }    else    {      /* if no object was found in the cache, create a new one */      build  = cache->clazz->init;      if ( MEM_Alloc( object, cache->clazz->object_size ) )        goto Memory_Fail;      current = Element_New( cache->engine );      if ( !current )        goto Memory_Fail;      current->data = object;      error = build( object, parent_object );      if ( error )      {        Element_Done( cache->engine, current );        goto Fail;      }    }    LOCK();    current->next = cache->active;    cache->active = current;    UNLOCK();    *new_object = current->data;    return TT_Err_Ok;  Exit:    *new_object = NULL;    return  error;  Memory_Fail:    error = TT_Err_Out_Of_Memory;  Fail:    FREE( object );    goto Exit;  }/******************************************************************* * *  Function    :  Cache_Done * *  Description :  Releases an object to the cache.  This will either *                 recycle or destroy the object, based on the cache's *                 class and state. * *  Input  :  cache   the cache to use *            data    the object to recycle/discard * *  Output :  error code. * *  Notes  :  The object's destructor is called only when *            the objectwill be effectively destroyed by this *            function.  This will not happen during recycling. * ******************************************************************/  LOCAL_FUNC  TT_Error  Cache_Done( TCache*  cache, void*  data )  {    TT_Error       error;    PList_Element  element;    PList_Element  prev;    PFinalizer     finalize;    Long           limit;    Bool           destroy;    /* Look for object in active list */    LOCK();    element = cache->active;    prev = NULL;    while ( element )    {      if ( element->data == data )      {        if ( prev )          prev->next = element->next;        else          cache->active = element->next;        goto Suite;      }      prev = element;      element = element->next;    }    UNLOCK();    return TT_Err_Unlisted_Object;  Suite:    limit   = cache->clazz->idle_limit;    destroy = (cache->idle_count >= limit);    UNLOCK();    if ( destroy )    {      /* destroy the object when the cache is full */      cache->clazz->done( element->data );      FREE( element->data );      Element_Done( cache->engine, element );    }    else    {      /* Finalize the object before adding it to the   */      /* idle list.  Return the error if any is found. */      finalize = cache->clazz->finalize;      if ( finalize )      {        error = finalize( element->data );        if ( error )          goto Exit;        /* Note: a failure at finalize time is a severe bug in     */        /*       the engine, which is why we allow ourselves to    */        /*       lose the object in this case.  A finalizer should */        /*       have its own error codes to spot this kind of     */        /*       problems easily.                                  */      }      LOCK();      element->next = cache->idle;      cache->idle   = element;      cache->idle_count++;      UNLOCK();    }    error = TT_Err_Ok;  Exit:    return error;  }  LOCAL_FUNC  TT_Error  TTCache_Init( PEngine_Instance  engine )  {    /* Create list elements mutex */    FREE_Elements = NULL;    return TT_Err_Ok;  }  LOCAL_FUNC  TT_Error  TTCache_Done( PEngine_Instance  engine )  {    /* We don't protect this function, as this is the end of the engine's */    /* execution..                                                        */    PList_Element  element, next;    /* frees the recycled list elements */    element = FREE_Elements;    while ( element )    {      next = element->next;      FREE( element );      element = next;    }    return TT_Err_Ok;  }/* END */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -