freetype/src/base/ftobject.c
David Turner 1093730447 * include/freetype/internal/fthash.h, src/base/fthash.c:
adding a generic implementation of dynamic hash tables using
          linear algorithm (to get rid of 'stalls' during resizes). This
          will be used in the future in at least three parts of the
          library: the cache sub-system, the object sub-system and
          the memory debugger.

        * include/freetype/internal/ftcore.h: added this header file to
          group all new definitions related to exception handling and
          memory management. It's very likely that this file will disappear
          or be renamed in the future..

        * include/freetype/internal/ftobject.h, include/freetype/ftsysmem.h:
          adding comments to better explain the object sub-system as well
          as the new memory manager interface.
2002-05-01 08:46:56 +00:00

303 lines
7.2 KiB
C

#include "ftobject.c"
#define FT_MAGIC_DEATH 0xDEADdead
#define FT_MAGIC_CLASS 0x12345678
#define FT_OBJECT_CHECK(o) \
( FT_OBJECT(o) != NULL && \
FT_OBJECT(o)->clazz != NULL && \
FT_OBJECT(o)->ref_count >= 1 && \
FT_OBJECT(o)->clazz->magic == FT_MAGIC_CLASS )
/*******************************************************************/
/*******************************************************************/
/***** *****/
/***** *****/
/***** M E T A - C L A S S *****/
/***** *****/
/***** *****/
/*******************************************************************/
/*******************************************************************/
/* we use a dynamic hash table to map types to classes */
/* this structure defines the layout of each node of */
/* this table */
typedef struct FT_ClassHNodeRec_
{
FT_HashNodeRec hnode;
FT_Type ctype;
FT_Class clazz;
} FT_ClassHNodeRec, *FT_ClassHNode;
/* the meta class contains a type -> class mapping */
/* and owns all class objects.. */
/* */
typedef struct FT_MetaClassRec_
{
FT_ClassRec clazz;
FT_HashRec type_to_class;
} FT_MetaClassRec, *FT_MetaClass;
/* forward declaration */
static const FT_TypeRec ft_meta_class_type;
/* destroy a given class */
static void
ft_class_hnode_destroy( FT_ClassHNode node )
{
FT_Clazz clazz = node->clazz;
FT_Memory memory = clazz->memory;
FT_Type ctype = clazz->type;
if ( ctype->class_done )
ctype->class_done( clazz );
FT_FREE( clazz );
node->clazz = NULL;
node->type = NULL;
FT_FREE( node );
}
static FT_Int
ft_class_hnode_compare( const FT_ClassHNode node1,
const FT_ClassHNode node2 )
{
return ( node1->type == node2->type );
}
static void
ft_metaclass_done( FT_MetaClass meta )
{
/* clear all objects */
ft_hash_done( &meta->type_to_class,
(FT_Hash_ForeachFunc) ft_class_destroy,
NULL );
meta->clazz->object.clazz = NULL;
meta->clazz->object.ref_count = 0;
meta->clazz->magic = FT_MAGIC_DEATH;
}
static void
ft_metaclass_init( FT_MetaClass meta,
FT_Library library )
{
FT_ClassRec* clazz = meta->clazz;
/* the meta-class is its OWN class !! */
clazz->object.clazz = (FT_Class) clazz;
clazz->object.ref_count = 1;
clazz->magic = FT_MAGIC_CLASS;
clazz->library = library;
clazz->memory = library->memory;
clazz->type = &ft_metaclass_type;
clazz->info = NULL;
clazz->obj_size = sizeof( FT_ClassRec );
clazz->obj_init = NULL;
clazz->obj_done = NULL;
ft_hash_init( &meta->type_to_class,
(FT_Hash_CompareFunc) ft_class_hnode_compare,
library->memory );
}
/* find or create the class corresponding to a given type */
static FT_Class
ft_metaclass_get_class( FT_MetaClass meta,
FT_Type ctype )
{
FT_ClassHNodeRec keynode, *node, **pnode;
FT_Memory memory;
keynode.hnode.hash = (FT_UInt32)( ctype >> 2 );
keynode.type = type;
pnode = (FT_ClassHNode) ft_hash_lookup( &meta->type_to_class,
&noderec );
node = *pnode;
if ( node != NULL )
return node->clazz;
memory = FT_CLASS__MEMORY(meta);
node = FT_MEM_SAFE_ALLOC( sizeof(*node) );
if ( node != NULL )
{
FT_ClassRec* clazz;
clazz = FT_MEM_SAFE_ALLOC( ctype->class_size );
if ( clazz == NULL )
{
FT_FREE( node );
FT_XTHROW( FT_Err_Out_Of_Memory );
}
}
}
static const FT_TypeRec ft_meta_class_type =
{
"FT2.MetaClass",
NULL,
sizeof( FT_MetaClassRec ),
(FT_Object_InitFunc) ft_metaclass_init,
(FT_Object_DoneFunc) ft_metaclass_done,
sizeof( FT_ClassRec ),
(FT_Object_InitFunc) ft_class_init,
(FT_Object_DoneFunc) ft_class_done
};
FT_BASE_DEF( FT_Int )
ft_object_check( FT_Pointer obj )
{
return FT_OBJECT_CHECK(obj);
}
FT_BASE_DEF( FT_Int )
ft_object_is_a( FT_Pointer obj,
FT_Class clazz )
{
if ( FT_OBJECT_CHECK(obj) )
{
FT_Object o = FT_OBJECT(obj);
FT_Class c = FT_OBJECT__CLASS(obj);
do
{
if ( c == clazz )
return 1;
c = c->super;
}
while ( c == NULL );
return (clazz == NULL);
}
}
/* the cleanup routine for all objects */
static void
ft_object_cleanup( FT_Object object )
{
FT_Memory memory = FT_OBJECT__MEMORY(object);
FT_Class clazz = FT_OBJECT__CLASS(object);
if ( clazz->obj_done )
clazz->obj_done( object );
FT_FREE( object );
}
FT_BASE_DEF( FT_Object )
ft_object_new( FT_Class clazz,
FT_Pointer init_data )
{
FT_Memory memory;
FT_Object obj;
FT_ASSERT_IS_CLASS(clazz);
memory = FT_CLASS__MEMORY(clazz);
obj = ft_mem_alloc( clazz->obj_size, memory );
obj->clazz = clazz;
obj->ref_count = 1;
if ( clazz->obj_init )
{
FT_CleanupStack stack = FT_MEMORY__CLEANUP(memory);
ft_cleanup_push( stack, obj, (FT_CleanupFunc) ft_object_cleanup, NULL );
clazz->obj_init( obj, init_data );
ft_cleanup_pop( stack, obj, 0 );
}
return obj;
}
FT_BASE_DEF( void )
ft_object_create( FT_Object *pobject,
FT_Class clazz,
FT_Pointer init_data )
{
FT_Memory memory;
FT_Object obj;
FT_ASSERT_IS_CLASS(clazz);
memory = FT_CLASS__MEMORY(memory);
obj = ft_mem_alloc( clazz->obj_size, memory );
obj->clazz = clazz;
obj->ref_count = 1;
*pobject = obj;
if ( clazz->obj_init )
clazz->obj_init( obj, init_data );
}
FT_BASE_DEF( FT_Class )
ft_class_find_by_type( FT_Type type,
FT_Memory memory )
{
}
FT_BASE_DEF( FT_Class )
ft_class_find_by_name( FT_CString class_name,
FT_Memory memory );
FT_BASE_DEF( FT_Object )
ft_object_new_from_type( FT_Type type,
FT_Pointer data,
FT_Memory memory );
FT_BASE_DEF( void )
ft_object_create_from_type( FT_Object *pobject,
FT_Type type,
FT_Pointer init_data,
FT_Memory memory );
FT_BASE_DEF( void )
ft_object_push( FT_Object object );
FT_BASE_DEF( void )
ft_object_pop( FT_Object object );
FT_BASE_DEF( void )
ft_object_pop_destroy( FT_Object object );