11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
26PROMEKI_NAMESPACE_BEGIN
37#define PROMEKI_OBJECT(ObjectName, ParentObjectName) \
39 static const MetaInfo &metaInfo() { \
40 static const MetaInfo __metaInfo(typeid(ObjectName).name(), &ParentObjectName::metaInfo()); \
44#define PROMEKI_SIGNAL(SIGNALNAME, ...) \
45 static constexpr const char *SIGNALNAME##SignalName = \
46 PROMEKI_STRINGIFY(SIGNALNAME) "(" PROMEKI_STRINGIFY_ARGS(__VA_ARGS__) ")"; \
47 static inline SignalMeta SIGNALNAME##SignalMeta = SignalMeta(metaInfo(), SIGNALNAME##SignalName); \
48 Signal<__VA_ARGS__> SIGNALNAME##Signal = Signal<__VA_ARGS__>(this, SIGNALNAME##SignalName);
50#define PROMEKI_SLOT(SLOTNAME, ...) \
51 static constexpr const char *SLOTNAME##SlotName = \
52 PROMEKI_STRINGIFY(SLOTNAME) "(" PROMEKI_STRINGIFY_ARGS(__VA_ARGS__) ")"; \
53 static inline SlotMeta SLOTNAME##SlotMeta = SlotMeta(metaInfo(), SLOTNAME##SlotName); \
54 void SLOTNAME(__VA_ARGS__); \
55 Slot<__VA_ARGS__> SLOTNAME##Slot = \
56 Slot<__VA_ARGS__>([this](auto &&...args) { this->SLOTNAME(std::forward<decltype(args)>(args)...); }, \
57 this, SLOTNAME##SlotName); \
58 int SLOTNAME##SlotID = registerSlot(&SLOTNAME##Slot);
63using ObjectBaseList = ::promeki::List<ObjectBase *>;
90template <
typename T = ObjectBase>
class ObjectBasePtr {
91 friend class ObjectBase;
92 template <
typename U>
friend class ObjectBasePtr;
96 ObjectBasePtr(T *
object =
nullptr) { linkTo(
object); }
99 ObjectBasePtr(
const ObjectBasePtr &other) { linkFromSource(other.p); }
106 template <
typename U,
typename = std::enable_if_t<std::is_base_of_v<T, U> && !std::is_same_v<T, U>>>
107 ObjectBasePtr(
const ObjectBasePtr<U> &other) {
108 linkFromSource(other.p);
112 ~ObjectBasePtr() { unlink(); }
115 ObjectBasePtr &operator=(
const ObjectBasePtr &other) {
116 if (
this == &other)
return *
this;
118 linkFromSource(other.p);
123 bool isValid()
const {
return p.load(MemoryOrder::Acquire) !=
nullptr; }
126 T *data() {
return static_cast<T *
>(p.load(MemoryOrder::Acquire)); }
129 const T *data()
const {
return static_cast<const T *
>(p.load(MemoryOrder::Acquire)); }
133 using TrackerPtr = promeki::Atomic<ObjectBase *>;
135 TrackerPtr p{
nullptr};
147 void linkTo(ObjectBase *obj);
153 void linkFromSource(
const TrackerPtr &source);
159template <
typename T> ObjectBasePtr(T *) -> ObjectBasePtr<T>;
187 template <
typename U>
friend class ObjectBasePtr;
188 friend class EventLoop;
198 friend class SignalMeta;
199 friend class SlotMeta;
202 using SignalList = ::promeki::List<SignalMeta *>;
203 using SlotList = ::promeki::List<SlotMeta *>;
209 MetaInfo(
const char *n,
const MetaInfo *p =
nullptr) : _parent(p), _name(n) {}
212 const MetaInfo *parent()
const {
return _parent; }
215 const char *name()
const;
218 const SignalList &signalList()
const {
return _signalList; }
221 const SlotList &slotList()
const {
return _slotList; }
224 void dumpToLog()
const;
227 const MetaInfo *_parent;
229 mutable String _demangledName;
230 mutable SignalList _signalList;
231 mutable SlotList _slotList;
242 SignalMeta(
const MetaInfo &m,
const char *n) : _meta(m), _name(n) {
243 m._signalList +=
this;
247 const char *name()
const {
return _name; }
250 const MetaInfo &_meta;
262 SlotMeta(
const MetaInfo &m,
const char *n) : _meta(m), _name(n) { m._slotList +=
this; }
265 const char *name()
const {
return _name; }
268 const MetaInfo &_meta;
273 static const MetaInfo &metaInfo() {
274 static const MetaInfo __metaInfo(
typeid(ObjectBase).name());
282 template <
typename... Args>
static void connect(Signal<Args...> *signal, Slot<Args...> *slot);
294 ObjectBase(ObjectBase *p =
nullptr);
296 ObjectBase(
const ObjectBase &) =
delete;
297 ObjectBase(ObjectBase &&) =
delete;
298 ObjectBase &operator=(
const ObjectBase &) =
delete;
299 ObjectBase &operator=(ObjectBase &&) =
delete;
302 virtual ~ObjectBase() {
303 aboutToDestroySignal.emit(
this);
313 ObjectBase *parent()
const {
return _parent; }
331 void setParent(ObjectBase *p);
337 const ObjectBaseList &childList()
const {
return _childList; }
345 template <
typename... Args>
int registerSlot(Slot<Args...> *slot) {
346 int ret = _slotList.size();
348 _slotList += SlotItem(ret, slot->prototype());
360 PROMEKI_SIGNAL(aboutToDestroy, ObjectBase *);
366 EventLoop *eventLoop()
const {
return _eventLoop; }
380 Thread *thread()
const {
return _thread; }
393 void moveToThread(Thread *t);
405 int startTimer(
unsigned int intervalMs,
bool singleShot =
false);
411 void stopTimer(
int timerId);
449 using CleanupHandler = Function<void(ObjectBase *)>;
474 void registerCleanup(ObjectBase *target, CleanupHandler fn);
478 ObjectBase *signalSender() {
return _signalSender; }
488 virtual void event(Event *e);
498 virtual void timerEvent(TimerEvent *e);
502 using CleanupFunc = CleanupHandler;
506 const char *prototype;
510 ObjectBasePtr<> object;
514 ObjectBase *_parent =
nullptr;
515 ObjectBase *_signalSender =
nullptr;
516 Thread *_thread =
nullptr;
517 EventLoop *_eventLoop =
nullptr;
518 ObjectBaseList _childList;
519 List<SlotItem> _slotList;
522 using PointerMapKey = promeki::Atomic<ObjectBase *> *;
523 using PointerMap = promeki::Map<PointerMapKey, PointerMapKey>;
524 PointerMap _pointerMap;
525 List<Cleanup> _cleanupList;
544 static Mutex &objectBasePtrMutex();
546 void setOwnerThreadRecursive(Thread *t, EventLoop *loop);
548 void addChild(ObjectBase *c) {
553 void removeChild(ObjectBase *c) {
554 _childList.removeFirst(c);
558 void destroyChildren() {
559 for (
auto child : _childList) {
560 child->_parent =
nullptr;
573 Mutex::Locker lock(objectBasePtrMutex());
574 for (
auto item : _pointerMap) {
575 item.first->store(
nullptr, MemoryOrder::Release);
581 for (
auto &item : _cleanupList) {
582 if (!item.object.isValid())
continue;
585 _cleanupList.clear();
590template <
typename T>
inline void ObjectBasePtr<T>::linkTo(ObjectBase *obj) {
610 Mutex::Locker lock(ObjectBase::objectBasePtrMutex());
611 p.store(obj, MemoryOrder::Relaxed);
612 if (obj !=
nullptr) {
613 obj->_pointerMap[&p] = &p;
619inline void ObjectBasePtr<T>::linkFromSource(
const TrackerPtr &source) {
631 Mutex::Locker lock(ObjectBase::objectBasePtrMutex());
632 ObjectBase *obj = source.load(MemoryOrder::Relaxed);
633 p.store(obj, MemoryOrder::Relaxed);
634 if (obj !=
nullptr) {
635 obj->_pointerMap[&p] = &p;
640template <
typename T>
inline void ObjectBasePtr<T>::unlink() {
645 Mutex::Locker lock(ObjectBase::objectBasePtrMutex());
646 ObjectBase *obj = p.exchange(
nullptr, MemoryOrder::AcqRel);
647 if (obj !=
nullptr) {
648 auto it = obj->_pointerMap.find(&p);
649 if (it != obj->_pointerMap.end()) {
650 obj->_pointerMap.remove(it);