2 Copyright © 1997-98, The AROS Development Team. All rights reserved.
5 Desc: Demo of new OOP system
10 /* These are not necessary in the demo */
11 #define InitSemaphore(x)
12 #define ObtainSemaphore(x)
13 #define ObtainSemaphoreShared(x)
14 #define ReleaseSemaphore(x)
28 #define UB(x) ((UBYTE *)x)
29 /* could go into a library base */
30 /*struct SignalSemaphore ClassListSema;
32 struct List ClassList
;
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
);
49 Class
*MakeClass(STRPTR classID
51 ,struct MethodDescr
*mDescr
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
66 D(bug("CreateClass(classID=%s, superID=%s, mDescr=%p, instDataSize=%ld)\n",
67 classID
, superID
, mDescr
, instDataSize
));
70 supercl
= (Class
*)FindName( &ClassList
, superID
);
73 /* Mark the class as busy, so it isn't freed while we are allocating
74 ** stuff for our class
76 supercl
->SubClassCount
++;
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
));
91 cl
->ClassID
= malloc( strlen(classID
) + 1 );
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
);
133 /* Initalization failed, free lock on superclass */
134 supercl
->SubClassCount
--;
136 ReturnPtr ("MakeClass", Class
*, NULL
);
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 */
157 /* Find the highest bit in 'initial' */
158 for (i
= 31; i
>= 0; i
--)
160 if ((temp
<< i
) & initial
)
164 /* Make sure table is never more than 50% full */
167 return ((temp
<< i
) - 1);
171 static struct Bucket
**AllocHash(Class
*cl
, ULONG numNewMethods
)
176 struct Bucket
**htable
= NULL
; /* keep compiler happy */
177 ULONG nummethods
, numentries
;
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
);
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 */
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
++)
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
)
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
) );
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
++)
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
;
296 must_allocate_new
= FALSE
;
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
) );
313 ReturnBool("InitHash", FALSE
);
315 new_b
->MethodID
= mDescr
->MethodID
;
316 new_b
->MethodFunc
= mDescr
->MethodFunc
;
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
)
339 /* Well, frees a hashtable + the buckets */
340 for (i
= 0; i
< htablesize
; i
++)
342 struct Bucket
*b
, *next_b
;
361 VOID
FreeClass(Class
*cl
)
364 D(bug("FreeClass(cl=%s)\n", cl
->ClassID
));
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
);
377 ReturnVoid("FreeClass");
380 /************************
381 ** Rootclass methods **
382 ************************/
388 #define NUMROOTMETHODS 2
390 Object
*Root_New(Class
*rootcl
, Class
*cl
, Msg msg
)
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
) );
402 D(bug("Mem allocated: %p\n", o
));
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
) ));
421 ReturnVoid("Root::Dispose");
429 #define NUM_ROOT_METHODS 2
434 Class
*RootClass
= &RootClassMem
;
435 struct MethodDescr RootMethodDescr
[] =
438 { Root_Dispose
, M_Dispose
},
443 InitSemaphore(&ClassListSema
);
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
) );
472 FreeHash(RootClass
->HashTable
, RootClass
->HashTableSize
);
486 Class
*RootClass
= &RootClassMem
;
488 D(bug("CleanupOOP()\n"));
490 FreeHash(RootClass
->HashTable
, RootClass
->HashTableSize
);
492 ReturnVoid("CleanupOOP");
498 Object
*NewObject(Class
*cl
, STRPTR classID
, Msg msg
)
507 cl
= (Class
*)FindName(&ClassList
, classID
);
509 cl
->ObjectCount
++; /* We don't want the class to be freed while we work on it */
516 /* Create a new instance */
521 o
= (Object
*)CoerceMethodA(cl
, (Object
*)cl
, (Msg
)&p
);
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
);
546 VOID
AddClass(Class
*cl
)
550 AddTail(&ClassList
, &(cl
->ClassNode
) );
558 VOID
RemoveClass(Class
*cl
)
561 Remove(&(cl
->ClassNode
) );