/******************************************************************* * * ttcache.h 1.1 * * Generic object cache * * Copyright 1996-1998 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. * * * This component defines and implements object caches. * * An object class is a structure layout that encapsulate one * given type of data used by the FreeType engine. Each object * class is completely described by: * * - a 'root' or 'leading' structure containing the first * important fields of the class. The root structure is * always of fixed size. * * It is implemented as a simple C structure, and may * contain several pointers to sub-tables that can be * sized and allocated dynamically. * * Examples: TFace, TInstance, TGlyph & TExecution_Context * (defined in 'ttobjs.h') * * - we make a difference between 'child' pointers and 'peer' * pointers. A 'child' pointer points to a sub-table that is * owned by the object, while a 'peer' pointer points to any * other kind of data the object isn't responsible for. * * An object class is thus usually a 'tree' of 'child' tables. * * - each object class needs a constructor and a destructor. * * A constructor is a function which receives the address of * freshly allocated and zeroed object root structure and * 'builds' all the valid child data that must be associated * to the object before it becomes 'valid'. * * A destructor does the inverse job: given the address of * a valid object, it must discard all its child data and * zero its main fields (essentially the pointers and array * sizes found in the root fields). * * * Important notes: * * When the constructor fails to allocate an object, it must * return immediately with an error code, and not try to release * what it has previously allocated before the error. The cache * manager detects the error and calls the destructor on the * partial object, before returning the error to the caller (along * with a NULL pointer for the "new" object). * * The destructor must thus be able to deal with "partial objects", * i.e., objects where only part of the child tables are allocated, * and only release these ones. As the TT_Free() function accepts * a NULL parameter (and returns successfuly in this case), no check * is really necessary when using the macro 'FREE()'. * * Currently, there is no check in the cache manager to see if a * destructor fails (double error state!). * * This scheme is more compact and more maintanable than the one * where de-allocation code is duplicated in the constructor * _and_ the destructor. * * * * Changes between 1.1 and 1.0: * * - introduced the refreshed and finalizer class definition/implementation * - inserted an engine instance pointer in the cache structure * ******************************************************************/ #ifndef TTCACHE_H #define TTCACHE_H #include "tttypes.h" #include "ttconfig.h" #include "ttmutex.h" #ifdef __cplusplus extern "C" { #endif typedef TT_Error TConstructor( void* object, void* parent ); typedef TT_Error TDestructor ( void* object ); typedef TConstructor TRefresher; typedef TDestructor TFinaliser; typedef TConstructor* PConstructor; typedef TDestructor* PDestructor; typedef TRefresher* PRefresher; typedef TFinaliser* PFinaliser; /* A Cache class record holds the data necessary to define */ /* a cache kind. */ struct TCache_Class_ { Long object_size; Long idle_limit; PConstructor init; PDestructor done; PRefresher reset; PFinaliser finalise; }; typedef struct TCache_Class_ TCache_Class; typedef TCache_Class* PCache_Class; /* Simple list node record. A list element is said to be 'unlinked' */ /* when it doesn't belong to any list. */ struct TList_Element_; typedef struct TList_Element_ TList_Element; typedef TList_Element* PList_Element; struct TList_Element_ { PList_Element next; void* data; }; /* Simple singly-linked list record - LIFO style, no tail field */ typedef PList_Element TSingle_List; struct TCache_ { PEngine_Instance engine; PCache_Class clazz; /* 'class' is a reserved word in C++ */ TMutex* lock; TSingle_List active; TSingle_List idle; Long idle_count; }; typedef struct TCache_ TCache; typedef TCache *PCache; /* Returns a new list element, either fresh or recycled. */ /* Note: the returned element is unlinked. */ /* An object cache holds two lists tracking the active and */ /* idle objects that are currently created and used by the */ /* engine. It can also be 'protected' by a mutex. */ /* Initializes a new cache, of class 'clazz', pointed by 'cache', */ /* protected by the 'lock' mutex. Set 'lock' to NULL if the cache */ /* doesn't need protection */ LOCAL_DEF TT_Error Cache_Create( PEngine_Instance engine, PCache_Class clazz, TCache* cache, TMutex* lock ); /* Destroys a cache and all its listed objects */ LOCAL_DEF TT_Error Cache_Destroy( TCache* cache ); /* Extracts a new object from the cache */ LOCAL_DEF TT_Error Cache_New( TCache* cache, void** new_object, void* parent_object ); /* Returns an object to the cache, or discards it depending */ /* on the cache class' 'idle_limit' field */ LOCAL_DEF TT_Error Cache_Done( TCache* cache, void* data ); #define CACHE_New( _cache, _newobj, _parent ) \ Cache_New( (TCache*)_cache, (void**)&_newobj, (void*)_parent ) #define CACHE_Done( _cache, _obj ) \ Cache_Done( (TCache*)_cache, (void*)_obj ) LOCAL_DEF TT_Error TTCache_Init( PEngine_Instance engine ); LOCAL_DEF TT_Error TTCache_Done( PEngine_Instance engine ); #ifdef __cplusplus } #endif #endif /* TTCACHE_H */ /* END */