Indentation fix, cleanup.
[AROS.git] / rom / oop / hiddmetaclass.c
blobff5dc98e79d9f88f987db66af35d0b8883bc951a
1 /*
2 Copyright © 1995-2011, 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 IntCallMethod(cl, o, msg) \
28 { \
29 register struct IFMethod *ifm; \
30 D(bug("mid=%ld\n", *msg)); ifm = &((struct hiddmeta_inst *)cl)->data.methodtable[*msg]; \
31 D(bug("ifm: func %p, cl %p\n", ifm->MethodFunc, ifm->mClass)); return (ifm->MethodFunc(ifm->mClass, o, msg)); \
35 static VOID get_info_on_ifs(OOP_Class *super, const struct OOP_InterfaceDescr *ifdescr,
36 ULONG *total_num_methods_ptr, ULONG *total_num_ifs_ptr, struct IntOOPBase *OOPBase);
38 static IPTR HIDD_DoMethod(OOP_Object *o, OOP_Msg msg);
39 static IPTR HIDD_CoerceMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg);
40 static IPTR HIDD_DoSuperMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg);
41 static inline ULONG get_max_midx(const struct OOP_MethodDescr *md);
44 The metaclass is used to create class. That means,
45 classes are instances of the meta class.
46 The meta class is itself both a class (you can
47 create instances of it), and an object (you can invoke
48 methods on it.
49 */
51 struct hiddmeta_inst
53 struct metadata base;
54 struct hiddmeta_data
56 struct if_info
58 /* The globally unique ID of the interface */
59 CONST_STRPTR interface_id;
60 ULONG num_methods;
61 ULONG mtab_offset;
63 } *ifinfo;
64 struct IFMethod *methodtable;
65 } data;
68 /**********************
69 ** HIDDMeta::New() **
70 **********************/
71 static OOP_Object *hiddmeta_new(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
73 struct IntOOPBase *OOPBase = (struct IntOOPBase *)cl->OOPBasePtr;
74 struct Library *UtilityBase = OOPBase->ob_UtilityBase;
75 IPTR (*domethod)(OOP_Object *, OOP_Msg) = NULL;
76 IPTR (*coercemethod)(OOP_Class *, OOP_Object *, OOP_Msg) = NULL;
77 IPTR (*dosupermethod)(OOP_Class *, OOP_Object *, OOP_Msg) = NULL;
80 EnterFunc(bug("HIDDMeta::New(cl=%s, msg = %p)\n",
81 cl->ClassNode.ln_Name, msg));
83 if (!UtilityBase)
84 ReturnPtr ("HIDDMeta::New", OOP_Object *, NULL);
86 /* Analyze the taglist before object is allocated,
87 ** so we can easily exit cleanly if some info is missing
90 domethod = (IPTR (*)())GetTagData(aMeta_DoMethod, 0, msg->attrList);
91 coercemethod = (IPTR (*)())GetTagData(aMeta_CoerceMethod, 0, msg->attrList);
92 dosupermethod = (IPTR (*)())GetTagData(aMeta_DoSuperMethod, 0, msg->attrList);
95 /* We are sure we have enough args, and can let rootclass alloc the instance data */
96 o = (OOP_Object *)OOP_DoSuperMethod((OOP_Class *)cl, o, (OOP_Msg)msg);
97 if (o)
100 D(bug("Instance allocated\n"));
103 /* Initialize class fields */
105 if (!domethod)
106 domethod = HIDD_DoMethod;
108 if (!coercemethod)
109 coercemethod = HIDD_CoerceMethod;
111 if (!dosupermethod)
114 /* Use superclass' DoSupermethod call if superclass isn't
115 an instance of the HIDDMetaClass
117 if (OOP_OCLASS(MD(o)->public.superclass) != (OOP_Class *)cl)
118 dosupermethod = MD(o)->public.superclass->cl_DoSuperMethod;
119 else
120 dosupermethod = HIDD_DoSuperMethod;
123 ((OOP_Class *)o)->cl_DoMethod = domethod;
124 ((OOP_Class *)o)->cl_CoerceMethod = coercemethod;
125 ((OOP_Class *)o)->cl_DoSuperMethod = dosupermethod;
129 ReturnPtr ("HIDDMeta::New", OOP_Object *, o);
132 /********************************
133 ** HIDDMeta::allocdisptabs() **
134 ********************************/
135 static BOOL hiddmeta_allocdisptabs(OOP_Class *cl, OOP_Object *o, struct P_meta_allocdisptabs *msg)
137 struct IntOOPBase *OOPBase = (struct IntOOPBase *)cl->OOPBasePtr;
138 ULONG disptab_size, total_num_methods = 0UL, total_num_ifs = 0UL;
140 struct hiddmeta_data *data = OOP_INST_DATA(cl, o);
141 struct IFMethod *mtab = NULL;
143 EnterFunc(bug("HIDDMeta::allocdisptabs(cl=%p, ifDescr=%p)\n", cl, msg->ifdescr));
145 /* Find the total number of methods in the superclass */
146 get_info_on_ifs(msg->superclass
147 ,msg->ifdescr
148 ,&total_num_methods
149 ,&total_num_ifs
150 ,(struct IntOOPBase *)OOPBase);
152 /* Set number of interfaces */
153 MD(o)->numinterfaces = total_num_ifs;
155 D(bug("Number of interfaces: %ld, methods %ld\n",
156 total_num_ifs, total_num_methods));
158 /* Allocate the dispatch table */
159 disptab_size = UB(&mtab[total_num_methods]) - UB(&mtab[0]);
161 data->methodtable = AllocVec(disptab_size, MEMF_ANY|MEMF_CLEAR);
162 if (data->methodtable)
164 struct if_info *ifinfo = NULL;
165 ULONG ifinfo_size;
167 mtab = data->methodtable;
169 /* Allocate memory for interface info table */
170 ifinfo_size = UB(&ifinfo[total_num_ifs]) - UB(&ifinfo[0]);
171 data->ifinfo = AllocVec(ifinfo_size, MEMF_ANY|MEMF_CLEAR);
172 if (data->ifinfo)
174 /* Iterate through all parent interfaces, copying relevant info
175 into our own dispatch tables.
177 CONST_STRPTR interface_id;
178 ULONG num_methods;
179 IPTR iterval = 0UL;
180 struct IFMethod *ifm;
181 ULONG mtab_offset = 0;
182 const struct OOP_InterfaceDescr *ifdescr = msg->ifdescr;
184 ifinfo = data->ifinfo;
186 while ((ifm = meta_iterateifs((OOP_Object *)msg->superclass, &iterval, &interface_id, &num_methods)))
188 ULONG copy_size;
189 const struct OOP_InterfaceDescr *ifd;
191 /* Copy interface into dispatch tables */
192 copy_size = UB(&mtab[num_methods]) - UB(&mtab[0]);
194 D(bug("Copying mtab (%p to %p) , size: %ld\n", ifm, mtab, copy_size));
195 CopyMem(ifm, mtab, copy_size);
197 D(bug("mtab copied, mtab=%p\n", mtab));
198 /* store interface info */
200 /* allready copied by superclass, no need to recopy it */
201 ifinfo->interface_id = interface_id;
202 D(bug("interfaceID for ifinfo %p set to %s\n", ifinfo, ifinfo->interface_id));
204 /* See if this class supplies more methods for the interace */
205 for (ifd = msg->ifdescr; ifd->MethodTable != 0; ifd ++)
207 if (0 == strcmp(ifd->InterfaceID, interface_id))
209 ULONG max_midx;
211 max_midx = get_max_midx(ifd->MethodTable);
212 if (max_midx >= num_methods)
213 num_methods = max_midx + 1;
216 ifinfo->num_methods = num_methods;
217 D(bug("numemthods set to %ld\n", num_methods));
218 ifinfo->mtab_offset = mtab_offset;
219 D(bug("mtab_offset set to %ld\n", mtab_offset));
221 mtab_offset += num_methods;
222 mtab += num_methods;
224 ULONG idx;
225 D(bug("\n"));
226 for (idx = 0; idx < total_num_ifs; idx ++)
228 D(bug("ifinfo: (%p, %s), idx: %ld\n"
229 ,&(data->ifinfo[idx])
230 ,data->ifinfo[idx].interface_id
231 ,idx ));
234 D(bug("\n"));
237 ifinfo ++;
240 D(bug("Finished copying super IFs\n\n"));
243 ULONG idx;
244 for (idx = 0; idx < total_num_ifs; idx ++)
246 D(bug(" ifinfo: (%p, %s), idx: %ld\n"
247 ,&(data->ifinfo[idx])
248 ,data->ifinfo[idx].interface_id
249 ,idx ));
256 /* Now find the interface (max one) that is new for this class,
257 and at the same time override all methods for all interfaces
260 D(bug("Find new interface\n"));
261 for (; ifdescr->MethodTable != NULL; ifdescr ++)
263 const struct OOP_MethodDescr *mdescr;
264 ULONG current_idx;
266 ifm = meta_getifinfo((OOP_Object *)msg->superclass, ifdescr->InterfaceID, &num_methods);
267 if (!ifm)
269 ULONG mbase = 0UL;
271 D(bug("Found new interface %s\n", ifdescr->InterfaceID));
272 /* Interface is new to this class */
275 /* Do NOT copy interfaceID */
276 ifinfo->interface_id = ifdescr->InterfaceID;
277 ifinfo->num_methods = get_max_midx(ifdescr->MethodTable) + 1;
278 ifinfo->mtab_offset = mtab_offset;
280 /* Install methodbase for this interface */
281 if (!init_methodbase( ifdescr->InterfaceID
282 ,mtab_offset
283 ,&mbase
284 ,(struct IntOOPBase *)OOPBase))
286 goto init_err;
291 /* The below is not necessary, since we never have more than one
292 new interface
294 ifinfo ++;
295 mtab_offset += ifdescr->NumMethods;
296 mtab = &mtab[mtab_offset];
301 /* Find the index into the ifinfo table for the current entry */
302 D(bug("Finding current idx\n"));
303 for (current_idx = 0; ; current_idx ++)
305 D(bug("ifdecr: %s, ifinfo: (%p, %s), idx: %ld\n", ifdescr->InterfaceID, &(data->ifinfo[current_idx]), data->ifinfo[current_idx].interface_id, current_idx ));
307 if (!strcmp(ifdescr->InterfaceID, data->ifinfo[current_idx].interface_id))
308 break;
311 D(bug("Overriding methods\n"));
314 for (mdescr = ifdescr->MethodTable; mdescr->MethodFunc != NULL; mdescr ++)
316 ULONG mtab_idx;
318 mtab_idx = mdescr->MethodIdx + data->ifinfo[current_idx].mtab_offset;
319 D(bug("Initing of if %s methods at %ld\n", ifdescr->InterfaceID, mtab_idx));
321 data->methodtable[mtab_idx].MethodFunc = mdescr->MethodFunc;
322 data->methodtable[mtab_idx].mClass = (OOP_Class *)o;
324 } /* for (each method in current interface) */
327 } /* for (each interface in this class' interface description) */
329 ReturnBool("HIIDMeta::allocdisptabs", TRUE);
330 init_err:
331 FreeVec(data->ifinfo);
333 } /* if (interface info table allocated) */
335 FreeVec(data->methodtable);
337 } /* if (methodtable allocated) */
339 ReturnBool("HIDDMeta::allocdisptabs", FALSE);
342 /*******************************
343 ** HIDDMeta::freedisptabs() **
344 ********************************/
345 static VOID hiddmeta_freedisptabs(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
347 struct hiddmeta_inst *inst = (struct hiddmeta_inst *)o;
349 FreeVec(inst->data.methodtable);
350 FreeVec(inst->data.ifinfo);
351 return;
356 /*****************************
357 ** HIDDMeta::iterateifs() **
358 *****************************/
359 static struct IFMethod *hiddmeta_iterateifs(OOP_Class *cl, OOP_Object *o, struct P_meta_iterateifs *msg)
361 struct hiddmeta_inst *inst = (struct hiddmeta_inst *)o;
362 ULONG idx = *msg->iterval_ptr;
363 struct IFMethod *mtab;
365 EnterFunc(bug("HIDDMeta::iterateifs(cl=%p, o=%p, iterval=%p)\n",
366 cl, o, *msg->iterval_ptr));
367 if (idx >= inst->base.numinterfaces)
368 mtab = NULL;
369 else
371 /* First iteration */
372 struct if_info *ifinfo;
373 ifinfo = &(inst->data.ifinfo[idx]);
375 *msg->interface_id_ptr = ifinfo->interface_id;
376 *msg->num_methods_ptr = ifinfo->num_methods;
378 mtab = &(inst->data.methodtable[ifinfo->mtab_offset]);
380 (*msg->iterval_ptr) ++;
383 ReturnPtr("HIDDMeta::iterateifs", struct IFMethod *, mtab);
386 /****************************
387 ** HIDDMeta::getifinfo() **
388 ****************************/
389 static struct IFMethod *hiddmeta_getifinfo(OOP_Class *cl, OOP_Object *o, struct P_meta_getifinfo *msg)
392 struct hiddmeta_inst *inst = (struct hiddmeta_inst *)o;
393 ULONG current_idx;
394 struct IFMethod *mtab = NULL;
396 EnterFunc(bug("HIDDMeta::getifinfo(cl=%p, o=%p, ifID=%s)\n",
397 cl, o, msg->interface_id));
399 /* Look up the interface */
401 for (current_idx = 0; current_idx < inst->base.numinterfaces; current_idx ++)
403 struct if_info *ifinfo;
405 ifinfo = &(inst->data.ifinfo[current_idx]);
406 if (!strcmp(msg->interface_id, ifinfo->interface_id))
408 *(msg->num_methods_ptr) = ifinfo->num_methods;
409 mtab = &(inst->data.methodtable[ifinfo->mtab_offset]);
410 break;
413 ReturnPtr("HIDDMeta::getifinfo", struct IFMethod *, mtab);
417 /*****************************
418 ** HIDDMeta::findmethod() **
419 *****************************/
420 struct IFMethod *hiddmeta_findmethod(OOP_Class *cl, OOP_Object *o, struct P_meta_findmethod *msg)
422 struct hiddmeta_inst *inst = (struct hiddmeta_inst *)o;
423 struct IFMethod *m;
425 EnterFunc(bug("HIDDMeta::findmethod(cl=%p, o=%p, mID=%ld)\n",
426 cl, o, msg->method_to_find));
428 m = &(inst->data.methodtable[msg->method_to_find]);
431 ReturnPtr("HIDDMeta::findmethod", struct IFMethod *, m);
435 #define NUM_ROOT_METHODS 1
436 #define NUM_META_METHODS 5
438 /************************
439 ** Support functions **
440 ************************/
441 OOP_Class *init_hiddmetaclass(struct IntOOPBase *OOPBase)
443 struct OOP_MethodDescr root_mdescr[NUM_ROOT_METHODS + 1] =
445 { (IPTR (*)())hiddmeta_new, moRoot_New },
446 { NULL, 0UL }
449 struct OOP_MethodDescr meta_mdescr[NUM_META_METHODS + 1] =
451 { (IPTR (*)())hiddmeta_allocdisptabs, MO_meta_allocdisptabs },
452 { (IPTR (*)())hiddmeta_freedisptabs, MO_meta_freedisptabs },
453 { (IPTR (*)())hiddmeta_getifinfo, MO_meta_getifinfo },
454 { (IPTR (*)())hiddmeta_iterateifs, MO_meta_iterateifs },
455 { (IPTR (*)())hiddmeta_findmethod, MO_meta_findmethod },
456 { NULL, 0UL }
460 struct OOP_InterfaceDescr ifdescr[] =
462 {root_mdescr, IID_Root, NUM_ROOT_METHODS},
463 {meta_mdescr, IID_Meta, NUM_META_METHODS},
464 {NULL, NULL, 0UL}
467 struct TagItem tags[] =
469 {aMeta_SuperPtr, (IPTR)BASEMETAPTR},
470 {aMeta_InterfaceDescr, (IPTR)ifdescr},
471 {aMeta_ID, (IPTR)CLID_SIMeta},
472 {aMeta_InstSize, (IPTR)sizeof (struct hiddmeta_data) },
473 {TAG_DONE, 0UL}
476 OOP_Class *cl;
477 EnterFunc(bug("init_hiddmetaclass()\n"));
479 cl = (OOP_Class *)OOP_NewObject(NULL, CLID_MIMeta, tags);
480 if (cl)
482 cl->UserData = OOPBase;
483 OOP_AddClass(cl);
485 D(bug("HIDD_CoerceMethod=%p\n", HIDD_CoerceMethod));
487 ReturnPtr ("init_hiddmetaclass()", OOP_Class *, cl);
491 static inline ULONG get_max_midx(const struct OOP_MethodDescr *md)
493 ULONG max_midx = 0;
495 for (; md->MethodFunc != NULL; md ++)
497 if (md->MethodIdx > max_midx)
499 max_midx = md->MethodIdx;
502 return max_midx;
505 /************************
506 ** get_info_on_ifs() **
507 ************************/
508 static VOID get_info_on_ifs(OOP_Class *super, const struct OOP_InterfaceDescr *ifdescr,
509 ULONG *total_num_methods_ptr, ULONG *total_num_ifs_ptr, struct IntOOPBase *OOPBase)
511 ULONG num_methods;
512 CONST_STRPTR interface_id;
513 IPTR iterval = 0UL;
514 EnterFunc(bug("get_info_on_ifs(super=%s, ifdescr=%p, OOPBase=%p\n",
515 super->ClassNode.ln_Name, ifdescr, OOPBase));
517 *total_num_methods_ptr = 0UL;
518 *total_num_ifs_ptr = 0UL;
520 /* Iterate all parent interfaces, counting methods and interfaces */
521 while (meta_iterateifs((OOP_Object *)super, &iterval, &interface_id, &num_methods))
523 const struct OOP_InterfaceDescr *ifd;
525 D(bug("if %s has %ld methods\n", interface_id, num_methods));
526 /* Check whether current class also supplies methods for this interface */
528 for (ifd = ifdescr; ifd->MethodTable != NULL; ifd ++)
530 if (0 == strcmp(ifd->InterfaceID, interface_id))
532 /* Interface also supplied here */
533 ULONG max_midx;
535 max_midx = get_max_midx(ifd->MethodTable);
536 if (max_midx >= num_methods)
537 num_methods = max_midx + 1;
541 *total_num_methods_ptr += num_methods;
542 (*total_num_ifs_ptr) ++;
544 D(bug("Finished counting methods\n"));
546 /* Go through all interface descrs for this class, and find evt. new ones */
547 for (; ifdescr->MethodTable != NULL; ifdescr ++)
549 if (!meta_getifinfo((OOP_Object *)super, ifdescr->InterfaceID, &num_methods))
551 /* The interface is new for this class.
552 For HIDDMeta class max. one interface can be new for a class
554 ULONG max_midx = 0;
555 max_midx = get_max_midx(ifdescr->MethodTable);
557 /* Get the largest method idx */
559 (*total_num_methods_ptr) += (max_midx + 1);
560 (*total_num_ifs_ptr) ++;
564 ReturnVoid("get_info_on_ifs");
567 /**********************
568 ** HIDD_DoMethod() **
569 **********************/
570 static IPTR HIDD_DoMethod(OOP_Object *o, OOP_Msg msg)
572 register struct hiddmeta_inst *cl = (struct hiddmeta_inst *)OOP_OCLASS(o);
573 D(bug("HIDD_DoMethod(o=%p. msg=%p)\n", o, msg));
575 IntCallMethod(cl, o, msg);
579 /************************
580 ** HIDD_CoerceMethod **
581 ************************/
582 static IPTR HIDD_CoerceMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
584 register struct IFMethod *ifm;
585 D(bug("HIDD_CoerceMethod()\n"));
586 D(bug("cl=%s, mid=%ld\n", cl->ClassNode.ln_Name, *msg)); ifm = &((struct hiddmeta_inst *)cl)->data.methodtable[*msg];
587 D(bug("ifm %p func %p, cl %p\n", ifm, ifm->MethodFunc, ifm->mClass)); return (ifm->MethodFunc(ifm->mClass, o, msg));
590 /************************
591 ** HIDD_DoSuperMethod **
592 ************************/
593 static IPTR HIDD_DoSuperMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
595 D(bug("HIDD_DoSuperMethod()\n"));
596 cl = MD(cl)->public.superclass;
597 IntCallMethod(cl, o, msg);