2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: OOP HIDD metaclass
11 #include <proto/exec.h>
12 #include <proto/utility.h>
13 #include <exec/memory.h>
15 #include <proto/oop.h>
23 #include <aros/debug.h>
25 #define UB(x) ((UBYTE *)x)
27 #define IntCallMethod(cl, o, msg) \
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
58 /* The globally unique ID of the interface */
59 CONST_STRPTR interface_id
;
64 struct IFMethod
*methodtable
;
68 /**********************
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
));
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
);
100 D(bug("Instance allocated\n"));
103 /* Initialize class fields */
106 domethod
= HIDD_DoMethod
;
109 coercemethod
= HIDD_CoerceMethod
;
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
;
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
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
;
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
);
174 /* Iterate through all parent interfaces, copying relevant info
175 into our own dispatch tables.
177 CONST_STRPTR interface_id
;
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
)))
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
))
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
;
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
240 D(bug("Finished copying super IFs\n\n"));
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
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
;
266 ifm
= meta_getifinfo((OOP_Object
*)msg
->superclass
, ifdescr
->InterfaceID
, &num_methods
);
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
284 ,(struct IntOOPBase
*)OOPBase
))
291 /* The below is not necessary, since we never have more than one
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
))
311 D(bug("Overriding methods\n"));
314 for (mdescr
= ifdescr
->MethodTable
; mdescr
->MethodFunc
!= NULL
; mdescr
++)
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
);
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
);
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
)
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
;
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
]);
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
;
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
},
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
},
460 struct OOP_InterfaceDescr ifdescr
[] =
462 {root_mdescr
, IID_Root
, NUM_ROOT_METHODS
},
463 {meta_mdescr
, IID_Meta
, NUM_META_METHODS
},
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
) },
477 EnterFunc(bug("init_hiddmetaclass()\n"));
479 cl
= (OOP_Class
*)OOP_NewObject(NULL
, CLID_MIMeta
, tags
);
482 cl
->UserData
= OOPBase
;
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
)
495 for (; md
->MethodFunc
!= NULL
; md
++)
497 if (md
->MethodIdx
> max_midx
)
499 max_midx
= md
->MethodIdx
;
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
)
512 CONST_STRPTR interface_id
;
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 */
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
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
);