updatinf the object sub-system and dynamic hash table implementations

This commit is contained in:
David Turner 2002-07-11 16:27:16 +00:00
parent 8db6a07021
commit 660138753b
8 changed files with 300 additions and 198 deletions

View File

@ -21,6 +21,7 @@
#include <ft2build.h> #include <ft2build.h>
#include FT_CONFIG_CONFIG_H
#include FT_SYSTEM_H #include FT_SYSTEM_H
#include FT_IMAGE_H #include FT_IMAGE_H

View File

@ -125,7 +125,7 @@ FT_BEGIN_HEADER
FT_Hash_EqualFunc node_equal; FT_Hash_EqualFunc node_equal;
FT_Memory memory; FT_Memory memory;
} FT_HashRec, *FT_Hash; } FT_HashRec;
/*********************************************************** /***********************************************************
@ -270,7 +270,7 @@ FT_BEGIN_HEADER
*/ */
FT_BASE_DEF( FT_HashLookup ) FT_BASE_DEF( FT_HashLookup )
ft_hash_lookup( FT_Hash table, ft_hash_lookup( FT_Hash table,
FT_HashNode keynode ) FT_HashNode keynode );
/**************************************************************** /****************************************************************
@ -380,7 +380,7 @@ FT_BEGIN_HEADER
*/ */
FT_BASE( FT_Error ) FT_BASE( FT_Error )
ft_hash_remove( FT_Hash table, ft_hash_remove( FT_Hash table,
FT_HashLookup lookup ) FT_HashLookup lookup );

View File

@ -288,14 +288,17 @@ FT_BEGIN_HEADER
* *
* @note: * @note:
* if 'obj_init' is NULL, the class will use it's parent * 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 * 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 object sub-system allocates a new class, copies
* the content of its super-class into the new structure, * the content of its super-class into the new structure,
* _then_ calls 'clazz_init'. * _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_ typedef struct FT_TypeRec_
{ {
@ -337,7 +340,7 @@ FT_BEGIN_HEADER
* @return: * @return:
* 1 iff the handle points to a valid object. 0 otherwise * 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 ); ft_object_check( FT_Pointer obj );
@ -357,7 +360,7 @@ FT_BEGIN_HEADER
* 1 iff the handle points to a valid 'clazz' instance. 0 * 1 iff the handle points to a valid 'clazz' instance. 0
* otherwise. * otherwise.
*/ */
FT_BASE_DEF( FT_Int ) FT_BASE( FT_Int )
ft_object_is_a( FT_Pointer obj, ft_object_is_a( FT_Pointer obj,
FT_Class clazz ); FT_Class clazz );
@ -379,7 +382,7 @@ FT_BEGIN_HEADER
* @return: * @return:
* error code. 0 means success * error code. 0 means success
*/ */
FT_BASE_DEF( FT_Error ) FT_BASE( FT_Error )
ft_object_create( FT_Object *aobject, ft_object_create( FT_Object *aobject,
FT_Class clazz, FT_Class clazz,
FT_Pointer init_data ); FT_Pointer init_data );
@ -408,7 +411,7 @@ FT_BEGIN_HEADER
* this is equivalent to calling @ft_class_from_type followed by * this is equivalent to calling @ft_class_from_type followed by
* @ft_object_create * @ft_object_create
*/ */
FT_BASE_DEF( FT_Error ) FT_BASE( FT_Error )
ft_object_create_from_type( FT_Object *aobject, ft_object_create_from_type( FT_Object *aobject,
FT_Type type, FT_Type type,
FT_Pointer init_data, FT_Pointer init_data,
@ -438,7 +441,7 @@ FT_BEGIN_HEADER
* code returned by the object constructor. * code returned by the object constructor.
*/ */
#define FT_CREATE( _obj, _clazz, _init ) \ #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. * code returned by the object constructor.
*/ */
#define FT_CREATE_FROM_TYPE( _obj, _type, _init, _lib ) \ #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: * @return:
* error code. 0 means success * error code. 0 means success
*/ */
FT_BASE_DEF( FT_Error ) FT_BASE( FT_Error )
ft_class_from_type( FT_Class *aclass, ft_class_from_type( FT_Class *aclass,
FT_Type type, FT_Type type,
FT_Library library ); 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 #include FT_INTERNAL_HASH_H
@ -542,12 +518,12 @@ FT_BEGIN_HEADER
/* initialize meta class */ /* initialize meta class */
FT_BASE_DEF( FT_Error ) FT_BASE( FT_Error )
ft_metaclass_init( FT_MetaClass meta, ft_metaclass_init( FT_MetaClass meta,
FT_Library library ); FT_Library library );
/* finalize meta class - destroy all registered class objects */ /* finalize meta class - destroy all registered class objects */
FT_BASE_DEF( void ) FT_BASE( void )
ft_metaclass_done( FT_MetaClass meta ); ft_metaclass_done( FT_MetaClass meta );
/* */ /* */

View File

@ -34,7 +34,7 @@
#include FT_INTERNAL_GLYPH_LOADER_H #include FT_INTERNAL_GLYPH_LOADER_H
#include FT_INTERNAL_DRIVER_H #include FT_INTERNAL_DRIVER_H
#include FT_INTERNAL_AUTOHINT_H #include FT_INTERNAL_AUTOHINT_H
#include FT_INTERNAL_OBJECT_H
FT_BEGIN_HEADER FT_BEGIN_HEADER
@ -695,6 +695,8 @@ FT_BEGIN_HEADER
FT_DebugHook_Func debug_hooks[4]; FT_DebugHook_Func debug_hooks[4];
FT_MetaClassRec meta_class;
} FT_LibraryRec; } FT_LibraryRec;

View File

@ -35,6 +35,8 @@
#define FT_INTERNAL_TRACE_H <freetype/internal/fttrace.h> #define FT_INTERNAL_TRACE_H <freetype/internal/fttrace.h>
#define FT_INTERNAL_GLYPH_LOADER_H <freetype/internal/ftgloadr.h> #define FT_INTERNAL_GLYPH_LOADER_H <freetype/internal/ftgloadr.h>
#define FT_INTERNAL_SFNT_H <freetype/internal/sfnt.h> #define FT_INTERNAL_SFNT_H <freetype/internal/sfnt.h>
#define FT_INTERNAL_HASH_H <freetype/internal/fthash.h>
#define FT_INTERNAL_OBJECT_H <freetype/internal/ftobject.h>
#define FT_INTERNAL_TRUETYPE_TYPES_H <freetype/internal/tttypes.h> #define FT_INTERNAL_TRUETYPE_TYPES_H <freetype/internal/tttypes.h>
#define FT_INTERNAL_TYPE1_TYPES_H <freetype/internal/t1types.h> #define FT_INTERNAL_TYPE1_TYPES_H <freetype/internal/t1types.h>

View File

@ -25,7 +25,7 @@ SubDirHdrs [ FT2_SubDir src base ] ;
# #
Library $(FT2_LIB) : ftsystem.c ftinit.c ftglyph.c ftmm.c ftbdf.c Library $(FT2_LIB) : ftsystem.c ftinit.c ftglyph.c ftmm.c ftbdf.c
ftbbox.c ftdebug.c ftxf86.c fttype1.c ftstroker.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. # Add Macintosh-specific file to the library when necessary.
# #

View File

@ -1,4 +1,6 @@
#include "fthash.h" #include <ft2build.h>
#include FT_TYPES_H
#include FT_INTERNAL_HASH_H
#include FT_INTERNAL_MEMORY_H #include FT_INTERNAL_MEMORY_H
#include FT_INTERNAL_DEBUG_H #include FT_INTERNAL_DEBUG_H
@ -27,7 +29,7 @@
table->mask = 0; table->mask = 0;
table->slack = 0; table->slack = 0;
table->compare = NULL; table->node_equal = NULL;
} }
} }
@ -46,17 +48,21 @@
FT_BASE_DEF( FT_Error ) FT_BASE_DEF( FT_Error )
ft_hash_init( FT_Hash table, ft_hash_init( FT_Hash table,
FT_Hash_CompareFunc compare, FT_Hash_EqualFunc equal,
FT_Memory memory ) FT_Memory memory )
{ {
hash->memory = memory; FT_Error error;
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_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_hash_lookup( FT_Hash table,
FT_HashNode keynode ) FT_HashNode keynode )
{ {
FT_UInt index; FT_UInt index;
FT_UInt23 hash = keynode->hash; FT_UInt32 hash = keynode->hash;
FT_HashNode node, *pnode;
index = (FT_UInt)(hash & table->mask); index = (FT_UInt)(hash & table->mask);
if ( index < table->p ) if ( index < table->p )
@ -102,7 +109,7 @@
if ( node == NULL ) if ( node == NULL )
break; break;
if ( node->hash == hash && table->compare( node, keynode ) ) if ( node->hash == hash && table->node_equal( node, keynode ) )
break; break;
pnode = &node->link; pnode = &node->link;
@ -114,20 +121,22 @@
FT_BASE_DEF( void ) FT_BASE_DEF( FT_Error )
ft_hash_add( FT_Hash table, ft_hash_add( FT_Hash table,
FT_HashNode* pnode, FT_HashLookup lookup,
FT_HashNode new_node ) FT_HashNode new_node )
{ {
FT_Error error = 0;
/* add it to the hash table */ /* add it to the hash table */
new_node->link = *pnode; new_node->link = *lookup;
*pnode = new_node; *lookup = new_node;
if ( --table->slack < 0 ) if ( --table->slack < 0 )
{ {
FT_UInt p = table->p; FT_UInt p = table->p;
FT_UInt mask = table->mask; FT_UInt mask = table->mask;
FT_HashNode new_list; FT_HashNode new_list, node, *pnode;
/* split a single bucket */ /* split a single bucket */
new_list = NULL; new_list = NULL;
@ -154,29 +163,37 @@
if ( p >= mask ) 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->mask = 2*mask + 1;
table->p = 0; table->p = 0;
} }
else else
table->p = p + 1; table->p = p + 1;
} }
Exit:
return error;
} }
FT_BASE_DEF( FT_Int ) FT_BASE_DEF( FT_Error )
ft_hash_remove( FT_Hash table, ft_hash_remove( FT_Hash table,
FT_HashNode* pnode ) FT_HashLookup lookup )
{ {
FT_HashNode node; FT_HashNode node;
FT_UInt num_buckets; FT_UInt num_buckets;
FT_Error error = 0;
FT_ASSERT( pnode != NULL && node != NULL ); FT_ASSERT( pnode != NULL && node != NULL );
node = *pnode; node = *lookup;
*pnode->link = node->link; *lookup = node->link;
node->link = NULL; node->link = NULL;
num_buckets = ( table->p + table->mask + 1) ; num_buckets = ( table->p + table->mask + 1) ;
@ -189,14 +206,26 @@
FT_HashNode* pold; FT_HashNode* pold;
if ( old_index < FT_HASH_INITIAL_SIZE ) if ( old_index < FT_HASH_INITIAL_SIZE )
return; goto Exit;
if ( p == 0 ) if ( p == 0 )
{ {
FT_Memory memory = table->memory;
table->mask >>= 1; table->mask >>= 1;
p = table->mask; 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 else
p--; p--;
@ -212,4 +241,6 @@
table->slack -= FT_HASH_MAX_LOAD; table->slack -= FT_HASH_MAX_LOAD;
table->p = p; table->p = p;
} }
Exit:
return error;
} }

View File

@ -1,13 +1,16 @@
#include "ftobject.h" #include <ft2build.h>
#include "fthash.h" #include FT_INTERNAL_OBJECT_H
#include FT_INTERNAL_OBJECTS_H
#define FT_MAGIC_DEATH 0xDEADdead #define FT_MAGIC_DEATH 0xDEADdead
#define FT_MAGIC_CLASS 0x12345678 #define FT_MAGIC_CLASS 0x12345678
#define FT_TYPE_HASH(x) (( (FT_UInt32)(x) >> 2 )^( (FT_UInt32)(x) >> 10 ))
#define FT_OBJECT_CHECK(o) \ #define FT_OBJECT_CHECK(o) \
( FT_OBJECT(o) != NULL && \ ( FT_OBJECT(o) != NULL && \
FT_OBJECT(o)->clazz != NULL && \ FT_OBJECT(o)->clazz != NULL && \
FT_OBJECT(o)->ref_count >= 1 && \ FT_OBJECT(o)->ref_count >= 1 && \
FT_OBJECT(o)->clazz->magic == FT_MAGIC_CLASS ) 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 */ /* forward declaration */
static const FT_TypeRec ft_meta_class_type; static const FT_TypeRec ft_meta_class_type;
@ -51,12 +32,12 @@
static void static void
ft_class_hnode_destroy( FT_ClassHNode node ) ft_class_hnode_destroy( FT_ClassHNode node )
{ {
FT_Clazz clazz = node->clazz; FT_Class clazz = node->clazz;
FT_Memory memory = clazz->memory; FT_Memory memory = clazz->memory;
FT_Type ctype = clazz->type; FT_Type ctype = clazz->type;
if ( ctype->class_done ) if ( clazz->class_done )
ctype->class_done( clazz ); clazz->class_done( (FT_Object) clazz );
FT_FREE( clazz ); FT_FREE( clazz );
@ -68,32 +49,81 @@
static FT_Int static FT_Int
ft_class_hnode_compare( const FT_ClassHNode node1, ft_type_equal( FT_Type type1,
const FT_ClassHNode node2 ) 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 ) ft_metaclass_done( FT_MetaClass meta )
{ {
/* clear all objects */ /* clear all classes */
ft_hash_done( &meta->type_to_class, ft_hash_done( &meta->type_to_class,
(FT_Hash_ForeachFunc) ft_class_destroy, (FT_Hash_ForeachFunc) ft_class_hnode_destroy,
NULL ); NULL );
meta->clazz->object.clazz = NULL; meta->clazz.object.clazz = NULL;
meta->clazz->object.ref_count = 0; meta->clazz.object.ref_count = 0;
meta->clazz->magic = FT_MAGIC_DEATH; meta->clazz.magic = FT_MAGIC_DEATH;
} }
static void FT_BASE_DEF( FT_Error )
ft_metaclass_init( FT_MetaClass meta, ft_metaclass_init( FT_MetaClass meta,
FT_Library library ) FT_Library library )
{ {
FT_ClassRec* clazz = meta->clazz; FT_ClassRec* clazz = (FT_ClassRec*) &meta->clazz;
/* the meta-class is its OWN class !! */ /* the meta-class is its OWN class !! */
clazz->object.clazz = (FT_Class) clazz; clazz->object.clazz = (FT_Class) clazz;
@ -101,49 +131,130 @@
clazz->magic = FT_MAGIC_CLASS; clazz->magic = FT_MAGIC_CLASS;
clazz->library = library; clazz->library = library;
clazz->memory = library->memory; clazz->memory = library->memory;
clazz->type = &ft_metaclass_type; clazz->type = &ft_meta_class_type;
clazz->info = NULL; clazz->info = NULL;
clazz->class_done = (FT_Object_DoneFunc) ft_metaclass_done;
clazz->obj_size = sizeof( FT_ClassRec ); clazz->obj_size = sizeof( FT_ClassRec );
clazz->obj_init = NULL; clazz->obj_init = NULL;
clazz->obj_done = NULL; clazz->obj_done = NULL;
ft_hash_init( &meta->type_to_class, return ft_hash_init( &meta->type_to_class,
(FT_Hash_CompareFunc) ft_class_hnode_compare, (FT_Hash_EqualFunc) ft_class_hnode_equal,
library->memory ); library->memory );
} }
/* find or create the class corresponding to a given type */ /* 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 static FT_Class
ft_metaclass_get_class( FT_MetaClass meta, ft_metaclass_get_class( FT_MetaClass meta,
FT_Type ctype ) FT_Type ctype )
{ {
FT_ClassHNodeRec keynode, *node, **pnode; FT_ClassHNodeRec keynode, *node, **pnode;
FT_Memory memory; FT_Memory memory;
FT_ClassRec* clazz;
FT_Class parent;
FT_Error error;
keynode.hnode.hash = (FT_UInt32)( ctype >> 2 ); keynode.hnode.hash = FT_TYPE_HASH( ctype );
keynode.type = type; keynode.type = ctype;
pnode = (FT_ClassHNode) ft_hash_lookup( &meta->type_to_class, pnode = (FT_ClassHNode*) ft_hash_lookup( &meta->type_to_class,
&noderec ); (FT_HashNode) &keynode );
node = *pnode; node = *pnode;
if ( node != NULL ) if ( node != NULL )
return node->clazz; {
clazz = (FT_ClassRec*) node->clazz;
goto Exit;
}
memory = FT_CLASS__MEMORY(meta); memory = FT_CLASS__MEMORY(meta);
node = FT_MEM_SAFE_ALLOC( sizeof(*node) ); clazz = NULL;
if ( node != 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 ); parent = ft_metaclass_get_class( meta, ctype->super );
if ( clazz == NULL ) }
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_FREE( node );
FT_XTHROW( FT_Err_Out_Of_Memory );
} }
} }
Exit:
return (FT_Class) clazz;
} }
@ -157,8 +268,8 @@
(FT_Object_DoneFunc) ft_metaclass_done, (FT_Object_DoneFunc) ft_metaclass_done,
sizeof( FT_ClassRec ), sizeof( FT_ClassRec ),
(FT_Object_InitFunc) ft_class_init, (FT_Object_InitFunc) NULL,
(FT_Object_DoneFunc) ft_class_done (FT_Object_DoneFunc) NULL
}; };
@ -204,90 +315,69 @@
} }
/* the cleanup routine for all objects */ FT_BASE_DEF( FT_Error )
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_object_create( FT_Object *pobject,
FT_Class clazz, FT_Class clazz,
FT_Pointer init_data ) FT_Pointer init_data )
{ {
FT_Memory memory; FT_Memory memory;
FT_Error error;
FT_Object obj; FT_Object obj;
FT_ASSERT_IS_CLASS(clazz); FT_ASSERT_IS_CLASS(clazz);
memory = FT_CLASS__MEMORY(memory); memory = FT_CLASS__MEMORY(memory);
obj = ft_mem_alloc( clazz->obj_size, memory ); if ( !FT_ALLOC( obj, clazz->obj_size ) )
obj->clazz = clazz; {
obj->ref_count = 1; obj->clazz = clazz;
*pobject = obj; obj->ref_count = 1;
if ( clazz->obj_init ) if ( clazz->obj_init )
clazz->obj_init( obj, init_data ); {
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_BASE_DEF( FT_Class )
ft_class_find_by_type( FT_Type type, ft_class_find_by_type( FT_Type type,
FT_Memory memory ) FT_Library library )
{ {
FT_MetaClass meta = &library->meta_class;
return ft_metaclass_get_class( meta, type );
} }
FT_BASE_DEF( FT_Class ) FT_BASE_DEF( FT_Error )
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_object_create_from_type( FT_Object *pobject,
FT_Type type, FT_Type type,
FT_Pointer init_data, 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;
}