2 #include FT_INTERNAL_OBJECT_H
3 #include FT_INTERNAL_DEBUG_H
4 #include FT_INTERNAL_OBJECTS_H
6 #define FT_MAGIC_DEATH 0xDEADdead
7 #define FT_MAGIC_CLASS 0x12345678
9 #define FT_TYPE_HASH(x) (( (FT_UInt32)(x) >> 2 )^( (FT_UInt32)(x) >> 10 ))
11 #define FT_OBJECT_CHECK(o) \
12 ( FT_OBJECT(o) != NULL && \
13 FT_OBJECT(o)->clazz != NULL && \
14 FT_OBJECT(o)->ref_count >= 1 && \
15 FT_OBJECT(o)->clazz->magic == FT_MAGIC_CLASS )
17 #define FT_CLASS_CHECK(c) \
18 ( FT_CLASS(c) != NULL && FT_CLASS(c)->magic == FT_MAGIC_CLASS )
20 #define FT_ASSERT_IS_CLASS(c) FT_ASSERT( FT_CLASS_CHECK(c) )
22 /*******************************************************************/
23 /*******************************************************************/
26 /***** M E T A - C L A S S *****/
29 /*******************************************************************/
30 /*******************************************************************/
32 /* forward declaration */
33 FT_BASE_DEF( FT_Error )
34 ft_metaclass_init( FT_MetaClass meta,
37 /* forward declaration */
39 ft_metaclass_done( FT_MetaClass meta );
42 /* class type for the meta-class itself */
43 static const FT_TypeRec ft_meta_class_type =
48 sizeof( FT_MetaClassRec ),
49 (FT_Object_InitFunc) ft_metaclass_init,
50 (FT_Object_DoneFunc) ft_metaclass_done,
52 sizeof( FT_ClassRec ),
53 (FT_Object_InitFunc) NULL,
54 (FT_Object_DoneFunc) NULL
60 /* destroy a given class */
62 ft_class_hnode_destroy( FT_ClassHNode node )
64 FT_Class clazz = node->clazz;
65 FT_Memory memory = clazz->memory;
67 if ( clazz->class_done )
68 clazz->class_done( (FT_Object) clazz );
80 ft_type_equal( FT_Type type1,
86 if ( type1 == NULL || type2 == NULL )
89 /* compare parent types */
90 if ( type1->super != type2->super )
92 if ( type1->super == NULL ||
93 type2->super == NULL ||
94 !ft_type_equal( type1, type2 ) )
98 /* compare type names */
99 if ( type1->name != type2->name )
101 if ( type1->name == NULL ||
102 type2->name == NULL ||
103 ft_strcmp( type1->name, type2->name ) != 0 )
107 /* compare the other type fields */
108 if ( type1->class_size != type2->class_size ||
109 type1->class_init != type2->class_init ||
110 type1->class_done != type2->class_done ||
111 type1->obj_size != type2->obj_size ||
112 type1->obj_init != type2->obj_init ||
113 type1->obj_done != type2->obj_done )
125 ft_class_hnode_equal( const FT_ClassHNode node1,
126 const FT_ClassHNode node2 )
128 FT_Type type1 = node1->type;
129 FT_Type type2 = node2->type;
131 /* comparing the pointers should work in 99% of cases */
132 return ( type1 == type2 ) ? 1 : ft_type_equal( type1, type2 );
137 ft_metaclass_done( FT_MetaClass meta )
139 /* clear all classes */
140 ft_hash_done( &meta->type_to_class,
141 (FT_Hash_ForeachFunc) ft_class_hnode_destroy,
144 meta->clazz.object.clazz = NULL;
145 meta->clazz.object.ref_count = 0;
146 meta->clazz.magic = FT_MAGIC_DEATH;
150 FT_BASE_DEF( FT_Error )
151 ft_metaclass_init( FT_MetaClass meta,
154 FT_ClassRec* clazz = (FT_ClassRec*) &meta->clazz;
156 /* the meta-class is its OWN class !! */
157 clazz->object.clazz = (FT_Class) clazz;
158 clazz->object.ref_count = 1;
159 clazz->magic = FT_MAGIC_CLASS;
160 clazz->library = library;
161 clazz->memory = library->memory;
162 clazz->type = &ft_meta_class_type;
165 clazz->class_done = (FT_Object_DoneFunc) ft_metaclass_done;
167 clazz->obj_size = sizeof( FT_ClassRec );
168 clazz->obj_init = NULL;
169 clazz->obj_done = NULL;
171 return ft_hash_init( &meta->type_to_class,
172 (FT_Hash_EqualFunc) ft_class_hnode_equal,
177 /* find or create the class corresponding to a given type */
178 /* note that this function will retunr NULL in case of */
179 /* memory overflow */
182 ft_metaclass_get_class( FT_MetaClass meta,
185 FT_ClassHNodeRec keynode, *node, **pnode;
191 keynode.hnode.hash = FT_TYPE_HASH( ctype );
192 keynode.type = ctype;
194 pnode = (FT_ClassHNode*) ft_hash_lookup( &meta->type_to_class,
195 (FT_HashNode) &keynode );
199 clazz = (FT_ClassRec*) node->clazz;
203 memory = FT_CLASS__MEMORY(meta);
206 if ( ctype->super != NULL )
208 FT_ASSERT( ctype->super->class_size <= ctype->class_size );
209 FT_ASSERT( ctype->super->obj_size <= ctype->obj_size );
211 parent = ft_metaclass_get_class( meta, ctype->super );
214 if ( !FT_NEW( node ) )
216 if ( !FT_ALLOC( clazz, ctype->class_size ) )
219 FT_MEM_COPY( (FT_ClassRec*)clazz, parent, parent->type->class_size );
221 clazz->object.clazz = (FT_Class) meta;
222 clazz->object.ref_count = 1;
224 clazz->memory = memory;
225 clazz->library = FT_CLASS__LIBRARY(meta);
226 clazz->super = parent;
229 clazz->magic = FT_MAGIC_CLASS;
231 clazz->class_done = ctype->class_done;
232 clazz->obj_size = ctype->obj_size;
233 clazz->obj_init = ctype->obj_init;
234 clazz->obj_done = ctype->obj_done;
238 if ( clazz->class_done == NULL )
239 clazz->class_done = parent->class_done;
241 if ( clazz->obj_init == NULL )
242 clazz->obj_init = parent->obj_init;
244 if ( clazz->obj_done == NULL )
245 clazz->obj_done = parent->obj_done;
248 /* find class initializer, if any */
250 FT_Type ztype = ctype;
251 FT_Object_InitFunc cinit = NULL;
255 cinit = ztype->class_init;
259 ztype = ztype->super;
261 while ( ztype != NULL );
263 /* then call it when needed */
265 error = cinit( (FT_Object) clazz, NULL );
273 /* we always call the class destructor when */
274 /* an error was detected in the constructor !! */
275 if ( clazz->class_done )
276 clazz->class_done( (FT_Object) clazz );
285 return (FT_Class) clazz;
301 FT_BASE_DEF( FT_Int )
302 ft_object_check( FT_Pointer obj )
304 return FT_OBJECT_CHECK(obj);
308 FT_BASE_DEF( FT_Int )
309 ft_object_is_a( FT_Pointer obj,
312 if ( FT_OBJECT_CHECK(obj) )
314 FT_Class c = FT_OBJECT__CLASS(obj);
325 return (clazz == NULL);
331 FT_BASE_DEF( FT_Error )
332 ft_object_create( FT_Object *pobject,
334 FT_Pointer init_data )
340 FT_ASSERT_IS_CLASS(clazz);
342 memory = FT_CLASS__MEMORY(clazz);
343 if ( !FT_ALLOC( obj, clazz->obj_size ) )
348 if ( clazz->obj_init )
350 error = clazz->obj_init( obj, init_data );
353 /* IMPORTANT: call the destructor when an error */
354 /* was detected in the constructor !! */
355 if ( clazz->obj_done )
356 clazz->obj_done( obj );
367 FT_BASE_DEF( FT_Class )
368 ft_class_find_by_type( FT_Type type,
371 FT_MetaClass meta = &library->meta_class;
373 return ft_metaclass_get_class( meta, type );
377 FT_BASE_DEF( FT_Error )
378 ft_object_create_from_type( FT_Object *pobject,
380 FT_Pointer init_data,
386 clazz = ft_class_find_by_type( type, library );
388 error = ft_object_create( pobject, clazz, init_data );
392 error = FT_Err_Out_Of_Memory;