ref: 44cb6fe8162588851dbb8a23e69a88b85e92fb56
dir: /src/base/ftobject.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 );