diff options
-rw-r--r-- | Documentation/Doxyfile.in | 1 | ||||
-rw-r--r-- | include/libcamera/base/bound_method.h | 31 | ||||
-rw-r--r-- | include/libcamera/base/signal.h | 19 | ||||
-rw-r--r-- | src/libcamera/base/signal.cpp | 24 | ||||
-rw-r--r-- | test/signal.cpp | 39 |
5 files changed, 114 insertions, 0 deletions
diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index 24ccf0c0..6e627192 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -878,6 +878,7 @@ EXCLUDE_PATTERNS = @TOP_BUILDDIR@/include/libcamera/ipa/*_serializer.h \ EXCLUDE_SYMBOLS = libcamera::BoundMethodArgs \ libcamera::BoundMethodBase \ + libcamera::BoundMethodFunctor \ libcamera::BoundMethodMember \ libcamera::BoundMethodPack \ libcamera::BoundMethodPackBase \ diff --git a/include/libcamera/base/bound_method.h b/include/libcamera/base/bound_method.h index 76ce8017..ebd297ab 100644 --- a/include/libcamera/base/bound_method.h +++ b/include/libcamera/base/bound_method.h @@ -128,6 +128,37 @@ public: virtual R invoke(Args... args) = 0; }; +template<typename T, typename R, typename Func, typename... Args> +class BoundMethodFunctor : public BoundMethodArgs<R, Args...> +{ +public: + using PackType = typename BoundMethodArgs<R, Args...>::PackType; + + BoundMethodFunctor(T *obj, Object *object, Func func, + ConnectionType type = ConnectionTypeAuto) + : BoundMethodArgs<R, Args...>(obj, object, type), func_(func) + { + } + + R activate(Args... args, bool deleteMethod = false) override + { + if (!this->object_) + return func_(args...); + + auto pack = std::make_shared<PackType>(args...); + bool sync = BoundMethodBase::activatePack(pack, deleteMethod); + return sync ? pack->returnValue() : R(); + } + + R invoke(Args... args) override + { + return func_(args...); + } + +private: + Func func_; +}; + template<typename T, typename R, typename... Args> class BoundMethodMember : public BoundMethodArgs<R, Args...> { diff --git a/include/libcamera/base/signal.h b/include/libcamera/base/signal.h index c2521769..8d9f82f6 100644 --- a/include/libcamera/base/signal.h +++ b/include/libcamera/base/signal.h @@ -61,6 +61,25 @@ public: SignalBase::connect(new BoundMethodMember<T, R, Args...>(obj, nullptr, func)); } +#ifndef __DOXYGEN__ + template<typename T, typename Func, + typename std::enable_if_t<std::is_base_of<Object, T>::value> * = nullptr> + void connect(T *obj, Func func, ConnectionType type = ConnectionTypeAuto) + { + Object *object = static_cast<Object *>(obj); + SignalBase::connect(new BoundMethodFunctor<T, void, Func, Args...>(obj, object, func, type)); + } + + template<typename T, typename Func, + typename std::enable_if_t<!std::is_base_of<Object, T>::value> * = nullptr> +#else + template<typename T, typename Func> +#endif + void connect(T *obj, Func func) + { + SignalBase::connect(new BoundMethodFunctor<T, void, Func, Args...>(obj, nullptr, func)); + } + template<typename R> void connect(R (*func)(Args...)) { diff --git a/src/libcamera/base/signal.cpp b/src/libcamera/base/signal.cpp index adcfa796..9c2319c5 100644 --- a/src/libcamera/base/signal.cpp +++ b/src/libcamera/base/signal.cpp @@ -122,6 +122,30 @@ SignalBase::SlotList SignalBase::slots() */ /** + * \fn Signal::connect(T *object, Func func) + * \brief Connect the signal to a function object slot + * \param[in] object The slot object pointer + * \param[in] func The function object + * + * If the typename T inherits from Object, the signal will be automatically + * disconnected from the \a func slot of \a object when \a object is destroyed. + * Otherwise the caller shall disconnect signals manually before destroying \a + * object. + * + * The function object is typically a lambda function, but may be any object + * that satisfies the FunctionObject named requirements. The types of the + * function object arguments shall match the types of the signal arguments. + * + * No matching disconnect() function exist, as it wouldn't be possible to pass + * to a disconnect() function the same lambda that was passed to connect(). The + * connection created by this function can not be removed selectively if the + * signal is connected to multiple slots of the same receiver, but may be + * otherwise be removed using the disconnect(T *object) function. + * + * \context This function is \threadsafe. + */ + +/** * \fn Signal::connect(R (*func)(Args...)) * \brief Connect the signal to a static function slot * \param[in] func The slot static function diff --git a/test/signal.cpp b/test/signal.cpp index 595782a2..fcf2def1 100644 --- a/test/signal.cpp +++ b/test/signal.cpp @@ -191,6 +191,24 @@ protected: signalVoid_.connect(slotStaticReturn); signalVoid_.connect(this, &SignalTest::slotReturn); + /* Test signal connection to a lambda. */ + int value = 0; + signalInt_.connect(this, [&](int v) { value = v; }); + signalInt_.emit(42); + + if (value != 42) { + cout << "Signal connection to lambda failed" << endl; + return TestFail; + } + + signalInt_.disconnect(this); + signalInt_.emit(0); + + if (value != 42) { + cout << "Signal disconnection from lambda failed" << endl; + return TestFail; + } + /* ----------------- Signal -> Object tests ----------------- */ /* @@ -256,6 +274,27 @@ protected: delete slotObject; + /* Test signal connection to a lambda. */ + slotObject = new SlotObject(); + value = 0; + signalInt_.connect(slotObject, [&](int v) { value = v; }); + signalInt_.emit(42); + + if (value != 42) { + cout << "Signal connection to Object lambda failed" << endl; + return TestFail; + } + + signalInt_.disconnect(slotObject); + signalInt_.emit(0); + + if (value != 42) { + cout << "Signal disconnection from Object lambda failed" << endl; + return TestFail; + } + + delete slotObject; + /* --------- Signal -> Object (multiple inheritance) -------- */ /* |