Merging NList MCC 0.119 into the main branch.
[AROS.git] / test / oopdemo.c
bloba7a9696c60ee91bd97cc68fc56e86c888a5b40ba
1 /*
2 Copyright © 1995-2002, The AROS Development Team. All rights reserved.
3 $Id$
5 Demo of new OOP system
6 */
8 /* Prevent inclusion of <intuition/classes.h>,
9 * which is referenced in the amiga inline macros
10 * imported below by <proto/exec.h>.
12 #define INTUITION_CLASSES_H
14 #include <proto/exec.h>
15 #include <exec/memory.h>
16 #include <exec/lists.h>
17 #include <exec/semaphores.h>
19 #include <string.h>
20 #include <stdio.h>
22 #include "class.h"
24 #define SDEBUG 0
25 #define DEBUG 0
26 #include <aros/debug.h>
29 #define ENABLE_RT 1
30 #include <aros/rt.h>
35 /**************** String class definitions ***********************/
37 /* Subclass of root */
38 #define CL_Level_String (CL_Level_Root + 1)
39 #define IF_Level_String (IF_Level_Root + 1)
41 #define STRINGCLASSNAME "stringclass"
43 /* Public New() parameter struct */
44 typedef struct NewStringParam
46 STRPTR InitStr;
47 ULONG MaxStrLen;
48 } P_String;
50 typedef struct StringInterface
52 VOID (*SetStr)(Object, STRPTR);
53 VOID (*PrintStr)(Object);
54 } IString;
56 typedef struct StringIFStorage
58 IRoot *IRoot;
59 IString *IString;
61 } IStringTable;
64 /* Private instance data definition */
65 struct StringData
67 STRPTR Buffer;
68 ULONG MaxStrLen;
71 /**************************************************/
72 VOID CleanupOOP();
73 BOOL InitOOP();
74 Object NewInstance(STRPTR classID, APTR, APTR *interfaceStorage);
75 Class *CreateClass(STRPTR classID, STRPTR superID, struct MTabDescr *mTabDescr,
76 ULONG instDataSize);
77 VOID DeleteClass(STRPTR classID);
80 /* could go into a library base */
81 struct SignalSemaphore ClassListSema;
82 struct List ClassList;
83 Class RootClassMem;
85 /*************************** String ***************************/
88 /* Method implementations */
90 Object String_New(Class *cl, P_String *p)
92 ULONG max = 50;
93 STRPTR str = "";
94 /* Get parent interface */
95 IRoot *ir = (IRoot *)CL_INTERFACE(cl, CL_Level_Root, IF_Level_Root);
96 Object o;
98 /* Whether it accepts NULL initparameter is class dependant.
99 ** The parameter could very well be a taglist
101 if (p)
103 if (p->InitStr)
104 str = p->InitStr;
105 if (p->MaxStrLen)
106 max = p->MaxStrLen;
109 o = ir->New(cl, NULL);
110 if (o)
112 STRPTR buffer;
114 /* Get instance data */
115 struct StringData *data = INST_DATA(o, CL_Level_String);
117 data->Buffer = NULL;
118 data->MaxStrLen = 0;
120 buffer = AllocVec(max + 1, MEMF_ANY);
121 if (buffer)
124 strncpy(buffer, str, max);
126 data->Buffer = buffer;
127 data->MaxStrLen = max;
129 return (o);
133 /* Do a "CoerceMethod" (I get the Root interface from the *String* class) */
134 ir = (IRoot *)CL_INTERFACE(cl, CL_Level_String, IF_Level_Root);
135 ir->Dispose(o);
137 return (NULL);
140 VOID String_Dispose(Object o)
142 struct StringData *data = INST_DATA(o, CL_Level_String);
144 IRoot *ir = (IRoot *)OBJ_INTERFACE(o, CL_Level_Root, IF_Level_Root);
147 if (data->Buffer)
149 FreeVec(data->Buffer);
152 ir->Dispose(o); /* Call supermethod */
154 return;
157 VOID String_SetStr(Object o, STRPTR str)
159 struct StringData *data = INST_DATA(o, CL_Level_String);
162 strncpy(data->Buffer, str, data->MaxStrLen);
164 return;
167 VOID String_PrintStr(Object o)
169 struct StringData *data;
171 data = INST_DATA(o, CL_Level_String);
173 printf("%s", data->Buffer);
175 return;
178 /* Method tables */
179 IRoot str_iroot = { (Object (*)(Class *, APTR))String_New, String_Dispose};
181 IString str_istring = {String_SetStr, String_PrintStr};
183 struct MTabDescr str_descr[] =
185 {(APTR *)&str_iroot, 2}, /* Table contains two entries */
186 {(APTR *)&str_istring, 2} /* Table contains two entries */
190 int main(int argc, char **argv)
193 SDInit();
195 RT_Init();
197 if (InitOOP())
199 struct Node *n;
200 Object o;
203 printf("Object system initialized\n");
205 /* Initialize the string class */
206 if (CreateClass(STRINGCLASSNAME, ROOTCLASSNAME, str_descr, sizeof (struct StringData)) )
208 IStringTable st;
209 P_String pstr = {"String test", 80};
211 printf("Class list:\n");
212 ForeachNode(&ClassList, n)
214 printf("%s\n", n->ln_Name);
216 printf("\n\n");
218 /* Create a new instance */
219 o = NewInstance(STRINGCLASSNAME, &pstr, (APTR *)&st);
220 if (o)
222 IString *is = st.IString;
224 printf("New instance: %p\n", o);
226 printf("Current string: ");
227 is->PrintStr(o);
228 printf("\n");
230 printf("Setting string\n");
231 is->SetStr(o, "Blah");
233 printf("New string value: ");
234 is->PrintStr(o);
235 printf("\n");
237 st.IRoot->Dispose(o);
239 printf("object deleted\n");
241 DeleteClass(STRINGCLASSNAME);
243 CleanupOOP();
246 RT_Exit();
248 return (0);
254 /******************************************************************/
256 /* The oop system code */
258 BOOL AllocInterfaces(Class *cl);
259 VOID FreeInterfaces(Class *cl);
264 /******************
265 ** CreateClass **
266 ******************/
267 Class *CreateClass(STRPTR classID, STRPTR superID, struct MTabDescr *mTabDescr,
268 ULONG instDataSize)
270 #define UB(x) ((UBYTE *)x)
272 #define UnlockCL ReleaseSemaphore( &ClassListSema )
273 #define LockCLShared ObtainSemaphoreShared( &ClassListSema )
274 #define LockCL ObtainSemaphore( &ClassListSema )
276 #define ClassID ClassNode.ln_Name
278 Class *cl, *supercl;
279 UWORD super_count;
281 /* Find superclass */
282 EnterFunc(bug("CreateClass(classID=%s, superID=%s, mTabDescr=%p, instDataSize=%d)\n",
283 classID, superID, mTabDescr, instDataSize));
285 LockCL;
286 supercl = (Class *)FindName( &ClassList, superID);
287 if (supercl)
289 /* Mark the class as busy, so it isn't freed while we are allocating
290 ** stuff for our class
292 supercl->SubClassCount ++;
294 UnlockCL;
296 if (!supercl)
297 return (FALSE);
299 D(bug("Found superclass %s\n", supercl->ClassID));
301 /* Allocate class structure */
302 D(bug("Allocating class of size %d\n", sizeof (Class) ));
303 cl = AllocMem(sizeof (Class), MEMF_PUBLIC|MEMF_CLEAR); /* Can be made read-only for MP */
304 if (cl)
306 ULONG cltab_size, iftab_size;
308 Class *superptr;
310 D(bug("Allocated class structure\n"));
312 /* Find this class's level in the hierarchy */
314 /* How many super-classes are there ? */
315 super_count = 1; /* have allready found one superclass */
316 for (superptr = supercl; superptr->SuperClass; superptr = superptr->SuperClass)
317 super_count ++;
319 D(bug("Number of superclasses: %d\n", super_count));
321 /* Get size of interface table */
322 iftab_size = UB(&(cl->InterfaceTable[super_count + 1])) - UB(&(cl->InterfaceTable[0]));
323 D(bug("IF tabsize: %d\n", iftab_size));
325 /* Allocate interface table pointers */
326 cl->InterfaceTable = AllocMem(iftab_size, MEMF_PUBLIC|MEMF_CLEAR); /* Can be made read-only for MP */
328 /* Get size of class table */
329 cltab_size = UB( &(cl->ClassTable[super_count + 1])) - UB( &(cl->ClassTable[0]));
330 D(bug("CL tabsize: %d\n", cltab_size));
332 /* Allocate interface methodtable pointers */
333 cl->ClassTable = AllocMem(cltab_size, MEMF_PUBLIC|MEMF_CLEAR); /* Can be made read-only for MP */
334 D(bug("Classtable allocated: %p\n"));
336 cl->ClassID = AllocVec( strlen(classID) + 1, MEMF_PUBLIC);
338 if (cl->InterfaceTable && cl->ClassTable && cl->ClassID)
341 D(bug("Tables allocated\n"));
342 /* Copy class ID */
343 strcpy(cl->ClassID, classID);
344 D(bug("class ID copied\n"));
346 /* !!! Important to fill in these before calling AllocInterfaces */
347 cl->NumMethods = mTabDescr[super_count].NumMethods;
348 cl->SuperClass = supercl;
350 D(bug("Number of methods introduced by class: %d\n", cl->NumMethods));
352 /* Allocate interfaces for class */
353 if (AllocInterfaces(cl))
355 IPTR *iftab;
356 APTR *mtab;
357 WORD idx, m_idx;
358 Class *superptr = supercl;
359 IPTR *ifptr;
361 /* Fill in the interfaces from the superclass */
362 for (idx = super_count - 1; idx >= 0; idx -- )
364 D(bug("Getting interface %d with %d methods from class %s\n",
365 idx, superptr->NumMethods, superptr->ClassID));
367 CopyMem( superptr->InterfaceTable[idx],
368 cl->InterfaceTable[idx],
369 UB( &ifptr[superptr->NumMethods]) - UB( &ifptr[0]) );
371 /* And fill in the class table while we're at it */
372 cl->ClassTable[idx] = superptr;
373 superptr = superptr->SuperClass;
377 /* Fill in ourselves in the classtable */
378 cl->ClassTable[super_count] = cl;
380 /* Override the interfaces with our own methods */
381 for (idx = super_count - 1; idx >= 0; idx -- )
383 mtab = mTabDescr[idx].Table;
384 iftab = cl->InterfaceTable[idx];
386 for (m_idx = mTabDescr[idx].NumMethods - 1; m_idx >= 0; m_idx -- )
388 if (mtab[m_idx] != NULL)
390 D(bug("Overriding method at cl_idx=%d, method=%d\n", idx, m_idx));
391 D(bug("Method overrided: %p, overrider: %p\n", iftab[m_idx], mtab[m_idx]));
392 /* Override method */
393 iftab[m_idx] = (IPTR)mtab[m_idx];
396 } /* For each method in the method table */
398 } /* For each level above us in the hierarchy */
400 /* Fill in the methods that are new with this class */
401 D(bug("Filling in methods at level %d\n", super_count));
402 CopyMem(mTabDescr[super_count].Table,
403 cl->InterfaceTable[super_count],
404 UB( &ifptr[ mTabDescr[super_count].NumMethods ]) - UB( &ifptr[0]) );
407 /* Update instance data info */
408 cl->InstOffset = supercl->InstOffset + supercl->InstSize;
409 cl->InstSize = instDataSize;
411 cl->SuperCount = super_count;
413 LockCL;
414 AddTail(&ClassList, &(cl->ClassNode) );
415 UnlockCL;
417 ReturnPtr ("CreateClass", Class *, cl);
421 if (cl->InterfaceTable)
422 FreeMem(cl->InterfaceTable, iftab_size);
424 if (cl->ClassTable)
425 FreeMem(cl->ClassTable, cltab_size);
427 if (cl->ClassID)
428 FreeVec(cl->ClassID);
432 FreeMem(cl, sizeof (struct IClass));
436 /* Initalization failed, free lock on superclass */
437 supercl->SubClassCount --;
439 ReturnPtr ("CreateClass", Class *, NULL);
441 } /* CreateClass */
445 /************************
446 ** AllocInterfaces() **
447 ************************/
448 BOOL AllocInterfaces(Class *param_cl)
450 IPTR **ifptr = param_cl->InterfaceTable;
451 Class *cl;
453 EnterFunc(bug("AllocInterfaces(cl=%s)\n", param_cl->ClassID));
455 /* Allocate the interfaces */
456 for ( cl = param_cl ; cl; cl = cl->SuperClass )
458 ULONG size = UB( &((*ifptr)[cl->NumMethods])) - UB( &((*ifptr)[0]));
460 D(bug("Allocating interface for class %s, size=%d\n", cl->ClassID, size));
461 *ifptr = AllocMem(size, MEMF_PUBLIC|MEMF_CLEAR); /* Should be read-only for MP */
462 D(bug("IF Allocated: %p\n", *ifptr));
463 if (!*ifptr)
465 FreeInterfaces(param_cl);
466 ReturnBool ("AllocInterfaces", FALSE);
469 ifptr ++;
472 ReturnBool ("AllocInterfaces", TRUE);
475 /***********************
476 ** FreeInterfaces() **
477 ***********************/
478 VOID FreeInterfaces(Class *cl)
480 IPTR **ifptr = cl->InterfaceTable;
482 EnterFunc(bug("FreeInterfaces(cl=%s)\n", cl->ClassID));
484 for ( ; cl; cl = cl->SuperClass )
486 if (*ifptr)
488 ULONG size = UB( &(*ifptr)[cl->NumMethods]) - UB(&(*ifptr)[0]);
490 D(bug("Freeing IF %p of size %d\n", *ifptr, size));
491 FreeMem(*ifptr, size);
494 ifptr ++;
496 ReturnVoid ("FreeInterfaces");
501 /******************
502 ** DeleteClass **
503 ******************/
505 VOID DeleteClass(STRPTR classID)
507 Class *cl;
509 EnterFunc(bug("DeleteClass(classID=%s)\n", classID));
511 LockCLShared;
512 cl = (Class *)FindName( &ClassList, classID);
513 UnlockCL;
515 if (cl)
517 ULONG size;
518 ULONG tab_entries = cl->SuperCount + 1;
521 /* What level are we ? */
522 if (cl->SuperCount == 0) /* Someone trying to remove the rootclass */
523 ReturnVoid("DeleteClass (Someone trying to remove rootclass)");
525 /* Free interfaces */
526 FreeInterfaces(cl);
528 size = UB(&cl->InterfaceTable[tab_entries]) - UB(&cl->InterfaceTable[0]);
529 D(bug("Freeing IFTab of size %d\n", size));
530 FreeMem(cl->InterfaceTable, size);
532 size = UB(&cl->ClassTable[tab_entries]) - UB(&cl->ClassTable[0]);
533 D(bug("Freeing ClassTab of size %d at %p\n", size, cl->ClassTable));
534 FreeMem(cl->ClassTable, size);
536 /* Free class ID */
537 D(bug("Freeing class ID %s\n", cl->ClassID));
538 FreeVec(cl->ClassID);
539 LockCL;
540 Remove(&(cl->ClassNode));
541 UnlockCL;
543 FreeMem(cl, sizeof (Class));
545 ReturnVoid("DeleteClass");
548 /************************
549 ** Rootclass methods **
550 ************************/
551 struct RootData
553 ULONG dummy;
556 #define NUMROOTMETHODS 2
558 Object Root_New(Class *cl, APTR param)
560 struct _Object *o;
562 EnterFunc(bug("Root::New(cl=%s, param = %p)\n",
563 cl->ClassNode.ln_Name, param));
565 /* Allocate memory for the object */
566 D(bug("Object size: %d\n", cl->InstOffset + cl->InstSize + sizeof (struct _Object)));
567 o = AllocVec(cl->InstOffset + cl->InstSize + sizeof (struct _Object), MEMF_ANY);
568 if (o)
570 D(bug("Mem allocated: %p\n", o));
571 o->Class = cl;
573 cl->ObjectCount ++;
575 ReturnPtr ("Root::New", Object, BASEOBJECT(o) );
578 ReturnPtr ("Root::New", Object, NULL);
581 VOID Root_Dispose(Object o)
583 EnterFunc(bug("Root::Dispose(o=%p, oclass=%s)\n", o, _OBJECT(o)->Class->ClassNode.ln_Name));
585 _OBJECT(o)->Class->ObjectCount --;
586 D(bug("Object mem: %p, size: %d\n", _OBJECT(o), ((ULONG *)_OBJECT(o))[-1] ));
587 FreeVec(_OBJECT(o));
589 ReturnVoid("Root::Dispose");
593 /****************
594 ** InitOOP() **
595 ****************/
598 BOOL InitOOP()
600 Class *RootClass = &RootClassMem;
602 InitSemaphore(&ClassListSema);
603 NEWLIST(&ClassList);
605 /* We must initialize the rootclass by hand */
607 /* Class table. Only needs place for myself */
608 RootClass->ClassTable = (struct IClass **)AllocMem( sizeof(Class *), MEMF_PUBLIC);
609 if (RootClass->ClassTable)
612 /* Interface table. Only needs place for our own interface */
613 RootClass->InterfaceTable = (IPTR **)AllocMem( sizeof (IPTR *), MEMF_PUBLIC);
614 if (RootClass->InterfaceTable)
616 IPTR *interface;
617 ULONG if_size;
619 /* Allocate interface */
620 if_size = UB(&interface[NUMROOTMETHODS]) - UB(&interface[0]);
621 interface = AllocMem(if_size, MEMF_PUBLIC);
622 if (interface)
624 /* Fill in methods */
625 interface[0] = (IPTR)Root_New;
626 interface[1] = (IPTR)Root_Dispose;
628 RootClass->InterfaceTable[0] = interface;
630 /* Fill in other stuff into the class structure */
631 RootClass->ClassNode.ln_Name = ROOTCLASSNAME;
632 RootClass->ClassTable[0] = RootClass;
633 RootClass->InstOffset = 0UL;
634 RootClass->InstSize = sizeof (struct RootData);
635 RootClass->NumMethods = NUMROOTMETHODS;
636 RootClass->SubClassCount = 0UL;
637 RootClass->ObjectCount = 0UL;
638 RootClass->SuperClass = NULL;
639 RootClass->SuperCount = 0UL;
641 /* Add the class. Arbitration not necessary, as
642 ** noone know about us yet
644 AddTail(&ClassList, &(RootClass->ClassNode) );
646 return (TRUE);
649 FreeMem(RootClass->InterfaceTable, sizeof (IPTR **));
651 FreeMem(RootClass->ClassTable, sizeof (Class *));
655 return (FALSE);
659 /*******************
660 ** CleanupOOP() **
661 *******************/
662 VOID CleanupOOP()
664 IPTR *interface;
665 ULONG if_size;
667 Class *RootClass = &RootClassMem;
669 FreeMem(RootClass->ClassTable, sizeof (APTR *));
671 interface = RootClass->InterfaceTable[0];
672 if_size = UB(&interface[NUMROOTMETHODS]) - UB(&interface[0]);
674 FreeMem(interface, if_size);
676 FreeMem(RootClass->InterfaceTable, sizeof (IPTR **));
678 return;
681 /*******************
682 ** NewInstance() **
683 *******************/
684 Object NewInstance(STRPTR classID, APTR param, APTR *interfaceStorage)
686 Class *cl;
687 LONG idx;
689 Object o;
691 EnterFunc(bug("NewInstance(classID=%s, param=%p, ifStorage=%p)\n",
692 classID, param, interfaceStorage));
694 LockCL;
695 cl = (Class *)FindName(&ClassList, classID);
696 if (cl)
697 cl->ObjectCount ++; /* We don't want the class to be freed while we work on it */
698 UnlockCL;
700 if (!cl)
701 return (NULL);
703 /* Get interfaces from class */
705 for ( idx = cl->SuperCount; idx >= 0; idx -- )
706 interfaceStorage[idx] = cl->InterfaceTable[idx];
708 /* Create a new instance */
709 D(bug("Calling New() at %p\n", ((IRoot *) interfaceStorage[cl->SuperCount])->New));
710 o = ((IRoot *) interfaceStorage[0])->New(cl, param);
712 if (!o)
714 LockCL;
715 cl->ObjectCount --; /* Object creation failed, release lock */
716 UnlockCL;
718 ReturnPtr ("NewInstance", Object, o);