updatinf the object sub-system and dynamic hash table implementations
This commit is contained in:
parent
8db6a07021
commit
660138753b
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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.
|
||||||
#
|
#
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue