2 Copyright © 1995-2001, 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 MD(cl) ((struct metadata *)cl)
29 #define IntCallMethod(cl, o, msg) \
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
63 /* The globally unique ID of the interface */
69 struct IFMethod
*methodtable
;
73 #define OOPBase ((struct IntOOPBase *)cl->OOPBasePtr)
75 /**********************
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
);
103 D(bug("Instance allocated\n"));
106 /* Initialize class fields */
109 domethod
= HIDD_DoMethod
;
112 coercemethod
= HIDD_CoerceMethod
;
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
;
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
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
;
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
);
176 /* Iterate through all parent interfaces, copying relevant info
177 into our own dispatch tables.
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
)))
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
))
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
;
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
242 D(bug("Finished copying super IFs\n\n"));
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
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
;
268 ifm
= meta_getifinfo((OOP_Object
*)msg
->superclass
, ifdescr
->InterfaceID
, &num_methods
);
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
286 ,(struct IntOOPBase
*)OOPBase
))
293 /* The below is not necessary, since we never have more than one
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
))
313 D(bug("Overriding methods\n"));
316 for (mdescr
= ifdescr
->MethodTable
; mdescr
->MethodFunc
!= NULL
; mdescr
++)
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
);
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
);
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
)
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
;
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
]);
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
;
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
);
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
},
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
},
464 struct OOP_InterfaceDescr ifdescr
[] =
466 {root_mdescr
, IID_Root
, NUM_ROOT_METHODS
},
467 {meta_mdescr
, IID_Meta
, NUM_META_METHODS
},
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
) },
481 EnterFunc(bug("init_hiddmetaclass()\n"));
483 cl
= (OOP_Class
*)OOP_NewObject(NULL
, CLID_MIMeta
, tags
);
486 cl
->UserData
= OOPBase
;
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
)
501 for (; md
->MethodFunc
!= NULL
; md
++)
503 if (md
->MethodIdx
> max_midx
)
505 max_midx
= md
->MethodIdx
;
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
)
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 */
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
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
);