#include #include FT_INTERNAL_OBJECT_H #include FT_INTERNAL_DEBUG_H #include FT_INTERNAL_OBJECTS_H #define FT_MAGIC_DEATH 0xDEADdead #define FT_MAGIC_CLASS 0x12345678 #define FT_TYPE_HASH(x) (( (FT_UInt32)(x) >> 2 )^( (FT_UInt32)(x) >> 10 )) #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 ) #define FT_CLASS_CHECK(c) \ ( FT_CLASS(c) != NULL && FT_CLASS(c)->magic == FT_MAGIC_CLASS ) #define FT_ASSERT_IS_CLASS(c) FT_ASSERT( FT_CLASS_CHECK(c) ) /*******************************************************************/ /*******************************************************************/ /***** *****/ /***** *****/ /***** M E T A - C L A S S *****/ /***** *****/ /***** *****/ /*******************************************************************/ /*******************************************************************/ /* forward declaration */ FT_BASE_DEF( FT_Error ) ft_metaclass_init( FT_MetaClass meta, FT_Library library ); /* forward declaration */ FT_BASE_DEF( void ) ft_metaclass_done( FT_MetaClass meta ); /* class type for the meta-class itself */ 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) NULL, (FT_Object_DoneFunc) NULL }; /* destroy a given class */ static void ft_class_hnode_destroy( FT_ClassHNode node ) { FT_Class clazz = node->clazz; FT_Memory memory = clazz->memory; if ( clazz->class_done ) clazz->class_done( (FT_Object) clazz ); FT_FREE( clazz ); node->clazz = NULL; node->type = NULL; FT_FREE( node ); } static FT_Int ft_type_equal( FT_Type type1, FT_Type type2 ) { if ( type1 == type2 ) goto Ok; if ( type1 == NULL || type2 == NULL ) goto Fail; /* compare parent types */ if ( type1->super != type2->super ) { if ( type1->super == NULL || type2->super == NULL || !ft_type_equal( type1, type2 ) ) goto Fail; } /* compare type names */ if ( type1->name != type2->name ) { if ( type1->name == NULL || type2->name == NULL || ft_strcmp( type1->name, type2->name ) != 0 ) goto Fail; } /* compare the other type fields */ if ( type1->class_size != type2->class_size || type1->class_init != type2->class_init || type1->class_done != type2->class_done || type1->obj_size != type2->obj_size || type1->obj_init != type2->obj_init || type1->obj_done != type2->obj_done ) goto Fail; Ok: return 1; Fail: return 0; } static FT_Int ft_class_hnode_equal( const FT_ClassHNode node1, const FT_ClassHNode node2 ) { FT_Type type1 = node1->type; FT_Type type2 = node2->type; /* comparing the pointers should work in 99% of cases */ return ( type1 == type2 ) ? 1 : ft_type_equal( type1, type2 ); } FT_BASE_DEF( void ) ft_metaclass_done( FT_MetaClass meta ) { /* clear all classes */ ft_hash_done( &meta->type_to_class, (FT_Hash_ForeachFunc) ft_class_hnode_destroy, NULL ); meta->clazz.object.clazz = NULL; meta->clazz.object.ref_count = 0; meta->clazz.magic = FT_MAGIC_DEATH; } FT_BASE_DEF( FT_Error ) ft_metaclass_init( FT_MetaClass meta, FT_Library library ) { FT_ClassRec* clazz = (FT_ClassRec*) &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_meta_class_type; clazz->info = NULL; clazz->class_done = (FT_Object_DoneFunc) ft_metaclass_done; clazz->obj_size = sizeof( FT_ClassRec ); clazz->obj_init = NULL; clazz->obj_done = NULL; return ft_hash_init( &meta->type_to_class, (FT_Hash_EqualFunc) ft_class_hnode_equal, library->memory ); } /* find or create the class corresponding to a given type */ /* note that this function will retunr NULL in case of */ /* memory overflow */ /* */ static FT_Class ft_metaclass_get_class( FT_MetaClass meta, FT_Type ctype ) { FT_ClassHNodeRec keynode, *node, **pnode; FT_Memory memory; FT_ClassRec* clazz; FT_Class parent; FT_Error error; keynode.hnode.hash = FT_TYPE_HASH( ctype ); keynode.type = ctype; pnode = (FT_ClassHNode*) ft_hash_lookup( &meta->type_to_class, (FT_HashNode) &keynode ); node = *pnode; if ( node != NULL ) { clazz = (FT_ClassRec*) node->clazz; goto Exit; } memory = FT_CLASS__MEMORY(meta); clazz = NULL; parent = NULL; if ( ctype->super != NULL ) { FT_ASSERT( ctype->super->class_size <= ctype->class_size ); FT_ASSERT( ctype->super->obj_size <= ctype->obj_size ); parent = ft_metaclass_get_class( meta, ctype->super ); } if ( !FT_NEW( node ) ) { if ( !FT_ALLOC( clazz, ctype->class_size ) ) { if ( parent ) FT_MEM_COPY( (FT_ClassRec*)clazz, parent, parent->type->class_size ); clazz->object.clazz = (FT_Class) meta; clazz->object.ref_count = 1; clazz->memory = memory; clazz->library = FT_CLASS__LIBRARY(meta); clazz->super = parent; clazz->type = ctype; clazz->info = NULL; clazz->magic = FT_MAGIC_CLASS; clazz->class_done = ctype->class_done; clazz->obj_size = ctype->obj_size; clazz->obj_init = ctype->obj_init; clazz->obj_done = ctype->obj_done; if ( parent ) { if ( clazz->class_done == NULL ) clazz->class_done = parent->class_done; if ( clazz->obj_init == NULL ) clazz->obj_init = parent->obj_init; if ( clazz->obj_done == NULL ) clazz->obj_done = parent->obj_done; } /* find class initializer, if any */ { FT_Type ztype = ctype; FT_Object_InitFunc cinit = NULL; do { cinit = ztype->class_init; if ( cinit != NULL ) break; ztype = ztype->super; } while ( ztype != NULL ); /* then call it when needed */ if ( cinit != NULL ) error = cinit( (FT_Object) clazz, NULL ); } } if (error) { if ( clazz ) { /* we always call the class destructor when */ /* an error was detected in the constructor !! */ if ( clazz->class_done ) clazz->class_done( (FT_Object) clazz ); FT_FREE( clazz ); } FT_FREE( node ); } } Exit: return (FT_Class) clazz; } 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_Class c = FT_OBJECT__CLASS(obj); do { if ( c == clazz ) return 1; c = c->super; } while ( c == NULL ); return (clazz == NULL); } return 0; } FT_BASE_DEF( FT_Error ) ft_object_create( FT_Object *pobject, FT_Class clazz, FT_Pointer init_data ) { FT_Memory memory; FT_Error error; FT_Object obj; FT_ASSERT_IS_CLASS(clazz); memory = FT_CLASS__MEMORY(clazz); if ( !FT_ALLOC( obj, clazz->obj_size ) ) { obj->clazz = clazz; obj->ref_count = 1; if ( clazz->obj_init ) { error = clazz->obj_init( obj, init_data ); if ( error ) { /* IMPORTANT: call the destructor when an error */ /* was detected in the constructor !! */ if ( clazz->obj_done ) clazz->obj_done( obj ); FT_FREE( obj ); } } } *pobject = obj; return error; } FT_BASE_DEF( FT_Class ) ft_class_find_by_type( FT_Type type, FT_Library library ) { FT_MetaClass meta = &library->meta_class; return ft_metaclass_get_class( meta, type ); } FT_BASE_DEF( FT_Error ) ft_object_create_from_type( FT_Object *pobject, FT_Type type, FT_Pointer init_data, FT_Library library ) { FT_Class clazz; FT_Error error; clazz = ft_class_find_by_type( type, library ); if ( clazz ) error = ft_object_create( pobject, clazz, init_data ); else { *pobject = NULL; error = FT_Err_Out_Of_Memory; } return error; }