summaryrefslogtreecommitdiff
path: root/Build/source/libs/freetype/freetype-1.5/lib/ttcache.c
diff options
context:
space:
mode:
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.c464
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 */