Files
pip/libs/main/core/piobject.h

780 lines
35 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \addtogroup Core
//! \{
//! \file piobject.h
//! \brief
//! \~english Base object class providing event -> handler mechanism
//! \~russian Базовый класс объектов, обеспечивающий механизм событий -> обработчиков
//! \details
//! \~english PIObject is the base class for all PIP classes that need event-driven communication.
//! It provides signal-slot mechanism, property system, and object lifetime management.
//! \~russian PIObject является базовым классом для всех классов PIP, которым необходима событийная коммуникация.
//! Он обеспечивает механизм сигналов-слотов, систему свойств и управление жизненным циклом объектов.
//! \~
/*
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 <http://www.gnu.org/licenses/>.
*/
#ifndef PIOBJECT_H
#define PIOBJECT_H
#include "piinit.h"
#include "pimutex.h"
#include "piobject_macros.h"
#include "piqueue.h"
#include "piset.h"
#include "pivariant.h"
#include "pivariantsimple.h"
//! \~english Base class for classes using event -> handler mechanism
//! \~russian Базовый класс для классов, использующих механизм событий -> обработчиков
class PIP_EXPORT PIObject {
#ifndef MICRO_PIP
friend class PIObjectManager;
friend PIP_EXPORT void dumpApplication(bool);
friend class PIIntrospection;
#endif
typedef PIObject __PIObject__;
typedef void __Parent__;
public:
NO_COPY_CLASS(PIObject);
//! \~english Constructs %PIObject with name "name"
//! \~russian Создает %PIObject с именем "name"
explicit PIObject(const PIString & name = PIString());
virtual ~PIObject();
//! \ingroup Core
//! \~\brief
//! \~english Helper class for obtain info about if connection successful and disconnect single connection.
//! \~russian Вспомогательный класс для получения информации об успешности соединения и возможности его разрыва.
class PIP_EXPORT Connection {
friend class PIObject;
Connection(void * sl,
void * si,
const PIString & e = PIString(),
PIObject * s_o = nullptr,
PIObject * d_o = nullptr,
void * d = nullptr,
int ac = 0,
PIObject * p = nullptr) {
slot = sl;
signal = si;
event = e;
eventID = e.hash();
src_o = s_o;
dest_o = d_o;
dest = d;
args_count = ac;
performer = p;
functor = 0;
}
void destroy();
void * slot;
void * signal;
std::function<void()> * functor;
PIString event;
uint eventID;
PIObject *src_o, *dest_o;
PIObject * performer;
void * dest;
int args_count;
public:
//! \~english Constructs invalid %Connection
//! \~russian Создает недействительный %Connection
Connection();
//! \~english Returns if %Connection is valid
//! \~russian Возвращает успешен ли %Connection
bool isValid() const { return signal; }
//! \~english Returns source object
//! \~russian Возвращает объект-источник
PIObject * sourceObject() const { return src_o; }
//! \~english Returns destination object or "nullptr" if this is lambda connection
//! \~russian Возвращает объект-приемник или "nullptr" если это соединение на лямбда-функцию
PIObject * destinationObject() const { return dest_o; }
//! \~english Returns performer object or "nullptr" if this is non-queued connection
//! \~russian Возвращает объект-исполнитель или "nullptr" если это соединение не отложенное
PIObject * performerObject() const { return performer; }
//! \~english Disconnect this %Connection, returns if operation successful
//! \~russian Разрывает этот %Connection, возвращает успешен ли разрыв
bool disconnect() const;
};
private:
uint _signature_;
public:
//! \~english Returns object name
//! \~russian Возвращает имя объекта
PIString name() const { return property("name").toString(); }
//! \~english Returns object class name
//! \~russian Возвращает имя класса объекта
virtual const char * className() const { return "PIObject"; }
virtual uint classNameID() const {
static uint ret = PIStringAscii("PIObject").hash();
return ret;
}
static const char * __classNameCC() { return "PIObject"; }
static uint __classNameIDS() {
static uint ret = PIStringAscii("PIObject").hash();
return ret;
}
//! \~english Returns parent class name
//! \~russian Возвращает имя родительского класса
virtual const char * parentClassName() const { return ""; }
//! \~english Return if \a piCoutObj of this object is active
//! \~russian Возвращает включен ли вывод \a piCoutObj для этого объекта
bool debug() const { return property("debug").toBool(); }
//! \~english Set object name
//! \~russian Устанавливает имя объекта
void setName(const PIString & name) { setProperty("name", name); }
//! \~english Set object \a piCoutObj active
//! \~russian Включает или отключает вывод \a piCoutObj для этого объекта
void setDebug(bool debug) { setProperty("debug", debug); }
//! \~english Returns property with name "name"
//! \~russian Возвращает свойство объекта по имени "name"
PIVariant property(const char * name) const { return properties_.value(piHashData((const uchar *)name, strlen(name))); }
//! \~english Set property with name "name" to "value". If there is no such property in object it will be added
//! \~russian Устанавливает у объекта свойство по имени "name" в "value". Если такого свойства нет, оно добавляется
void setProperty(const char * name, const PIVariant & value) {
properties_[piHashData((const uchar *)name, strlen(name))] = value;
propertyChanged(name);
}
//! \~english Returns if property with name "name" exists
//! \~russian Возвращает присутствует ли свойство по имени "name"
bool isPropertyExists(const char * name) const { return properties_.contains(piHashData((const uchar *)name, strlen(name))); }
void setThreadSafe(bool yes) { thread_safe_ = yes; }
//! \~english Returns if object is thread safe
//! \~russian Возвращает является ли объект потокобезопасным
bool isThreadSafe() const { return thread_safe_; }
//! \~english Executes method with specified arguments
//! \~russian Выполняет метод с указанными аргументами
bool execute(const PIString & method, const PIVector<PIVariantSimple> & vl);
//! \~english Executes method without arguments
//! \~russian Выполняет метод без аргументов
bool execute(const PIString & method) { return execute(method, PIVector<PIVariantSimple>()); }
//! \~english Executes method with one argument
//! \~russian Выполняет метод с одним аргументом
bool execute(const PIString & method, const PIVariantSimple & v0) { return execute(method, PIVector<PIVariantSimple>() << v0); }
//! \~english Executes method with two arguments
//! \~russian Выполняет метод с двумя аргументами
bool execute(const PIString & method, const PIVariantSimple & v0, const PIVariantSimple & v1) {
return execute(method, PIVector<PIVariantSimple>() << v0 << v1);
}
//! \~english Executes method with three arguments
//! \~russian Выполняет метод с тремя аргументами
bool execute(const PIString & method, const PIVariantSimple & v0, const PIVariantSimple & v1, const PIVariantSimple & v2) {
return execute(method, PIVector<PIVariantSimple>() << v0 << v1 << v2);
}
//! \~english Executes method with four arguments
//! \~russian Выполняет метод с четырьмя аргументами
bool execute(const PIString & method,
const PIVariantSimple & v0,
const PIVariantSimple & v1,
const PIVariantSimple & v2,
const PIVariantSimple & v3) {
return execute(method, PIVector<PIVariantSimple>() << v0 << v1 << v2 << v3);
}
//! \~english Executes method queued with performer
//! \~russian Выполняет метод в очереди с исполнителем
bool executeQueued(PIObject * performer, const PIString & method, const PIVector<PIVariantSimple> & vl);
//! \~english Executes method without arguments queued with performer
//! \~russian Выполняет метод без аргументов в очереди с исполнителем
bool executeQueued(PIObject * performer, const PIString & method) {
return executeQueued(performer, method, PIVector<PIVariantSimple>());
}
//! \~english Executes method with one argument queued with performer
//! \~russian Выполняет метод с одним аргументом в очереди с исполнителем
bool executeQueued(PIObject * performer, const PIString & method, const PIVariantSimple & v0) {
return executeQueued(performer, method, PIVector<PIVariantSimple>() << v0);
}
//! \~english Executes method with two arguments queued with performer
//! \~russian Выполняет метод с двумя аргументами в очереди с исполнителем
bool executeQueued(PIObject * performer, const PIString & method, const PIVariantSimple & v0, const PIVariantSimple & v1) {
return executeQueued(performer, method, PIVector<PIVariantSimple>() << v0 << v1);
}
//! \~english Executes method with three arguments queued with performer
//! \~russian Выполняет метод с тремя аргументами в очереди с исполнителем
bool executeQueued(PIObject * performer,
const PIString & method,
const PIVariantSimple & v0,
const PIVariantSimple & v1,
const PIVariantSimple & v2) {
return executeQueued(performer, method, PIVector<PIVariantSimple>() << v0 << v1 << v2);
}
//! \~english Executes method with four arguments queued with performer
//! \~russian Выполняет метод с четырьмя аргументами в очереди с исполнителем
bool executeQueued(PIObject * performer,
const PIString & method,
const PIVariantSimple & v0,
const PIVariantSimple & v1,
const PIVariantSimple & v2,
const PIVariantSimple & v3) {
return executeQueued(performer, method, PIVector<PIVariantSimple>() << v0 << v1 << v2 << v3);
}
//! \~english Executes method on object with specified arguments
//! \~russian Выполняет метод на объекте с указанными аргументами
static bool execute(PIObject * o, const PIString & method, const PIVector<PIVariantSimple> & vl) { return o->execute(method, vl); }
//! \~english Executes method on object without arguments
//! \~russian Выполняет метод на объекте без аргументов
static bool execute(PIObject * o, const PIString & method) { return execute(o, method, PIVector<PIVariantSimple>()); }
//! \~english Executes method on object with one argument
//! \~russian Выполняет метод на объекте с одним аргументом
static bool execute(PIObject * o, const PIString & method, const PIVariantSimple & v0) {
return execute(o, method, PIVector<PIVariantSimple>() << v0);
}
//! \~english Executes method on object with two arguments
//! \~russian Выполняет метод на объекте с двумя аргументами
static bool execute(PIObject * o, const PIString & method, const PIVariantSimple & v0, const PIVariantSimple & v1) {
return execute(o, method, PIVector<PIVariantSimple>() << v0 << v1);
}
//! \~english Executes method on object with three arguments
//! \~russian Выполняет метод на объекте с тремя аргументами
static bool
execute(PIObject * o, const PIString & method, const PIVariantSimple & v0, const PIVariantSimple & v1, const PIVariantSimple & v2) {
return execute(o, method, PIVector<PIVariantSimple>() << v0 << v1 << v2);
}
//! \~english Executes method on object with four arguments
//! \~russian Выполняет метод на объекте с четырьмя аргументами
static bool execute(PIObject * o,
const PIString & method,
const PIVariantSimple & v0,
const PIVariantSimple & v1,
const PIVariantSimple & v2,
const PIVariantSimple & v3) {
return execute(o, method, PIVector<PIVariantSimple>() << v0 << v1 << v2 << v3);
}
//! \~english Executes method on object queued with performer
//! \~russian Выполняет метод на объекте в очереди с исполнителем
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVector<PIVariantSimple> & vl) {
return o->executeQueued(performer, method, vl);
}
//! \~english Executes method on object without arguments queued with performer
//! \~russian Выполняет метод на объекте без аргументов в очереди с исполнителем
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method) {
return executeQueued(o, performer, method, PIVector<PIVariantSimple>());
}
//! \~english Executes method on object with one argument queued with performer
//! \~russian Выполняет метод на объекте с одним аргументом в очереди с исполнителем
static bool executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariantSimple & v0) {
return executeQueued(o, performer, method, PIVector<PIVariantSimple>() << v0);
}
//! \~english Executes method on object with two arguments queued with performer
//! \~russian Выполняет метод на объекте с двумя аргументами в очереди с исполнителем
static bool
executeQueued(PIObject * o, PIObject * performer, const PIString & method, const PIVariantSimple & v0, const PIVariantSimple & v1) {
return executeQueued(o, performer, method, PIVector<PIVariantSimple>() << v0 << v1);
}
//! \~english Executes method on object with three arguments queued with performer
//! \~russian Выполняет метод на объекте с тремя аргументами в очереди с исполнителем
static bool executeQueued(PIObject * o,
PIObject * performer,
const PIString & method,
const PIVariantSimple & v0,
const PIVariantSimple & v1,
const PIVariantSimple & v2) {
return executeQueued(o, performer, method, PIVector<PIVariantSimple>() << v0 << v1 << v2);
}
//! \~english Executes method on object with four arguments queued with performer
//! \~russian Выполняет метод на объекте с четырьмя аргументами в очереди с исполнителем
static bool executeQueued(PIObject * o,
PIObject * performer,
const PIString & method,
const PIVariantSimple & v0,
const PIVariantSimple & v1,
const PIVariantSimple & v2,
const PIVariantSimple & v3) {
return executeQueued(o, performer, method, PIVector<PIVariantSimple>() << v0 << v1 << v2 << v3);
}
//! \~english Dumps object information
//! \~russian Выводит информацию об объекте
void dump(const PIString & line_prefix = PIString()) const;
//! \~english Returns subclass scope of this object (including this class name)
//! \~russian Возвращает цепочку наследования объекта (вместе с классом самого объекта)
PIStringList scopeList() const;
//! \~english Returns list of all event-handler methods
//! \~russian Возвращает список всех методов-обработчиков событий
PIStringList methodsEH() const;
//! \~english Returns if method "name" is event-handler
//! \~russian Возвращает является ли метод "name" обработчиком событий
bool isMethodEHContains(const PIString & name) const;
//! \~english Returns arguments of event-handler method "name"
//! \~russian Возвращает аргументы метода-обработчика событий "name"
PIString methodEHArguments(const PIString & name) const;
//! \~english Returns full format of event-handler method "name"
//! \~russian Возвращает полный формат метода-обработчика событий "name"
PIString methodEHFullFormat(const PIString & name) const;
//! \~english Returns event-handler method name from address "addr"
//! \~russian Возвращает имя метода-обработчика событий по адресу "addr"
PIString methodEHFromAddr(const void * addr) const;
// / Direct connect
static PIObject::Connection
piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc);
static PIObject::Connection piConnectU(PIObject * src,
const PIString & sig,
PIObject * dest_o,
void * dest,
const PIString & hname,
const char * loc,
PIObject * performer = 0);
static PIObject::Connection piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc);
template<typename PIINPUT, typename... PITYPES>
static std::function<void()> * __newFunctor(void (*stat_handler)(void *, PITYPES...), PIINPUT functor) {
return (std::function<void()> *)(new std::function<void(PITYPES...)>(functor));
}
//! \~english Disconnect object from all connections with event name "sig", connected to destination object "dest" and handler "ev_h"
//! \~russian Разрывает все соединения от события "sig" к объекту "dest" и обработчику "ev_h"
void piDisconnect(const PIString & sig, PIObject * dest, void * ev_h) { piDisconnect(this, sig, dest, ev_h); }
//! \~english Disconnect object from all connections with event name "sig", connected to destination object "dest"
//! \~russian Разрывает все соединения от события "sig" к объекту "dest"
void piDisconnect(const PIString & sig, PIObject * dest) { piDisconnect(this, sig, dest); }
//! \~english Disconnect object from all connections with event name "sig"
//! \~russian Разрывает все соединения от события "sig"
void piDisconnect(const PIString & sig) { piDisconnect(this, sig); }
//! \~english Disconnect object "src" from all connections with event name "sig", connected to destination object "dest" and handler
//! "ev_h"
//! \~russian Разрывает все соединения от события "sig" объекта "src" к объекту "dest" и обработчику "ev_h"
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest, void * ev_h);
//! \~english Disconnect object "src" from all connections with event name "sig", connected to destination object "dest"
//! \~russian Разрывает все соединения от события "sig" объекта "src" к объекту "dest"
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest);
//! \~english Disconnect object "src" from all connections with event name "sig"
//! \~russian Разрывает все соединения от события "sig" объекта "src"
static void piDisconnect(PIObject * src, const PIString & sig);
// / 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;
if (i.functor) {
(*(i.functor))();
} else {
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->eventBegin();
sender->eventBegin();
i.dest_o->emitter_ = sender;
((void (*)(void *))i.slot)(i.dest);
sender->eventEnd();
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
i.dest_o->eventEnd();
}
}
}
if (!sender->isPIObject()) break;
}
}
template<typename T0>
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;
if (i.functor) {
(*((std::function<void(T0)> *)i.functor))(v0);
} else {
if (i.performer) {
PIVector<PIVariantSimple> vl;
if (i.args_count > 0) vl << PIVariantSimple::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->eventBegin();
sender->eventBegin();
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);
sender->eventEnd();
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
i.dest_o->eventEnd();
}
}
}
if (!sender->isPIObject()) break;
}
}
template<typename T0, typename T1>
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;
if (i.functor) {
(*((std::function<void(T0, T1)> *)i.functor))(v0, v1);
} else {
if (i.performer) {
PIVector<PIVariantSimple> vl;
if (i.args_count > 0) vl << PIVariantSimple::fromValue(v0);
if (i.args_count > 1) vl << PIVariantSimple::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->eventBegin();
sender->eventBegin();
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;
}
sender->eventEnd();
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
i.dest_o->eventEnd();
}
}
}
if (!sender->isPIObject()) break;
}
}
template<typename T0, typename T1, typename T2>
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;
if (i.functor) {
(*((std::function<void(T0, T1, T2)> *)i.functor))(v0, v1, v2);
} else {
if (i.performer) {
PIVector<PIVariantSimple> vl;
if (i.args_count > 0) vl << PIVariantSimple::fromValue(v0);
if (i.args_count > 1) vl << PIVariantSimple::fromValue(v1);
if (i.args_count > 2) vl << PIVariantSimple::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->eventBegin();
sender->eventBegin();
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;
}
sender->eventEnd();
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
i.dest_o->eventEnd();
}
}
}
if (!sender->isPIObject()) break;
}
}
template<typename T0, typename T1, typename T2, typename T3>
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;
if (i.functor) {
(*((std::function<void(T0, T1, T2, T3)> *)i.functor))(v0, v1, v2, v3);
} else {
if (i.performer) {
PIVector<PIVariantSimple> vl;
if (i.args_count > 0) vl << PIVariantSimple::fromValue(v0);
if (i.args_count > 1) vl << PIVariantSimple::fromValue(v1);
if (i.args_count > 2) vl << PIVariantSimple::fromValue(v2);
if (i.args_count > 3) vl << PIVariantSimple::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->eventBegin();
sender->eventBegin();
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;
}
sender->eventEnd();
if (i.dest_o->isPIObject()) {
i.dest_o->emitter_ = 0;
if (ts) i.dest_o->mutex_.unlock();
i.dest_o->eventEnd();
}
}
}
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());
for (auto * i: PIObject::objects()) {
if (i->name() != name) continue;
return i;
}
return nullptr;
}
//! \~english Returns if this is valid %PIObject (check signature)
//! \~russian Возвращает действительный ли это %PIObject (проверяет подпись)
bool isPIObject() const { return isPIObject(this); }
//! \~english Returns if this is valid %PIObject subclass "T" (check signature and classname)
//! \~russian Возвращает действительный ли это наследник %PIObject типа "T" (проверяет подпись и имя класса)
template<typename T>
bool isTypeOf() const {
if (!isPIObject()) return false;
PIMutexLocker ml(__meta_mutex());
return __meta_data()[classNameID()].scope_id.contains(T::__classNameIDS());
}
//! \~english Returns cast to T if this is valid subclass "T" (check by \a isTypeOf()) or "nullptr"
//! \~russian Возвращает преобразование к типу T если это действительный наследник типа "T" (проверяет через \a isTypeOf()), или
//! "nullptr"
template<typename T>
T * cast() const {
if (!isTypeOf<T>()) return (T *)nullptr;
return (T *)this;
}
//! \~english Returns if "o" is valid %PIObject (check signature)
//! \~russian Возвращает действительный ли "o" %PIObject (проверяет подпись)
static bool isPIObject(const PIObject * o);
//! \~english Returns if "o" is valid %PIObject (check signature)
//! \~russian Возвращает действительный ли "o" %PIObject (проверяет подпись)
static bool isPIObject(const void * o) { return isPIObject((PIObject *)o); }
//! \~english Returns if "o" is valid %PIObject subclass "T" (check signature and classname)
//! \~russian Возвращает действительный ли "o" наследник %PIObject типа "T" (проверяет подпись и имя класса)
template<typename T>
static bool isTypeOf(const PIObject * o) {
return o->isTypeOf<T>();
}
template<typename T>
static bool isTypeOf(const void * o) {
return isTypeOf<T>((PIObject *)o);
}
//! \~english Simplifies type name "a" to readable format
//! \~russian Упрощает имя типа "a" в читаемый формат
static PIString simplifyType(const char * a, bool readable = true);
struct PIP_EXPORT __MetaFunc {
__MetaFunc();
bool isNull() const { return addr == nullptr; }
int argumentsCount() const;
PIString arguments() const;
PIString fullFormat() const;
void __setFuncName(const char * n);
void __addArgument(const char * t, const char * n);
bool canConnectTo(const __MetaFunc & dst, int & args_count) const;
void * addr = nullptr;
void * addrV = nullptr;
uint func_name_id = 0;
const char * func_name = nullptr;
const char * type_ret = nullptr;
const char * scope = nullptr;
const char * types[__PIOBJECT_MAX_ARGS__];
const char * names[__PIOBJECT_MAX_ARGS__];
uint types_id[__PIOBJECT_MAX_ARGS__];
};
struct PIP_EXPORT __MetaData {
__MetaData() {
scope_list << "PIObject";
scope_id << PIStringAscii("PIObject").hash();
}
void addScope(const char * s, uint shash);
PIVector<const char *> scope_list;
PISet<uint> scope_id;
PISet<const void *> eh_set;
PIMap<const void *, __MetaFunc> eh_func;
};
typedef PIPair<const void *, __MetaFunc> __EHPair;
//! \~english Execute all posted events from CONNECTU_QUEUED connections
//! \~russian Выполнить все отложенные события от CONNECTU_QUEUED соединений
void callQueuedEvents();
//! \~english
//! \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
//! \~russian
//! \brief Если было хотя бы одно CONNECTU_QUEUED соединение с исполнителем this, то выполнить события
//! \details Этот метод более оптимален, чем \a callQueuedEvents(), для объектов, которые не были в роли
//! \"performer\" в макросе CONNECTU_QUEUED
bool maybeCallQueuedEvents() {
if (proc_event_queue) callQueuedEvents();
return proc_event_queue;
}
//! \~english Mark object to delete
//! \~russian Пометить объект на удаление
void deleteLater();
EVENT1(deleted, PIObject *, o);
//! \events
//! \{
//! \fn void deleted(PIObject * o)
//! \brief
//! \~english Raise before object delete
//! \~russian Вызывается перед удалением объекта
//! \~\warning
//! \~english
//! This event raised from destructor, so use only "o" numeric value,
//! don`t try to cast deleted object to some subclass!
//! \~russian
//! Это событие вызывается из деструктора, поэтому используйте
//! только численное значение "o", не надо кастовать его в другие типы!
//! \}
static PIMutex & __meta_mutex();
static PIMap<uint, __MetaData> & __meta_data(); // [hash(classname)]=__MetaData
protected:
//! \~english Returns %PIObject* which has raised an event. This value is correct only in definition of some event handler
//! \~russian Возвращает %PIObject* который вызвал это событие. Значение допустимо только из методов обработчиков событий
PIObject * emitter() const { return emitter_; }
//! \~english Virtual function executes after property with name "name" has been changed
//! \~russian Виртуальная функция, вызывается после изменения любого свойства.
virtual void propertyChanged(const char * name) {}
private:
struct __QueuedEvent {
__QueuedEvent(void * sl = 0,
void * d = 0,
PIObject * d_o = 0,
PIObject * s = 0,
const PIVector<PIVariantSimple> & v = PIVector<PIVariantSimple>()) {
slot = sl;
dest = d;
dest_o = d_o;
src = s;
values = v;
}
void * slot;
void * dest;
PIObject * dest_o;
PIObject * src;
PIVector<PIVariantSimple> values;
};
class Deleter {
public:
Deleter();
~Deleter();
static Deleter * instance();
void post(PIObject * o);
private:
void deleteObject(PIObject * o);
PRIVATE_DECLARATION(PIP_EXPORT)
};
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 piDisconnectAll();
void postQueuedEvent(const __QueuedEvent & e);
void eventBegin() { in_event_cnt++; }
void eventEnd() { in_event_cnt--; }
bool isInEvent() const { return in_event_cnt > 0; }
void * toThis() const;
virtual int ptrOffset() const { return 0; }
static PIVector<PIObject *> & objects();
static PIMutex & mutexObjects();
static void callAddrV(void * slot, void * obj, int args, const PIVector<PIVariantSimple> & vl);
PIVector<Connection> connections;
PIMap<uint, PIVariant> properties_;
PISet<PIObject *> connectors;
PIVector<__QueuedEvent> events_queue;
PIMutex mutex_, mutex_connect, mutex_queue;
PIObject * emitter_;
bool thread_safe_, proc_event_queue;
std::atomic_int in_event_cnt;
};
#ifndef MICRO_PIP
PIP_EXPORT void dumpApplication(bool with_objects = true);
PIP_EXPORT bool dumpApplicationToFile(const PIString & path, bool with_objects = true);
#endif
#endif // PIOBJECT_H