From 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d Mon Sep 17 00:00:00 2001 From: Jef Date: Tue, 24 Sep 2024 14:54:57 +0200 Subject: Initial community commit --- Src/Wasabi/bfc/multipatch.h | 412 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 Src/Wasabi/bfc/multipatch.h (limited to 'Src/Wasabi/bfc/multipatch.h') diff --git a/Src/Wasabi/bfc/multipatch.h b/Src/Wasabi/bfc/multipatch.h new file mode 100644 index 00000000..242737b4 --- /dev/null +++ b/Src/Wasabi/bfc/multipatch.h @@ -0,0 +1,412 @@ +#ifndef _WASABI_MULTIPATCH_H +#define _WASABI_MULTIPATCH_H +// (c) 2005 Nullsoft, Inc. + +#include "dispatch.h" +/* +Author: Ben Allison + +The purpose of the MultiPatch class is to allow a class to have multiple Dispatchable interfaces. + +It is an alternative to the method of using a stub class with virtual functions. +(you see these classes all over Wasabi, either ending in I or X, depending on age) +Since each vtable entry costs 4 bytes per object (8 on 64bit), using this method adds some code size +(and, in some multiple-inheritance situations, memory per object for vtable overrides) + +Of course, MultiPatch's dispatching function adds code size, too. But the function shouldn't be any +larger or slower than the dispatching in the api_X class anyway. + +Using MultiPatch, each method call goes through this chain: + dispatch->multipatch->your class method + + as opposed to: + dispatch->your class method (single inheritance) + + or: + dispatch->virtual function->your class method (api_X method) + +A clever compiler might be able to optimize away the _multipatch function call by +pushing "patch" on the top of the parameter stack and jmp'ing. + +For an example on usage, scroll down to the bottom of the page. +*/ + +template +class MultiPatch : public base_t +{ +protected: + virtual int _multipatch(int patch, int msg, void *retval, void **params=0, int nparam=0) = 0; + +private: + int _dispatch(int msg, void *retval, void **params=0, int nparam=0) + { + return _multipatch(patch_t, msg, retval, params, nparam); + } + +public: + /* these helper functions are a direct copy from Dispatchable... + * They need to be duplicated, because the compiler gets confused when trying to cast + * from Dispatchable to the child class (since that class has multiple Dispatchable parents) + * + * They could potentially be eliminated by modifying Dispatchable's versions, but the risk of breakage + * isn't worth it. + */ + template + void cb(RETVAL (CLASSNAME::*fn)(), void *retval, void **params) { + *static_cast(retval) = (static_cast(this)->*fn)(); + } + + template + void vcb(void (CLASSNAME::*fn)(), void *retval, void **params) { + (static_cast(this)->*fn)(); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1); + } + + template + void vcb(void (CLASSNAME::*fn)(PARAM1), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + (static_cast(this)->*fn)(*p1); + } + + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + (static_cast(this)->*fn)(*p1, *p2); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1, *p2); + } + + // 3 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + (static_cast(this)->*fn)(*p1, *p2, *p3); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1, *p2, *p3); + } + + // 4 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1, *p2, *p3, *p4); + } + + // 5 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5); + } + + // 6 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6); + } + + // 7 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7); + } + + // 8 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8); + } + + // 9 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9); + } + + // 10 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + *static_cast(retval) = (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10); + } + + // 14 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + PARAM11 *p11 = static_cast(params[10]); + PARAM12 *p12 = static_cast(params[11]); + PARAM13 *p13 = static_cast(params[12]); + PARAM14 *p14 = static_cast(params[13]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14); + } + + // 16 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14, PARAM15, PARAM16), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + PARAM11 *p11 = static_cast(params[10]); + PARAM12 *p12 = static_cast(params[11]); + PARAM13 *p13 = static_cast(params[12]); + PARAM14 *p14 = static_cast(params[13]); + PARAM15 *p15 = static_cast(params[14]); + PARAM16 *p16 = static_cast(params[15]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14, *p15, *p16); + } + + // 17 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14, PARAM15, PARAM16, PARAM17), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + PARAM11 *p11 = static_cast(params[10]); + PARAM12 *p12 = static_cast(params[11]); + PARAM13 *p13 = static_cast(params[12]); + PARAM14 *p14 = static_cast(params[13]); + PARAM15 *p15 = static_cast(params[14]); + PARAM16 *p16 = static_cast(params[15]); + PARAM17 *p17 = static_cast(params[16]); + (static_cast(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14, *p15, *p16, *p17); + } + +}; + + +#define RECVS_MULTIPATCH int _multipatch(int patch, int msg, void *retval, void **params=0, int nparam=0) +#define START_MULTIPATCH \ + int CBCLASS::_multipatch(int patch, int msg, void *retval, void **params, int nparam) { \ + switch (patch) { +//FINISH case DESTRUCT: delete this; return 1; +#define END_MULTIPATCH \ + default: return 0; \ + } \ + return 1; \ + } +#define FORWARD_MULTIPATCH(x) \ + default: return x::_multipatch(patch, msg, retval, params, nparam); \ + } \ + return 1; \ + } + +#define START_PATCH(x) case x: switch(msg) { +#define END_PATCH default: return 0; } break; +#define NEXT_PATCH(x) END_PATCH START_PATCH(x) + +#define M_CB(p, c, x, y) case (x): MultiPatch::cb(&CBCLASS::y, retval, params); break; +#define M_VCB(p, c, x, y) case (x): MultiPatch::vcb(&CBCLASS::y, retval, params); break; + + +#define MULTIPATCH_CODES enum +#endif + + +/* use example: + +enum +{ + Test_Patch1 = 10, + Test_Patch2 = 20, +}; + +class Test : public MultiPatch, + public MultiPatch +{ +public: + int TestFunc1(); + void TestFunc2(); + void TestFunc3(); +protected: + RECVS_MULTIPATCH; +}; + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS Test +START_MULTIPATCH; + START_PATCH(Test_Patch1) + M_CB(Test_Patch1, api_class1, API_CLASS1_FUNC1, TestFunc1); + NEXT_PATCH(Test_Patch2) + M_VCB(Test_Patch2, api_class2, API_CLASS1_FUNC1, TestFunc2); + M_VCB(Test_Patch2, api_class2, API_CLASS1_FUNC2, TestFunc3); + END_PATCH +END_MULTIPATCH; +#undef CBCLASS + +*/ \ No newline at end of file -- cgit