Re-enabled use of AROS.Boot file due to lack of general enthusiasm for
[tangerine.git] / test / oop / oop.c
blob5d72aab153f31326eadae0112ce440a8c28110e0
1 /*
2 Copyright © 1997-98, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Demo of new OOP system
6 Lang: english
7 */
10 /* These are not necessary in the demo */
11 #define InitSemaphore(x)
12 #define ObtainSemaphore(x)
13 #define ObtainSemaphoreShared(x)
14 #define ReleaseSemaphore(x)
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdlib.h>
20 #include "types.h"
21 #include "oop.h"
22 #include "protos.h"
23 #include "intern.h"
25 #define DEBUG 0
26 #include "debug.h"
28 #define UB(x) ((UBYTE *)x)
29 /* could go into a library base */
30 /*struct SignalSemaphore ClassListSema;
32 struct List ClassList;
33 Class RootClassMem;
35 /* Method implementations */
38 /******************************************************************/
40 /* The oop system code */
42 static struct Bucket **AllocHash(Class *cl, ULONG numnewmethods);
43 static VOID FreeHash(struct Bucket **htable, ULONG htablesize);
44 static BOOL InitHash(Class *cl, struct MethodDescr *mDescr);
46 /****************
47 ** MakeClass **
48 ****************/
49 Class *MakeClass(STRPTR classID
50 ,STRPTR superID
51 ,struct MethodDescr *mDescr
52 ,ULONG instDataSize
53 ,ULONG numNewMethods)
55 #define UB(x) ((UBYTE *)x)
57 #define UnlockCL ReleaseSemaphore( &ClassListSema )
58 #define LockCLShared ObtainSemaphoreShared( &ClassListSema )
59 #define LockCL ObtainSemaphore( &ClassListSema )
61 #define ClassID ClassNode.ln_Name
63 Class *cl, *supercl;
65 /* Find superclass */
66 D(bug("CreateClass(classID=%s, superID=%s, mDescr=%p, instDataSize=%ld)\n",
67 classID, superID, mDescr, instDataSize));
69 LockCL;
70 supercl = (Class *)FindName( &ClassList, superID);
71 if (supercl)
73 /* Mark the class as busy, so it isn't freed while we are allocating
74 ** stuff for our class
76 supercl->SubClassCount ++;
78 UnlockCL;
80 if (!supercl)
81 return (FALSE);
83 D(bug("Found superclass %s\n", supercl->ClassID));
85 /* Allocate class structure */
86 D(bug("Allocating class of size %d\n", sizeof (Class) ));
87 cl = malloc(sizeof (Class));
88 if (cl)
91 cl->ClassID = malloc( strlen(classID) + 1 );
93 if (cl->ClassID)
96 /* Copy class ID */
97 strcpy(cl->ClassID, classID);
98 D(bug("class ID copied\n"));
100 /* Must be done before calling AllocHash().
101 ** This is because AllocHash() must know the number
102 ** of methods in this class and suoerclasses, so it can
103 ** allocate a hashtable of a sane size-
105 cl->SuperClass = supercl;
106 cl->NumMethods = numNewMethods;
108 D(bug("Number of methods introduced by class: %ld\n", numNewMethods));
110 /* Allocate interfaces for class */
111 if ( (cl->HashTable = AllocHash(cl, numNewMethods)) )
113 /* Initialize hash table with methods */
114 if (InitHash(cl, mDescr))
116 /* Well, same as in BOOPSI */
117 cl->InstOffset = supercl->InstOffset + supercl->InstSize;
118 cl->InstSize = instDataSize;
120 supercl->SubClassCount ++;
122 ReturnPtr ("MakeClass", Class *, cl);
124 FreeHash(cl->HashTable, cl->HashTableSize);
128 free(cl->ClassID);
130 free(cl);
133 /* Initalization failed, free lock on superclass */
134 supercl->SubClassCount --;
136 ReturnPtr ("MakeClass", Class *, NULL);
138 } /* CreateClass */
141 /******************
142 ** AllocHash() **
143 ******************/
145 /* Allocates and initializes the hashtable that is used
146 ** to look up interface IDs.
147 ** We always make sure that
150 static ULONG NumHashEntries(ULONG initial)
153 /* Calulates hashsize as 2^n - 1 so that htsize >= 2*initial */
154 ULONG temp = 1;
155 BYTE i;
157 /* Find the highest bit in 'initial' */
158 for (i = 31; i >= 0; i --)
160 if ((temp << i) & initial)
161 break;
164 /* Make sure table is never more than 50% full */
165 i ++;
167 return ((temp << i) - 1);
171 static struct Bucket **AllocHash(Class *cl, ULONG numNewMethods)
174 LONG htable_size;
176 struct Bucket **htable = NULL; /* keep compiler happy */
177 ULONG nummethods, numentries;
179 Class *super;
181 D(bug("AllocHash(class=%s, numNewMethods=%ld)\n",
182 cl->ClassID, numNewMethods));
184 /* Count the number of methods for superclasses and their interfaces.
185 ** Note that the same methods are NOT counted twice as
186 ** class->NumMethods is the number of methods that are new for 'class'.
188 nummethods = numNewMethods;
189 for (super = cl->SuperClass; super; super = super->SuperClass)
190 nummethods += super->NumMethods;
192 D(bug("Total number of methods: %ld\n", nummethods));
194 /* Calculate hash table size, counted in entries */
195 numentries = NumHashEntries(nummethods);
197 /* Calculate hash table size, counted in bytes */
198 htable_size = UB(&htable[numentries]) - UB(&htable[0]);
200 D(bug("Hash table size: %ld\n", htable_size));
202 /* Save hash table size, counted in entries */
203 cl->HashTableSize = numentries;
205 /* Allocate hash table */
206 htable = malloc(htable_size);
207 if (htable)
208 memset(htable, 0, htable_size);
210 ReturnPtr ("AllocHash", struct Bucket **, htable);
213 static BOOL AddMethods(Class *cl, struct Bucket **desthtable, ULONG htable_size)
215 /* The class's methods into the supplied hashtable */
217 ULONG i;
219 D(bug("AddMethods(cl=%s, desthtable=%p, htable_size=%ld)\n",
220 cl->ClassID, desthtable, htable_size));
222 /* For each entry in the class' hashtable */
223 for (i = 0; i < cl->HashTableSize; i ++)
225 struct Bucket *b;
226 D(bug("Adding methods at idx %ld\n", i));
228 /* For each bucket at the current entry */
229 for (b = cl->HashTable[i]; b; b = b->Next)
231 ULONG idx;
232 struct Bucket *new_b, *temp_b;
234 D(bug("Adding method %ld\n", b->MethodID));
236 /* Allocate new bucket into which the method is copied */
237 new_b = malloc( sizeof (struct Bucket) );
238 if (!new_b)
239 ReturnBool ("AddMethods", FALSE);
241 /* Copuy methid info into new bucket */
242 new_b->MethodID = b->MethodID;
243 new_b->MethodFunc = b->MethodFunc;
244 new_b->mClass = b->mClass;
247 /* Add bucket to destination hashtable */
248 idx = CalcHash(b->MethodID, htable_size);
250 /* Adding it at the first position in the bucket linked list */
251 temp_b = desthtable[idx];
252 desthtable[idx] = new_b;
253 new_b->Next = temp_b;
255 } /* for (each bucket at the current index) */
257 } /* for (each index in the hashtable) */
258 ReturnBool ("AddMethods", TRUE);
261 static BOOL InitHash(Class *cl, struct MethodDescr *mDescr)
263 D(bug("InitHash(cl=%s, mDescr=%p\n", cl->ClassID, mDescr));
264 if (cl->SuperClass) /* This test is so we can use this function to initalize ROOTCLASS */
266 D(bug("Superclass found: %s\n", cl->SuperClass->ClassID));
268 /* Put all superclass' methods into our hash table */
269 if (!AddMethods(cl->SuperClass, cl->HashTable, cl->HashTableSize))
270 ReturnBool ("InitHash", FALSE);
273 /* Override/insert the methods supplied in MakeClass() */
274 D(bug("Ovverriding methods\n"));
276 /* For each entry in the method description array supplied to MakeClass() */
277 for (; mDescr->MethodFunc; mDescr ++)
279 ULONG idx;
280 struct Bucket *b;
281 BOOL must_allocate_new = TRUE;
283 /* Look at which entry in the hdestination hashtable to put the ID */
284 idx = CalcHash(mDescr->MethodID, cl->HashTableSize);
286 /* Search for allready existing bucket containing the ID */
287 for (b = cl->HashTable[idx]; b; b = b->Next)
289 if (b->MethodID == mDescr->MethodID)
292 /* The method existed in the superclass. Override it */
293 b->MethodFunc = mDescr->MethodFunc;
294 b->mClass = cl;
296 must_allocate_new = FALSE;
297 break;
301 if (must_allocate_new)
303 struct Bucket *new_b, *temp_b;
305 /* A new method introduced by this class
306 ** (belonging to this class' interface)
309 /* Allocate bucket for the new mwthod */
311 new_b = malloc( sizeof (struct Bucket) );
312 if(!new_b)
313 ReturnBool("InitHash", FALSE);
315 new_b->MethodID = mDescr->MethodID;
316 new_b->MethodFunc = mDescr->MethodFunc;
317 new_b->mClass = cl;
319 /* Insert the bucket at the start of the hash entry */
320 temp_b = cl->HashTable[idx];
322 cl->HashTable[idx] = new_b;
324 /* If there are no buckets in this table entry,
325 ** dest_b will be NULL, and new_b->Next becomes NULL
327 new_b->Next = temp_b;
330 } /* for (each method this class overrides) */
331 ReturnBool ("InitHash", TRUE);
335 static VOID FreeHash(struct Bucket **htable, ULONG htablesize)
337 ULONG i;
339 /* Well, frees a hashtable + the buckets */
340 for (i = 0; i < htablesize; i ++)
342 struct Bucket *b, *next_b;
344 b = htable[i];
345 while (b)
347 next_b = b->Next;
348 free(b);
349 b = next_b;
353 free(htable);
354 return;
357 /*****************
358 ** Freelass() **
359 *****************/
361 VOID FreeClass(Class *cl)
364 D(bug("FreeClass(cl=%s)\n", cl->ClassID));
367 if (cl)
369 /* What level are we ? */
370 if (cl->SuperClass == NULL) /* Someone trying to remove the rootclass */
371 ReturnVoid("FreeClass (Someone trying to remove rootclass)");
373 FreeHash(cl->HashTable, cl->HashTableSize);
374 free(cl->ClassID);
375 free(cl);
377 ReturnVoid("FreeClass");
380 /************************
381 ** Rootclass methods **
382 ************************/
383 struct RootData
385 ULONG dummy;
388 #define NUMROOTMETHODS 2
390 Object *Root_New(Class *rootcl, Class *cl, Msg msg)
392 struct _Object *o;
394 D(bug("Root::New(cl=%s, msg = %p)\n",
395 cl->ClassNode.ln_Name, msg));
397 /* Allocate memory for the object */
398 D(bug("Object size: %ld\n", cl->InstOffset + cl->InstSize + sizeof (struct _Object)));
399 o = malloc(cl->InstOffset + cl->InstSize + sizeof (struct _Object) );
400 if (o)
402 D(bug("Mem allocated: %p\n", o));
403 o->oClass = cl;
405 cl->ObjectCount ++;
407 ReturnPtr ("Root::New", Object *, BASEOBJECT(o) );
410 ReturnPtr ("Root::New", Object *, NULL);
413 VOID Root_Dispose(Class *cl, Object *o, Msg msg)
415 D(bug("Root::Dispose(o=%p, oclass=%s)\n", o, _OBJECT(o)->oClass->ClassNode.ln_Name));
417 _OBJECT(o)->oClass->ObjectCount --;
418 D(bug("Object mem: %p\n", _OBJECT(o) ));
419 free(_OBJECT(o));
421 ReturnVoid("Root::Dispose");
425 /****************
426 ** InitOOP() **
427 ****************/
429 #define NUM_ROOT_METHODS 2
432 BOOL InitOOP()
434 Class *RootClass = &RootClassMem;
435 struct MethodDescr RootMethodDescr[] =
437 { Root_New, M_New },
438 { Root_Dispose, M_Dispose},
439 { NULL, 0 }
443 InitSemaphore(&ClassListSema);
444 NEWLIST(&ClassList);
447 /* We must initialize the rootclass by hand */
449 RootClass->SuperClass = NULL; /* !!! Very important to do before AllocHash() !!! */
450 RootClass->HashTable = AllocHash(RootClass, NUM_ROOT_METHODS);
451 if (RootClass->HashTable)
453 if (InitHash(RootClass, RootMethodDescr))
455 /* Fill in other stuff into the class structure */
456 RootClass->ClassNode.ln_Name = ROOTCLASS;
457 RootClass->InstOffset = 0UL;
458 RootClass->InstSize = sizeof (struct RootData);
459 RootClass->NumMethods = NUMROOTMETHODS;
460 RootClass->SubClassCount = 0UL;
461 RootClass->ObjectCount = 0UL;
462 RootClass->SuperClass = NULL;
464 /* Add the class. Arbitration not necessary, as
465 ** noone know about us yet
467 AddTail(&ClassList, &(RootClass->ClassNode) );
469 return (TRUE);
472 FreeHash(RootClass->HashTable, RootClass->HashTableSize);
476 return (FALSE);
480 /*******************
481 ** CleanupOOP() **
482 *******************/
483 VOID CleanupOOP()
486 Class *RootClass = &RootClassMem;
488 D(bug("CleanupOOP()\n"));
490 FreeHash(RootClass->HashTable, RootClass->HashTableSize);
492 ReturnVoid("CleanupOOP");
495 /*****************
496 ** NewObject() **
497 *****************/
498 Object *NewObject(Class *cl, STRPTR classID, Msg msg)
500 Object *o;
502 struct P_New p;
504 if (!cl)
506 LockCL;
507 cl = (Class *)FindName(&ClassList, classID);
508 if (cl)
509 cl->ObjectCount ++; /* We don't want the class to be freed while we work on it */
511 UnlockCL;
513 if (!cl)
514 return (NULL);
516 /* Create a new instance */
518 p.MethodID = M_New;
519 p.ParamPtr = msg;
521 o = (Object *)CoerceMethodA(cl, (Object *)cl, (Msg)&p);
522 if (!o)
524 cl->ObjectCount --; /* Object creation failed, release lock */
526 ReturnPtr ("NewInstance", Object *, o);
529 VOID DisposeObject(Object *o)
531 ULONG methodid = M_Dispose;
534 Class *cl = OCLASS(o);
536 DoMethodA(o, (Msg)&methodid);
538 cl->ObjectCount --;
540 return;
543 /***************
544 ** AddClass **
545 ***************/
546 VOID AddClass(Class *cl)
549 LockCL;
550 AddTail(&ClassList, &(cl->ClassNode) );
551 UnlockCL;
552 return;
555 /******************
556 ** RemoveClass **
557 ******************/
558 VOID RemoveClass(Class *cl)
560 LockCL;
561 Remove(&(cl->ClassNode) );
562 UnlockCL;
564 return;