/*! \file piobject.h * \brief Base object * * This file declare PIObject class and associated macros */ /* PIP - Platform Independent Primitives Object, base class of some PIP classes, provide EVENT -> EVENT_HANDLER mechanism Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIOBJECT_H #define PIOBJECT_H #include "piinit.h" #include "pivariant.h" #include "pimutex.h" #include "piset.h" #include "piqueue.h" #ifdef DOXYGEN /// \relatesalso PIObject \brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER and correct piCoutObj output #define PIOBJECT(name) /// \relatesalso PIObject \brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER of parent class, and \a scopeList() #define PIOBJECT_SUBCLASS(name, parent) /// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name() #define EVENT_HANDLER0(ret, name) ret name() /// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0) #define EVENT_HANDLER1(ret, name, type0, var0) ret name(type0 var0) /// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1) #define EVENT_HANDLER2(ret, name, type0, var0, type1, var1) ret name(type0 var0, type1 var1) /// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2) #define EVENT_HANDLER3(ret, name, type0, var0, type1, var1, type2, var2) ret name(type0 var0, type1 var1, type2 var2) /// \relatesalso PIObject \brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2, type3 var3) #define EVENT_HANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) ret name(type0 var0, type1 var1, type2 var2, type3 var3) /// \relatesalso PIObject \brief EVENT_HANDLER is synonym of EVENT_HANDLER0 #define EVENT_HANDLER EVENT_HANDLER0 /// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name() #define EVENT_VHANDLER0(ret, name) virtual ret name() /// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0) #define EVENT_VHANDLER1(ret, name, type0, var0) virtual ret name(type0 var0) /// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1) #define EVENT_VHANDLER2(ret, name, type0, var0, type1, var1) virtual ret name(type0 var0, type1 var1) /// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2) #define EVENT_VHANDLER3(ret, name, type0, var0, type1, var1, type2, var2) virtual ret name(type0 var0, type1 var1, type2 var2) /// \relatesalso PIObject \brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3) #define EVENT_VHANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3) /// \relatesalso PIObject \brief EVENT_VHANDLER is synonym of EVENT_VHANDLER0 #define EVENT_VHANDLER EVENT_VHANDLER0 /// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(); #define EVENT0(name) void name(); /// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0); #define EVENT1(name, type0, var0) void name(type0 var0); /// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1); #define EVENT2(name, type0, var0, type1, var1) void name(type0 var0, type1 var1); /// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2); #define EVENT3(name, type0, var0, type1, var1, type2, var2) void name(type0 var0, type1 var1, type2 var2); /// \relatesalso PIObject \brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2, type3 var3); #define EVENT4(name, type0, var0, type1, var1, type2, var2, type3, var3) void name(type0 var0, type1 var1, type2 var2, type3 var3); /// \relatesalso PIObject \brief EVENT is synonym of EVENT0 #define EVENT EVENT0 #define RAISE_EVENT0(src, event) #define RAISE_EVENT1(src, event, v0) #define RAISE_EVENT2(src, event, v0, v1) #define RAISE_EVENT3(src, event, v0, v1, v2) #define RAISE_EVENT4(src, event, v0, v1, v2, v3) #define RAISE_EVENT RAISE_EVENT0 /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\". \"Event\" and \"handler\" must has equal argument lists. #define CONNECTU(src, event, dest, handler) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\". /// Event handler will be executed by \"performer\". \"Event\" and \"handler\" must has equal argument lists. #define CONNECTU_QUEUED(src, event, dest, handler, performer) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to lambda-expression \"functor\". \"Event\" and \"functor\" must has equal argument lists. #define CONNECTL(src, event, functor) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists #define CONNECT0(ret, src, event, dest, handler) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists #define CONNECT1(ret, type0, src, event, dest, handler) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists #define CONNECT2(ret, type0, type1, src, event, dest, handler) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists #define CONNECT3(ret, type0, type1, type2, src, event, dest, handler) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists #define CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler) /// \relatesalso PIObject \brief CONNECT is synonym of CONNECT0 #define CONNECT CONNECT0 /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists #define WEAK_CONNECT0(ret, src, event, dest, handler) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists #define WEAK_CONNECT1(ret, type0, src, event, dest, handler) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists #define WEAK_CONNECT2(ret, type0, type1, src, event, dest, handler) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists #define WEAK_CONNECT3(ret, type0, type1, type2, src, event, dest, handler) /// \relatesalso PIObject \brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists #define WEAK_CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler) /// \relatesalso PIObject \brief WEAK_CONNECT is synonym of WEAK_CONNECT0 #define WEAK_CONNECT WEAK_CONNECT0 /// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\" #define DISCONNECT0(ret, src, event, dest, handler) /// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\" #define DISCONNECT1(ret, type0, src, event, dest, handler) /// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\" #define DISCONNECT2(ret, type0, type1, src, event, dest, handler) /// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\" #define DISCONNECT3(ret, type0, type1, type2, src, event, dest, handler) /// \relatesalso PIObject \brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\" #define DISCONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler) /// \relatesalso PIObject \brief DISCONNECT is synonym of DISCONNECT0 #define DISCONNECT DISCONNECT0 /// \relatesalso PIObject \brief Returns pointer to events handler \"handler\" #define HANDLER(handler) #define PIOBJECT(name) #define PIOBJECT_SUBCLASS(name) #else #define _PI_STR(x) #x #define _PI_SSTR(x) _PI_STR(x) #define LOCATION __FILE__ ":" _PI_SSTR(__LINE__) #ifdef CC_GCC # define __PTYPE(t) typename __PIVariantTypeInfo__::PureType #else # define __PTYPE(t) __PIVariantTypeInfo__::PureType #endif #define __VVALUE(t, v) v.value< __PTYPE(t) >() #define PIOBJECT(name) \ protected: \ typedef name __PIObject__; \ public: \ static const PIString __classNameS() {return PIStringAscii(#name);} \ static const uint __classNameIDS() {static uint ret = PIStringAscii(#name).hash(); return ret;} \ virtual const char * className() const {return #name;} \ virtual const uint classNameID() const {static uint ret = PIStringAscii(#name).hash(); return ret;} \ private: \ virtual int ptrOffset() const {name * o = (name*)100; return int(llong((PIObject*)o) - llong(o));} \ class __BaseInitializer__ { \ public: \ __BaseInitializer__() { \ uint pid = PIObject::__classNameIDS(); \ if (pid == 0) return; \ uint id = __classNameIDS(); \ PIMutexLocker ml(__meta_mutex()); \ if (__meta_data().contains(id)) return; \ __meta_data()[pid]; \ __meta_data()[id]; \ __MetaData & ehp(__meta_data()[pid]); \ __MetaData & eh(__meta_data()[id]); \ eh.eh_set << ehp.eh_set; \ eh.eh_func << ehp.eh_func; \ eh.addScope(__classNameS()); \ } \ }; \ __BaseInitializer__ __base_init__; #define PIOBJECT_PARENT(name) \ class __ParentInitializer__ { \ public: \ __ParentInitializer__() { \ uint pid = name::__classNameIDS(); \ if (pid == 0) return; \ uint id = __classNameIDS(); \ PIMutexLocker ml(__meta_mutex()); \ __meta_data()[pid]; \ __MetaData & eh(__meta_data()[id]); \ if (eh.scope_id.contains(pid)) return; \ __MetaData & ehp(__meta_data()[pid]); \ eh.eh_set << ehp.eh_set; \ eh.eh_func << ehp.eh_func; \ eh.scope_list = ehp.scope_list; \ eh.addScope(__classNameS()); \ } \ }; \ __ParentInitializer__ __parent_init__; \ public: \ virtual const char * parentClassName() const {return #name;} \ typedef name __Parent__; \ private: #define PIOBJECT_SUBCLASS(name, parent) PIOBJECT(name) PIOBJECT_PARENT(parent) #define EH_INIT0(ret, name) \ class __##name##0_Initializer__ { \ public: \ __##name##0_Initializer__() { \ PIMutexLocker ml(__meta_mutex()); \ __MetaData & eh(__meta_data()[__classNameIDS()]); \ void * fp = (void*)(ret(*)(void*))__stat_eh_##name##__; \ void * fpV = fp; \ if (eh.eh_set[fp]) return; \ eh.eh_set << fp; \ __MetaFunc & f(eh.eh_func[fp]); \ f.scope = __classNameS(); \ f.func_name = PIStringAscii(#name); \ f.addr = fp; \ f.addrV = fpV; \ f.type_ret = PIStringAscii(#ret); \ } \ }; \ __##name##0_Initializer__ __##name##0_init__; \ #define EH_INIT1(ret, name, a0, n0) \ class __##name##1##n0##_Initializer__ { \ public: \ __##name##1##n0##_Initializer__() { \ PIMutexLocker ml(__meta_mutex()); \ __MetaData & eh(__meta_data()[__classNameIDS()]); \ void * fp = (void*)(ret(*)(void*, a0))__stat_eh_##name##__; \ void * fpV = (void*)(ret(*)(void*, const PIVariant &))__stat_eh_v_##name##__; \ if (eh.eh_set[fp]) return; \ eh.eh_set << fp; \ __MetaFunc & f(eh.eh_func[fp]); \ f.scope = __classNameS(); \ f.func_name = PIStringAscii(#name); \ f.addr = fp; \ f.addrV = fpV; \ f.type_ret = PIStringAscii(#ret); \ f.types << PIObject::simplifyType(#a0); \ f.names << PIStringAscii(#n0); \ } \ }; \ __##name##1##n0##_Initializer__ __##name##1##n0##_init__; \ #define EH_INIT2(ret, name, a0, n0, a1, n1) \ class __##name##2##n0##n1##_Initializer__ { \ public: \ __##name##2##n0##n1##_Initializer__() { \ PIMutexLocker ml(__meta_mutex()); \ __MetaData & eh(__meta_data()[__classNameIDS()]); \ void * fp = (void*)(ret(*)(void*, a0, a1))__stat_eh_##name##__; \ void * fpV = (void*)(ret(*)(void*, const PIVariant &, const PIVariant &))__stat_eh_v_##name##__; \ if (eh.eh_set[fp]) return; \ eh.eh_set << fp; \ __MetaFunc & f(eh.eh_func[fp]); \ f.scope = __classNameS(); \ f.func_name = PIStringAscii(#name); \ f.addr = fp; \ f.addrV = fpV; \ f.type_ret = PIStringAscii(#ret); \ f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1); \ f.names << PIStringAscii(#n0) << PIStringAscii(#n1); \ } \ }; \ __##name##2##n0##n1##_Initializer__ __##name##2##n0##n1##_init__; \ #define EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \ class __##name##3##n0##n1##n2##_Initializer__ { \ public: \ __##name##3##n0##n1##n2##_Initializer__() { \ PIMutexLocker ml(__meta_mutex()); \ __MetaData & eh(__meta_data()[__classNameIDS()]); \ void * fp = (void*)(ret(*)(void*, a0, a1, a2))__stat_eh_##name##__; \ void * fpV = (void*)(ret(*)(void*, const PIVariant &, const PIVariant &, const PIVariant &))__stat_eh_v_##name##__; \ if (eh.eh_set[fp]) return; \ eh.eh_set << fp; \ __MetaFunc & f(eh.eh_func[fp]); \ f.scope = __classNameS(); \ f.func_name = PIStringAscii(#name); \ f.addr = fp; \ f.addrV = fpV; \ f.type_ret = PIStringAscii(#ret); \ f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1) << PIObject::simplifyType(#a2); \ f.names << PIStringAscii(#n0) << PIStringAscii(#n1) << PIStringAscii(#n2); \ } \ }; \ __##name##3##n0##n1##n2##_Initializer__ __##name##3##n0##n1##n2##_init__; \ #define EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \ class __##name##4##n0##n1##n2##n3##_Initializer__ { \ public: \ __##name##4##n0##n1##n2##n3##_Initializer__() { \ PIMutexLocker ml(__meta_mutex()); \ __MetaData & eh(__meta_data()[__classNameIDS()]); \ void * fp = (void*)(ret(*)(void*, a0, a1, a2, a3))__stat_eh_##name##__; \ void * fpV = (void*)(ret(*)(void*, const PIVariant &, const PIVariant &, const PIVariant &, const PIVariant &))__stat_eh_v_##name##__; \ if (eh.eh_set[fp]) return; \ eh.eh_set << fp; \ __MetaFunc & f(eh.eh_func[fp]); \ f.scope = __classNameS(); \ f.func_name = PIStringAscii(#name); \ f.addr = fp; \ f.addrV = fpV; \ f.type_ret = PIStringAscii(#ret); \ f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1) << PIObject::simplifyType(#a2) << PIObject::simplifyType(#a3); \ f.names << PIStringAscii(#n0) << PIStringAscii(#n1) << PIStringAscii(#n2) << PIStringAscii(#n3); \ } \ }; \ __##name##4##n0##n1##n2##n3##_Initializer__ __##name##4##n0##n1##n2##n3##_init__; \ #define EVENT_HANDLER0(ret, name) \ EH_INIT0(ret, name) \ static ret __stat_eh_##name##__(void * __o__) {return ((__PIObject__*)__o__)->name();} \ ret name() #define EVENT_HANDLER1(ret, name, a0, n0) \ EH_INIT1(ret, name, a0, n0) \ static ret __stat_eh_##name##__(void * __o__, a0 n0) {return ((__PIObject__*)__o__)->name(n0);} \ static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0) { \ __PTYPE(a0) tv0 = __VVALUE(a0, v0); \ return ((__PIObject__*)__o__)->name(tv0);} \ ret name(a0 n0) #define EVENT_HANDLER2(ret, name, a0, n0, a1, n1) \ EH_INIT2(ret, name, a0, n0, a1, n1) \ static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1) {return ((__PIObject__*)__o__)->name(n0, n1);} \ static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1) { \ __PTYPE(a0) tv0 = __VVALUE(a0, v0); \ __PTYPE(a1) tv1 = __VVALUE(a1, v1); \ return ((__PIObject__*)__o__)->name(tv0, tv1);} \ ret name(a0 n0, a1 n1) #define EVENT_HANDLER3(ret, name, a0, n0, a1, n1, a2, n2) \ EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \ static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)__o__)->name(n0, n1, n2);} \ static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) { \ __PTYPE(a0) tv0 = __VVALUE(a0, v0); \ __PTYPE(a1) tv1 = __VVALUE(a1, v1); \ __PTYPE(a2) tv2 = __VVALUE(a2, v2); \ return ((__PIObject__*)__o__)->name(tv0, tv1, tv2);} \ ret name(a0 n0, a1 n1, a2 n2) #define EVENT_HANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \ EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \ static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)__o__)->name(n0, n1, n2, n3);} \ static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) { \ __PTYPE(a0) tv0 = __VVALUE(a0, v0); \ __PTYPE(a1) tv1 = __VVALUE(a1, v1); \ __PTYPE(a2) tv2 = __VVALUE(a2, v2); \ __PTYPE(a3) tv3 = __VVALUE(a3, v3); \ return ((__PIObject__*)__o__)->name(tv0, tv1, tv2, tv3);} \ ret name(a0 n0, a1 n1, a2 n2, a3 n3) #define EVENT_HANDLER EVENT_HANDLER0 #define EVENT_VHANDLER0(ret, name) \ EH_INIT0(ret, name) \ static ret __stat_eh_##name##__(void * __o__) {return ((__PIObject__*)__o__)->name();} \ virtual ret name() #define EVENT_VHANDLER1(ret, name, a0, n0) \ EH_INIT1(ret, name, a0, n0) \ static ret __stat_eh_##name##__(void * __o__, a0 n0) {return ((__PIObject__*)__o__)->name(n0);} \ static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0));} \ virtual ret name(a0 n0) #define EVENT_VHANDLER2(ret, name, a0, n0, a1, n1) \ EH_INIT2(ret, name, a0, n0, a1, n1) \ static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1) {return ((__PIObject__*)__o__)->name(n0, n1);} \ static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0), __VVALUE(a1, v1));} \ virtual ret name(a0 n0, a1 n1) #define EVENT_VHANDLER3(ret, name, a0, n0, a1, n1, a2, n2) \ EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \ static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2) {return ((__PIObject__*)__o__)->name(n0, n1, n2);} \ static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0), __VVALUE(a1, v1), __VVALUE(a2, v2));} \ virtual ret name(a0 n0, a1 n1, a2 n2) #define EVENT_VHANDLER4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \ EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \ static ret __stat_eh_##name##__(void * __o__, a0 n0, a1 n1, a2 n2, a3 n3) {return ((__PIObject__*)__o__)->name(n0, n1, n2, n3);} \ static ret __stat_eh_v_##name##__(void * __o__, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return ((__PIObject__*)__o__)->name(__VVALUE(a0, v0), __VVALUE(a1, v1), __VVALUE(a2, v2), __VVALUE(a3, v3));} \ virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3) #define EVENT_VHANDLER EVENT_VHANDLER0 #define EVENT0(name) EVENT_HANDLER0(void, name) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid);} #define EVENT1(name, a0, n0) EVENT_HANDLER1(void, name, a0, n0) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0);} #define EVENT2(name, a0, n0, a1, n1) EVENT_HANDLER2(void, name, a0, n0, a1, n1) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0, n1);} #define EVENT3(name, a0, n0, a1, n1, a2, n2) EVENT_HANDLER3(void, name, a0, n0, a1, n1, a2, n2) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0, n1, n2);} #define EVENT4(name, a0, n0, a1, n1, a2, n2, a3, n3) EVENT_HANDLER4(void, name, a0, n0, a1, n1, a2, n2, a3, n3) {static uint eid = PIStringAscii(#name).hash(); PIObject::raiseEvent(this, eid, n0, n1, n2, n3);} #define EVENT EVENT0 #define RAISE_EVENT0(src, event) (src)->event(); #define RAISE_EVENT1(src, event, v0) (src)->event(v0); #define RAISE_EVENT2(src, event, v0, v1) (src)->event(v0, v1); #define RAISE_EVENT3(src, event, v0, v1, v2) (src)->event(v0, v1, v2); #define RAISE_EVENT4(src, event, v0, v1, v2, v3) (src)->event(v0, v1, v2, v3); #define RAISE_EVENT RAISE_EVENT0 #define CONNECTU(src, event, dest, handler) PIObject::piConnectU(src, PIStringAscii(#event), dest, dest, PIStringAscii(#handler), LOCATION); #define CONNECTU_QUEUED(src, event, dest, handler, performer) PIObject::piConnectU(src, PIStringAscii(#event), dest, dest, PIStringAscii(#handler), LOCATION, performer); #ifdef PIP_CXX11_SUPPORT # define CONNECTL(src, event, functor) PIObject::piConnectLS(src, PIStringAscii(#event), PIObject::__newFunctor(&(src)->__stat_eh_##event##__, functor), LOCATION); #endif #define CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*))(&(src)->__stat_eh_##event##__), 0, LOCATION); #define CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0))(&(src)->__stat_eh_##event##__), 1, LOCATION); #define CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1))(&(src)->__stat_eh_##event##__), 2, LOCATION); #define CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2))(&(src)->__stat_eh_##event##__), 3, LOCATION); #define CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__), (void*)(void(*)(void*, a0, a1, a2, a3))(&(src)->__stat_eh_##event##__), 4, LOCATION); #define CONNECT CONNECT0 #define WEAK_CONNECT0(ret, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__), 0, 0, LOCATION); #define WEAK_CONNECT1(ret, a0, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__), 0, 1, LOCATION); #define WEAK_CONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__), 0, 2, LOCATION); #define WEAK_CONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__), 0, 3, LOCATION); #define WEAK_CONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piConnect(src, PIStringAscii(#event), dest, dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__), 0, 4, LOCATION); #define WEAK_CONNECT WEAK_CONNECT0 #define DISCONNECT0(ret, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*))(&(dest)->__stat_eh_##handler##__)); #define DISCONNECT1(ret, a0, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0))(&(dest)->__stat_eh_##handler##__)); #define DISCONNECT2(ret, a0, a1, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0, a1))(&(dest)->__stat_eh_##handler##__)); #define DISCONNECT3(ret, a0, a1, a2, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0, a1, a2))(&(dest)->__stat_eh_##handler##__)); #define DISCONNECT4(ret, a0, a1, a2, a3, src, event, dest, handler) PIObject::piDisconnect(src, PIStringAscii(#event), dest, (void*)(ret(*)(void*, a0, a1, a2, a3))(&(dest)->__stat_eh_##handler##__)); #define DISCONNECT DISCONNECT0 #define HANDLER(handler) __stat_eh_##handler##__ #define __PIOBJECT_SIGNATURE__ 0xabcdbadc #endif typedef void (*Handler)(void * ); class PIP_EXPORT PIObject { friend class PIObjectManager; friend void dumpApplication(); typedef PIObject __PIObject__; typedef void __Parent__; friend class PIIntrospection; public: //! Contructs PIObject with name "name" explicit PIObject(const PIString & name = PIString()); virtual ~PIObject(); private: explicit PIObject(const PIObject & ); void operator =(const PIObject & ); uint _signature_; public: //! Returns object name PIString name() const {return property(PIStringAscii("name")).toString();} //! Returns object class name virtual const char * className() const {return "PIObject";} virtual const uint classNameID() const {static uint ret = PIStringAscii("PIObject").hash(); return ret;} static const PIString __classNameS() {return PIStringAscii("PIObject");} static const uint __classNameIDS() {static uint ret = PIStringAscii("PIObject").hash(); return ret;} //! Returns parent object class name virtual const char * parentClassName() const {return "";} //! Return if debug of this object is active bool debug() const {return property(PIStringAscii("debug")).toBool();} //! Set object name void setName(const PIString & name) {setProperty(PIStringAscii("name"), name);} void setName(const char * name) {setName(PIStringAscii(name));} //! Set object debug active void setDebug(bool debug) {setProperty(PIStringAscii("debug"), debug);} //! Returns properties of the object PIMap properties() const; //! Returns properties count of the object int propertiesCount() const {return properties_.size_s();} //! Returns property with name "name" PIVariant property(const PIString & name) const {return properties_.value(name.hash(), Property(PIString(), PIVariant())).second;} PIVariant property(const char * name) const {return property(PIStringAscii(name));} //! Set property with name "name" to "value". If there is no such property in object it will be added void setProperty(const PIString & name, const PIVariant & value) {properties_[name.hash()] = Property(name, value); propertyChanged(name);} void setProperty(const char * name, const PIVariant & value) {setProperty(PIStringAscii(name), value);} //! Returns if property with name "name" exists bool isPropertyExists(const PIString & name) const {return properties_.contains(name.hash());} bool isPropertyExists(const char * name) const {return isPropertyExists(PIStringAscii(name));} void setThreadSafe(bool yes) {thread_safe_ = yes;} bool isThreadSafe() const {return thread_safe_;} bool execute(const PIString & method, const PIVector & vl); bool execute(const PIString & method) {return execute(method, PIVector());} bool execute(const PIString & method, const PIVariant & v0) {return execute(method, PIVector() << v0);} bool execute(const PIString & method, const PIVariant & v0, const PIVariant & v1) {return execute(method, PIVector() << v0 << v1);} bool execute(const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return execute(method, PIVector() << v0 << v1 << v2);} bool execute(const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return execute(method, PIVector() << v0 << v1 << v2 << v3);} bool executeQueued(PIObject * performer, const PIString & method, const PIVector & vl); bool executeQueued(PIObject * performer, const PIString & method) {return executeQueued(performer, method, PIVector());} bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0) {return executeQueued(performer, method, PIVector() << v0);} bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1) {return executeQueued(performer, method, PIVector() << v0 << v1);} bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return executeQueued(performer, method, PIVector() << v0 << v1 << v2);} bool executeQueued(PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return executeQueued(performer, method, PIVector() << v0 << v1 << v2 << v3);} static bool execute(PIObject * o, const PIString & method, const PIVector & vl) {return o->execute(method, vl);} static bool execute(PIObject * o, const PIString & method) {return execute(o, method, PIVector());} static bool execute(PIObject * o, const PIString & method, const PIVariant & v0) {return execute(o, method, PIVector() << v0);} static bool execute(PIObject * o, const PIString & method, const PIVariant & v0, const PIVariant & v1) {return execute(o, method, PIVector() << v0 << v1);} static bool execute(PIObject * o, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return execute(o, method, PIVector() << v0 << v1 << v2);} static bool execute(PIObject * o, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return execute(o, method, PIVector() << v0 << v1 << v2 << v3);} static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVector & vl) {return o->executeQueued(performer, method, vl);} static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method) {return executeQueued(o, performer, method, PIVector());} static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0) {return executeQueued(o, performer, method, PIVector() << v0);} static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1) {return executeQueued(o, performer, method, PIVector() << v0 << v1);} static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2) {return executeQueued(o, performer, method, PIVector() << v0 << v1 << v2);} static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariant & v0, const PIVariant & v1, const PIVariant & v2, const PIVariant & v3) {return executeQueued(o, performer, method, PIVector() << v0 << v1 << v2 << v3);} void dump(const PIString & line_prefix = PIString()) const; PIStringList scopeList() const; PIStringList methodsEH() const; bool isMethodEHContains(const PIString & name) const; PIString methodEHArguments(const PIString & name) const; PIString methodEHFullFormat(const PIString & name) const; PIString methodEHFromAddr(const void * addr) const; // / Direct connect static void piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc); static bool piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer = 0); #ifdef PIP_CXX11_SUPPORT static bool piConnectLS(PIObject * src, const PIString & sig, std::function * f, const char * loc); template static std::function * __newFunctor(void(*stat_handler)(void*,TYPES...), INPUT functor) { return (std::function*)(new std::function(functor)); } #endif // / Through names and mixed static void piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h); static void piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h); static void piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h); static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest, void * ev_h); static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest); //! Disconnect object "src" from all connections with event name "sig" static void piDisconnect(PIObject * src, const PIString & sig); //! Disconnect object "src" from all connections, i.e. all connections where object "src" is emitter static void piDisconnect(PIObject * src); // / Raise events static void raiseEvent(PIObject * sender, const uint eventID) { for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; #ifdef PIP_CXX11_SUPPORT if (i.functor) { (*(i.functor))(); } else { #endif if (i.performer) { i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender)); } else { bool ts = sender->thread_safe_; if (ts) i.dest_o->mutex_.lock(); i.dest_o->emitter_ = sender; ((void( *)(void * ))i.slot)(i.dest); if (i.dest_o->isPIObject()) { i.dest_o->emitter_ = 0; if (ts) i.dest_o->mutex_.unlock(); } } #ifdef PIP_CXX11_SUPPORT } #endif if (!sender->isPIObject()) break; } } template static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0()) { for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; #ifdef PIP_CXX11_SUPPORT if (i.functor) { (*((std::function*)i.functor))(v0); } else { #endif if (i.performer) { PIVector vl; if (i.args_count > 0) vl << PIVariant::fromValue(v0); i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl)); } else { bool ts = sender->thread_safe_; if (ts) i.dest_o->mutex_.lock(); i.dest_o->emitter_ = sender; if (i.args_count == 0) ((void(*)(void *))i.slot)(i.dest); else ((void(*)(void * , T0))i.slot)(i.dest, v0); if (i.dest_o->isPIObject()) { i.dest_o->emitter_ = 0; if (ts) i.dest_o->mutex_.unlock(); } } #ifdef PIP_CXX11_SUPPORT } #endif if (!sender->isPIObject()) break; } } template static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1()) { for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; #ifdef PIP_CXX11_SUPPORT if (i.functor) { (*((std::function*)i.functor))(v0, v1); } else { #endif if (i.performer) { PIVector vl; if (i.args_count > 0) vl << PIVariant::fromValue(v0); if (i.args_count > 1) vl << PIVariant::fromValue(v1); i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl)); } else { bool ts = sender->thread_safe_; if (ts) i.dest_o->mutex_.lock(); i.dest_o->emitter_ = sender; switch (i.args_count) { case 0: ((void(*)(void *))i.slot)(i.dest); break; case 1: ((void(*)(void * , T0))i.slot)(i.dest, v0); break; default: ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); break; } if (i.dest_o->isPIObject()) { i.dest_o->emitter_ = 0; if (ts) i.dest_o->mutex_.unlock(); } } #ifdef PIP_CXX11_SUPPORT } #endif if (!sender->isPIObject()) break; } } template static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) { for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; #ifdef PIP_CXX11_SUPPORT if (i.functor) { (*((std::function*)i.functor))(v0, v1, v2); } else { #endif if (i.performer) { PIVector vl; if (i.args_count > 0) vl << PIVariant::fromValue(v0); if (i.args_count > 1) vl << PIVariant::fromValue(v1); if (i.args_count > 2) vl << PIVariant::fromValue(v2); i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl)); } else { bool ts = sender->thread_safe_; if (ts) i.dest_o->mutex_.lock(); i.dest_o->emitter_ = sender; switch (i.args_count) { case 0: ((void(*)(void *))i.slot)(i.dest); break; case 1: ((void(*)(void * , T0))i.slot)(i.dest, v0); break; case 2: ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); break; default: ((void(*)(void * , T0, T1, T2))i.slot)(i.dest, v0, v1, v2); break; } if (i.dest_o->isPIObject()) { i.dest_o->emitter_ = 0; if (ts) i.dest_o->mutex_.unlock(); } } #ifdef PIP_CXX11_SUPPORT } #endif if (!sender->isPIObject()) break; } } template static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) { for (int j = 0; j < sender->connections.size_s(); ++j) { __Connection i(sender->connections[j]); if (i.eventID != eventID) continue; #ifdef PIP_CXX11_SUPPORT if (i.functor) { (*((std::function*)i.functor))(v0, v1, v2, v3); } else { #endif if (i.performer) { PIVector vl; if (i.args_count > 0) vl << PIVariant::fromValue(v0); if (i.args_count > 1) vl << PIVariant::fromValue(v1); if (i.args_count > 2) vl << PIVariant::fromValue(v2); if (i.args_count > 3) vl << PIVariant::fromValue(v3); i.performer->postQueuedEvent(__QueuedEvent(i.slot, i.dest, i.dest_o, sender, vl)); } else { bool ts = sender->thread_safe_; if (ts) i.dest_o->mutex_.lock(); i.dest_o->emitter_ = sender; switch (i.args_count) { case 0: ((void(*)(void *))i.slot)(i.dest); break; case 1: ((void(*)(void * , T0))i.slot)(i.dest, v0); break; case 2: ((void(*)(void * , T0, T1))i.slot)(i.dest, v0, v1); break; case 3: ((void(*)(void * , T0, T1, T2))i.slot)(i.dest, v0, v1, v2); break; default: ((void(*)(void * , T0, T1, T2, T3))i.slot)(i.dest, v0, v1, v2, v3); break; } if (i.dest_o->isPIObject()) { i.dest_o->emitter_ = 0; if (ts) i.dest_o->mutex_.unlock(); } } #ifdef PIP_CXX11_SUPPORT } #endif if (!sender->isPIObject()) break; } } //! Returns PIObject* with name "name" or 0, if there is no object found static PIObject * findByName(const PIString & name) { PIMutexLocker _ml(mutexObjects()); piForeach (PIObject * i, PIObject::objects()) { if (i->name() != name) continue; return i; } return 0; } bool isPIObject() const {return isPIObject(this);} template bool isTypeOf() const { if (!isPIObject()) return false; return scopeList().contains(T::__classNameS()); } template T * cast() const { if (!isTypeOf()) return (T*)0; return (T*)this; } static bool isPIObject(const PIObject * o); static bool isPIObject(const void * o) {return isPIObject((PIObject*)o);} template static bool isTypeOf(const PIObject * o) {return o->isTypeOf();} template static bool isTypeOf(const void * o) {return isTypeOf((PIObject*)o);} static PIString simplifyType(const char * a); struct __MetaFunc { __MetaFunc(): addr(0), addrV(0) {;} bool isNull() const {return addr == 0;} PIString arguments() const; PIString fullFormat() const; void * addr; void * addrV; PIString func_name; PIString type_ret; PIString scope; PIStringList types; PIStringList names; }; struct __MetaData { __MetaData() {scope_list << PIStringAscii("PIObject");} void addScope(const PIString & s); PIStringList scope_list; PISet scope_id; PISet eh_set; PIMap eh_func; }; typedef PIPair __EHPair; static PIMutex & __meta_mutex(); static PIMap & __meta_data(); // [hash(classname)]=__MetaData //! \brief Execute all posted events from CONNECTU_QUEUED connections void callQueuedEvents(); //! \brief Check if any CONNECTU_QUEUED connections to this object and execute them. //! \details This function is more optimized than \a callQueuedEvents() for objects that doesn`t //! appears as \"performer\" target at CONNECTU_QUEUED bool maybeCallQueuedEvents() {if (proc_event_queue) callQueuedEvents(); return proc_event_queue;} protected: //! Returns PIObject* which has raised an event. This value is correct only in definition of some event handler PIObject * emitter() const {return emitter_;} //! Virtual function executes after property with name "name" has been changed virtual void propertyChanged(const PIString & name) {} EVENT(deleted) //! \events //! \{ /** \fn void deleted() * \brief Raise before object delete * \note This event raised from destructor, so use only emitter() value, * don`t try to cast deleted object to some subclass! */ //! \} private: struct __Connection { __Connection(void * sl = 0, void * si = 0, const PIString & e = PIString(), PIObject * d_o = 0, void * d = 0, int ac = 0, PIObject * p = 0) { slot = sl; signal = si; event = e; eventID = e.hash(); dest_o = d_o; dest = d; args_count = ac; performer = p; #ifdef PIP_CXX11_SUPPORT functor = 0; #endif } void destroy(); void * slot; void * signal; #ifdef PIP_CXX11_SUPPORT std::function * functor; #endif PIString event; uint eventID; PIObject * dest_o; PIObject * performer; void * dest; int args_count; }; struct __QueuedEvent { __QueuedEvent(void * sl = 0, void * d = 0, PIObject * d_o = 0, PIObject * s = 0, const PIVector & v = PIVector()) { slot = sl; dest = d; dest_o = d_o; src = s; values = v; } void * slot; void * dest; PIObject * dest_o; PIObject * src; PIVector values; }; typedef PIPair Property; typedef PIPair > PropertyHash; bool findSuitableMethodV(const PIString & method, int args, int & ret_args, __MetaFunc & ret); PIVector<__MetaFunc> findEH(const PIString & name) const; __MetaFunc methodEH(const void * addr) const; void updateConnectors(); void postQueuedEvent(const __QueuedEvent & e); void * toThis() const; virtual int ptrOffset() const {return 0;} static PIVector & objects(); static PIMutex & mutexObjects(); static void callAddrV(void * slot, void * obj, int args, const PIVector & vl); PIVector<__Connection> connections; PIMap > properties_; PISet connectors; PIVector<__QueuedEvent> events_queue; PIMutex mutex_, mutex_connect, mutex_queue; PIObject * emitter_; bool thread_safe_, proc_event_queue; }; void dumpApplication(); bool dumpApplicationToFile(const PIString & path); #endif // PIOBJECT_H