diff options
Diffstat (limited to 'Build/source/libs/freetype/freetype-1.5/lib/ttcache.c')
-rw-r--r-- | Build/source/libs/freetype/freetype-1.5/lib/ttcache.c | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/Build/source/libs/freetype/freetype-1.5/lib/ttcache.c b/Build/source/libs/freetype/freetype-1.5/lib/ttcache.c new file mode 100644 index 00000000000..21e6bf54c0f --- /dev/null +++ b/Build/source/libs/freetype/freetype-1.5/lib/ttcache.c @@ -0,0 +1,464 @@ +/******************************************************************* + * + * ttcache.c 1.1 + * + * Generic object cache + * + * Copyright 1996-2000 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. + * + ******************************************************************/ + + FT_INTERNAL_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. + * + ******************************************************************/ + + FT_INTERNAL_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. + * + ******************************************************************/ + + FT_INTERNAL_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. + * + ******************************************************************/ + + FT_INTERNAL_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; + } + + + FT_INTERNAL_FUNC( TT_Error ) + TTCache_Init( PEngine_Instance engine ) + { + /* Create list elements mutex */ + FREE_Elements = NULL; + return TT_Err_Ok; + } + + + FT_INTERNAL_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 */ |