/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019, Google Inc. * * signal.h - Signal & slot implementation */ #ifndef __LIBCAMERA_SIGNAL_H__ #define __LIBCAMERA_SIGNAL_H__ #include #include namespace libcamera { template class Signal; template class SlotBase { public: SlotBase(void *obj) : obj_(obj) { } virtual ~SlotBase() { } virtual void invoke(Args... args) = 0; protected: friend class Signal; void *obj_; }; template class SlotMember : public SlotBase { public: SlotMember(T *obj, void(T::*func)(Args...)) : SlotBase(obj), func_(func) { } void invoke(Args... args) { (reinterpret_cast(this->obj_)->*func_)(args...); } private: friend class Signal; void(T::*func_)(Args...); }; template class SlotStatic : public SlotBase { public: SlotStatic(void(*func)(Args...)) : SlotBase(nullptr), func_(func) { } void invoke(Args... args) { (*func_)(args...); } private: friend class Signal; void(*func_)(Args...); }; template class Signal { public: Signal() { } ~Signal() { for (SlotBase *slot : slots_) delete slot; } template void connect(T *object, void(T::*func)(Args...)) { slots_.push_back(new SlotMember(object, func)); } void connect(void(*func)(Args...)) { slots_.push_back(new SlotStatic(func)); } void disconnect() { for (SlotBase *slot : slots_) delete slot; slots_.clear(); } template void disconnect(T *object) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { SlotBase *slot = *iter; if (slot->obj_ == object) { iter = slots_.erase(iter); delete slot; } else { ++iter; } } } template void disconnect(T *object, void(T::*func)(Args...)) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { SlotBase *slot = *iter; /* * If the obj_ pointer matches the object types must * match, so we can safely cast to SlotMember. */ if (slot->obj_ == object && reinterpret_cast *>(slot)->func_ == func) { iter = slots_.erase(iter); delete slot; } else { ++iter; } } } void disconnect(void(*func)(Args...)) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { SlotBase *slot = *iter; if (slot->obj_ == nullptr && reinterpret_cast *>(slot)->func_ == func) { iter = slots_.erase(iter); delete slot; } else { ++iter; } } } void emit(Args... args) { /* * Make a copy of the slots list as the slot could call the * disconnect operation, invalidating the iterator. */ std::vector *> slots{ slots_.begin(), slots_.end() }; for (SlotBase *slot : slots) slot->invoke(args...); } private: std::list *> slots_; }; } /* namespace libcamera */ #endif /* __LIBCAMERA_SIGNAL_H__ */