From 660138753b036ea5fe14c55c1ee2a57ea7615431 Mon Sep 17 00:00:00 2001 From: David Turner Date: Thu, 11 Jul 2002 16:27:16 +0000 Subject: [PATCH] updatinf the object sub-system and dynamic hash table implementations --- include/freetype/fttypes.h | 1 + include/freetype/internal/fthash.h | 6 +- include/freetype/internal/ftobject.h | 52 ++--- include/freetype/internal/ftobjs.h | 4 +- include/freetype/internal/internal.h | 2 + src/base/Jamfile | 2 +- src/base/fthash.c | 93 +++++--- src/base/ftobject.c | 338 +++++++++++++++++---------- 8 files changed, 300 insertions(+), 198 deletions(-) diff --git a/include/freetype/fttypes.h b/include/freetype/fttypes.h index 3abb0f887..7fe477706 100644 --- a/include/freetype/fttypes.h +++ b/include/freetype/fttypes.h @@ -21,6 +21,7 @@ #include +#include FT_CONFIG_CONFIG_H #include FT_SYSTEM_H #include FT_IMAGE_H diff --git a/include/freetype/internal/fthash.h b/include/freetype/internal/fthash.h index 4aa62db83..b95b6c925 100644 --- a/include/freetype/internal/fthash.h +++ b/include/freetype/internal/fthash.h @@ -125,7 +125,7 @@ FT_BEGIN_HEADER FT_Hash_EqualFunc node_equal; FT_Memory memory; - } FT_HashRec, *FT_Hash; + } FT_HashRec; /*********************************************************** @@ -270,7 +270,7 @@ FT_BEGIN_HEADER */ FT_BASE_DEF( FT_HashLookup ) ft_hash_lookup( FT_Hash table, - FT_HashNode keynode ) + FT_HashNode keynode ); /**************************************************************** @@ -380,7 +380,7 @@ FT_BEGIN_HEADER */ FT_BASE( FT_Error ) ft_hash_remove( FT_Hash table, - FT_HashLookup lookup ) + FT_HashLookup lookup ); diff --git a/include/freetype/internal/ftobject.h b/include/freetype/internal/ftobject.h index f050eb09b..f285d9e20 100644 --- a/include/freetype/internal/ftobject.h +++ b/include/freetype/internal/ftobject.h @@ -288,14 +288,17 @@ FT_BEGIN_HEADER * * @note: * if 'obj_init' is NULL, the class will use it's parent - * constructor. + * constructor, if any * * if 'obj_done' is NULL, the class will use it's parent - * finalizer. + * finalizer, if any * * the object sub-system allocates a new class, copies * the content of its super-class into the new structure, * _then_ calls 'clazz_init'. + * + * 'class_init' and 'class_done' can be NULL, in which case + * the parent's class constructor and destructor wil be used */ typedef struct FT_TypeRec_ { @@ -337,7 +340,7 @@ FT_BEGIN_HEADER * @return: * 1 iff the handle points to a valid object. 0 otherwise */ - FT_BASE_DEF( FT_Int ) + FT_BASE( FT_Int ) ft_object_check( FT_Pointer obj ); @@ -357,7 +360,7 @@ FT_BEGIN_HEADER * 1 iff the handle points to a valid 'clazz' instance. 0 * otherwise. */ - FT_BASE_DEF( FT_Int ) + FT_BASE( FT_Int ) ft_object_is_a( FT_Pointer obj, FT_Class clazz ); @@ -379,7 +382,7 @@ FT_BEGIN_HEADER * @return: * error code. 0 means success */ - FT_BASE_DEF( FT_Error ) + FT_BASE( FT_Error ) ft_object_create( FT_Object *aobject, FT_Class clazz, FT_Pointer init_data ); @@ -408,7 +411,7 @@ FT_BEGIN_HEADER * this is equivalent to calling @ft_class_from_type followed by * @ft_object_create */ - FT_BASE_DEF( FT_Error ) + FT_BASE( FT_Error ) ft_object_create_from_type( FT_Object *aobject, FT_Type type, FT_Pointer init_data, @@ -438,7 +441,7 @@ FT_BEGIN_HEADER * code returned by the object constructor. */ #define FT_CREATE( _obj, _clazz, _init ) \ - FT_MEM_SET( FT_OBJ_CREATE( _obj, _clazz, _init ) ) + FT_SET_ERROR( FT_OBJ_CREATE( _obj, _clazz, _init ) ) /************************************************************** * @@ -462,7 +465,7 @@ FT_BEGIN_HEADER * code returned by the object constructor. */ #define FT_CREATE_FROM_TYPE( _obj, _type, _init, _lib ) \ - FT_MEM_SET( FT_OBJ_CREATE( _obj, _type, _init, _lib ) ) + FT_SET_ERROR( FT_OBJ_CREATE_FROM_TYPE( _obj, _type, _init, _lib ) ) /* */ @@ -486,39 +489,12 @@ FT_BEGIN_HEADER * @return: * error code. 0 means success */ - FT_BASE_DEF( FT_Error ) + FT_BASE( FT_Error ) ft_class_from_type( FT_Class *aclass, FT_Type type, FT_Library library ); - /************************************************************** - * - * @function: ft_class_from_name - * - * @description: - * retrieves the class object corresponding to a given type - * name. The class is created when needed - * - * @output: - * aclass :: handle to corresponding class object. NULL - * in case of error - * - * @input: - * name :: class name - * library :: library handle - * - * @return: - * error code. 0 means success - * - * @note: - * this function is _very_ slow. You should only use it for - * debugging purposes.. - */ - FT_BASE_DEF( FT_Error ) - ft_class_from_name( FT_Class *aclass, - FT_CString class_name, - FT_Library library ); /* */ #include FT_INTERNAL_HASH_H @@ -542,12 +518,12 @@ FT_BEGIN_HEADER /* initialize meta class */ - FT_BASE_DEF( FT_Error ) + FT_BASE( FT_Error ) ft_metaclass_init( FT_MetaClass meta, FT_Library library ); /* finalize meta class - destroy all registered class objects */ - FT_BASE_DEF( void ) + FT_BASE( void ) ft_metaclass_done( FT_MetaClass meta ); /* */ diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h index 015349ab0..6b94a6f3b 100644 --- a/include/freetype/internal/ftobjs.h +++ b/include/freetype/internal/ftobjs.h @@ -34,7 +34,7 @@ #include FT_INTERNAL_GLYPH_LOADER_H #include FT_INTERNAL_DRIVER_H #include FT_INTERNAL_AUTOHINT_H - +#include FT_INTERNAL_OBJECT_H FT_BEGIN_HEADER @@ -695,6 +695,8 @@ FT_BEGIN_HEADER FT_DebugHook_Func debug_hooks[4]; + FT_MetaClassRec meta_class; + } FT_LibraryRec; diff --git a/include/freetype/internal/internal.h b/include/freetype/internal/internal.h index cfae9605b..069593ee9 100644 --- a/include/freetype/internal/internal.h +++ b/include/freetype/internal/internal.h @@ -35,6 +35,8 @@ #define FT_INTERNAL_TRACE_H #define FT_INTERNAL_GLYPH_LOADER_H #define FT_INTERNAL_SFNT_H +#define FT_INTERNAL_HASH_H +#define FT_INTERNAL_OBJECT_H #define FT_INTERNAL_TRUETYPE_TYPES_H #define FT_INTERNAL_TYPE1_TYPES_H diff --git a/src/base/Jamfile b/src/base/Jamfile index d8b7429e5..b061897f5 100644 --- a/src/base/Jamfile +++ b/src/base/Jamfile @@ -25,7 +25,7 @@ SubDirHdrs [ FT2_SubDir src base ] ; # Library $(FT2_LIB) : ftsystem.c ftinit.c ftglyph.c ftmm.c ftbdf.c ftbbox.c ftdebug.c ftxf86.c fttype1.c ftstroker.c - ftsynth.c ; + ftsynth.c ftobject.c fthash.c ; # Add Macintosh-specific file to the library when necessary. # diff --git a/src/base/fthash.c b/src/base/fthash.c index 6a72a3ebe..036922452 100644 --- a/src/base/fthash.c +++ b/src/base/fthash.c @@ -1,4 +1,6 @@ -#include "fthash.h" +#include +#include FT_TYPES_H +#include FT_INTERNAL_HASH_H #include FT_INTERNAL_MEMORY_H #include FT_INTERNAL_DEBUG_H @@ -27,7 +29,7 @@ table->mask = 0; table->slack = 0; - table->compare = NULL; + table->node_equal = NULL; } } @@ -46,17 +48,21 @@ FT_BASE_DEF( FT_Error ) - ft_hash_init( FT_Hash table, - FT_Hash_CompareFunc compare, - FT_Memory memory ) + ft_hash_init( FT_Hash table, + FT_Hash_EqualFunc equal, + FT_Memory memory ) { - hash->memory = memory; - hash->compare = node_compare; - hash->p = 0; - hash->mask = FT_HASH_INITIAL_SIZE-1; - hash->slack = FT_HASH_INITIAL_SIZE*FT_HASH_MAX_LOAD; + FT_Error error; - FT_NEW_ARRAY( hash->buckets, FT_HASH_INITIAL_SIZE*2 ); + table->memory = memory; + table->p = 0; + table->mask = FT_HASH_INITIAL_SIZE-1; + table->slack = FT_HASH_INITIAL_SIZE*FT_HASH_MAX_LOAD; + table->node_equal = equal; + + (void)FT_NEW_ARRAY( table->buckets, FT_HASH_INITIAL_SIZE*2 ); + + return error; } @@ -84,12 +90,13 @@ - FT_BASE_DEF( FT_HashNode* ) + FT_BASE_DEF( FT_HashLookup ) ft_hash_lookup( FT_Hash table, FT_HashNode keynode ) { - FT_UInt index; - FT_UInt23 hash = keynode->hash; + FT_UInt index; + FT_UInt32 hash = keynode->hash; + FT_HashNode node, *pnode; index = (FT_UInt)(hash & table->mask); if ( index < table->p ) @@ -102,7 +109,7 @@ if ( node == NULL ) break; - if ( node->hash == hash && table->compare( node, keynode ) ) + if ( node->hash == hash && table->node_equal( node, keynode ) ) break; pnode = &node->link; @@ -114,20 +121,22 @@ - FT_BASE_DEF( void ) - ft_hash_add( FT_Hash table, - FT_HashNode* pnode, - FT_HashNode new_node ) + FT_BASE_DEF( FT_Error ) + ft_hash_add( FT_Hash table, + FT_HashLookup lookup, + FT_HashNode new_node ) { + FT_Error error = 0; + /* add it to the hash table */ - new_node->link = *pnode; - *pnode = new_node; + new_node->link = *lookup; + *lookup = new_node; if ( --table->slack < 0 ) { FT_UInt p = table->p; FT_UInt mask = table->mask; - FT_HashNode new_list; + FT_HashNode new_list, node, *pnode; /* split a single bucket */ new_list = NULL; @@ -154,29 +163,37 @@ if ( p >= mask ) { - FT_RENEW_ARRAY( hash->buckets, (mask+1)*2, (mask+1)*4 ); + FT_Memory memory = table->memory; + + + if (FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1)*4 )) + goto Exit; + table->mask = 2*mask + 1; table->p = 0; } else table->p = p + 1; } + Exit: + return error; } - FT_BASE_DEF( FT_Int ) - ft_hash_remove( FT_Hash table, - FT_HashNode* pnode ) + FT_BASE_DEF( FT_Error ) + ft_hash_remove( FT_Hash table, + FT_HashLookup lookup ) { FT_HashNode node; FT_UInt num_buckets; + FT_Error error = 0; FT_ASSERT( pnode != NULL && node != NULL ); - node = *pnode; - *pnode->link = node->link; - node->link = NULL; + node = *lookup; + *lookup = node->link; + node->link = NULL; num_buckets = ( table->p + table->mask + 1) ; @@ -189,14 +206,26 @@ FT_HashNode* pold; if ( old_index < FT_HASH_INITIAL_SIZE ) - return; + goto Exit; if ( p == 0 ) { + FT_Memory memory = table->memory; + table->mask >>= 1; p = table->mask; - FT_RENEW_ARRAY( hash->buckets, (mask+1)*2, (mask+1) ); + if ( FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1) ) ) + { + /* this should never happen normally, but who knows :-) */ + /* we need to re-inject the node in the hash table before */ + /* returning there, since it's safer */ + pnode = table->buckets; + node->link = *pnode; + *pnode = node; + + goto Exit; + } } else p--; @@ -212,4 +241,6 @@ table->slack -= FT_HASH_MAX_LOAD; table->p = p; } + Exit: + return error; } diff --git a/src/base/ftobject.c b/src/base/ftobject.c index b7ee27d81..f51e6c031 100644 --- a/src/base/ftobject.c +++ b/src/base/ftobject.c @@ -1,13 +1,16 @@ -#include "ftobject.h" -#include "fthash.h" +#include +#include FT_INTERNAL_OBJECT_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) != NULL && \ + FT_OBJECT(o)->clazz != NULL && \ + FT_OBJECT(o)->ref_count >= 1 && \ FT_OBJECT(o)->clazz->magic == FT_MAGIC_CLASS ) @@ -21,28 +24,6 @@ /*******************************************************************/ /*******************************************************************/ - /* 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; @@ -51,12 +32,12 @@ static void ft_class_hnode_destroy( FT_ClassHNode node ) { - FT_Clazz clazz = node->clazz; + FT_Class clazz = node->clazz; FT_Memory memory = clazz->memory; FT_Type ctype = clazz->type; - if ( ctype->class_done ) - ctype->class_done( clazz ); + if ( clazz->class_done ) + clazz->class_done( (FT_Object) clazz ); FT_FREE( clazz ); @@ -68,32 +49,81 @@ static FT_Int - ft_class_hnode_compare( const FT_ClassHNode node1, - const FT_ClassHNode node2 ) + ft_type_equal( FT_Type type1, + FT_Type type2 ) { - return ( node1->type == node2->type ); + 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_compare( 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 void + 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 objects */ + /* clear all classes */ ft_hash_done( &meta->type_to_class, - (FT_Hash_ForeachFunc) ft_class_destroy, + (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; + meta->clazz.object.clazz = NULL; + meta->clazz.object.ref_count = 0; + meta->clazz.magic = FT_MAGIC_DEATH; } - static void + FT_BASE_DEF( FT_Error ) ft_metaclass_init( FT_MetaClass meta, FT_Library library ) { - FT_ClassRec* clazz = meta->clazz; + FT_ClassRec* clazz = (FT_ClassRec*) &meta->clazz; /* the meta-class is its OWN class !! */ clazz->object.clazz = (FT_Class) clazz; @@ -101,49 +131,130 @@ clazz->magic = FT_MAGIC_CLASS; clazz->library = library; clazz->memory = library->memory; - clazz->type = &ft_metaclass_type; + 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; - ft_hash_init( &meta->type_to_class, - (FT_Hash_CompareFunc) ft_class_hnode_compare, - library->memory ); + 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_UInt32)( ctype >> 2 ); - keynode.type = type; + keynode.hnode.hash = FT_TYPE_HASH( ctype ); + keynode.type = ctype; - pnode = (FT_ClassHNode) ft_hash_lookup( &meta->type_to_class, - &noderec ); + pnode = (FT_ClassHNode*) ft_hash_lookup( &meta->type_to_class, + (FT_HashNode) &keynode ); node = *pnode; if ( node != NULL ) - return node->clazz; + { + clazz = (FT_ClassRec*) node->clazz; + goto Exit; + } memory = FT_CLASS__MEMORY(meta); - node = FT_MEM_SAFE_ALLOC( sizeof(*node) ); - if ( node != NULL ) + clazz = NULL; + parent = NULL; + if ( ctype->super != NULL ) { - FT_ClassRec* clazz; + FT_ASSERT( ctype->super->class_size <= ctype->class_size ); + FT_ASSERT( ctype->super->obj_size <= ctype->obj_size ); - clazz = FT_MEM_SAFE_ALLOC( ctype->class_size ); - if ( clazz == NULL ) + 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 ); - FT_XTHROW( FT_Err_Out_Of_Memory ); } } + + Exit: + return (FT_Class) clazz; } @@ -157,8 +268,8 @@ (FT_Object_DoneFunc) ft_metaclass_done, sizeof( FT_ClassRec ), - (FT_Object_InitFunc) ft_class_init, - (FT_Object_DoneFunc) ft_class_done + (FT_Object_InitFunc) NULL, + (FT_Object_DoneFunc) NULL }; @@ -204,90 +315,69 @@ } - /* 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_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(memory); - obj = ft_mem_alloc( clazz->obj_size, memory ); - obj->clazz = clazz; - obj->ref_count = 1; - *pobject = obj; + memory = FT_CLASS__MEMORY(memory); + if ( !FT_ALLOC( obj, clazz->obj_size ) ) + { + obj->clazz = clazz; + obj->ref_count = 1; - if ( clazz->obj_init ) - clazz->obj_init( obj, init_data ); + 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_Memory memory ) + 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_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_BASE_DEF( FT_Error ) ft_object_create_from_type( FT_Object *pobject, FT_Type type, FT_Pointer init_data, - FT_Memory memory ); + 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; + }