303 lines
7.2 KiB
C
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 );
|
||
|
|