Commit of the code which was suggested by Georg as a fix for:
[cake.git] / rom / oop / hiddmetaclass.c
blobde55de091b42f7eff506b94ac9b4d58ba87b7738
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: OOP HIDD metaclass
6 Lang: english
7 */
9 #include <string.h>
11 #include <proto/exec.h>
12 #include <proto/utility.h>
13 #include <exec/memory.h>
15 #include <proto/oop.h>
17 #include "intern.h"
19 #undef SDEBUG
20 #undef DEBUG
21 #define SDEBUG 0
22 #define DEBUG 0
23 #include <aros/debug.h>
25 #define UB(x) ((UBYTE *)x)
27 #define MD(cl) ((struct metadata *)cl)
29 #define IntCallMethod(cl, o, msg) \
30 { \
31 register struct IFMethod *ifm; \
32 D(bug("mid=%ld\n", *msg)); ifm = &((struct hiddmeta_inst *)cl)->data.methodtable[*msg]; \
33 D(bug("ifm: func %p, cl %p\n", ifm->MethodFunc, ifm->mClass)); return (ifm->MethodFunc(ifm->mClass, o, msg)); \
37 static VOID get_info_on_ifs(OOP_Class *super
38 ,struct OOP_InterfaceDescr *ifdescr
39 ,ULONG *total_num_methods_ptr
40 ,ULONG *total_num_ifs_ptr
41 ,struct IntOOPBase *OOPBase);
43 static IPTR HIDD_DoMethod(OOP_Object *o, OOP_Msg msg);
44 static IPTR HIDD_CoerceMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg);
45 static IPTR HIDD_DoSuperMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg);
46 static inline ULONG get_max_midx(struct OOP_MethodDescr *md);
49 The metaclass is used to create class. That means,
50 classes are instances of the meta class.
51 The meta class is itself both a class (you can
52 create instances of it), and an object (you can invoke
53 methods on it.
54 */
56 struct hiddmeta_inst
58 struct metadata base;
59 struct hiddmeta_data
61 struct if_info
63 /* The globally unique ID of the interface */
64 STRPTR interface_id;
65 ULONG num_methods;
66 ULONG mtab_offset;
68 } *ifinfo;
69 struct IFMethod *methodtable;
70 } data;
73 #define OOPBase ((struct IntOOPBase *)cl->OOPBasePtr)
75 /**********************
76 ** HIDDMeta::New() **
77 **********************/
78 static OOP_Object *hiddmeta_new(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
81 IPTR (*domethod)(OOP_Object *, OOP_Msg) = NULL;
82 IPTR (*coercemethod)(OOP_Class *, OOP_Object *, OOP_Msg) = NULL;
83 IPTR (*dosupermethod)(OOP_Class *, OOP_Object *, OOP_Msg) = NULL;
86 EnterFunc(bug("HIDDMeta::New(cl=%s, msg = %p)\n",
87 cl->ClassNode.ln_Name, msg));
89 /* Analyze the taglist before object is allocated,
90 ** so we can easily exit cleanly if some info is missing
93 domethod = (IPTR (*)())GetTagData(aMeta_DoMethod, NULL, msg->attrList);
94 coercemethod = (IPTR (*)())GetTagData(aMeta_CoerceMethod, NULL, msg->attrList);
95 dosupermethod = (IPTR (*)())GetTagData(aMeta_DoSuperMethod, NULL, msg->attrList);
98 /* We are sure we have enough args, and can let rootclass alloc the instance data */
99 o = (OOP_Object *)OOP_DoSuperMethod((OOP_Class *)cl, o, (OOP_Msg)msg);
100 if (o)
103 D(bug("Instance allocated\n"));
106 /* Initialize class fields */
108 if (!domethod)
109 domethod = HIDD_DoMethod;
111 if (!coercemethod)
112 coercemethod = HIDD_CoerceMethod;
114 if (!dosupermethod)
117 /* Use superclass' DoSupermethod call if superclass isn't
118 an instance of the HIDDMetaClass
120 if (OOP_OCLASS(MD(o)->superclass) != (OOP_Class *)cl)
121 dosupermethod = MD(o)->superclass->cl_DoSuperMethod;
122 else
123 dosupermethod = HIDD_DoSuperMethod;
126 ((OOP_Class *)o)->cl_DoMethod = domethod;
127 ((OOP_Class *)o)->cl_CoerceMethod = coercemethod;
128 ((OOP_Class *)o)->cl_DoSuperMethod = dosupermethod;
132 ReturnPtr ("HIDDMeta::New", Object *, o);
135 /********************************
136 ** HIDDMeta::allocdisptabs() **
137 ********************************/
138 static BOOL hiddmeta_allocdisptabs(OOP_Class *cl, OOP_Object *o, struct P_meta_allocdisptabs *msg)
140 ULONG disptab_size, total_num_methods = 0UL, total_num_ifs = 0UL;
142 struct hiddmeta_data *data = OOP_INST_DATA(cl, o);
143 struct IFMethod *mtab = NULL;
145 EnterFunc(bug("HIDDMeta::allocdisptabs(cl=%p, ifDescr=%p)\n", cl, msg->ifdescr));
147 /* Find the total number of methods in the superclass */
148 get_info_on_ifs(msg->superclass
149 ,msg->ifdescr
150 ,&total_num_methods
151 ,&total_num_ifs
152 ,(struct IntOOPBase *)OOPBase);
154 /* Set number of interfaces */
155 MD(o)->numinterfaces = total_num_ifs;
157 D(bug("Number of interfaces: %ld, methods %ld\n",
158 total_num_ifs, total_num_methods));
160 /* Allocate the dispatch table */
161 disptab_size = UB(&mtab[total_num_methods]) - UB(&mtab[0]);
163 data->methodtable = AllocVec(disptab_size, MEMF_ANY|MEMF_CLEAR);
164 if (data->methodtable)
166 struct if_info *ifinfo = NULL;
167 ULONG ifinfo_size;
169 mtab = data->methodtable;
171 /* Allocate memory for interface info table */
172 ifinfo_size = UB(&ifinfo[total_num_ifs]) - UB(&ifinfo[0]);
173 data->ifinfo = AllocVec(ifinfo_size, MEMF_ANY|MEMF_CLEAR);
174 if (data->ifinfo)
176 /* Iterate through all parent interfaces, copying relevant info
177 into our own dispatch tables.
179 STRPTR interface_id;
180 ULONG num_methods;
181 IPTR iterval = 0UL;
182 struct IFMethod *ifm;
183 ULONG mtab_offset = 0;
184 struct OOP_InterfaceDescr *ifdescr = msg->ifdescr;
186 ifinfo = data->ifinfo;
188 while ((ifm = meta_iterateifs((OOP_Object *)msg->superclass, &iterval, &interface_id, &num_methods)))
190 ULONG copy_size;
191 struct OOP_InterfaceDescr *ifd;
193 /* Copy interface into dispatch tables */
194 copy_size = UB(&mtab[num_methods]) - UB(&mtab[0]);
196 D(bug("Copying mtab (%p to %p) , size: %ld\n", ifm, mtab, copy_size));
197 CopyMem(ifm, mtab, copy_size);
199 D(bug("mtab copied, mtab=%p\n", mtab));
200 /* store interface info */
202 /* allready copied by superclass, no need to recopy it */
203 ifinfo->interface_id = interface_id;
204 D(bug("interfaceID for ifinfo %p set to %s\n", ifinfo, ifinfo->interface_id));
206 /* See if this class supplies more methods for the interace */
207 for (ifd = msg->ifdescr; ifd->MethodTable != 0; ifd ++)
209 if (0 == strcmp(ifd->InterfaceID, interface_id))
211 ULONG max_midx;
213 max_midx = get_max_midx(ifd->MethodTable);
214 if (max_midx >= num_methods)
215 num_methods = max_midx + 1;
218 ifinfo->num_methods = num_methods;
219 D(bug("numemthods set to %ld\n", num_methods));
220 ifinfo->mtab_offset = mtab_offset;
221 D(bug("mtab_offset set to %ld\n", mtab_offset));
223 mtab_offset += num_methods;
224 mtab += num_methods;
226 ULONG idx;
227 D(bug("\n"));
228 for (idx = 0; idx < total_num_ifs; idx ++)
230 D(bug("ifinfo: (%p, %s), idx: %ld\n"
231 ,&(data->ifinfo[idx])
232 ,data->ifinfo[idx].interface_id
233 ,idx ));
236 D(bug("\n"));
239 ifinfo ++;
242 D(bug("Finished copying super IFs\n\n"));
245 ULONG idx;
246 for (idx = 0; idx < total_num_ifs; idx ++)
248 D(bug(" ifinfo: (%p, %s), idx: %ld\n"
249 ,&(data->ifinfo[idx])
250 ,data->ifinfo[idx].interface_id
251 ,idx ));
258 /* Now find the interface (max one) that is new for this class,
259 and at the same time override all methods for all interfaces
262 D(bug("Find new interface\n"));
263 for (; ifdescr->MethodTable != NULL; ifdescr ++)
265 struct OOP_MethodDescr *mdescr;
266 ULONG current_idx;
268 ifm = meta_getifinfo((OOP_Object *)msg->superclass, ifdescr->InterfaceID, &num_methods);
269 if (!ifm)
271 ULONG mbase = 0UL;
273 D(bug("Found new interface %s\n", ifdescr->InterfaceID));
274 /* Interface is new to this class */
277 /* Do NOT copy interfaceID */
278 ifinfo->interface_id = ifdescr->InterfaceID;
279 ifinfo->num_methods = get_max_midx(ifdescr->MethodTable) + 1;
280 ifinfo->mtab_offset = mtab_offset;
282 /* Install methodbase for this interface */
283 if (!init_methodbase( ifdescr->InterfaceID
284 ,mtab_offset
285 ,&mbase
286 ,(struct IntOOPBase *)OOPBase))
288 goto init_err;
293 /* The below is not necessary, since we never have more than one
294 new interface
296 ifinfo ++;
297 mtab_offset += ifdescr->NumMethods;
298 mtab = &mtab[mtab_offset];
303 /* Find the index into the ifinfo table for the current entry */
304 D(bug("Finding current idx\n"));
305 for (current_idx = 0; ; current_idx ++)
307 D(bug("ifdecr: %s, ifinfo: (%p, %s), idx: %ld\n", ifdescr->InterfaceID, &(data->ifinfo[current_idx]), data->ifinfo[current_idx].interface_id, current_idx ));
309 if (!strcmp(ifdescr->InterfaceID, data->ifinfo[current_idx].interface_id))
310 break;
313 D(bug("Overriding methods\n"));
316 for (mdescr = ifdescr->MethodTable; mdescr->MethodFunc != NULL; mdescr ++)
318 ULONG mtab_idx;
320 mtab_idx = mdescr->MethodIdx + data->ifinfo[current_idx].mtab_offset;
321 D(bug("Initing of if %s methods at %ld\n", ifdescr->InterfaceID, mtab_idx));
323 data->methodtable[mtab_idx].MethodFunc = mdescr->MethodFunc;
324 data->methodtable[mtab_idx].mClass = (OOP_Class *)o;
326 } /* for (each method in current interface) */
329 } /* for (each interface in this class' interface description) */
331 ReturnBool("HIIDMeta::allocdisptabs", TRUE);
332 init_err:
333 FreeVec(data->ifinfo);
335 } /* if (interface info table allocated) */
337 FreeVec(data->methodtable);
339 } /* if (methodtable allocated) */
341 ReturnBool("HIDDMeta::allocdisptabs", FALSE);
344 /*******************************
345 ** HIDDMeta::freedisptabs() **
346 ********************************/
347 static VOID hiddmeta_freedisptabs(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
349 struct hiddmeta_inst *inst = (struct hiddmeta_inst *)o;
351 FreeVec(inst->data.methodtable);
352 FreeVec(inst->data.ifinfo);
353 return;
358 /*****************************
359 ** HIDDMeta::iterateifs() **
360 *****************************/
361 static struct IFMethod *hiddmeta_iterateifs(OOP_Class *cl, OOP_Object *o, struct P_meta_iterateifs *msg)
363 struct hiddmeta_inst *inst = (struct hiddmeta_inst *)o;
364 ULONG idx = *msg->iterval_ptr;
365 struct IFMethod *mtab;
367 EnterFunc(bug("HIDDMeta::iterateifs(cl=%p, o=%p, iterval=%p)\n",
368 cl, o, *msg->iterval_ptr));
369 if (idx >= inst->base.numinterfaces)
370 mtab = NULL;
371 else
373 /* First iteration */
374 struct if_info *ifinfo;
375 ifinfo = &(inst->data.ifinfo[idx]);
377 *msg->interface_id_ptr = ifinfo->interface_id;
378 *msg->num_methods_ptr = ifinfo->num_methods;
380 mtab = &(inst->data.methodtable[ifinfo->mtab_offset]);
382 (*msg->iterval_ptr) ++;
385 ReturnPtr("HIDDMeta::iterateifs", struct IFMethod *, mtab);
388 /****************************
389 ** HIDDMeta::getifinfo() **
390 ****************************/
391 static struct IFMethod *hiddmeta_getifinfo(OOP_Class *cl, OOP_Object *o, struct P_meta_getifinfo *msg)
394 struct hiddmeta_inst *inst = (struct hiddmeta_inst *)o;
395 ULONG current_idx;
396 struct IFMethod *mtab = NULL;
398 EnterFunc(bug("HIDDMeta::getifinfo(cl=%p, o=%p, ifID=%s)\n",
399 cl, o, msg->interface_id));
401 /* Look up the interface */
403 for (current_idx = 0; current_idx < inst->base.numinterfaces; current_idx ++)
405 struct if_info *ifinfo;
407 ifinfo = &(inst->data.ifinfo[current_idx]);
408 if (!strcmp(msg->interface_id, ifinfo->interface_id))
410 *(msg->num_methods_ptr) = ifinfo->num_methods;
411 mtab = &(inst->data.methodtable[ifinfo->mtab_offset]);
412 break;
415 ReturnPtr("HIDDMeta::getifinfo", struct IFMethod *, mtab);
419 /*****************************
420 ** HIDDMeta::findmethod() **
421 *****************************/
422 struct IFMethod *hiddmeta_findmethod(OOP_Class *cl, OOP_Object *o, struct P_meta_findmethod *msg)
424 struct hiddmeta_inst *inst = (struct hiddmeta_inst *)o;
425 struct IFMethod *m;
427 EnterFunc(bug("HIDDMeta::findmethod(cl=%p, o=%p, mID=%ld)\n",
428 cl, o, msg->method_to_find));
430 m = &(inst->data.methodtable[msg->method_to_find]);
433 ReturnPtr("HIDDMeta::findmethod", struct IFMethod *, m);
437 #undef OOPBase
439 #define NUM_ROOT_METHODS 1
440 #define NUM_META_METHODS 5
442 /************************
443 ** Support functions **
444 ************************/
445 OOP_Class *init_hiddmetaclass(struct IntOOPBase *OOPBase)
447 struct OOP_MethodDescr root_mdescr[NUM_ROOT_METHODS + 1] =
449 { (IPTR (*)())hiddmeta_new, moRoot_New },
450 { NULL, 0UL }
453 struct OOP_MethodDescr meta_mdescr[NUM_META_METHODS + 1] =
455 { (IPTR (*)())hiddmeta_allocdisptabs, MO_meta_allocdisptabs },
456 { (IPTR (*)())hiddmeta_freedisptabs, MO_meta_freedisptabs },
457 { (IPTR (*)())hiddmeta_getifinfo, MO_meta_getifinfo },
458 { (IPTR (*)())hiddmeta_iterateifs, MO_meta_iterateifs },
459 { (IPTR (*)())hiddmeta_findmethod, MO_meta_findmethod },
460 { NULL, 0UL }
464 struct OOP_InterfaceDescr ifdescr[] =
466 {root_mdescr, IID_Root, NUM_ROOT_METHODS},
467 {meta_mdescr, IID_Meta, NUM_META_METHODS},
468 {NULL, NULL, 0UL}
471 struct TagItem tags[] =
473 {aMeta_SuperPtr, (IPTR)BASEMETAPTR},
474 {aMeta_InterfaceDescr, (IPTR)ifdescr},
475 {aMeta_ID, (IPTR)CLID_SIMeta},
476 {aMeta_InstSize, (IPTR)sizeof (struct hiddmeta_data) },
477 {TAG_DONE, 0UL}
480 OOP_Class *cl;
481 EnterFunc(bug("init_hiddmetaclass()\n"));
483 cl = (OOP_Class *)OOP_NewObject(NULL, CLID_MIMeta, tags);
484 if (cl)
486 cl->UserData = OOPBase;
487 OOP_AddClass(cl);
489 D(bug("HIDD_CoerceMethod=%p\n", HIDD_CoerceMethod));
491 ReturnPtr ("init_hiddmetaclass()", OOP_Class *, cl);
495 static inline ULONG get_max_midx(struct OOP_MethodDescr *md)
498 ULONG max_midx = 0;
501 for (; md->MethodFunc != NULL; md ++)
503 if (md->MethodIdx > max_midx)
505 max_midx = md->MethodIdx;
508 return max_midx;
511 /************************
512 ** get_info_on_ifs() **
513 ************************/
514 static VOID get_info_on_ifs(OOP_Class *super
515 ,struct OOP_InterfaceDescr *ifdescr
516 ,ULONG *total_num_methods_ptr
517 ,ULONG *total_num_ifs_ptr
518 ,struct IntOOPBase *OOPBase)
520 ULONG num_methods;
521 STRPTR interface_id;
522 IPTR iterval = 0UL;
523 EnterFunc(bug("get_info_on_ifs(super=%s, ifdescr=%p, OOPBase=%p\n",
524 super->ClassNode.ln_Name, ifdescr, OOPBase));
526 *total_num_methods_ptr = 0UL;
527 *total_num_ifs_ptr = 0UL;
529 /* Iterate all parent interfaces, counting methods and interfaces */
530 while (meta_iterateifs((OOP_Object *)super, &iterval, &interface_id, &num_methods))
532 struct OOP_InterfaceDescr *ifd;
533 D(bug("if %s has %ld methods\n", interface_id, num_methods));
534 /* Check whether current class also supplies methods for this interface */
536 for (ifd = ifdescr; ifd->MethodTable != NULL; ifd ++)
538 if (0 == strcmp(ifd->InterfaceID, interface_id))
540 /* Interface also supplied here */
541 ULONG max_midx;
543 max_midx = get_max_midx(ifd->MethodTable);
544 if (max_midx >= num_methods)
545 num_methods = max_midx + 1;
549 *total_num_methods_ptr += num_methods;
550 (*total_num_ifs_ptr) ++;
552 D(bug("Finished counting methods\n"));
554 /* Go through all interface descrs for this class, and find evt. new ones */
555 for (; ifdescr->MethodTable != NULL; ifdescr ++)
557 if (!meta_getifinfo((OOP_Object *)super, ifdescr->InterfaceID, &num_methods))
559 /* The interface is new for this class.
560 For HIDDMeta class max. one interface can be new for a class
562 ULONG max_midx = 0;
563 max_midx = get_max_midx(ifdescr->MethodTable);
565 /* Get the largest method idx */
567 (*total_num_methods_ptr) += (max_midx + 1);
568 (*total_num_ifs_ptr) ++;
572 ReturnVoid("get_info_on_ifs");
575 #define OOPBase (cl->OOPBasePtr)
577 /**********************
578 ** HIDD_DoMethod() **
579 **********************/
580 static IPTR HIDD_DoMethod(OOP_Object *o, OOP_Msg msg)
582 register struct hiddmeta_inst *cl = (struct hiddmeta_inst *)OOP_OCLASS(o);
583 D(bug("HIDD_DoMethod(o=%p. msg=%p)\n", o, msg));
585 IntCallMethod(cl, o, msg);
589 /************************
590 ** HIDD_CoerceMethod **
591 ************************/
592 static IPTR HIDD_CoerceMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
594 register struct IFMethod *ifm;
595 D(bug("HIDD_CoerceMethod()\n"));
596 D(bug("cl=%s, mid=%ld\n", cl->ClassNode.ln_Name, *msg)); ifm = &((struct hiddmeta_inst *)cl)->data.methodtable[*msg];
597 D(bug("ifm %p func %p, cl %p\n", ifm, ifm->MethodFunc, ifm->mClass)); return (ifm->MethodFunc(ifm->mClass, o, msg));
600 /************************
601 ** HIDD_DoSuperMethod **
602 ************************/
603 static IPTR HIDD_DoSuperMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
605 D(bug("HIDD_DoSuperMethod()\n"));
606 cl = MD(cl)->superclass;
607 IntCallMethod(cl, o, msg);