/* 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 #include #include #include namespace libcamera { class SignalBase { public: template void disconnect(T *obj) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { BoundMethodBase *slot = *iter; if (slot->match(obj)) { iter = slots_.erase(iter); delete slot; } else { ++iter; } } } protected: friend class Object; std::list slots_; }; template class Signal : public SignalBase { public: Signal() {} ~Signal() { for (BoundMethodBase *slot : slots_) { Object *object = slot->object(); if (object) object->disconnect(this); delete slot; } } #ifndef __DOXYGEN__ template::value>::type * = nullptr> void connect(T *obj, void (T::*func)(Args...)) { Object *object = static_cast(obj); object->connect(this); slots_.push_back(new BoundMemberMethod(obj, object, func)); } template::value>::type * = nullptr> #else template #endif void connect(T *obj, void (T::*func)(Args...)) { slots_.push_back(new BoundMemberMethod(obj, nullptr, func)); } void connect(void (*func)(Args...)) { slots_.push_back(new BoundStaticMethod(func)); } void disconnect() { for (BoundMethodBase *slot : slots_) delete slot; slots_.clear(); } template void disconnect(T *obj) { SignalBase::disconnect(obj); } template void disconnect(T *obj, void (T::*func)(Args...)) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { BoundMethodArgs *slot = static_cast *>(*iter); /* * If the object matches the slot, the slot is * guaranteed to be a member slot, so we can safely * cast it to BoundMemberMethod to match * func. */ if (slot->match(obj) && static_cast *>(slot)->match(func)) { iter = slots_.erase(iter); delete slot; } else { ++iter; } } } void disconnect(void (*func)(Args...)) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { BoundMethodArgs *slot = *iter; if (slot->match(nullptr) && static_cast *>(slot)->match(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 (BoundMethodBase *slot : slots) static_cast *>(slot)->activate(args...); } }; } /* namespace libcamera */ #endif /* __LIBCAMERA_SIGNAL_H__ */