* include/freetype/internal/fthash.h, src/base/fthash.c:

adding a generic implementation of dynamic hash tables using
          linear algorithm (to get rid of 'stalls' during resizes). This
          will be used in the future in at least three parts of the
          library: the cache sub-system, the object sub-system and
          the memory debugger.

        * include/freetype/internal/ftcore.h: added this header file to
          group all new definitions related to exception handling and
          memory management. It's very likely that this file will disappear
          or be renamed in the future..

        * include/freetype/internal/ftobject.h, include/freetype/ftsysmem.h:
          adding comments to better explain the object sub-system as well
          as the new memory manager interface.
This commit is contained in:
David Turner 2002-05-01 08:46:56 +00:00
parent f031ffd3bc
commit 8ff18d7f74
10 changed files with 1925 additions and 108 deletions

View File

@ -7,6 +7,35 @@
* src/sfnt/ttload.c (TT_Load_Names): applied a small work-around to
manage fonts containing a broken name table (e.g. "hya6gb.ttf")
* src/sfnt/ttcmap0.c (tt_cmap4_validate):
fixed over-restrictive validation test. the charmap validator
now accepts overlapping ranges in format 4 charmaps.
* src/sfnt/ttcmap0.c (tt_cmap4_char_index):
switched to a binary search algorithm. Certain fonts contain
more than 170 distinct segments !!
* include/freetype/config/ftstdlib.h: adding an alias for the
'exit' function. This will be used in the near future to panic
in case of un-expected exception (which shouldn't happen in
theory, but as everyone knows, shit happens :-) )
* include/freetype/internal/fthash.h, src/base/fthash.c:
adding a generic implementation of dynamic hash tables using
linear algorithm (to get rid of 'stalls' during resizes). This
will be used in the future in at least three parts of the
library: the cache sub-system, the object sub-system and
the memory debugger.
* include/freetype/internal/ftcore.h: added this header file to
group all new definitions related to exception handling and
memory management. It's very likely that this file will disappear
or be renamed in the future..
* include/freetype/internal/ftobject.h, include/freetype/ftsysmem.h:
adding comments to better explain the object sub-system as well
as the new memory manager interface.
2002-04-30 Wenlin Institute (Tom Bishop) <wenlin@wenlin.com>
* src/base/ftmac.c (p2c_str): Removed.

View File

@ -1,42 +1,146 @@
#ifndef __FT_SYSTEM_IO_H__
#define __FT_SYSTEM_IO_H__
/********************************************************************
*
* designing custom streams is a bit different now
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#include <ft2build.h>
#include FT_INTERNAL_OBJECT_H
FT_BEGIN_HEADER
/* handle to a FT_Stream object */
/********************************************************************
*
* @type: FT_Stream
*
* @description:
* handle to an input stream object. These are also @FT_Object handles
*/
typedef struct FT_StreamRec_* FT_Stream;
/* handle to the FT_Stream class */
/********************************************************************
*
* @type: FT_Stream_Class
*
* @description:
* opaque handle to a @FT_Stream_ClassRec class structure describing
* the methods of input streams
*/
typedef const struct FT_Stream_ClassRec_* FT_Stream_Class;
/* a method used to read data from a stream into a buffer */
/********************************************************************
*
* @functype: FT_Stream_ReadFunc
*
* @description:
* a method used to read bytes from an input stream into memory
*
* @input:
* stream :: target stream handle
* buffer :: target buffer address
* size :: number of bytes to read
*
* @return:
* number of bytes effectively read. Must be <= 'size'.
*/
typedef FT_ULong (*FT_Stream_ReadFunc)( FT_Stream stream,
FT_Byte* buffer,
FT_ULong size );
/* a method used to seek to a new position within a stream */
/* position is always relative to the start */
/********************************************************************
*
* @functype: FT_Stream_SeekFunc
*
* @description:
* a method used to seek to a new position within a stream
*
* @input:
* stream :: target stream handle
* pos :: new read position, from start of stream
*
* @return:
* error code. 0 means success
*/
typedef FT_Error (*FT_Stream_SeekFunc)( FT_Stream stream,
FT_ULong pos );
/* the stream class structure + some useful macros */
/********************************************************************
*
* @struct: FT_Stream_ClassRec
*
* @description:
* a structure used to describe an input stream class
*
* @input:
* clazz :: root @FT_ClassRec fields
* stream_read :: stream byte read method
* stream_seek :: stream seek method
*/
typedef struct FT_Stream_ClassRec_
{
FT_ClassRec clazz;
FT_Stream_ReadFunc stream_read;
FT_Stream_SeekFunc stream_seek;
} FT_Stream_ClassRec;
#define FT_STREAM_CLASS(x) ((FT_Stream_Class)(x))
/* */
#define FT_STREAM_CLASS(x) ((FT_Stream_Class)(x))
#define FT_STREAM_CLASS__READ(x) FT_STREAM_CLASS(x)->stream_read
#define FT_STREAM_CLASS__SEEK(x) FT_STREAM_CLASS(x)->stream_seek;
/* the base FT_Stream object structure */
/********************************************************************
*
* @struct: FT_StreamRec
*
* @description:
* the input stream object structure. See @FT_Stream_ClassRec for
* its class descriptor
*
* @fields:
* object :: root @FT_ObjectRec fields
* size :: size of stream in bytes (0 if unknown)
* pos :: current position within stream
* base :: for memory-based streams, the address of the stream's
* first data byte in memory. NULL otherwise
*
* cursor :: the current cursor position within an input stream
* frame. Only valid within a FT_FRAME_ENTER .. FT_FRAME_EXIT
* block; NULL otherwise
*
* limit :: the current frame limit within a FT_FRAME_ENTER ..
* FT_FRAME_EXIT block. NULL otherwise
*/
typedef struct FT_StreamRec_
{
FT_ObjectRec object;
@ -57,13 +161,24 @@ FT_BEGIN_HEADER
#define FT_STREAM_IS_BASED(x) ( FT_STREAM(x)->base != NULL )
#if 0
#endif
/* */
/* create new memory-based stream */
FT_BASE( FT_Error ) ft_stream_new_memory( const FT_Byte* stream_base,
FT_ULong stream_size,
FT_Memory memory,
FT_Stream *astream );
FT_BASE( FT_Error ) ft_stream_new_iso( const char* pathanme,
FT_Memory memory,
FT_Stream *astream );
/* handle to default stream class implementation for a given build */
/* this is used by "FT_New_Face" */
/* */
FT_APIVAR( FT_Type ) ft_stream_default_type;
FT_END_HEADER
#endif /* __FT_SYSTEM_STREAM_H__ */

View File

@ -5,35 +5,131 @@
FT_BEGIN_HEADER
/* handle to memory structure */
/***********************************************************************
*
* @type: FT_Memory
*
* @description:
* opaque handle to a memory manager handle. Note that since FreeType
* 2.2, the memory manager structure FT_MemoryRec is hidden to client
* applications.
*
* however, you can still define custom allocators easily using the
* @ft_memory_new API
*/
typedef struct FT_MemoryRec_* FT_Memory;
/* a function used to allocate a new block of memory from a heap */
/***********************************************************************
*
* @functype: FT_Memory_AllocFunc
*
* @description:
* a function used to allocate a block of memory.
*
* @input:
* size :: size of blocks in bytes. Always > 0 !!
* mem_data :: memory-manager specific optional argument
* (see @ft_memory_new)
*
* @return:
* address of new block. NULL in case of memory exhaustion
*/
typedef FT_Pointer (*FT_Memory_AllocFunc)( FT_ULong size,
FT_Memory memory );
/* a function used to free a block of memory */
FT_Pointer mem_data );
/***********************************************************************
*
* @functype: FT_Memory_FreeFunc
*
* @description:
* a function used to release a block of memory created through
* @FT_Memory_AllocFunc or @FT_Memory_ReallocFunc
*
* @input:
* block :: address of target memory block. cannot be NULL !!
* mem_data :: memory-manager specific optional argument
* (see @ft_memory_new)
*/
typedef void (*FT_Memory_FreeFunc) ( FT_Pointer block,
FT_Memory memory );
/* a function used to reallocate a given memory block to a new size */
FT_Pointer mem_data );
/***********************************************************************
*
* @functype: FT_Memory_ReallocFunc
*
* @description:
* a function used to reallocate a memory block.
*
* @input:
* block :: address of target memory block. cannot be NULL !!
* new_size :: new requested size in bytes
* cur_size :: current block size in bytes
* mem_data :: memory-manager specific optional argument
* (see @ft_memory_new)
*/
typedef FT_Pointer (*FT_Memory_ReallocFunc)( FT_Pointer block,
FT_ULong new_size,
FT_ULong cur_size,
FT_Memory memory );
FT_Pointer mem_data );
/* a function called to allocate a new structure of 'size' bytes that */
/* will be used for a new FT_Memory object.. */
/* */
/***********************************************************************
*
* @functype: FT_Memory_CreateFunc
*
* @description:
* a function used to create a @FT_Memory object to model a
* memory manager
*
* @input:
* size :: size of memory manager structure in bytes
* init_data :: optional initialisation argument
*
* @output:
* amem_data :: memory-manager specific argument to block management
* routines.
*
* @return:
* handle to new memory manager object. NULL in case of failure
*/
typedef FT_Pointer (*FT_Memory_CreateFunc)( FT_UInt size,
FT_Pointer init_data );
FT_Pointer init_data,
FT_Pointer *amem_data );
/* a function used to destroy a FT_Memory object */
typedef void (*FT_Memory_DestroyFunc)( FT_Memory memory );
/* a structure holding the functions used to describe a given FT_Memory */
/* implementation.. */
/* */
/***********************************************************************
*
* @functype: FT_Memory_DestroyFunc
*
* @description:
* a function used to destroy a given @FT_Memory manager
*
* @input:
* memory :: target memory manager handle
* mem_data :: option manager-specific argument
*/
typedef void (*FT_Memory_DestroyFunc)( FT_Memory memory,
FT_Pointer mem_data );
/***********************************************************************
*
* @struct: FT_Memory_FuncsRec
*
* @description:
* a function used to hold all methods of a given memory manager
* implementation.
*
* @fields:
* mem_alloc :: block allocation routine
* mem_free :: block release routine
* mem_realloc :: block re-allocation routine
* mem_create :: manager creation routine
* mem_destroy :: manager destruction routine
*/
typedef struct FT_Memory_FuncsRec_
{
FT_Memory_AllocFunc mem_alloc;
@ -41,24 +137,53 @@ FT_BEGIN_HEADER
FT_Memory_ReallocFunc mem_realloc;
FT_Memory_CreateFunc mem_create;
FT_Memory_DestroyFunc mem_destroy;
} FT_Memory_FuncsRec, *FT_Memory_Funcs;
/* a function used to create a new custom FT_Memory object */
/* */
FT_BASE_DEF( FT_Memory )
/***********************************************************************
*
* @type: FT_Memory_Funcs
*
* @description:
* a pointer to a constant @FT_Memory_FuncsRec structure used to
* describe a given memory manager implementation.
*/
typedef const FT_Memory_FuncsRec* FT_Memory_Funcs;
/***********************************************************************
*
* @function: ft_memory_new
*
* @description:
* create a new memory manager, given a set of memory methods
*
* @input:
* mem_funcs :: handle to memory manager implementation descriptor
* mem_init_data :: optional initialisation argument, passed to
* @FT_Memory_CreateFunc
*
* @return:
* new memory manager handle. NULL in case of failure
*/
FT_BASE( FT_Memory )
ft_memory_new( FT_Memory_Funcs mem_funcs,
FT_Pointer mem_init_data );
/* a function used to destroy a custom FT_Memory object */
FT_BASE_DEF( void )
ft_memory_destroy( FT_Memory memory );
/* a pointer to the default memory functions used by FreeType in a */
/* given build. By default, uses the ISO C malloc/free/realloc */
/* */
FT_APIVAR( const FT_MemoryFuncs ) ft_memory_funcs_default;
/***********************************************************************
*
* @function: ft_memory_destroy
*
* @description:
* destroy a given memory manager
*
* @input:
* memory :: handle to target memory manager
*/
FT_BASE( void )
ft_memory_destroy( FT_Memory memory );
/* */

View File

@ -0,0 +1,185 @@
#ifndef __FT_CORE_H__
#define __FT_CORE_H__
#include <ft2build.h>
#include FT_TYPES_H
#include FT_SYSTEM_MEMORY_H
FT_BEGIN_HEADER
/**************************************************************************/
/**************************************************************************/
/***** *****/
/***** C L E A N U P S T A C K *****/
/***** *****/
/**************************************************************************/
/**************************************************************************/
/************************************************************************
*
* @functype: FT_CleanupFunc
*
* @description:
* a function used to cleanup a given item on the cleanup stack
*
* @input:
* item :: target item pointer
* item_data :: optional argument to cleanup routine
*/
typedef void (*FT_CleanupFunc)( FT_Pointer item,
FT_Pointer item_data );
/************************************************************************
*
* @type: FT_XHandler
*
* @description:
* handle to an exception-handler structure for the FreeType
* exception sub-system
*
* @note:
* exception handlers are allocated on the stack within a
* @FT_XTRY macro. Do not try to access them directly.
*/
typedef struct FT_XHandlerRec_* FT_XHandler;
/* the size of a cleanup chunk in bytes is FT_CLEANUP_CHUNK_SIZE*12 + 4 */
/* this must be a small power of 2 whenever possible.. */
/* */
/* with a value of 5, we have a byte size of 64 bytes per chunk.. */
/* */
#define FT_CLEANUP_CHUNK_SIZE 5
typedef struct FT_CleanupItemRec_
{
FT_Pointer item;
FT_CleanupFunc item_func;
FT_Pointer item_data;
} FT_CleanupItemRec;
typedef struct FT_CleanupChunkRec_* FT_CleanupChunk;
typedef struct FT_CleanupChunkRec_
{
FT_CleanupChunk link;
FT_CleanupItemRec items[ FT_CLEANUP_CHUNK_SIZE ];
} FT_CleanupChunkRec;
typedef struct FT_CleanupStackRec_
{
FT_CleanupItem top;
FT_CleanupItem limit;
FT_CleanupChunk chunk;
FT_CleanupChunkRec chunk_0; /* avoids stupid dynamic allocation */
FT_Memory memory;
} FT_CleanupStackRec, *FT_CleanupStack;
FT_BASE( void )
ft_cleanup_stack_push( FT_CleanupStack stack,
FT_Pointer item,
FT_CleanupFunc item_func,
FT_Pointer item_data );
FT_BASE( void )
ft_cleanup_stack_pop( FT_CleanupStack stack,
FT_Int destroy );
FT_BASE( FT_CleanupItem )
ft_cleanup_stack_peek( FT_CleanupStack stack );
FT_BASE( void )
ft_cleanup_throw( FT_CleanupStack stack,
FT_Error error );
/**************************************************************************/
/**************************************************************************/
/***** *****/
/***** M E M O R Y M A N A G E R *****/
/***** *****/
/**************************************************************************/
/**************************************************************************/
typedef struct FT_MemoryRec_
{
FT_Memory_AllocFunc mem_alloc; /* shortcut to funcs->mem_alloc */
FT_Memory_FreeFunc mem_free; /* shortcut to funcs->mem_free */
FT_Pointer mem_data;
const FT_Memory_Funcs mem_funcs;
FT_CleanupStackRec cleanup_stack;
FT_Pointer meta_class;
} FT_MemoryRec;
#define FT_MEMORY(x) ((FT_Memory)(x))
#define FT_MEMORY__ALLOC(x) FT_MEMORY(x)->mem_alloc
#define FT_MEMORY__FREE(x) FT_MEMORY(x)->mem_free
#define FT_MEMORY__REALLOC(x) FT_MEMORY(x)->mem_funcs->mem_realloc
#define FT_MEMORY__CLEANUP(x) (&FT_MEMORY(x)->cleanup_stack)
#define FT_MEMORY__META_CLASS(x) ((FT_MetaClass)(FT_MEMORY(x)->meta_class))
/**************************************************************************/
/**************************************************************************/
/***** *****/
/***** E X C E P T I O N H A N D L I N G *****/
/***** *****/
/**************************************************************************/
/**************************************************************************/
/************************************************************************
*
* @struct: FT_XHandlerRec
*
* @description:
* exception handler structure
*
* @fields:
* previous :: previous handler in chain.
* jum_buffer :: processor state used by setjmp/longjmp to implement
* exception control transfer
* error :: exception error code
* mark :: top of cleanup stack when @FT_XTRY is used
*/
typedef struct FT_XHandlerRec_
{
FT_XHandler previous;
ft_jmp_buf jump_buffer;
volatile FT_Error error;
FT_Pointer mark;
} FT_XHandlerRec;
FT_BASE( void )
ft_xhandler_enter( FT_XHandler xhandler,
FT_Memory memory );
FT_BASE( void )
ft_xhandler_exit( FT_XHandler xhandler );
FT_END_HEADER
#endif /* __FT_CORE_H__ */

View File

@ -6,21 +6,12 @@
FT_BEGIN_HEADER
typedef struct FT_XHandlerRec_* FT_XHandler;
typedef struct FT_XHandlerRec_
{
FT_XHandler previous;
ft_jmp_buf jump_buffer;
volatile FT_Error error;
FT_Pointer cleanup;
} FT_XHandlerRec;
typedef void (*FT_CleanupFunc)( FT_Pointer item,
FT_Pointer item_data );
/* I can't find a better place for this for now */
<<<<<<< ftexcept.h
=======
/* the size of a cleanup chunk in bytes is FT_CLEANUP_CHUNK_SIZE*12 + 4 */
/* this must be a small power of 2 whenever possible.. */
@ -85,6 +76,7 @@ FT_BEGIN_HEADER
ft_cleanup_throw( FT_CleanupStack stack,
FT_Error error );
>>>>>>> 1.2
FT_END_HEADER
#endif /* __FT_EXCEPT_H__ */

View File

@ -0,0 +1,484 @@
/******************************************************************
*
* fthash.h - fast dynamic hash tables
*
* Copyright 2002 by
* David Turner, Robert Wilhelm, and Werner Lemberg
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*
* This header is used to define dynamic hash tables as described
* by the article "Main-Memory Linear Hashing - Some Enhancements
* of Larson's Algorithm" by Mikael Petterson.
*
* Basically, linear hashing prevents big "stalls" during
* resizes of the buckets array by only splitting one bucket
* at a time. This ensures excellent response time even when
* the table is frequently resized..
*
*
* Note that the use of the FT_Hash type is rather unusual in order
* to be as generic and efficient as possible. See the comments in the
* following definitions for more details.
*/
#ifndef __FT_HASH_H__
#define __FT_HASH_H__
#include <ft2build.h>
#include FT_TYPES_H
FT_BEGIN_HEADER
/***********************************************************
*
* @type: FT_Hash
*
* @description:
* handle to a @FT_HashRec structure used to model a
* dynamic hash table
*/
typedef struct FT_HashRec_* FT_Hash;
/***********************************************************
*
* @type: FT_HashNode
*
* @description:
* handle to a @FT_HashNodeRec structure used to model a
* single node of a hash table
*/
typedef struct FT_HashNodeRec_* FT_HashNode;
/***********************************************************
*
* @type: FT_Hash_CompareFunc
*
* @description:
* a function used to compare two nodes of the hash table
*
* @input:
* node1 :: handle to first node
* node2 :: handle to second node
*
* @return:
* 1 iff the 'keys' in 'node1' and 'node2' are identical.
* 0 otherwise.
*/
typedef FT_Int (*FT_Hash_CompareFunc)( const FT_HashNode node1,
const FT_HashNode node2 );
/***********************************************************
*
* @struct: FT_HashRec
*
* @description:
* a structure used to model a dynamic hash table.
*
* @fields:
* memory :: memory manager used to allocate
* the buckets array and the hash nodes
*
* buckets :: array of hash buckets
*
* node_size :: size of node in bytes
* node_compare :: a function used to compare two nodes
* node_hash :: a function used to compute the hash
* value of a given node
* p ::
* mask ::
* slack ::
*
* @note:
* 'p', 'mask' and 'slack' are control values managed by
* the hash table. Do not try to interpret them directly.
*
* You can grab the hash table size by calling
* '@ft_hash_get_size'.
*/
typedef struct FT_HashRec_
{
FT_Memory memory;
FT_HashNode* buckets;
FT_UInt p;
FT_UInt mask; /* really maxp-1 */
FT_UInt slack;
FT_UInt node_size;
FT_Hash_CompareFunc node_compare;
FT_Hash_ComputeFunc node_hash;
} FT_HashRec, *FT_Hash;
/***********************************************************
*
* @struct: FT_HashNodeRec
*
* @description:
* a structure used to model the root fields of a dynamic
* hash table node.
*
* it's up to client applications to "sub-class" this
* structure to add relevant (key,value) definitions
*
* @fields:
* link :: pointer to next node in bucket's collision list
* hash :: 32-bit hash value for this node
*
* @note:
* it's up to client applications to "sub-class" this structure
* to add relevant (key,value) type definitions. For example,
* if we want to build a "string -> int" mapping, we could use
* something like:
*
* {
* typedef struct MyNodeRec_
* {
* FT_HashNodeRec hnode;
* const char* key;
* int value;
*
* } MyNodeRec, *MyNode;
* }
*
*/
typedef struct FT_HashNodeRec_
{
FT_HashNode link;
FT_UInt32 hash;
} FT_HashNodeRec;
/****************************************************************
*
* @function: ft_hash_init
*
* @description:
* initialize a dynamic hash table
*
* @input:
* table :: handle to target hash table structure
* compare :: node comparison function
* memory :: memory manager handle used to allocate the
* buckets array within the hash table
*
* @note:
* the node comparison function should only compare node _keys_
* and ignore values !! with good hashing computation (which the
* user must perform itself), the comparison function should be
* pretty selfom called.
*
* here is a simple example:
*
* {
* static int my_compare( const MyNode node1,
* const MyNode node2 )
* {
* // compare keys of 'node1' and 'node2'
* return strcmp( node1->key, node2->key );
* }
*
* ....
*
* ft_hash_init( &hash, (FT_Hash_CompareFunc) my_compare, memory );
* ....
* }
*/
FT_BASE( void )
ft_hash_init( FT_Hash table,
FT_Hash_CompareFunc compare,
FT_Memory memory );
/****************************************************************
*
* @function: ft_hash_lookup
*
* @description:
* search a hash table to find a node corresponding to a given
* key.
*
* @input:
* table :: handle to target hash table structure
* keynode :: handle to a reference hash node that will be
* only used for key comparisons with the table's
* elements
*
* @return:
* a pointer-to-hash-node value, which must be used as followed:
*
* - if '*result' is NULL, the key wasn't found in the hash
* table. The value of 'result' can be used to add new elements
* through @ft_hash_add however..
*
* - if '*result' is not NULL, it's a handle to the first table
* node that corresponds to the search key. The value of 'result'
* can be used to remove this element through @ft_hash_remove
*
* @note:
* here is an example:
*
* {
* // maps a string to an integer with a hash table
* // returns -1 in case of failure
* //
* int my_lookup( FT_Hash table,
* const char* key )
* {
* MyNode* pnode;
* MyNodeRec noderec;
*
* // set-up key node. It's 'hash' and 'key' fields must
* // be set correctly.. we ignore 'link' and 'value'
* //
* noderec.hnode.hash = strhash( key );
* noderec.key = key;
*
* // perform search - return value
* //
* pnode = (MyNode) ft_hash_lookup( table, &noderec );
* if ( *pnode )
* {
* // we found it
* return (*pnode)->value;
* }
* return -1;
* }
* }
*/
FT_BASE_DEF( FT_HashNode* )
ft_hash_lookup( FT_Hash table,
FT_HashNode keynode )
/****************************************************************
*
* @function: ft_hash_add
*
* @description:
* add a new node to a dynamic hash table. the user must
* call @ft_hash_lookup and allocate a new node before calling
* this function.
*
* @input:
* table :: hash table handle
* pnode :: pointer-to-hash-node value returned by @ft_hash_lookup
* new_node :: handle to new hash node. All its fields must be correctly
* set, including 'hash'.
*
* @note:
* this function should always be used _after_ a call to @ft_hash_lookup
* that returns a pointer to a NULL handle. Here's an example:
*
* {
* // sets the value corresponding to a given string key
* //
* void my_set( FT_Hash table,
* const char* key,
* int value )
* {
* MyNode* pnode;
* MyNodeRec noderec;
* MyNode node;
*
* // set-up key node. It's 'hash' and 'key' fields must
* // be set correctly..
* noderec.hnode.hash = strhash( key );
* noderec.key = key;
*
* // perform search - return value
* pnode = (MyNode) ft_hash_lookup( table, &noderec );
* if ( *pnode )
* {
* // we found it, simply replace the value in the node
* (*pnode)->value = value;
* return;
* }
*
* // allocate a new node - and set it up
* node = (MyNode) malloc( sizeof(*node) );
* node->hnode.hash = noderec.hnode.hash;
* node->key = key;
* node->value = value;
*
* // add it to the hash table
* ft_hash_add( table, pnode, node );
* }
*/
FT_BASE( void )
ft_hash_add( FT_Hash table,
FT_HashNode* pnode,
FT_HashNode new_node );
/****************************************************************
*
* @function: ft_hash_remove
*
* @description:
* try to remove the node corresponding to a given key from
* a hash table. This must be called after @ft_hash_lookup
*
* @input:
* table :: hash table handle
* pnode :: pointer-to-hash-node value returned by @ft_hash_lookup
*
* @note:
* this function doesn't free the node itself !! Here's an example:
*
* {
* // sets the value corresponding to a given string key
* //
* void my_remove( FT_Hash table,
* const char* key )
* {
* MyNodeRec noderec;
* MyNode node;
*
* noderec.hnode.hash = strhash(key);
* noderec.key = key;
* node = &noderec;
*
* pnode = ft_hash_lookup( table, &noderec );
* node = *pnode;
* if ( node != NULL )
* {
* ft_hash_remove( table, pnode );
* free( node );
* }
* }
* }
*/
FT_BASE( void )
ft_hash_remove( FT_Hash table,
FT_HashNode* pnode );
/****************************************************************
*
* @function: ft_hash_get_size
*
* @description:
* return the number of elements in a given hash table
*
* @input:
* table :: handle to target hash table structure
*
* @return:
* number of elements. 0 if empty
*/
FT_BASE( FT_UInt )
ft_hash_get_size( FT_Hash table );
/****************************************************************
*
* @functype: FT_Hash_ForeachFunc
*
* @description:
* a function used to iterate over all elements of a given
* hash table
*
* @input:
* node :: handle to target @FT_HashNodeRec node structure
* data :: optional argument to iteration routine
*
* @also: @ft_hash_foreach
*/
typedef void (*FT_Hash_ForeachFunc)( const FT_HashNode node,
const FT_Pointer data );
/****************************************************************
*
* @function: ft_hash_foreach
*
* @description:
* parse over all elements in a hash table
*
* @input:
* table :: handle to target hash table structure
* foreach_func :: iteration routine called for each element
* foreach_data :: optional argument to the iteration routine
*
* @note:
* this function is often used to release all elements from a
* hash table. See the example given for @ft_hash_done
*/
FT_BASE( void )
ft_hash_foreach( FT_Hash table,
FT_Hash_ForeachFunc foreach_func,
const FT_Pointer foreach_data );
/****************************************************************
*
* @function: ft_hash_done
*
* @description:
* finalize a given hash table
*
* @input:
* table :: handle to target hash table structure
* node_func :: optional iteration function pointer. this
* can be used to destroy all nodes explicitely
* node_data :: optional argument to the node iterator
*
* @note:
* this function simply frees the hash table's buckets.
* you probably will need to call @ft_hash_foreach to
* destroy all its elements before @ft_hash_done, as in
* the following example:
*
* {
* static void my_node_clear( const MyNode node )
* {
* free( node );
* }
*
* static void my_done( FT_Hash table )
* {
* ft_hash_done( table, (FT_Hash_ForeachFunc) my_node_clear, NULL );
* }
* }
*/
FT_BASE( void )
ft_hash_done( FT_Hash table,
FT_Hash_ForeachFunc item_func,
const FT_Pointer item_data );
/* */
/* compute bucket index from hash value in a dynamic hash table */
/* this is only used to break encapsulation to speed lookups in */
/* the FreeType cache manager !! */
/* */
#define FT_HASH_COMPUTE_INDEX(_table,_hash,_index) \
{ \
FT_UInt _mask = (_table)->mask; \
FT_UInt _hash0 = (_hash); \
\
(_index) = (FT_UInt)( (_hash0) & _mask ) ); \
if ( (_index) < (_table)->p ) \
(_index) = (FT_uInt)( (_hash0) & ( 2*_mask+1 ) ); \
}
FT_END_HEADER
#endif /* __FT_HASH_H__ */

View File

@ -6,35 +6,189 @@
FT_BEGIN_HEADER
/**************************************************************
*
* @type: FT_Object
*
* @description:
* handle to a FreeType Object. See @FT_ObjectRec
*/
typedef struct FT_ObjectRec_* FT_Object;
/**************************************************************
*
* @type: FT_Class
*
* @description:
* handle to a constant class handle to a FreeType Object.
*
* Note that a class is itself a @FT_Object and are dynamically
* allocated on the heap.
*
* @also:
* @FT_ClassRec, @FT_Object, @FT_ObjectRec, @FT_Type, @FT_TypeRec
*/
typedef const struct FT_ClassRec_* FT_Class;
/**************************************************************
*
* @type: FT_Type
*
* @description:
* handle to a constant structure (of type @FT_TypeRec) used
* to describe a given @FT_Class type to the FreeType object
* sub-system.
*/
typedef const struct FT_TypeRec_* FT_Type;
/**************************************************************
*
* @struct: FT_ObjectRec
*
* @description:
* a structure describing the root fields of all @FT_Object
* class instances in FreeType
*
* @fields:
* clazz :: handle to the object's class
* ref_count :: object's reference count. Starts at 1
*/
typedef struct FT_ObjectRec_
{
FT_Class clazz;
FT_Int ref_count;
} FT_ObjectRec;
/**************************************************************
*
* @macro: FT_OBJECT (x)
*
* @description:
* a useful macro to type-cast anything to a @FT_Object
* handle. No check performed..
*/
#define FT_OBJECT(x) ((FT_Object)(x))
/**************************************************************
*
* @macro: FT_OBJECT_P (x)
*
* @description:
* a useful macro to type-cast anything to a pointer to
* @FT_Object handle.
*/
#define FT_OBJECT_P(x) ((FT_Object*)(x))
/**************************************************************
*
* @macro: FT_OBJECT__CLASS (obj)
*
* @description:
* a useful macro to return the class of any object
*/
#define FT_OBJECT__CLASS(x) FT_OBJECT(x)->clazz
/**************************************************************
*
* @macro: FT_OBJECT__REF_COUNT (obj)
*
* @description:
* a useful macro to return the reference count of any object
*/
#define FT_OBJECT__REF_COUNT(x) FT_OBJECT(x)->ref_count
/**************************************************************
*
* @macro: FT_OBJECT__MEMORY (obj)
*
* @description:
* a useful macro to return a handle to the memory manager
* used to allocate a given object
*/
#define FT_OBJECT__MEMORY(x) FT_CLASS__MEMORY(FT_OBJECT(x)->clazz)
/**************************************************************
*
* @macro: FT_OBJECT__LIBRARY (obj)
*
* @description:
* a useful macro to return a handle to the library handle
* that owns the object
*/
#define FT_OBJECT__LIBRARY(x) FT_CLASS__LIBRARY(FT_OBJECT(x)->clazz)
/**************************************************************
*
* @functype: FT_Object_InitFunc
*
* @description:
* a function used to initialize a new object
*
* @input:
* object :: target object handle
* init_data :: optional pointer to initialization data
*
* @throws: any
*
* the object is _assumed_ to be reachable from the cleanup
* stack when the constructor is called. This means that
* any exception can be thrown safely in it.
*/
typedef void (*FT_Object_InitFunc)( FT_Object object,
FT_Pointer init_data );
/**************************************************************
*
* @functype: FT_Object_DoneFunc
*
* @description:
* a function used to finalize a given object
*
* @input:
* object :: handle to target object
*
* @throws: *never* !!
*/
typedef void (*FT_Object_DoneFunc)( FT_Object object );
typedef void (*FT_Object_CopyFunc)( FT_Object target,
FT_Object source );
/**************************************************************
*
* @struct: FT_ClassRec
*
* @description:
* a structure used to describe a given object class within
* FreeType
*
* @fields:
* object :: root @FT_ObjectRec fields, since each class is
* itself an object. (it's an instance of the
* "metaclass", a special object of the FreeType
* object sub-system.)
*
* magic :: a 32-bit magic number used for decoding
* type :: the @FT_Type descriptor of this class
* memory :: the current memory manager handle
* library :: the current library handle
* info :: an opaque pointer to class-specific information
* managed by the FreeType object sub-system
*
* obj_size :: size of class instances in bytes
* obj_init :: class instance constructor
* obj_done :: class instance destructor
*/
typedef struct FT_ClassRec_
{
FT_ObjectRec object;
@ -43,60 +197,247 @@ FT_BEGIN_HEADER
FT_Memory memory;
FT_Library library;
FT_Pointer info;
FT_Pointer data;
FT_UInt obj_size;
FT_Object_InitFunc obj_init;
FT_Object_DoneFunc obj_done;
FT_Object_CopyFunc obj_copy;
} FT_ClassRec;
/**************************************************************
*
* @macro: FT_CLASS (x)
*
* @description:
* a useful macro to convert anything to a class handle
* without checks
*/
#define FT_CLASS(x) ((FT_Class)(x))
/**************************************************************
*
* @macro: FT_CLASS_P (x)
*
* @description:
* a useful macro to convert anything to a pointer to a class
* handle without checks
*/
#define FT_CLASS_P(x) ((FT_Class*)(x))
#define FT_CLASS__MEMORY(x) FT_CLASS(x)->memory
#define FT_CLASS__LIBRARY(x) FT_CLASS(x)->library
#define FT_CLASS__MAGIC(x) FT_CLASS(x)->magic
#define FT_CLASS__TYPE(x) FT_CLASS(x)->type
#define FT_CLASS__DATA(x) FT_CLASS(x)->data
#define FT_CLASS__INFO(x) FT_CLASS(x)->info
/**************************************************************
*
* @macro: FT_CLASS__MEMORY (clazz)
*
* @description:
* a useful macro to return the memory manager handle of a
* given class
*/
#define FT_CLASS__MEMORY(x) FT_CLASS(x)->memory
/**************************************************************
*
* @macro: FT_CLASS__LIBRARY (clazz)
*
* @description:
* a useful macro to return the library handle of a
* given class
*/
#define FT_CLASS__LIBRARY(x) FT_CLASS(x)->library
/**************************************************************
*
* @macro: FT_CLASS__TYPE (clazz)
*
* @description:
* a useful macro to return the type of a given class
* given class
*/
#define FT_CLASS__TYPE(x) FT_CLASS(x)->type
/* */
#define FT_CLASS__INFO(x) FT_CLASS(x)->info
#define FT_CLASS__MAGIC(x) FT_CLASS(x)->magic
/**************************************************************
*
* @struct: FT_TypeRec
*
* @description:
* a structure used to describe a given class to the FreeType
* object sub-system.
*
* @fields:
* name :: class name. only used for debugging
* super :: type of super-class. NULL if none
*
* class_size :: size of class structure in bytes
* class_init :: class constructor
* class_done :: class finalizer
*
* obj_size :: instance size in bytes
* obj_init :: instance constructor. can be NULL
* obj_done :: instance destructor. can be NULL
*
* @note:
* if 'obj_init' is NULL, the class will use it's parent
* constructor.
*
* if 'obj_done' is NULL, the class will use it's parent
* finalizer.
*
* the object sub-system allocates a new class, copies
* the content of its super-class into the new structure,
* _then_ calls 'clazz_init'.
*/
typedef struct FT_TypeRec_
{
const char* name;
FT_Type super;
FT_UInt class_size;
FT_Object_InitFunc class_init;
FT_Object_DoneFunc class_done;
FT_UInt obj_size;
FT_Object_InitFunc obj_init;
FT_Object_DoneFunc obj_done;
FT_Object_CopyFunc obj_copy;
} FT_TypeRec;
/**************************************************************
*
* @macro: FT_TYPE (x)
*
* @description:
* a useful macro to convert anything to a class type handle
* without checks
*/
#define FT_TYPE(x) ((FT_Type)(x))
/* check that a handle points to a valid object */
/**************************************************************
*
* @function: ft_object_check
*
* @description:
* checks that a handle points to a valid @FT_Object
*
* @input:
* obj :: handle/pointer
*
* @return:
* 1 iff the handle points to a valid object. 0 otherwise
*/
FT_BASE_DEF( FT_Int )
ft_object_check( FT_Pointer obj );
/* check that an object is of a given class */
/**************************************************************
*
* @function: ft_object_is_a
*
* @description:
* checks that a handle points to a valid @FT_Object that
* is an instance of a given class (or of any of its sub-classes)
*
* @input:
* obj :: handle/pointer
* clazz :: class handle to check
*
* @return:
* 1 iff the handle points to a valid 'clazz' instance. 0
* otherwise.
*/
FT_BASE_DEF( FT_Int )
ft_object_is_a( FT_Pointer obj,
FT_Class clazz );
/**************************************************************
*
* @function: ft_object_new
*
* @description:
* create a new object (class instance)
*
* @input:
* clazz :: object's class pointer
* init_data :: optional pointer to initialization data
*
* @return:
* handle to new object. Cannot be NULL !
*/
FT_BASE_DEF( FT_Object )
ft_object_new( FT_Class clazz,
FT_Pointer init_data );
/**************************************************************
*
* @function: ft_object_create
*
* @description:
* a variation of @ft_object_new that should be used when
* creating a new object that is owned by another object
* which is reachable from the cleanup stack.
*
* this function is a bit more akward to use but completely
* avoids push/pop pairs during object construction and is
* therefore faster.
*
* @output:
* pobject :: new object handle
*
* @input:
* clazz :: object's class pointer
* init_data :: optional pointer to initialization data
* push :: boolean. If true, the new object is pushed
* on top of the cleanup stack.
*/
FT_BASE_DEF( void )
ft_object_create( FT_Object *pobject,
FT_Class clazz,
FT_Pointer init_data );
/* */
FT_BASE_DEF( FT_Class )
ft_class_find_by_type( FT_Type type,
FT_Memory memory );
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_object_create_from_type( FT_Object *pobject,
FT_Type type,
FT_Pointer init_data,
FT_Memory memory );
FT_BASE_DEF( void )
ft_object_push( FT_Object object );
FT_BASE_DEF( void )
ft_object_pop( FT_Object object );
FT_BASE_DEF( void )
ft_object_pop_destroy( FT_Object object );
FT_END_HEADER
#endif /* __FT_OBJECT_H__ */

View File

@ -10,9 +10,9 @@
stack->top = stack->chunk->items;
stack->limit = stack->top + FT_CLEANUP_CHUNK_SIZE;
stack->chunk_0.link = NULL;
stack->memory = memory;
}
}
@ -21,7 +21,7 @@
{
FT_Memory memory = stack->memory;
FT_CleanupChunk chunk, next;
for (;;)
{
chunk = stack->chunk;
@ -29,10 +29,10 @@
break;
stack->chunk = chunk->link;
FT_FREE( chunk );
FT_Free( chunk, memory );
}
stack->memory = NULL;
}
@ -49,22 +49,20 @@
FT_ASSERT( stack && stack->chunk && stack->top );
FT_ASSERT( item && item_func );
top = stack->top;
top->item = item;
top->item_func = item_func;
top->item_data = item_data;
top ++;
if ( top == stack->limit )
{
FT_CleanupChunk chunk;
FT_Error error;
if ( FT_ALLOC( chunk, stack->memory ) )
ft_cleanup_stack_throw( stack, error );
chunk = FT_QAlloc( sizeof(*chunk), stack->memory );
chunk->link = stack->chunk;
stack->chunk = chunk;
@ -73,7 +71,7 @@
}
stack->top = top;
}
}
@ -82,17 +80,17 @@
FT_Int destroy )
{
FT_CleanupItem top;
FT_ASSERT( stack && stack->chunk && stack->top );
top = stack->top;
if ( top == stack->chunk->items )
{
FT_CleanupChunk chunk;
chunk = stack->chunk;
if ( chunk == &stack->chunk_0 )
{
FT_ERROR(( "cleanup.pop: empty cleanup stack !!\n" ));
@ -101,21 +99,21 @@
chunk = chunk->link;
FT_QFree( stack->chunk, stack->memory );
stack->chunk = chunk;
stack->limit = chunk->items + FT_CLEANUP_CHUNK_SIZE;
top = stack->limit;
}
top --;
if ( destroy )
top->item_func( top->item, top->item_data );
top->item = NULL;
top->item_func = NULL;
top->item_data = NULL;
stack->top = top;
}
@ -129,10 +127,10 @@
FT_ASSERT( stack && stack->chunk && stack->top );
top = stack->top;
chunk = stack->chunk;
if ( top > chunk->items )
top--;
else
@ -146,17 +144,17 @@
}
FT_BASE_DEF( void )
ft_cleanup_stack_throw( FT_CleanupStack stack, FT_Error error )
{
}
FT_BASE_DEF( void )
ft_xhandler_enter( FT_XHandler xhandler,
FT_Memory memory )
{
FT_CleanupStack stack = FT_MEMORY__CLEANUP(memory);
xhandler->previous = stack->xhandler;
xhandler->cleanup = stack->top;
xhandler->error = 0;
stack->xhandler = xhandler;
}
@ -164,5 +162,36 @@
FT_BASE_DEF( void )
ft_xhandler_exit( FT_XHandler xhandler )
{
FT_CleanupStack stack = FT_MEMORY__CLEANUP(memory);
stack->xhandler = xhandler->previous;
xhandler->previous = NULL;
xhandler->error = error;
xhandler->cleanup = NULL;
}
FT_BASE_DEF( void )
ft_cleanup_throw( FT_CleanupStack stack,
FT_Error error )
{
FT_XHandler xhandler = stack->xhandler;
if ( xhandler == NULL )
{
/* no exception handler was registered. this */
/* means that we have an un-handled exception */
/* the only thing we can do is _PANIC_ and */
/* halt the current program.. */
/* */
FT_ERROR(( "FREETYPE PANIC: An un-handled exception occured. Program aborted" ));
ft_exit(1);
}
/* cleanup the stack until we reach the handler's */
/* starting stack location.. */
xhandler->error = error;
longmp( xhandler->jump_buffer, 1 );
}

215
src/base/fthash.c Normal file
View File

@ -0,0 +1,215 @@
#include "fthash.h"
#include FT_INTERNAL_MEMORY_H
#include FT_INTERNAL_DEBUG_H
#define FT_HASH_MAX_LOAD 2
#define FT_HASH_MIN_LOAD 1
#define FT_HASH_SUB_LOAD (FT_HASH_MAX_LOAD-FT_HASH_MIN_LOAD)
/* this one _must_ be a power of 2 !! */
#define FT_HASH_INITIAL_SIZE 8
FT_BASE_DEF( void )
ft_hash_done( FT_Hash table,
FT_Hash_ForeachFunc node_func,
const FT_Pointer node_data )
{
if ( table )
{
FT_Memory memory = table->memory;
if ( node_func )
ft_hash_foreach( table, node_func, node_data );
FT_FREE( table->buckets );
table->p = 0;
table->mask = 0;
table->slack = 0;
table->compare = NULL;
}
}
FT_BASE_DEF( FT_UInt )
ft_hash_get_size( FT_Hash table )
{
FT_UInt result = 0;
if ( table )
result = (table->p + table->mask + 1)*FT_HASH_MAX_LOAD - table->slack;
return result;
}
FT_BASE_DEF( void )
ft_hash_init( FT_Hash table,
FT_Hash_CompareFunc compare,
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_NEW_ARRAY( hash->buckets, FT_HASH_INITIAL_SIZE*2 );
}
FT_BASE_DEF( void )
ft_hash_foreach( FT_Hash table,
FT_Hash_ForeachFunc foreach_func,
const FT_Pointer foreach_data )
{
FT_UInt count = table->p + table->mask + 1;
FT_HashNode* pnode = table->buckets;
FT_HashNode node, next;
for ( ; count > 0; count--, pnode++ )
{
node = *pnode;
while ( node )
{
next = node->link;
foreach_func( node, foreach_data );
node = next;
}
}
}
FT_BASE_DEF( FT_HashNode* )
ft_hash_lookup( FT_Hash table,
FT_HashNode keynode )
{
FT_UInt index;
FT_UInt23 hash = keynode->hash;
index = (FT_UInt)(hash & table->mask);
if ( index < table->p )
index = (FT_UInt)(hash & (2*table->mask+1));
pnode = &table->buckets[index];
for (;;)
{
node = *pnode;
if ( node == NULL )
break;
if ( node->hash == hash && table->compare( node, keynode ) )
break;
pnode = &node->link;
}
return pnode;
}
FT_BASE_DEF( void )
ft_hash_add( FT_Hash table,
FT_HashNode* pnode,
FT_HashNode new_node )
{
/* add it to the hash table */
new_node->link = *pnode;
*pnode = new_node;
if ( --table->slack < 0 )
{
FT_UInt p = table->p;
FT_UInt mask = table->mask;
FT_HashNode new_list;
/* split a single bucket */
new_list = NULL;
pnode = table->buckets + p;
for (;;)
{
node = *pnode;
if ( node == NULL )
break;
if ( node->hash & mask )
{
*pnode = node->link;
node->link = new_list;
new_list = node;
}
else
pnode = &node->link;
}
table->buckets[ p + mask + 1 ] = new_list;
table->slack += FT_HASH_MAX_LOAD;
if ( p >= mask )
{
FT_RENEW_ARRAY( hash->buckets, (mask+1)*2, (mask+1)*4 );
table->mask = 2*mask + 1;
table->p = 0;
}
else
table->p = p + 1;
}
}
FT_BASE_DEF( FT_Int )
ft_hash_remove( FT_Hash table,
FT_HashNode* pnode )
{
FT_HashNode node;
FT_UInt num_buckets;
FT_ASSERT( pnode != NULL && node != NULL );
node = *pnode;
*pnode->link = node->link;
node->link = NULL;
num_buckets = ( table->p + table->mask + 1) ;
if ( ++ table->slack > num_buckets*FT_HASH_SUB_LOAD )
{
FT_UInt p = table->p;
FT_UInt mask = table->mask;
FT_UInt old_index = p + mask;
FT_HashNode* pnode;
FT_HashNode* pold;
if ( old_index < FT_HASH_INITIAL_SIZE )
return;
if ( p == 0 )
{
table->mask >>= 1;
p = table->mask;
FT_RENEW_ARRAY( hash->buckets, (mask+1)*2, (mask) );
}
else
p--;
pnode = table->buckets + p;
while ( *pnode )
pnode = &(*pnode)->link;
pold = table->buckets + old_index;
*pnode = *pold;
*pold = NULL;
table->slack -= FT_HASH_MAX_LOAD;
table->p = p;
}
}

302
src/base/ftobject.c Normal file
View File

@ -0,0 +1,302 @@
#include "ftobject.c"
#define FT_MAGIC_DEATH 0xDEADdead
#define FT_MAGIC_CLASS 0x12345678
#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 )
/*******************************************************************/
/*******************************************************************/
/***** *****/
/***** *****/
/***** M E T A - C L A S S *****/
/***** *****/
/***** *****/
/*******************************************************************/
/*******************************************************************/
/* 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;
/* destroy a given class */
static void
ft_class_hnode_destroy( FT_ClassHNode node )
{
FT_Clazz clazz = node->clazz;
FT_Memory memory = clazz->memory;
FT_Type ctype = clazz->type;
if ( ctype->class_done )
ctype->class_done( clazz );
FT_FREE( clazz );
node->clazz = NULL;
node->type = NULL;
FT_FREE( node );
}
static FT_Int
ft_class_hnode_compare( const FT_ClassHNode node1,
const FT_ClassHNode node2 )
{
return ( node1->type == node2->type );
}
static void
ft_metaclass_done( FT_MetaClass meta )
{
/* clear all objects */
ft_hash_done( &meta->type_to_class,
(FT_Hash_ForeachFunc) ft_class_destroy,
NULL );
meta->clazz->object.clazz = NULL;
meta->clazz->object.ref_count = 0;
meta->clazz->magic = FT_MAGIC_DEATH;
}
static void
ft_metaclass_init( FT_MetaClass meta,
FT_Library library )
{
FT_ClassRec* clazz = 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_metaclass_type;
clazz->info = NULL;
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 );
}
/* find or create the class corresponding to a given type */
static FT_Class
ft_metaclass_get_class( FT_MetaClass meta,
FT_Type ctype )
{
FT_ClassHNodeRec keynode, *node, **pnode;
FT_Memory memory;
keynode.hnode.hash = (FT_UInt32)( ctype >> 2 );
keynode.type = type;
pnode = (FT_ClassHNode) ft_hash_lookup( &meta->type_to_class,
&noderec );
node = *pnode;
if ( node != NULL )
return node->clazz;
memory = FT_CLASS__MEMORY(meta);
node = FT_MEM_SAFE_ALLOC( sizeof(*node) );
if ( node != NULL )
{
FT_ClassRec* clazz;
clazz = FT_MEM_SAFE_ALLOC( ctype->class_size );
if ( clazz == NULL )
{
FT_FREE( node );
FT_XTHROW( FT_Err_Out_Of_Memory );
}
}
}
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) ft_class_init,
(FT_Object_DoneFunc) ft_class_done
};
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_Object o = FT_OBJECT(obj);
FT_Class c = FT_OBJECT__CLASS(obj);
do
{
if ( c == clazz )
return 1;
c = c->super;
}
while ( c == NULL );
return (clazz == NULL);
}
}
/* 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_object_create( FT_Object *pobject,
FT_Class clazz,
FT_Pointer init_data )
{
FT_Memory memory;
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;
if ( clazz->obj_init )
clazz->obj_init( obj, init_data );
}
FT_BASE_DEF( FT_Class )
ft_class_find_by_type( FT_Type type,
FT_Memory memory )
{
}
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_object_create_from_type( FT_Object *pobject,
FT_Type type,
FT_Pointer init_data,
FT_Memory memory );
FT_BASE_DEF( void )
ft_object_push( FT_Object object );
FT_BASE_DEF( void )
ft_object_pop( FT_Object object );
FT_BASE_DEF( void )
ft_object_pop_destroy( FT_Object object );