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 7f12a7fba2
commit 2ade80c8e9
8 changed files with 300 additions and 198 deletions

View File

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

View File

@ -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 );

View File

@ -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 );
/* */

View File

@ -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;

View File

@ -35,6 +35,8 @@
#define FT_INTERNAL_TRACE_H <freetype/internal/fttrace.h>
#define FT_INTERNAL_GLYPH_LOADER_H <freetype/internal/ftgloadr.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_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
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.
#

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_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;
}

View File

@ -1,13 +1,16 @@
#include "ftobject.h"
#include "fthash.h"
#include <ft2build.h>
#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;
}