1 /*  NAME:
2         E3ClassTree.c
3 
4     DESCRIPTION:
5         Quesa class tree.
6 
7         Quesa maintains a class tree, which identifies the various classes
8         which are registered with the system.
9 
10         A class contains all the non-instance specific data for a Quesa
11         object. A Quesa object contains a pointer to the relevent node in the
12         class tree, along with the instance-specific data for that object.
13 
14         The class tree is populated with the default Quesa objects when Quesa
15         initialises itself, and applications can register additional classes
16         such as renderers/etc.
17 
18         The class tree is stored as a hash table for efficiency, but nodes
19         within the tree maintain pointers to their children/parent in order
20         to record their relationship to the rest of the tree.
21 
22     COPYRIGHT:
23         Copyright (c) 1999-2005, Quesa Developers. All rights reserved.
24 
25         For the current release of Quesa, please see:
26 
27             <http://www.quesa.org/>
28 
29         Redistribution and use in source and binary forms, with or without
30         modification, are permitted provided that the following conditions
31         are met:
32 
33             o Redistributions of source code must retain the above copyright
34               notice, this list of conditions and the following disclaimer.
35 
36             o Redistributions in binary form must reproduce the above
37               copyright notice, this list of conditions and the following
38               disclaimer in the documentation and/or other materials provided
39               with the distribution.
40 
41             o Neither the name of Quesa nor the names of its contributors
42               may be used to endorse or promote products derived from this
43               software without specific prior written permission.
44 
45         THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46         "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47         LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48         A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
49         OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50         SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
51         TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52         PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53         LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54         NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55         SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56     ___________________________________________________________________________
57 */
58 //=============================================================================
59 //      Include files
60 //-----------------------------------------------------------------------------
61 #include "E3Prefix.h"
62 #include "E3ClassTree.h"
63 #include "E3HashTable.h"
64 #include "E3Set.h"
65 
66 #include <time.h>
67 #include <stdio.h>
68 #include <new>
69 
70 
71 
72 
73 
74 //=============================================================================
75 //      Internal constants
76 //-----------------------------------------------------------------------------
77 #define kClassHashTableSize							64
78 #define kMethodHashTableSize						32
79 
80 
81 
82 
83 
84 //=============================================================================
85 //      Internal types
86 //-----------------------------------------------------------------------------
87 
88 
89 
90 
91 
92 
93 
94 //=============================================================================
95 //      Internal macros
96 //-----------------------------------------------------------------------------
97 // Called through macro to avoid superfluous function call in release builds
98 #if Q3_DEBUG
99 	#define Q3_CLASS_VERIFY(_o)			_o->Verify()
100 #else
101 	#define Q3_CLASS_VERIFY(_o)
102 #endif
103 
104 
105 
106 
107 
108 //=============================================================================
109 //      Internal functions
110 //-----------------------------------------------------------------------------
111 //      e3class_verify : Verify the instance data hasn't been corrupted.
112 //-----------------------------------------------------------------------------
113 //		Note :	Used for debug builds, to verify object instance data doesn't
114 //				write beyond the space allocated for it.
115 //-----------------------------------------------------------------------------
116 #if Q3_DEBUG
117 
118 void
Verify()119 OpaqueTQ3Object::Verify ()
120 	{
121 	// Verify the object
122 	Q3_ASSERT ( quesaTag == kQ3ObjectTypeQuesa ) ;
123 	Q3_ASSERT_VALID_PTR ( theClass ) ;
124 
125 	TQ3ObjectType* instanceTrailer = (TQ3ObjectType*) ( ( (TQ3Uns8 *) this ) + theClass->instanceSize ) ;
126 
127 	Q3_ASSERT ( *instanceTrailer == kQ3ObjectTypeQuesa ) ;
128 	}
129 
130 #endif // Q3_DEBUG
131 
132 
133 
134 
135 
136 //=============================================================================
137 //      E3ClassInfo::E3ClassInfo : Constructor for class info of root class.
138 //-----------------------------------------------------------------------------
139 #pragma mark -
140 
E3ClassInfo(TQ3XMetaHandler newClassMetaHandler,E3ClassInfo * newParent)141 E3ClassInfo::E3ClassInfo	(
142 							TQ3XMetaHandler	newClassMetaHandler,
143 							E3ClassInfo*	newParent // nil for root class of course
144 						 	)
145 	{
146 	classType = 0 ;
147 	className = NULL ;
148 	methodTable = NULL ;
149 	abstract = kQ3False ;
150 	numInstances = 0 ;
151 	instanceSize = 0 ;
152 	numChildren = 0 ;
153 	theChildren = NULL ;
154 	for ( TQ3Int32 i = kQ3MaxBuiltInClassHierarchyDepth - 1 ; i >= 0 ; --i )
155 		ownAndParentTypes [ i ] = 0 ;
156 
157 	classMetaHandler = newClassMetaHandler ;
158 	theParent = newParent ;
159 	// The above two must be done before any sub class constructors are called as these
160 	// two fields are used in Find_Method which is called in the sub class constructors.
161 
162 	// Also before this:
163 	registerMethod = (TQ3XObjectRegisterMethod) Find_Method ( kQ3XMethodTypeNewObjectClass , kQ3True ) ;
164 	} ;
165 
166 
167 //=============================================================================
168 //      e3class_attach : Attach a child node to its parent.
169 //-----------------------------------------------------------------------------
170 //		Note :	We assume the child currently has no parent.
171 //-----------------------------------------------------------------------------
172 TQ3Status
Attach(E3ClassInfoPtr theChild,E3ClassInfoPtr theParent)173 E3ClassInfo::Attach ( E3ClassInfoPtr theChild, E3ClassInfoPtr theParent )
174 	{
175 	// Validate our parameters
176 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(theChild),      kQ3Failure);
177 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(theParent),     kQ3Failure);
178 
179 
180 
181 	// Grow the list of child pointers
182 	TQ3Status qd3dStatus = Q3Memory_Reallocate(&theParent->theChildren,
183 									 sizeof(E3ClassInfoPtr) * (theParent->numChildren+1));
184 	if ( qd3dStatus == kQ3Failure )
185 		return kQ3Failure ;
186 
187 
188 
189 	// Connect the child to the parent and the parent to the child
190 	theParent->theChildren [ theParent->numChildren ] = theChild ;
191 	theParent->numChildren++ ;
192 
193 	return kQ3Success ;
194 	}
195 
196 
197 
198 
199 
200 //=============================================================================
201 //      e3class_detach : Detach a node from its parent.
202 //-----------------------------------------------------------------------------
203 void
Detach(void)204 E3ClassInfo::Detach ( void )
205 	{
206 	// Validate our parameters
207 	Q3_REQUIRE(Q3_VALID_PTR(this));
208 	Q3_REQUIRE(Q3_VALID_PTR(theParent));
209 
210 
211 
212 	// and shift everything above that slot down by one (overwriting
213 	// thepointer to theChild, and leaving a bogus entry at the end).
214 	for ( TQ3Uns32 n = 0 ; n < theParent->numChildren ; ++n )
215 		{
216 		// If this child matches, shift everything else down
217 		if ( theParent->theChildren [ n ] == this )
218 			{
219 			// If there's anything above us, copy it down
220 			if (n != (theParent->numChildren-1))
221 				Q3Memory_Copy(&theParent->theChildren[n+1],
222 					   		  &theParent->theChildren[n],
223 					   		  sizeof(E3ClassInfoPtr) * (theParent->numChildren-n-1));
224 
225 
226 			// We're done
227 			break;
228 			}
229 		}
230 
231 
232 
233 	// Shrink the parent's list of children
234 	--theParent->numChildren ;
235 	TQ3Status qd3dStatus = Q3Memory_Reallocate(&theParent->theChildren,
236 									 sizeof(E3ClassInfoPtr) * theParent->numChildren);
237 	Q3_ASSERT(qd3dStatus == kQ3Success);
238 
239 
240 
241 	// Remove the parent from the child
242 	theParent = NULL ;
243 	}
244 
245 
246 
247 
248 
249 //=============================================================================
250 //      e3class_find_by_name : Recursive search for a class given a name.
251 //-----------------------------------------------------------------------------
252 E3ClassInfoPtr
Find(const char * theClassName)253 E3ClassInfo::Find ( const char *theClassName )
254 	{
255 	// Validate our parameters
256 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this),							NULL);
257 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(theClassName),                    NULL);
258 	Q3_REQUIRE_OR_RESULT(strlen(theClassName) < kQ3StringMaximumLength, NULL);
259 
260 
261 
262 	// Check this node
263 	if ( E3CString_IsEqual ( className, theClassName ) )
264 		return this ;
265 
266 
267 
268 	// Check the children of the class
269 	for ( TQ3Uns32 n = 0 ; n < numChildren ; ++n )
270 		{
271 		// Get the child
272 		E3ClassInfoPtr theChild = theChildren [ n ] ;
273 		Q3_ASSERT_VALID_PTR(theChild);
274 
275 
276 		// Check it
277 		E3ClassInfoPtr theResult = theChild->Find ( theClassName ) ;
278 		if ( theResult != NULL )
279 			return theResult ;
280 		}
281 
282 	return NULL ;
283 	}
284 
285 
286 
287 
288 
289 //=============================================================================
290 //      e3class_find_method : Find a method for a class.
291 //-----------------------------------------------------------------------------
292 TQ3XFunctionPointer
Find_Method(TQ3XMethodType methodType,TQ3Boolean canInherit)293 E3ClassInfo::Find_Method ( TQ3XMethodType methodType, TQ3Boolean canInherit )
294 	{
295 	// Validate our parameters
296 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), NULL);
297 
298 
299 
300 	// Walk up the class tree until we find the method
301 
302 	if ( classMetaHandler != NULL )
303 		if ( TQ3XFunctionPointer leafMethod = classMetaHandler ( methodType ) )
304 			return leafMethod ;
305 
306 	// If this class doesn't implement it, and we can inherit, try each of the parents in turn
307 	if ( canInherit )
308 		for ( E3ClassInfoPtr theClass = theParent ; theClass != NULL ; theClass = theClass->theParent )
309 			if ( theClass->classMetaHandler != NULL ) // Check the current class
310 				if ( TQ3XFunctionPointer theMethod = theClass->classMetaHandler ( methodType ) )
311 					return theMethod ;
312 
313 
314 
315 	// Did not find a suitable method, return NULL
316 	return NULL ;
317 	}
318 
319 
320 
321 
322 
323 //=============================================================================
324 //      e3class_dump_class : Dump some stats on a class.
325 //-----------------------------------------------------------------------------
326 //		Note :	Debug only - dumps some stats on a class to a file, and calls
327 //				itself recursively to dump the children of the class.
328 //-----------------------------------------------------------------------------
329 void
Dump_Class(FILE * theFile,TQ3Uns32 indent)330 E3ClassInfo::Dump_Class ( FILE *theFile, TQ3Uns32 indent )
331 	{
332 	char				thePad[100];
333 	TQ3Uns32			n;
334 
335 	E3GlobalsPtr theGlobals = E3Globals_Get () ;
336 
337 
338 
339 	// Validate our parameters
340 	Q3_ASSERT_VALID_PTR(theFile);
341 	Q3_ASSERT_VALID_PTR(this);
342 	Q3_ASSERT(indent < (sizeof(thePad)-1));
343 
344 
345 
346 	// Prepare the pad string
347 	for (n = 0; n < indent; ++n )
348 		thePad[n] = ' ';
349 
350 	thePad[n] = 0x00;
351 
352 
353 
354 	// Dump the class
355 	fprintf(theFile, "\n%s%s%s\n",
356 					thePad,
357 					className,
358 					numInstances == 0 ? "" : " *** MEMORY LEAK ***");
359 
360 	if ( ( classType < 0) && ( classType >= theGlobals->classNextType) )
361 		fprintf(theFile, "%s-> classType    = 0x%lx\n", thePad, classType);
362 	else
363 		fprintf(theFile, "%s-> classType    = %c%c%c%c\n", thePad,
364 						((char *) &classType)[0],
365 						((char *) &classType)[1],
366 						((char *) &classType)[2],
367 						((char *) &classType)[3]);
368 
369 	fprintf(theFile, "%s-> numInstances = %lu\n", thePad, numInstances);
370 
371 	fprintf(theFile, "%s-> instanceSize = %lu\n", thePad, instanceSize);
372 
373 	fprintf(theFile, "%s-> numChildren  = %lu\n", thePad, numChildren);
374 
375 	if (E3HashTable_GetNumItems( methodTable) == 0)
376 		fprintf(theFile, "%s-> method cache is empty\n", thePad);
377 	else
378 		{
379 		fprintf(theFile, "%s-> method cache, collision max = %lu\n", thePad,
380 							E3HashTable_GetCollisionMax( methodTable));
381 
382 		fprintf(theFile, "%s-> method cache, collision avg = %.2f\n", thePad,
383 							E3HashTable_GetCollisionAverage( methodTable));
384 
385 		fprintf(theFile, "%s-> method cache, num items     = %lu\n", thePad,
386 							E3HashTable_GetNumItems( methodTable));
387 
388 		fprintf(theFile, "%s-> method cache, table size    = %lu\n", thePad,
389 							E3HashTable_GetTableSize( methodTable));
390 		}
391 
392 
393 
394 	// Dump the children of the class
395 	for (n = 0; n < numChildren; ++n )
396 		{
397 		// Get the child
398 		E3ClassInfoPtr theChild = theChildren[n];
399 		Q3_ASSERT_VALID_PTR(theChild);
400 
401 
402 		// Dump it
403 		theChild->Dump_Class ( theFile, indent + 2 ) ;
404 		}
405 	}
406 
407 
408 
409 
410 
411 //=============================================================================
412 //      Public functions
413 //-----------------------------------------------------------------------------
414 //      E3ClassTree_Destroy : Destroy the class tree.
415 //-----------------------------------------------------------------------------
416 #pragma mark -
417 
418 void
Destroy(void)419 E3ClassTree::Destroy ( void )
420 	{
421 	E3GlobalsPtr theGlobals = E3Globals_Get () ;
422 
423 	// If we have a class tree, destroy it
424 	if (theGlobals->classTree != NULL)
425 		{
426 		E3HashTable_Destroy(&theGlobals->classTree);
427 		theGlobals->classTreeRoot = NULL;
428 		}
429 	}
430 
431 
432 
433 
434 
435 
436 
437 //=============================================================================
438 //      E3ClassTree_GetNextClassType : Get the next available class type.
439 //-----------------------------------------------------------------------------
440 TQ3ObjectType
GetNextClassType(void)441 E3ClassTree::GetNextClassType ( void )
442 	{
443 	E3GlobalsPtr theGlobals = E3Globals_Get () ;
444 
445 	// Decrement the class type, and return the next available type
446 	theGlobals->classNextType--;
447 
448 	return theGlobals->classNextType ;
449 	}
450 
451 
452 
453 
454 
455 
456 
457 //=============================================================================
458 //      E3ClassTree_RegisterClass : Register a new class.
459 //-----------------------------------------------------------------------------
460 //		Note :	Attempts to register a new class within the class tree.
461 //
462 //				If parentClass is kQ3ObjectTypeInvalid, the new node is created
463 //				at the root of the class tree. This can only be performed once,
464 //				and it is an error to attempt to create two nodes at the root.
465 //
466 //-----------------------------------------------------------------------------
467 TQ3Status
RegisterExternalClass(TQ3ObjectType parentClassType,TQ3ObjectType classType,const char * className,TQ3XMetaHandler classMetaHandler,TQ3Uns32 leafInstanceSize)468 E3ClassTree::RegisterExternalClass (
469 								TQ3ObjectType		parentClassType,
470 								TQ3ObjectType		classType,
471 								const char			*className,
472 								TQ3XMetaHandler		classMetaHandler,
473 								TQ3Uns32			leafInstanceSize )
474 	{
475 	if ( E3ClassInfo* theParent = E3ClassTree::GetClass ( parentClassType ) )
476 		return E3ClassTree::RegisterClass ( parentClassType,
477 										classType,
478 										className,
479 										classMetaHandler,
480 										leafInstanceSize + theParent->instanceSize ) ;
481 
482 	return kQ3Failure ;
483 	}
484 
485 
486 TQ3Status
RegisterClass(TQ3ObjectType parentClassType,TQ3ObjectType classType,const char * className,TQ3XMetaHandler classMetaHandler,TQ3Uns32 instanceSize)487 E3ClassTree::RegisterClass (	TQ3ObjectType		parentClassType,
488 								TQ3ObjectType		classType,
489 								const char			*className,
490 								TQ3XMetaHandler		classMetaHandler,
491 								TQ3Uns32			instanceSize )
492 	{
493 	E3GlobalsPtr theGlobals = E3Globals_Get () ;
494 	TQ3Status qd3dStatus = kQ3Success ;
495 
496 	// Validate our parameters
497 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(className),                    kQ3Failure);
498 	Q3_REQUIRE_OR_RESULT(strlen(className) < kQ3StringMaximumLength, kQ3Failure);
499 
500 	E3ClassInfo* theParent = E3ClassTree::GetClass ( parentClassType ) ;
501 	if ( theParent == NULL )
502 		Q3_REQUIRE_OR_RESULT(theGlobals->classTree == NULL, kQ3Failure);
503 
504 	// Make sure the class isn't registered yet
505 	if ( E3ClassTree::GetClass ( classType ) != NULL )
506 		return kQ3Failure ;
507 
508 
509 
510 	// Find the parent class
511 	if ( theParent != NULL )
512 		{
513 		Q3_ASSERT ( instanceSize >= theParent->instanceSize ) ;
514 		}
515 
516 	TQ3XObjectRegisterMethod registerMethod = NULL ;
517 	if ( classMetaHandler != NULL )
518 		registerMethod = (TQ3XObjectRegisterMethod) classMetaHandler ( kQ3XMethodTypeNewObjectClass ) ;
519 
520 	if ( registerMethod == NULL )
521 		for ( E3ClassInfoPtr theClass = theParent ; theClass != NULL ; theClass = theClass->theParent )
522 			if ( theClass->classMetaHandler != NULL ) // Check the current class
523 				if ( ( registerMethod = (TQ3XObjectRegisterMethod) theClass->classMetaHandler ( kQ3XMethodTypeNewObjectClass ) ) != NULL )
524 					break ;
525 
526 	if ( registerMethod == NULL )
527 		return kQ3Failure ;
528 
529 	E3ClassInfo* newClass = registerMethod ( classMetaHandler, theParent ) ; // performs the new ( std::nothrow ) of the most appropriate C++ class
530 
531 	if ( newClass == NULL )
532 		return kQ3Failure ;
533 
534 	newClass->className   = (char *) Q3Memory_Allocate ( strlen ( className ) + 1 ) ;
535 	newClass->methodTable = E3HashTable_Create ( kMethodHashTableSize)  ;
536 
537 	if ( newClass->className == NULL || newClass->methodTable == NULL )
538 		{
539 		if ( newClass->className != NULL )
540 			Q3Memory_Free ( & newClass->className ) ;
541 
542 		if ( newClass->methodTable != NULL )
543 			E3HashTable_Destroy ( &newClass->methodTable ) ;
544 
545 		delete newClass ;
546 		return kQ3Failure ;
547 		}
548 
549 
550 
551 	// Initialise the class
552 	newClass->classType        = classType ;
553 	newClass->instanceSize     = instanceSize ;
554 
555 	strcpy ( newClass->className, className ) ;
556 
557 
558 
559 	// If we don't have a hash table yet, create it
560 	if ( theGlobals->classTree == NULL )
561 		{
562 		theGlobals->classTreeRoot = newClass ;
563 		theGlobals->classTree     = E3HashTable_Create ( kClassHashTableSize ) ;
564 		if ( theGlobals->classTree == NULL )
565 			qd3dStatus = kQ3Failure ;
566 		}
567 
568 
569 
570 	// Store the class in the hash table
571 	if ( qd3dStatus != kQ3Failure )
572 		qd3dStatus = E3HashTable_Add ( theGlobals->classTree, classType, newClass ) ;
573 
574 	if ( qd3dStatus != kQ3Failure && newClass->theParent != NULL )
575 		qd3dStatus = E3ClassInfo::Attach ( newClass, newClass->theParent ) ;
576 
577 
578 	// Fill out the ownAndParentTypes array
579 	TQ3Int32 ourClassDepth = 0 ;
580 	E3ClassInfoPtr aClass ;
581 	for ( aClass = newClass->theParent ; aClass ; aClass = aClass->theParent )
582 		++ourClassDepth ;
583 
584 	for ( aClass = newClass ; aClass ; aClass = aClass->theParent )
585 		{
586 		if ( ourClassDepth < kQ3MaxBuiltInClassHierarchyDepth )
587 			newClass->ownAndParentTypes [ ourClassDepth ] = aClass->classType ;
588 		--ourClassDepth ;
589 		}
590 
591 
592 
593 	// Handle failure
594 	if ( qd3dStatus == kQ3Failure )
595 		{
596 		// Clean up the class tree
597 		if ( theGlobals->classTree != NULL )
598 			{
599 			if ( E3HashTable_Find ( theGlobals->classTree, classType) != NULL )
600 				E3HashTable_Remove ( theGlobals->classTree, classType ) ;
601 			}
602 
603 		if ( theGlobals->classTreeRoot == newClass )
604 				theGlobals->classTreeRoot = NULL ;
605 
606 
607 		// Clean up the class
608 		Q3Memory_Free ( & newClass->className ) ;
609 		E3HashTable_Destroy ( & newClass->methodTable ) ;
610 		delete newClass ;
611 		}
612 
613 	return qd3dStatus ;
614 	}
615 
616 
617 
618 
619 //=============================================================================
620 //      E3ClassTree_UnregisterClass : Unregister a class.
621 //-----------------------------------------------------------------------------
622 //		Note :	Any child classes derived from this class will also be removed
623 //				from the class tree.
624 //
625 //				If isRequired is true, we always unregister the class.
626 //				Otherwise we check to see if this class has any instances left.
627 //				If it does, those instances will have pointers back to the
628 //				class and so it ca't be unregistered.
629 //-----------------------------------------------------------------------------
630 TQ3Status
UnregisterClass(TQ3ObjectType classType,TQ3Boolean isRequired)631 E3ClassTree::UnregisterClass ( TQ3ObjectType classType, TQ3Boolean isRequired )
632 	{
633 	E3GlobalsPtr theGlobals = E3Globals_Get () ;
634 
635 
636 
637 	// Find the class to unregister
638 	E3ClassInfoPtr theClass = E3ClassTree::GetClass ( classType ) ;
639 	if ( theClass == NULL )
640 		return kQ3Failure ;
641 
642 
643 
644 	// If we're not required to unregister the class, check the instance count
645 	if (!isRequired)
646 		{
647 		// Make sure the class doesn't have any instances left. Instances have
648 		// a pointer back to the class tree, so we can't remove the class from
649 		// the tree while those pointers still exist.
650 		if (theClass->numInstances != 0)
651 			{
652 			E3ErrorManager_PostError(kQ3ErrorObjectClassInUse, kQ3False);
653 			return kQ3Failure ;
654 			}
655 		}
656 
657 
658 
659 	// Unregister any children of the class
660 	while (theClass->numChildren != 0)
661 		{
662 		// Get the first child
663 		E3ClassInfoPtr theChild = theClass->theChildren[0];
664 		Q3_ASSERT_VALID_PTR(theChild);
665 
666 
667 		// Try and unregister it
668 		TQ3Status qd3dStatus = E3ClassTree::UnregisterClass ( theChild->classType, isRequired ) ;
669 		if ( qd3dStatus == kQ3Failure )
670 			return qd3dStatus ;
671 		}
672 
673 
674 
675 	// Remove the class from the tree
676 	if ( theClass->theParent != NULL )
677 		theClass->E3ClassInfo::Detach () ;
678 
679 	if ( theGlobals->classTreeRoot == theClass )
680 		theGlobals->classTreeRoot = NULL ;
681 
682 	E3HashTable_Remove(theGlobals->classTree, classType);
683 
684 
685 
686 	// Dispose of the class itself
687 	Q3_ASSERT(theClass->numChildren == 0);
688 	Q3_ASSERT(theClass->theChildren == NULL);
689 
690 	Q3Memory_Free(&theClass->className);
691 	E3HashTable_Destroy(&theClass->methodTable);
692 
693 	delete theClass ;
694 
695 	return kQ3Success ;
696 	}
697 
698 
699 
700 
701 
702 //=============================================================================
703 //      E3ClassTree_InitialiseInstanceDataOfClass : Initialise the instance data of a class.
704 //-----------------------------------------------------------------------------
705 //		Note :	Initialises instances of the specified class and its parent
706 //				classes, passing paramData to the new method.
707 //
708 //				If sharedParams is true, the paramData parameter is passed to
709 //				the specified class and its parent classes.
710 //
711 //				Otherwise, NULL is passed as the paramData for any classes
712 //				above the parent.
713 //
714 //				The sharedParams behaviour is necessary to support the QD3D
715 //				call Q3XObjectHierarchy_NewObject.
716 //-----------------------------------------------------------------------------
717 TQ3Status
InitialiseInstanceData(E3ClassInfoPtr inClass,TQ3Boolean sharedParams,const void * paramData)718 OpaqueTQ3Object::InitialiseInstanceData (	E3ClassInfoPtr	inClass,
719 											TQ3Boolean		sharedParams,
720 											const void		*paramData )
721 	{
722 	TQ3Status qd3dStatus = kQ3Success ;
723 	TQ3Uns32 parentInstanceSize = 0 ;
724 	E3ClassInfoPtr parentClass = inClass->theParent ;
725 
726 	// If this class has a parent, initialise the parent object
727 	if ( parentClass != NULL )
728 		{
729 		parentInstanceSize = parentClass->instanceSize ;
730 		if (sharedParams)
731 			qd3dStatus = InitialiseInstanceData ( parentClass, sharedParams, paramData ) ;
732 		else
733 			qd3dStatus = InitialiseInstanceData ( parentClass, sharedParams, NULL ) ;
734 		}
735 
736 	// If this class has any private data, initialise it
737 	if ( inClass->instanceSize != parentInstanceSize )
738 		{
739 		// If the object has a new method, call it to initialise the object
740 		if ( ( (E3Root*) inClass )->newMethod != NULL )
741 			return ( (E3Root*) inClass )->newMethod (	(TQ3Object) this,
742 														(void*) ( (TQ3Uns8*) this + parentInstanceSize ),
743 														(void *) paramData ) ;
744 
745 		// If the object is an element, it might have a copy add method
746 		// which we call to initialise the object.
747 		TQ3XElementCopyAddMethod elementCopyAddMethod = NULL ;
748 		if ( Q3_CLASS_INFO_IS_CLASS ( inClass , E3Element ) )
749 			elementCopyAddMethod = ( (E3ElementInfo*) inClass )->elementCopyAddMethod ;
750 
751 		if ( elementCopyAddMethod != NULL )
752 			return elementCopyAddMethod ( paramData, ( (TQ3Uns8*) this + parentInstanceSize ) ) ;
753 
754 
755 		// Otherwise if there was no new method, but there was parameter data, do a
756 		// bitwise copy. Classes which require more advanced initialisation must supply
757 		// a new method, and classes which don't have any parameter data will be left
758 		// with instance data that's initialised to 0s.
759 
760 		if ( paramData != NULL )
761 			Q3Memory_Copy ( paramData, ( (TQ3Uns8*) this ) + parentInstanceSize, inClass->instanceSize - parentInstanceSize ) ;
762 
763 		}
764 
765 	return qd3dStatus ;
766 	}
767 
768 
769 
770 
771 
772 //=============================================================================
773 //      E3ClassTree_CreateInstance : Create an instance of a class.
774 //-----------------------------------------------------------------------------
775 //		Note :	Creates instances of the specified class and its parent
776 //				classes, passing paramData to the new method.
777 //
778 //				If sharedParams is true, the paramData parameter is passed to
779 //				the specified class and its parent classes.
780 //
781 //				Otherwise, NULL is passed as the paramData for any classes
782 //				above the parent.
783 //
784 //				The sharedParams behaviour is necessary to support the QD3D
785 //				call Q3XObjectHierarchy_NewObject.
786 //-----------------------------------------------------------------------------
787 TQ3Object
CreateInstance(TQ3ObjectType classType,TQ3Boolean sharedParams,const void * paramData)788 E3ClassTree::CreateInstance (	TQ3ObjectType	classType,
789 								TQ3Boolean		sharedParams,
790 								const void		*paramData )
791 	{
792 	// Find the class to instantiate
793 	//
794 	// Instantiating objects is often the first thing to fail if the library
795 	// has not been initialised yet, so we also check for that case here.
796 	E3ClassInfoPtr theClass = E3ClassTree::GetClass ( classType ) ;
797 	if ( theClass == NULL )
798 		{
799 		E3ErrorManager_PostWarning ( kQ3WarningTypeHasNotBeenRegistered ) ;
800 
801 		if ( ! Q3IsInitialized () )
802 			E3ErrorManager_PostError ( kQ3ErrorNotInitialized, kQ3False ) ;
803 
804 		return NULL ;
805 		}
806 
807 
808 	return theClass->CreateInstance ( sharedParams , paramData ) ;
809 	}
810 
811 
812 
813 TQ3Object
CreateInstance(TQ3Boolean sharedParams,const void * paramData)814 E3ClassInfo::CreateInstance (	TQ3Boolean		sharedParams,
815 								const void		*paramData )
816 	{
817 	Q3_ASSERT ( ! abstract ) ;
818 
819 	if ( abstract )
820 		return NULL ; // Cannot create an object of an abstract class, the required methods are missing (pure virtual)
821 
822 	// Allocate and initialise the object
823 	TQ3Object theObject = (TQ3Object) Q3Memory_AllocateClear ( instanceSize + sizeof ( TQ3ObjectType ) ) ;
824 	if ( theObject == NULL )
825 		return NULL ;
826 
827 	theObject->quesaTag = kQ3ObjectTypeQuesa ;
828 	theObject->theClass = this ;
829 
830 	// Initialise the trailer
831 	TQ3ObjectType* instanceTrailer = (TQ3ObjectType *) (((TQ3Uns8 *) theObject) + instanceSize ) ;
832 	*instanceTrailer = kQ3ObjectTypeQuesa ;
833 
834 	TQ3Status qd3dStatus = theObject->InitialiseInstanceData ( this, sharedParams, paramData ) ;
835 
836 	if ( qd3dStatus == kQ3Failure )
837 		{
838 		Q3Memory_Free ( &theObject ) ;
839 		return NULL ;
840 		}
841 
842 	// Increment the instance count of the class (watch for overflow)
843 	++numInstances ;
844 	Q3_ASSERT ( numInstances > 0 ) ;
845 
846 
847 
848 	// Verify the object and return it
849 	Q3_CLASS_VERIFY ( theObject ) ;
850 
851 	return theObject ;
852 	}
853 
854 
855 
856 
857 
858 //=============================================================================
859 //      e3ClassTree_DeleteInstanceDataOfClass : Call delete methods on the instance data of a class and its parent classes.
860 //-----------------------------------------------------------------------------
861 void
DeleteInstanceData(E3ClassInfoPtr inClass)862 OpaqueTQ3Object::DeleteInstanceData ( E3ClassInfoPtr inClass )
863 	{
864 	TQ3Uns32 parentInstanceSize = 0 ;
865 
866 	if ( inClass->theParent != NULL )
867 		parentInstanceSize = inClass->theParent->instanceSize ;
868 
869 	TQ3XElementDeleteMethod elementDeleteMethod = NULL ;
870 	if ( Q3_CLASS_INFO_IS_CLASS ( inClass , E3Element ) )
871 		elementDeleteMethod = ( (E3ElementInfo*) inClass )->elementDeleteMethod ;
872 
873 	// Call the object's delete method
874 	if ( elementDeleteMethod != NULL )
875 		{
876 		OpaqueTQ3Object* thisPtr = this ; // So can be set to null in delete method
877 		elementDeleteMethod ( ( (TQ3Uns8*) this + parentInstanceSize ) ) ;
878 		}
879 	else
880 		{
881 		if ( ( (E3Root*) inClass )->deleteMethod != NULL )
882 			( (E3Root*) inClass )->deleteMethod ( (TQ3Object) this , (void*)  ( (TQ3Uns8*) this + parentInstanceSize ) ) ;
883 		}
884 
885 
886 
887 	// Dispose of the parent object, if any
888 	if ( inClass->theParent != NULL )
889 		DeleteInstanceData ( inClass->theParent ) ;
890 
891 	}
892 
893 
894 
895 
896 
897 //=============================================================================
898 //      E3ClassTree_DestroyInstance : Destroy an instance of a class.
899 //-----------------------------------------------------------------------------
900 void
DestroyInstance(void)901 OpaqueTQ3Object::DestroyInstance ( void )
902 	{
903 	// Validate our parameters
904 	Q3_REQUIRE(Q3_VALID_PTR(this));
905 	Q3_CLASS_VERIFY(this);
906 
907 
908 
909 	// Call the object's delete method and all its parent classes' delete methods
910 	DeleteInstanceData ( theClass ) ;
911 
912 
913 
914 	// Decrement the instance count of the class
915 	Q3_ASSERT(theClass->numInstances > 0);
916 	theClass->numInstances-- ;
917 
918 
919 
920 	// Dispose of the object
921 	TQ3Object theObject = (TQ3Object) this ;
922 	Q3Memory_Free ( & theObject ) ;
923 	}
924 
925 
926 
927 
928 
929 //=============================================================================
930 //      E3ClassTree_DuplicateInstanceDataOfClass : Duplicate the instance data of a class and its parent classes.
931 //-----------------------------------------------------------------------------
932 TQ3Status
DuplicateInstanceData(TQ3Object newObject,E3ClassInfoPtr inClass)933 OpaqueTQ3Object::DuplicateInstanceData (	TQ3Object		newObject,
934 										E3ClassInfoPtr	inClass )
935 	{
936 	TQ3Uns32 parentInstanceSize = 0 ;
937 
938 	// If the object has a parent, duplicate the parent object
939 	if ( inClass->theParent != NULL )
940 		{
941 		parentInstanceSize = inClass->theParent->instanceSize ;
942 		if ( DuplicateInstanceData ( newObject , inClass->theParent ) == kQ3Failure )
943 			return kQ3Failure ;
944 		}
945 
946 
947 
948 	// If the object has any private data, allocate and duplicate it
949 	if ( inClass->instanceSize != parentInstanceSize )
950 		{
951 		// Call the object's duplicate method to initialise it. If the object
952 		// does not have duplicate method, we do a bitwise copy.
953 
954 		if ( ( (E3Root*) inClass )->duplicateMethod != NULL)
955 			{
956 			if ( ( (E3Root*) inClass )->duplicateMethod (
957 					(TQ3Object) this,
958 					(void*) ( (TQ3Uns8*) this + parentInstanceSize ),
959 					newObject,
960 					(void*) ( (TQ3Uns8*) newObject + parentInstanceSize ) ) == kQ3Failure )
961 				{
962 				if ( inClass->theParent != NULL )
963 					newObject->DeleteInstanceData (	inClass->theParent ) ;
964 				return kQ3Failure ;
965 				}
966 			}
967 		else
968 			{
969 			TQ3XElementCopyDuplicateMethod elementDuplicateMethod = NULL ;
970 			if ( Q3_CLASS_INFO_IS_CLASS ( inClass , E3Element ) )
971 				elementDuplicateMethod = ( (E3ElementInfo*) inClass )->elementCopyDuplicateMethod ;
972 
973 			if ( elementDuplicateMethod != NULL )
974 				{
975 				TQ3Status qd3dStatus = elementDuplicateMethod ( (void*) ( (TQ3Uns8*) this + parentInstanceSize ) , (void*) ( (TQ3Uns8*) newObject + parentInstanceSize ) ) ;
976 				if ( qd3dStatus == kQ3Failure )
977 					{
978 					if ( inClass->theParent != NULL )
979 						newObject->DeleteInstanceData ( inClass->theParent ) ;
980 					return kQ3Failure ;
981 					}
982 				}
983 			else
984 				Q3Memory_Copy ( (void*) ( (TQ3Uns8*) this + parentInstanceSize ) ,
985 								(void*) ( (TQ3Uns8*) newObject + parentInstanceSize ) , inClass->instanceSize - parentInstanceSize ) ;
986 			}
987 		}
988 	return kQ3Success ;
989 	}
990 
991 
992 
993 
994 //=============================================================================
995 //      E3ClassTree_DuplicateInstance : Duplicate an instance of a class.
996 //-----------------------------------------------------------------------------
997 TQ3Object
DuplicateInstance(void)998 OpaqueTQ3Object::DuplicateInstance ( void )
999 	{
1000 	// Verify our parameters
1001 	Q3_CLASS_VERIFY(this);
1002 	Q3_ASSERT_VALID_PTR(theClass);
1003 
1004 
1005 
1006 	// Allocate and initialise the object
1007 	TQ3Object newObject = (TQ3Object) Q3Memory_AllocateClear ( theClass->instanceSize + sizeof ( TQ3ObjectType ) ) ;
1008 	if ( newObject == NULL )
1009 		return NULL ;
1010 
1011 	newObject->quesaTag = kQ3ObjectTypeQuesa ;
1012 	newObject->theClass = theClass;
1013 
1014 	// Initialise the trailer
1015 	TQ3ObjectType* instanceTrailer = (TQ3ObjectType *) (((TQ3Uns8 *) newObject) + theClass->instanceSize ) ;
1016 	*instanceTrailer = kQ3ObjectTypeQuesa ;
1017 
1018 
1019 	TQ3Status qd3dStatus = DuplicateInstanceData ( newObject , theClass ) ;
1020 	if ( qd3dStatus == kQ3Failure )
1021 		{
1022 		Q3Memory_Free ( &newObject ) ;
1023 		return NULL ;
1024 		}
1025 
1026 
1027 	// Increment the instance count of the object's class
1028 	theClass->numInstances++ ;
1029 	Q3_ASSERT ( theClass->numInstances > 0 ) ;
1030 
1031 
1032 
1033 	// Verify the object and return it
1034 	Q3_CLASS_VERIFY ( newObject ) ;
1035 
1036 	return newObject ;
1037 	}
1038 
1039 
1040 
1041 //=============================================================================
1042 //      E3ClassTree_FindInstanceData : Find the instance data of an object.
1043 //-----------------------------------------------------------------------------
1044 //		Note :	Returns the instance data of an object or one of its parents.
1045 //
1046 //				If passed kQ3ObjectTypeLeaf, returns the instance data of the
1047 //				leaf object.
1048 //-----------------------------------------------------------------------------
1049 
1050 void *
FindLeafInstanceData(void)1051 OpaqueTQ3Object::FindLeafInstanceData ( void ) // Same as the old FindInstanceData ( kQ3ObjectTypeLeaf ) but simpler
1052 	{
1053 	// Validate our parameters
1054 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), NULL);
1055 	Q3_CLASS_VERIFY(this);
1056 
1057 	if ( theClass->theParent != NULL )
1058 		return (void*) ( (TQ3Uns8*) this + theClass->theParent->instanceSize ) ;
1059 
1060 	return (void*) this ;
1061 	}
1062 
1063 
1064 
1065 
1066 
1067 //=============================================================================
1068 //      E3ClassTree_GetObjectType : Get a method for a class.
1069 //-----------------------------------------------------------------------------
1070 //		Note :	Gets the type of the first sub-class of baseType.
1071 //-----------------------------------------------------------------------------
1072 TQ3ObjectType
GetObjectType(TQ3ObjectType baseType)1073 OpaqueTQ3Object::GetObjectType ( TQ3ObjectType baseType )
1074 	{
1075 	// Verify our parameters
1076 	Q3_CLASS_VERIFY(this);
1077 
1078 	E3ClassInfoPtr aClass = theClass ;
1079 
1080 
1081 	// Walk up to the level immediately below the base class
1082 	while ( ( aClass != NULL )
1083 	&& ( aClass->theParent != NULL )
1084 	&& ( aClass->theParent->classType != baseType ) )
1085 		{
1086 		Q3_ASSERT_VALID_PTR(aClass);
1087 		aClass = aClass->theParent ;
1088 		}
1089 
1090 	if ( ( aClass == NULL ) || ( aClass->theParent == NULL ) )
1091 		return kQ3ObjectTypeInvalid ;
1092 
1093 	return aClass->classType ;
1094 	}
1095 
1096 
1097 
1098 
1099 
1100 //=============================================================================
1101 //      E3ClassTree_GetLeafObject : Get the leaf object for an object.
1102 //-----------------------------------------------------------------------------
1103 //		Note : Not available in release builds.
1104 //-----------------------------------------------------------------------------
1105 #if Q3_DEBUG
1106 TQ3Object
GetLeafObject(void)1107 OpaqueTQ3Object::GetLeafObject ( void )
1108 	{
1109 	return (TQ3Object) this ;
1110 	}
1111 #endif
1112 
1113 
1114 
1115 
1116 
1117 //=============================================================================
1118 //      E3ClassTree_GetClassByType : Find a node in the tree by type.
1119 //-----------------------------------------------------------------------------
1120 E3ClassInfoPtr
GetClass(TQ3ObjectType classType)1121 E3ClassTree::GetClass ( TQ3ObjectType classType )
1122 	{
1123 	E3GlobalsPtr theGlobals = E3Globals_Get () ;
1124 
1125 
1126 
1127 	// Validate our parameters
1128 	Q3_REQUIRE_OR_RESULT(classType != kQ3ObjectTypeInvalid, NULL);
1129 
1130 
1131 
1132 	// We can't find anything if we don't have a tree
1133 	if ( theGlobals->classTree == NULL )
1134 		return NULL ;
1135 
1136 
1137 
1138 	// Find the class
1139 	return (E3ClassInfoPtr) E3HashTable_Find ( theGlobals->classTree, classType ) ;
1140 	}
1141 
1142 
1143 
1144 
1145 
1146 //=============================================================================
1147 //      E3ClassTree_GetClassByName : Find a node in the tree by name.
1148 //-----------------------------------------------------------------------------
1149 //		Note :	NB - the class tree is implemented as a hash table, keyed off
1150 //				the class type. This means that searches by name are very much
1151 //				sub-optimal, and are implemented as a linear search.
1152 //-----------------------------------------------------------------------------
1153 E3ClassInfoPtr
GetClass(const char * className)1154 E3ClassTree::GetClass ( const char *className )
1155 	{
1156 	E3GlobalsPtr theGlobals = E3Globals_Get () ;
1157 
1158 
1159 
1160 	// Validate our parameters
1161 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(className),                    NULL);
1162 	Q3_REQUIRE_OR_RESULT(strlen(className) < kQ3StringMaximumLength, NULL);
1163 
1164 
1165 
1166 	// Make sure we have a root
1167 	if ( theGlobals->classTreeRoot == NULL )
1168 		return NULL ;
1169 
1170 
1171 
1172 	// Find the class, starting at the root
1173 	E3ClassInfoPtr theClass = theGlobals->classTreeRoot->Find ( className ) ;
1174 
1175 	return theClass ;
1176 	}
1177 
1178 
1179 
1180 
1181 
1182 //=============================================================================
1183 //      E3ClassTree_GetClassByObject : Find a node in the tree from an object.
1184 //-----------------------------------------------------------------------------
1185 E3ClassInfoPtr
GetClass(TQ3Object theObject)1186 E3ClassTree::GetClass ( TQ3Object theObject )
1187 	{
1188 	// Validate our parameters
1189 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(theObject), NULL);
1190 
1191 
1192 
1193 	// Get the class
1194 	return theObject->theClass ;
1195 	}
1196 
1197 
1198 
1199 
1200 
1201 E3ClassInfoPtr
GetClass(void)1202 OpaqueTQ3Object::GetClass ( void )
1203 	{
1204 	// Validate our parameters
1205 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), NULL);
1206 
1207 
1208 
1209 	// Get the class
1210 	return theClass ;
1211 	}
1212 
1213 
1214 
1215 
1216 
1217 //=============================================================================
1218 //      E3ClassTree_GetParent : Get the parent of a class, if any.
1219 //-----------------------------------------------------------------------------
1220 //		Note : The root node of the class tree has no parent.
1221 //-----------------------------------------------------------------------------
1222 E3ClassInfoPtr
GetParent(void)1223 E3ClassInfo::GetParent ( void )
1224 	{
1225 	// Validate our parameters
1226 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), NULL);
1227 
1228 
1229 
1230 	// Return the parent of the class
1231 	return theParent ;
1232 	}
1233 
1234 
1235 
1236 
1237 
1238 //=============================================================================
1239 //      E3ClassTree_GetNumChildren : Get the number of children of a class.
1240 //-----------------------------------------------------------------------------
1241 TQ3Uns32
GetNumChildren(void)1242 E3ClassInfo::GetNumChildren ( void )
1243 	{
1244 	// Validate our parameters
1245 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), 0);
1246 
1247 
1248 
1249 	// Return the number of children of the class
1250 	return numChildren ;
1251 	}
1252 
1253 
1254 
1255 
1256 
1257 //=============================================================================
1258 //      E3ClassTree_GetChild : Get a child of a class.
1259 //-----------------------------------------------------------------------------
1260 //		Note : We assume the index of theChild is valid.
1261 //-----------------------------------------------------------------------------
1262 E3ClassInfoPtr
GetChild(TQ3Uns32 childIndex)1263 E3ClassInfo::GetChild ( TQ3Uns32 childIndex )
1264 	{
1265 	// Validate our parameters
1266 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), NULL);
1267 	Q3_REQUIRE_OR_RESULT(childIndex >= 0 && childIndex < numChildren, NULL);
1268 
1269 
1270 
1271 	// Return the child of the class
1272 	E3ClassInfoPtr theChild = theChildren [ childIndex ] ;
1273 	Q3_ASSERT_VALID_PTR(theChild);
1274 
1275 	return theChild ;
1276 	}
1277 
1278 
1279 
1280 
1281 
1282 //=============================================================================
1283 //      E3ClassTree_GetType : Get the type of a class.
1284 //-----------------------------------------------------------------------------
1285 TQ3ObjectType
GetType(void)1286 E3ClassInfo::GetType ( void )
1287 	{
1288 	// Validate our parameters
1289 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), kQ3ObjectTypeInvalid);
1290 
1291 
1292 
1293 	// Return the type of the class
1294 	return classType ;
1295 	}
1296 
1297 
1298 
1299 
1300 
1301 //=============================================================================
1302 //      E3ClassTree_IsType : Is a class an instance of a type?
1303 //-----------------------------------------------------------------------------
1304 TQ3Boolean
IsType(TQ3ObjectType theType)1305 E3ClassInfo::IsType ( TQ3ObjectType theType)
1306 	{
1307 	E3ClassInfoPtr theClass = this ;
1308 
1309 	// Walk up through the class and its parents, checking the type
1310 	while ( theClass != NULL)
1311 		{
1312 		// Check this object
1313 		if (theClass->classType == theType)
1314 			return kQ3True ;
1315 
1316 
1317 
1318 		// Move up a level
1319 		theClass = theClass->theParent;
1320 		}
1321 
1322 
1323 
1324 	// If we're still here, we didn't find the type
1325 	return kQ3False ;
1326 	}
1327 
1328 
1329 
1330 
1331 
1332 //=============================================================================
1333 //      E3ClassTree_GetName : Get the name of a class.
1334 //-----------------------------------------------------------------------------
1335 //		Note : The pointer returned is read-only, and owned by the class tree.
1336 //-----------------------------------------------------------------------------
1337 const char *
GetName(void)1338 E3ClassInfo::GetName ( void )
1339 	{
1340 	// Validate our parameters
1341 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), NULL);
1342 
1343 
1344 
1345 	// Return the name of the class
1346 	return className ;
1347 	}
1348 
1349 
1350 
1351 
1352 
1353 //=============================================================================
1354 //      E3ClassTree_GetMetaHandler : Get the metahandler of a class.
1355 //-----------------------------------------------------------------------------
1356 TQ3XMetaHandler
GetMetaHandler(void)1357 E3ClassInfo::GetMetaHandler ( void )
1358 	{
1359 	// Validate our parameters
1360 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), NULL);
1361 
1362 
1363 
1364 	// Return the metahandler of the class
1365 	return classMetaHandler ;
1366 	}
1367 
1368 
1369 
1370 
1371 
1372 //=============================================================================
1373 //      E3ClassTree_GetInstanceSize : Get the size of a class's instance data.
1374 //-----------------------------------------------------------------------------
1375 TQ3Uns32
GetInstanceSize(void)1376 E3ClassInfo::GetInstanceSize ( void )
1377 	{
1378 	// Validate our parameters
1379 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), 0);
1380 
1381 
1382 
1383 	// Return the size of the instance data for the class
1384 	if ( theParent )
1385 		return instanceSize - theParent->instanceSize ;
1386 
1387 	return instanceSize ;
1388 	}
1389 
1390 
1391 
1392 
1393 
1394 //=============================================================================
1395 //      E3ClassTree_GetNumInstances : Get number of instances of a class.
1396 //-----------------------------------------------------------------------------
1397 TQ3Uns32
GetNumInstances(void)1398 E3ClassInfo::GetNumInstances ( void )
1399 	{
1400 	// Validate our parameters
1401 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), 0);
1402 
1403 
1404 
1405 	// Return the number of instances of the class
1406 	return numInstances ;
1407 	}
1408 
1409 
1410 
1411 
1412 
1413 //=============================================================================
1414 //      E3ClassTree_GetMethod : Get a method for a class.
1415 //-----------------------------------------------------------------------------
1416 //		Note :	When looking for methods, we first check the method table for
1417 //				the class. If this fails, we call the class metahandler.
1418 //
1419 //				When calling the metahandler, we inherit methods that the class
1420 //				does't implement from the parent of the class.
1421 //
1422 //				If we find the method, we store it in the method table to cache
1423 //				it for the next time.
1424 //-----------------------------------------------------------------------------
1425 TQ3XFunctionPointer
GetMethod(TQ3XMethodType methodType)1426 E3ClassInfo::GetMethod ( TQ3XMethodType methodType )
1427 	{
1428 	// Validate our parameters
1429 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), NULL);
1430 
1431 
1432 
1433 	// Find the method
1434 	//
1435 	// We first check the hash table for the class. If this fails, we invoke the
1436 	// metahandler for the class to obtain the method and store it away in the
1437 	// hash table for future use.
1438 	//
1439 	// When invoking the metahandler, we inherit methods that this class doesn't
1440 	// implement from the parent - ensuring that the hash table is eventually
1441 	// populated with all of the (invoked) methods of the class.
1442 	TQ3XFunctionPointer theMethod = (TQ3XFunctionPointer) E3HashTable_Find ( methodTable, methodType ) ;
1443 	if ( theMethod == NULL )
1444 		{
1445 		theMethod = Find_Method ( methodType, kQ3True ) ;
1446 		if (theMethod != NULL)
1447 			E3HashTable_Add ( methodTable, methodType, (void *)theMethod ) ;
1448 		}
1449 
1450 	return theMethod ;
1451 	}
1452 
1453 
1454 
1455 
1456 
1457 //=============================================================================
1458 //      E3ClassTree_GetMethodByObject : Get a method for an object's class.
1459 //-----------------------------------------------------------------------------
1460 TQ3XFunctionPointer
GetMethod(TQ3XMethodType methodType)1461 OpaqueTQ3Object::GetMethod ( TQ3XMethodType methodType )
1462 	{
1463 	// Validate our parameters
1464 	Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(this), NULL);
1465 
1466 
1467 
1468 	// Get the method
1469 	return theClass->GetMethod ( methodType ) ;
1470 	}
1471 
1472 
1473 
1474 
1475 
1476 //=============================================================================
1477 //      E3ClassTree_AddMethod : Add a method for a class.
1478 //-----------------------------------------------------------------------------
1479 //		Note :	In order to support renderers, we need to be able to add
1480 //				methods to the class tree's cache - this is because these
1481 //				objects go through a secondary metahandler, which needs to be
1482 //				queried by the renderer class itself.
1483 //-----------------------------------------------------------------------------
1484 void
AddMethod(TQ3XMethodType methodType,TQ3XFunctionPointer theMethod)1485 E3ClassInfo::AddMethod ( TQ3XMethodType methodType, TQ3XFunctionPointer theMethod )
1486 	{
1487 	// Validate our parameters
1488 	Q3_REQUIRE(Q3_VALID_PTR(this));
1489 	Q3_REQUIRE(Q3_VALID_PTR(theMethod));
1490 
1491 
1492 
1493 	// Add the method to the hash table for the class
1494 	E3HashTable_Add ( methodTable, methodType, (void*)theMethod ) ;
1495 	}
1496 
1497 
1498 
1499 
1500 
1501 //=============================================================================
1502 //      E3ClassTree_AddMethodByType : Add a method for a class given its type.
1503 //-----------------------------------------------------------------------------
1504 void
AddMethod(TQ3ObjectType classType,TQ3XMethodType methodType,TQ3XFunctionPointer theMethod)1505 E3ClassTree::AddMethod ( TQ3ObjectType classType, TQ3XMethodType methodType, TQ3XFunctionPointer theMethod )
1506 	{
1507 	// Validate our parameters
1508 	Q3_REQUIRE(Q3_VALID_PTR(theMethod));
1509 
1510 
1511 
1512 	// Find the class, then add the method
1513 	E3ClassInfoPtr theClass = E3ClassTree::GetClass ( classType ) ;
1514 	Q3_ASSERT( theClass != NULL );
1515 	if ( theClass != NULL )
1516 		theClass->AddMethod ( methodType, theMethod ) ;
1517 	}
1518 
1519 
1520 
1521 
1522 
1523 //=============================================================================
1524 //      E3ClassTree_Dump : Dump some stats on the class tree.
1525 //-----------------------------------------------------------------------------
1526 //		Note :	Dumps some stats on the class tree to a file, for testing hash
1527 //				table sizes/memory leaks/etc.
1528 //-----------------------------------------------------------------------------
1529 void
Dump(void)1530 E3ClassTree::Dump ( void )
1531 	{
1532 	E3GlobalsPtr theGlobals = E3Globals_Get () ;
1533 
1534 
1535 
1536 	// Open our file
1537 	FILE* theFile = fopen("Quesa class tree.dump", "wt");
1538 	if (theFile == NULL)
1539 		return;
1540 
1541 
1542 
1543 	// Write out a header
1544 	time_t theTime = time(NULL);
1545 	fprintf(theFile, "Dumping Quesa class tree - %s", ctime(&theTime));
1546 
1547 
1548 
1549 	// Print some stats on the class tree
1550 	fprintf(theFile, "class tree, collision max = %lu\n",
1551 						E3HashTable_GetCollisionMax(theGlobals->classTree));
1552 
1553 	fprintf(theFile, "class tree, collision avg = %.2f\n",
1554 						E3HashTable_GetCollisionAverage(theGlobals->classTree));
1555 
1556 	fprintf(theFile, "class tree, num items     = %lu\n",
1557 						E3HashTable_GetNumItems(theGlobals->classTree));
1558 
1559 	fprintf(theFile, "class tree, table size    = %lu\n",
1560 						E3HashTable_GetTableSize(theGlobals->classTree));
1561 
1562 	fprintf(theFile, "class tree, stat counters = %d/%d/%d/%d/%d\n",
1563 						theGlobals->classStats1,
1564 						theGlobals->classStats2,
1565 						theGlobals->classStats3,
1566 						theGlobals->classStats4,
1567 						theGlobals->classStats5);
1568 
1569 	fprintf(theFile, "class tree, table size    = %lu\n",
1570 						E3HashTable_GetTableSize(theGlobals->classTree));
1571 
1572 
1573 
1574 	// Dump the class tree, starting at the root
1575 	theGlobals->classTreeRoot->Dump_Class ( theFile, 1 ) ;
1576 
1577 
1578 
1579 	// Clean up
1580 	fclose(theFile);
1581 	}
1582