[{"id":2407,"web_url":"https://patchwork.libcamera.org/comment/2407/","msgid":"<20190815084741.7qurumsza7cglent@uno.localdomain>","date":"2019-08-15T08:47:41","subject":"Re: [libcamera-devel] [PATCH 04/18] libcamera: signal: Split Slot\n\timplementation to reusable classes","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Mon, Aug 12, 2019 at 03:46:28PM +0300, Laurent Pinchart wrote:\n> Move the Slot* classes to bound_method.{h,cpp} and rename them to\n> Bound*Method*. They will be reused to implement asynchronous method\n> invocation similar to cross-thread signal delivery.\n\nStupid question, but why do you need to rename to a longer\n\"Bound*Method*\" when \"Slot\" was quite efficient as a name? Couldn't\nyou just move the Slot hierarchy definition and implementation to\ntheir own files?\n\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  Documentation/Doxyfile.in        |  10 +--\n>  include/libcamera/bound_method.h | 131 ++++++++++++++++++++++++++++\n>  include/libcamera/meson.build    |   1 +\n>  include/libcamera/object.h       |   5 +-\n>  include/libcamera/signal.h       | 145 ++++---------------------------\n>  src/libcamera/bound_method.cpp   |  33 +++++++\n>  src/libcamera/include/message.h  |   8 +-\n>  src/libcamera/meson.build        |   1 +\n>  src/libcamera/message.cpp        |   4 +-\n>  src/libcamera/object.cpp         |   2 +-\n>  src/libcamera/signal.cpp         |  23 -----\n>  11 files changed, 197 insertions(+), 166 deletions(-)\n>  create mode 100644 include/libcamera/bound_method.h\n>  create mode 100644 src/libcamera/bound_method.cpp\n>\n> diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in\n> index 3d94623a4b8f..a9596c2a32d8 100644\n> --- a/Documentation/Doxyfile.in\n> +++ b/Documentation/Doxyfile.in\n> @@ -865,11 +865,11 @@ EXCLUDE_PATTERNS       =\n>  # Note that the wildcards are matched against the file with absolute path, so to\n>  # exclude all test directories use the pattern */test/*\n>\n> -EXCLUDE_SYMBOLS        = libcamera::SignalBase \\\n> -                         libcamera::SlotArgs \\\n> -                         libcamera::SlotBase \\\n> -                         libcamera::SlotMember \\\n> -                         libcamera::SlotStatic \\\n> +EXCLUDE_SYMBOLS        = libcamera::BoundMemberMethod \\\n> +                         libcamera::BoundMethodArgs \\\n> +                         libcamera::BoundMethodBase \\\n> +                         libcamera::BoundStaticMethod \\\n> +                         libcamera::SignalBase \\\n>                           std::*\n>\n>  # The EXAMPLE_PATH tag can be used to specify one or more files or directories\n> diff --git a/include/libcamera/bound_method.h b/include/libcamera/bound_method.h\n> new file mode 100644\n> index 000000000000..38c44b923ba1\n> --- /dev/null\n> +++ b/include/libcamera/bound_method.h\n> @@ -0,0 +1,131 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * bound_method.h - Method bind and invocation\n> + */\n> +#ifndef __LIBCAMERA_BOUND_METHOD_H__\n> +#define __LIBCAMERA_BOUND_METHOD_H__\n> +\n> +#include <tuple>\n> +#include <type_traits>\n> +\n> +namespace libcamera {\n> +\n> +class Object;\n> +template<typename... Args>\n> +class Signal;\n> +class SignalBase;\n> +\n> +class BoundMethodBase\n> +{\n> +public:\n> +\tBoundMethodBase(void *obj, Object *object)\n> +\t\t: obj_(obj), object_(object) {}\n> +\tvirtual ~BoundMethodBase() {}\n> +\n> +\ttemplate<typename T, typename std::enable_if<!std::is_same<Object, T>::value>::type * = nullptr>\n> +\tbool match(T *obj) { return obj == obj_; }\n> +\tbool match(Object *object) { return object == object_; }\n> +\n> +\tvoid disconnect(SignalBase *signal);\n> +\n> +\tvoid activatePack(void *pack);\n> +\tvirtual void invokePack(void *pack) = 0;\n> +\n> +protected:\n> +\tvoid *obj_;\n> +\tObject *object_;\n> +};\n> +\n> +template<typename... Args>\n> +class BoundMethodArgs : public BoundMethodBase\n> +{\n> +private:\n> +#ifndef __DOXYGEN__\n> +\t/*\n> +\t * This is a cheap partial implementation of std::integer_sequence<>\n> +\t * from C++14.\n> +\t */\n> +\ttemplate<int...>\n> +\tstruct sequence {\n> +\t};\n> +\n> +\ttemplate<int N, int... S>\n> +\tstruct generator : generator<N-1, N-1, S...> {\n> +\t};\n> +\n> +\ttemplate<int... S>\n> +\tstruct generator<0, S...> {\n> +\t\ttypedef sequence<S...> type;\n> +\t};\n> +#endif\n> +\n> +\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> +\n> +\ttemplate<int... S>\n> +\tvoid invokePack(void *pack, sequence<S...>)\n> +\t{\n> +\t\tPackType *args = static_cast<PackType *>(pack);\n> +\t\tinvoke(std::get<S>(*args)...);\n> +\t\tdelete args;\n> +\t}\n> +\n> +public:\n> +\tBoundMethodArgs(void *obj, Object *object)\n> +\t\t: BoundMethodBase(obj, object) {}\n> +\n> +\tvoid invokePack(void *pack) override\n> +\t{\n> +\t\tinvokePack(pack, typename generator<sizeof...(Args)>::type());\n> +\t}\n> +\n> +\tvirtual void activate(Args... args) = 0;\n> +\tvirtual void invoke(Args... args) = 0;\n> +};\n> +\n> +template<typename T, typename... Args>\n> +class BoundMemberMethod : public BoundMethodArgs<Args...>\n> +{\n> +public:\n> +\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> +\n> +\tBoundMemberMethod(T *obj, Object *object, void (T::*func)(Args...))\n> +\t\t: BoundMethodArgs<Args...>(obj, object), func_(func) {}\n> +\n> +\tvoid activate(Args... args)\n> +\t{\n> +\t\tif (this->object_)\n> +\t\t\tBoundMethodBase::activatePack(new PackType{ args... });\n> +\t\telse\n> +\t\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> +\t}\n> +\n> +\tvoid invoke(Args... args)\n> +\t{\n> +\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> +\t}\n> +\n> +private:\n> +\tfriend class Signal<Args...>;\n> +\tvoid (T::*func_)(Args...);\n> +};\n> +\n> +template<typename... Args>\n> +class BoundStaticMethod : public BoundMethodArgs<Args...>\n> +{\n> +public:\n> +\tBoundStaticMethod(void (*func)(Args...))\n> +\t\t: BoundMethodArgs<Args...>(nullptr, nullptr), func_(func) {}\n> +\n> +\tvoid activate(Args... args) { (*func_)(args...); }\n> +\tvoid invoke(Args... args) {}\n> +\n> +private:\n> +\tfriend class Signal<Args...>;\n> +\tvoid (*func_)(Args...);\n> +};\n> +\n> +}; /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_BOUND_METHOD_H__ */\n> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build\n> index 920eb5fcbfd1..a8a38a9b1db7 100644\n> --- a/include/libcamera/meson.build\n> +++ b/include/libcamera/meson.build\n> @@ -1,4 +1,5 @@\n>  libcamera_api = files([\n> +    'bound_method.h',\n>      'buffer.h',\n>      'camera.h',\n>      'camera_manager.h',\n> diff --git a/include/libcamera/object.h b/include/libcamera/object.h\n> index 3d08d69a9044..e3b39cf547b0 100644\n> --- a/include/libcamera/object.h\n> +++ b/include/libcamera/object.h\n> @@ -10,13 +10,14 @@\n>  #include <list>\n>  #include <memory>\n>\n> +#include <libcamera/bound_method.h>\n> +\n>  namespace libcamera {\n>\n>  class Message;\n>  template<typename... Args>\n>  class Signal;\n>  class SignalBase;\n> -class SlotBase;\n>  class Thread;\n>\n>  class Object\n> @@ -36,7 +37,7 @@ protected:\n>  private:\n>  \ttemplate<typename... Args>\n>  \tfriend class Signal;\n> -\tfriend class SlotBase;\n> +\tfriend class BoundMethodBase;\n>  \tfriend class Thread;\n>\n>  \tvoid connect(SignalBase *signal);\n> diff --git a/include/libcamera/signal.h b/include/libcamera/signal.h\n> index 8f6db700cd80..3b6de30f7d35 100644\n> --- a/include/libcamera/signal.h\n> +++ b/include/libcamera/signal.h\n> @@ -8,127 +8,14 @@\n>  #define __LIBCAMERA_SIGNAL_H__\n>\n>  #include <list>\n> -#include <tuple>\n>  #include <type_traits>\n>  #include <vector>\n>\n> +#include <libcamera/bound_method.h>\n>  #include <libcamera/object.h>\n>\n>  namespace libcamera {\n>\n> -template<typename... Args>\n> -class Signal;\n> -class SignalBase;\n> -\n> -class SlotBase\n> -{\n> -public:\n> -\tSlotBase(void *obj, Object *object)\n> -\t\t: obj_(obj), object_(object) {}\n> -\tvirtual ~SlotBase() {}\n> -\n> -\ttemplate<typename T, typename std::enable_if<!std::is_same<Object, T>::value>::type * = nullptr>\n> -\tbool match(T *obj) { return obj == obj_; }\n> -\tbool match(Object *object) { return object == object_; }\n> -\n> -\tvoid disconnect(SignalBase *signal);\n> -\n> -\tvoid activatePack(void *pack);\n> -\tvirtual void invokePack(void *pack) = 0;\n> -\n> -protected:\n> -\tvoid *obj_;\n> -\tObject *object_;\n> -};\n> -\n> -template<typename... Args>\n> -class SlotArgs : public SlotBase\n> -{\n> -private:\n> -#ifndef __DOXYGEN__\n> -\t/*\n> -\t * This is a cheap partial implementation of std::integer_sequence<>\n> -\t * from C++14.\n> -\t */\n> -\ttemplate<int...>\n> -\tstruct sequence {\n> -\t};\n> -\n> -\ttemplate<int N, int... S>\n> -\tstruct generator : generator<N-1, N-1, S...> {\n> -\t};\n> -\n> -\ttemplate<int... S>\n> -\tstruct generator<0, S...> {\n> -\t\ttypedef sequence<S...> type;\n> -\t};\n> -#endif\n> -\n> -\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> -\n> -\ttemplate<int... S>\n> -\tvoid invokePack(void *pack, sequence<S...>)\n> -\t{\n> -\t\tPackType *args = static_cast<PackType *>(pack);\n> -\t\tinvoke(std::get<S>(*args)...);\n> -\t\tdelete args;\n> -\t}\n> -\n> -public:\n> -\tSlotArgs(void *obj, Object *object)\n> -\t\t: SlotBase(obj, object) {}\n> -\n> -\tvoid invokePack(void *pack) override\n> -\t{\n> -\t\tinvokePack(pack, typename generator<sizeof...(Args)>::type());\n> -\t}\n> -\n> -\tvirtual void activate(Args... args) = 0;\n> -\tvirtual void invoke(Args... args) = 0;\n> -};\n> -\n> -template<typename T, typename... Args>\n> -class SlotMember : public SlotArgs<Args...>\n> -{\n> -public:\n> -\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> -\n> -\tSlotMember(T *obj, Object *object, void (T::*func)(Args...))\n> -\t\t: SlotArgs<Args...>(obj, object), func_(func) {}\n> -\n> -\tvoid activate(Args... args)\n> -\t{\n> -\t\tif (this->object_)\n> -\t\t\tSlotBase::activatePack(new PackType{ args... });\n> -\t\telse\n> -\t\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> -\t}\n> -\n> -\tvoid invoke(Args... args)\n> -\t{\n> -\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> -\t}\n> -\n> -private:\n> -\tfriend class Signal<Args...>;\n> -\tvoid (T::*func_)(Args...);\n> -};\n> -\n> -template<typename... Args>\n> -class SlotStatic : public SlotArgs<Args...>\n> -{\n> -public:\n> -\tSlotStatic(void (*func)(Args...))\n> -\t\t: SlotArgs<Args...>(nullptr, nullptr), func_(func) {}\n> -\n> -\tvoid activate(Args... args) { (*func_)(args...); }\n> -\tvoid invoke(Args... args) {}\n> -\n> -private:\n> -\tfriend class Signal<Args...>;\n> -\tvoid (*func_)(Args...);\n> -};\n> -\n>  class SignalBase\n>  {\n>  public:\n> @@ -136,7 +23,7 @@ public:\n>  \tvoid disconnect(T *obj)\n>  \t{\n>  \t\tfor (auto iter = slots_.begin(); iter != slots_.end(); ) {\n> -\t\t\tSlotBase *slot = *iter;\n> +\t\t\tBoundMethodBase *slot = *iter;\n>  \t\t\tif (slot->match(obj)) {\n>  \t\t\t\titer = slots_.erase(iter);\n>  \t\t\t\tdelete slot;\n> @@ -148,7 +35,7 @@ public:\n>\n>  protected:\n>  \tfriend class Object;\n> -\tstd::list<SlotBase *> slots_;\n> +\tstd::list<BoundMethodBase *> slots_;\n>  };\n>\n>  template<typename... Args>\n> @@ -158,7 +45,7 @@ public:\n>  \tSignal() {}\n>  \t~Signal()\n>  \t{\n> -\t\tfor (SlotBase *slot : slots_) {\n> +\t\tfor (BoundMethodBase *slot : slots_) {\n>  \t\t\tslot->disconnect(this);\n>  \t\t\tdelete slot;\n>  \t\t}\n> @@ -170,7 +57,7 @@ public:\n>  \t{\n>  \t\tObject *object = static_cast<Object *>(obj);\n>  \t\tobject->connect(this);\n> -\t\tslots_.push_back(new SlotMember<T, Args...>(obj, object, func));\n> +\t\tslots_.push_back(new BoundMemberMethod<T, Args...>(obj, object, func));\n>  \t}\n>\n>  \ttemplate<typename T, typename std::enable_if<!std::is_base_of<Object, T>::value>::type * = nullptr>\n> @@ -179,17 +66,17 @@ public:\n>  #endif\n>  \tvoid connect(T *obj, void (T::*func)(Args...))\n>  \t{\n> -\t\tslots_.push_back(new SlotMember<T, Args...>(obj, nullptr, func));\n> +\t\tslots_.push_back(new BoundMemberMethod<T, Args...>(obj, nullptr, func));\n>  \t}\n>\n>  \tvoid connect(void (*func)(Args...))\n>  \t{\n> -\t\tslots_.push_back(new SlotStatic<Args...>(func));\n> +\t\tslots_.push_back(new BoundStaticMethod<Args...>(func));\n>  \t}\n>\n>  \tvoid disconnect()\n>  \t{\n> -\t\tfor (SlotBase *slot : slots_)\n> +\t\tfor (BoundMethodBase *slot : slots_)\n>  \t\t\tdelete slot;\n>  \t\tslots_.clear();\n>  \t}\n> @@ -204,15 +91,15 @@ public:\n>  \tvoid disconnect(T *obj, void (T::*func)(Args...))\n>  \t{\n>  \t\tfor (auto iter = slots_.begin(); iter != slots_.end(); ) {\n> -\t\t\tSlotArgs<Args...> *slot = static_cast<SlotArgs<Args...> *>(*iter);\n> +\t\t\tBoundMethodArgs<Args...> *slot = static_cast<BoundMethodArgs<Args...> *>(*iter);\n>  \t\t\t/*\n>  \t\t\t * If the object matches the slot, the slot is\n>  \t\t\t * guaranteed to be a member slot, so we can safely\n> -\t\t\t * cast it to SlotMember<T, Args...> and access its\n> +\t\t\t * cast it to BoundMemberMethod<T, Args...> and access its\n>  \t\t\t * func_ member.\n>  \t\t\t */\n>  \t\t\tif (slot->match(obj) &&\n> -\t\t\t    static_cast<SlotMember<T, Args...> *>(slot)->func_ == func) {\n> +\t\t\t    static_cast<BoundMemberMethod<T, Args...> *>(slot)->func_ == func) {\n>  \t\t\t\titer = slots_.erase(iter);\n>  \t\t\t\tdelete slot;\n>  \t\t\t} else {\n> @@ -224,9 +111,9 @@ public:\n>  \tvoid disconnect(void (*func)(Args...))\n>  \t{\n>  \t\tfor (auto iter = slots_.begin(); iter != slots_.end(); ) {\n> -\t\t\tSlotArgs<Args...> *slot = *iter;\n> +\t\t\tBoundMethodArgs<Args...> *slot = *iter;\n>  \t\t\tif (slot->match(nullptr) &&\n> -\t\t\t    static_cast<SlotStatic<Args...> *>(slot)->func_ == func) {\n> +\t\t\t    static_cast<BoundStaticMethod<Args...> *>(slot)->func_ == func) {\n>  \t\t\t\titer = slots_.erase(iter);\n>  \t\t\t\tdelete slot;\n>  \t\t\t} else {\n> @@ -241,9 +128,9 @@ public:\n>  \t\t * Make a copy of the slots list as the slot could call the\n>  \t\t * disconnect operation, invalidating the iterator.\n>  \t\t */\n> -\t\tstd::vector<SlotBase *> slots{ slots_.begin(), slots_.end() };\n> -\t\tfor (SlotBase *slot : slots)\n> -\t\t\tstatic_cast<SlotArgs<Args...> *>(slot)->activate(args...);\n> +\t\tstd::vector<BoundMethodBase *> slots{ slots_.begin(), slots_.end() };\n> +\t\tfor (BoundMethodBase *slot : slots)\n> +\t\t\tstatic_cast<BoundMethodArgs<Args...> *>(slot)->activate(args...);\n>  \t}\n>  };\n>\n> diff --git a/src/libcamera/bound_method.cpp b/src/libcamera/bound_method.cpp\n> new file mode 100644\n> index 000000000000..0a2d61a6c805\n> --- /dev/null\n> +++ b/src/libcamera/bound_method.cpp\n> @@ -0,0 +1,33 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * bound_method.cpp - Method bind and invocation\n> + */\n> +\n> +#include <libcamera/bound_method.h>\n> +\n> +#include \"message.h\"\n> +#include \"thread.h\"\n> +#include \"utils.h\"\n> +\n> +namespace libcamera {\n> +\n> +void BoundMethodBase::disconnect(SignalBase *signal)\n> +{\n> +\tif (object_)\n> +\t\tobject_->disconnect(signal);\n> +}\n> +\n> +void BoundMethodBase::activatePack(void *pack)\n> +{\n> +\tif (Thread::current() == object_->thread()) {\n> +\t\tinvokePack(pack);\n> +\t} else {\n> +\t\tstd::unique_ptr<Message> msg =\n> +\t\t\tutils::make_unique<SignalMessage>(this, pack);\n> +\t\tobject_->postMessage(std::move(msg));\n> +\t}\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/include/message.h b/src/libcamera/include/message.h\n> index 416fe74b10ad..b4670c0eab76 100644\n> --- a/src/libcamera/include/message.h\n> +++ b/src/libcamera/include/message.h\n> @@ -11,8 +11,8 @@\n>\n>  namespace libcamera {\n>\n> +class BoundMethodBase;\n>  class Object;\n> -class SlotBase;\n>  class Thread;\n>\n>  class Message\n> @@ -44,12 +44,12 @@ private:\n>  class SignalMessage : public Message\n>  {\n>  public:\n> -\tSignalMessage(SlotBase *slot, void *pack)\n> -\t\t: Message(Message::SignalMessage), slot_(slot), pack_(pack)\n> +\tSignalMessage(BoundMethodBase *method, void *pack)\n> +\t\t: Message(Message::SignalMessage), method_(method), pack_(pack)\n>  \t{\n>  \t}\n>\n> -\tSlotBase *slot_;\n> +\tBoundMethodBase *method_;\n>  \tvoid *pack_;\n>  };\n>\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index 7d5d3c04fba0..c5d8f116ffc6 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -1,4 +1,5 @@\n>  libcamera_sources = files([\n> +    'bound_method.cpp',\n>      'buffer.cpp',\n>      'camera.cpp',\n>      'camera_manager.cpp',\n> diff --git a/src/libcamera/message.cpp b/src/libcamera/message.cpp\n> index d44d2a4c73a8..8d3376d8a533 100644\n> --- a/src/libcamera/message.cpp\n> +++ b/src/libcamera/message.cpp\n> @@ -114,12 +114,12 @@ Message::Type Message::registerMessageType()\n>  /**\n>   * \\fn SignalMessage::SignalMessage()\n>   * \\brief Construct a SignalMessage\n> - * \\param[in] slot The slot that the signal targets\n> + * \\param[in] method The slot that the signal targets\n>   * \\param[in] pack The signal arguments\n>   */\n>\n>  /**\n> - * \\var SignalMessage::slot_\n> + * \\var SignalMessage::method_\n>   * \\brief The slot that the signal targets\n>   */\n>\n> diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp\n> index 61787fadac0b..0adbc203add8 100644\n> --- a/src/libcamera/object.cpp\n> +++ b/src/libcamera/object.cpp\n> @@ -90,7 +90,7 @@ void Object::message(Message *msg)\n>  \tswitch (msg->type()) {\n>  \tcase Message::SignalMessage: {\n>  \t\tSignalMessage *smsg = static_cast<SignalMessage *>(msg);\n> -\t\tsmsg->slot_->invokePack(smsg->pack_);\n> +\t\tsmsg->method_->invokePack(smsg->pack_);\n>  \t\tbreak;\n>  \t}\n>\n> diff --git a/src/libcamera/signal.cpp b/src/libcamera/signal.cpp\n> index ab7dba508dfb..6ee348acc8d4 100644\n> --- a/src/libcamera/signal.cpp\n> +++ b/src/libcamera/signal.cpp\n> @@ -7,10 +7,6 @@\n>\n>  #include <libcamera/signal.h>\n>\n> -#include \"message.h\"\n> -#include \"thread.h\"\n> -#include \"utils.h\"\n> -\n>  /**\n>   * \\file signal.h\n>   * \\brief Signal & slot implementation\n> @@ -57,25 +53,6 @@ namespace libcamera {\n>   * passed through the signal will remain valid after the signal is emitted.\n>   */\n>\n> -void SlotBase::disconnect(SignalBase *signal)\n> -{\n> -\tif (object_)\n> -\t\tobject_->disconnect(signal);\n> -}\n> -\n> -void SlotBase::activatePack(void *pack)\n> -{\n> -\tObject *obj = static_cast<Object *>(object_);\n> -\n> -\tif (Thread::current() == obj->thread()) {\n> -\t\tinvokePack(pack);\n> -\t} else {\n> -\t\tstd::unique_ptr<Message> msg =\n> -\t\t\tutils::make_unique<SignalMessage>(this, pack);\n> -\t\tobj->postMessage(std::move(msg));\n> -\t}\n> -}\n> -\n>  /**\n>   * \\fn Signal::connect(T *object, void(T::*func)(Args...))\n>   * \\brief Connect the signal to a member function slot\n> --\n> Regards,\n>\n> Laurent Pinchart\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net\n\t[217.70.183.199])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E43D960E2C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 15 Aug 2019 10:46:15 +0200 (CEST)","from uno.localdomain\n\t(host64-130-dynamic.5-87-r.retail.telecomitalia.it [87.5.130.64])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 6FF12FF805;\n\tThu, 15 Aug 2019 08:46:14 +0000 (UTC)"],"X-Originating-IP":"87.5.130.64","Date":"Thu, 15 Aug 2019 10:47:41 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190815084741.7qurumsza7cglent@uno.localdomain>","References":"<20190812124642.24287-1-laurent.pinchart@ideasonboard.com>\n\t<20190812124642.24287-5-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"6txqmk7gmoupswzp\"","Content-Disposition":"inline","In-Reply-To":"<20190812124642.24287-5-laurent.pinchart@ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH 04/18] libcamera: signal: Split Slot\n\timplementation to reusable classes","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Thu, 15 Aug 2019 08:46:16 -0000"}},{"id":2410,"web_url":"https://patchwork.libcamera.org/comment/2410/","msgid":"<20190815094907.GB5011@pendragon.ideasonboard.com>","date":"2019-08-15T09:49:07","subject":"Re: [libcamera-devel] [PATCH 04/18] libcamera: signal: Split Slot\n\timplementation to reusable classes","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Thu, Aug 15, 2019 at 10:47:41AM +0200, Jacopo Mondi wrote:\n> On Mon, Aug 12, 2019 at 03:46:28PM +0300, Laurent Pinchart wrote:\n> > Move the Slot* classes to bound_method.{h,cpp} and rename them to\n> > Bound*Method*. They will be reused to implement asynchronous method\n> > invocation similar to cross-thread signal delivery.\n> \n> Stupid question, but why do you need to rename to a longer\n> \"Bound*Method*\" when \"Slot\" was quite efficient as a name? Couldn't\n> you just move the Slot hierarchy definition and implementation to\n> their own files?\n\nThe name \"Slot\" is tied to Signal, and I wanted a better name that would\nreflect the extended purpose of this class. I'm open to better\nsuggestions of course :-)\n\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  Documentation/Doxyfile.in        |  10 +--\n> >  include/libcamera/bound_method.h | 131 ++++++++++++++++++++++++++++\n> >  include/libcamera/meson.build    |   1 +\n> >  include/libcamera/object.h       |   5 +-\n> >  include/libcamera/signal.h       | 145 ++++---------------------------\n> >  src/libcamera/bound_method.cpp   |  33 +++++++\n> >  src/libcamera/include/message.h  |   8 +-\n> >  src/libcamera/meson.build        |   1 +\n> >  src/libcamera/message.cpp        |   4 +-\n> >  src/libcamera/object.cpp         |   2 +-\n> >  src/libcamera/signal.cpp         |  23 -----\n> >  11 files changed, 197 insertions(+), 166 deletions(-)\n> >  create mode 100644 include/libcamera/bound_method.h\n> >  create mode 100644 src/libcamera/bound_method.cpp\n> >\n> > diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in\n> > index 3d94623a4b8f..a9596c2a32d8 100644\n> > --- a/Documentation/Doxyfile.in\n> > +++ b/Documentation/Doxyfile.in\n> > @@ -865,11 +865,11 @@ EXCLUDE_PATTERNS       =\n> >  # Note that the wildcards are matched against the file with absolute path, so to\n> >  # exclude all test directories use the pattern */test/*\n> >\n> > -EXCLUDE_SYMBOLS        = libcamera::SignalBase \\\n> > -                         libcamera::SlotArgs \\\n> > -                         libcamera::SlotBase \\\n> > -                         libcamera::SlotMember \\\n> > -                         libcamera::SlotStatic \\\n> > +EXCLUDE_SYMBOLS        = libcamera::BoundMemberMethod \\\n> > +                         libcamera::BoundMethodArgs \\\n> > +                         libcamera::BoundMethodBase \\\n> > +                         libcamera::BoundStaticMethod \\\n> > +                         libcamera::SignalBase \\\n> >                           std::*\n> >\n> >  # The EXAMPLE_PATH tag can be used to specify one or more files or directories\n> > diff --git a/include/libcamera/bound_method.h b/include/libcamera/bound_method.h\n> > new file mode 100644\n> > index 000000000000..38c44b923ba1\n> > --- /dev/null\n> > +++ b/include/libcamera/bound_method.h\n> > @@ -0,0 +1,131 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * bound_method.h - Method bind and invocation\n> > + */\n> > +#ifndef __LIBCAMERA_BOUND_METHOD_H__\n> > +#define __LIBCAMERA_BOUND_METHOD_H__\n> > +\n> > +#include <tuple>\n> > +#include <type_traits>\n> > +\n> > +namespace libcamera {\n> > +\n> > +class Object;\n> > +template<typename... Args>\n> > +class Signal;\n> > +class SignalBase;\n> > +\n> > +class BoundMethodBase\n> > +{\n> > +public:\n> > +\tBoundMethodBase(void *obj, Object *object)\n> > +\t\t: obj_(obj), object_(object) {}\n> > +\tvirtual ~BoundMethodBase() {}\n> > +\n> > +\ttemplate<typename T, typename std::enable_if<!std::is_same<Object, T>::value>::type * = nullptr>\n> > +\tbool match(T *obj) { return obj == obj_; }\n> > +\tbool match(Object *object) { return object == object_; }\n> > +\n> > +\tvoid disconnect(SignalBase *signal);\n> > +\n> > +\tvoid activatePack(void *pack);\n> > +\tvirtual void invokePack(void *pack) = 0;\n> > +\n> > +protected:\n> > +\tvoid *obj_;\n> > +\tObject *object_;\n> > +};\n> > +\n> > +template<typename... Args>\n> > +class BoundMethodArgs : public BoundMethodBase\n> > +{\n> > +private:\n> > +#ifndef __DOXYGEN__\n> > +\t/*\n> > +\t * This is a cheap partial implementation of std::integer_sequence<>\n> > +\t * from C++14.\n> > +\t */\n> > +\ttemplate<int...>\n> > +\tstruct sequence {\n> > +\t};\n> > +\n> > +\ttemplate<int N, int... S>\n> > +\tstruct generator : generator<N-1, N-1, S...> {\n> > +\t};\n> > +\n> > +\ttemplate<int... S>\n> > +\tstruct generator<0, S...> {\n> > +\t\ttypedef sequence<S...> type;\n> > +\t};\n> > +#endif\n> > +\n> > +\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> > +\n> > +\ttemplate<int... S>\n> > +\tvoid invokePack(void *pack, sequence<S...>)\n> > +\t{\n> > +\t\tPackType *args = static_cast<PackType *>(pack);\n> > +\t\tinvoke(std::get<S>(*args)...);\n> > +\t\tdelete args;\n> > +\t}\n> > +\n> > +public:\n> > +\tBoundMethodArgs(void *obj, Object *object)\n> > +\t\t: BoundMethodBase(obj, object) {}\n> > +\n> > +\tvoid invokePack(void *pack) override\n> > +\t{\n> > +\t\tinvokePack(pack, typename generator<sizeof...(Args)>::type());\n> > +\t}\n> > +\n> > +\tvirtual void activate(Args... args) = 0;\n> > +\tvirtual void invoke(Args... args) = 0;\n> > +};\n> > +\n> > +template<typename T, typename... Args>\n> > +class BoundMemberMethod : public BoundMethodArgs<Args...>\n> > +{\n> > +public:\n> > +\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> > +\n> > +\tBoundMemberMethod(T *obj, Object *object, void (T::*func)(Args...))\n> > +\t\t: BoundMethodArgs<Args...>(obj, object), func_(func) {}\n> > +\n> > +\tvoid activate(Args... args)\n> > +\t{\n> > +\t\tif (this->object_)\n> > +\t\t\tBoundMethodBase::activatePack(new PackType{ args... });\n> > +\t\telse\n> > +\t\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> > +\t}\n> > +\n> > +\tvoid invoke(Args... args)\n> > +\t{\n> > +\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> > +\t}\n> > +\n> > +private:\n> > +\tfriend class Signal<Args...>;\n> > +\tvoid (T::*func_)(Args...);\n> > +};\n> > +\n> > +template<typename... Args>\n> > +class BoundStaticMethod : public BoundMethodArgs<Args...>\n> > +{\n> > +public:\n> > +\tBoundStaticMethod(void (*func)(Args...))\n> > +\t\t: BoundMethodArgs<Args...>(nullptr, nullptr), func_(func) {}\n> > +\n> > +\tvoid activate(Args... args) { (*func_)(args...); }\n> > +\tvoid invoke(Args... args) {}\n> > +\n> > +private:\n> > +\tfriend class Signal<Args...>;\n> > +\tvoid (*func_)(Args...);\n> > +};\n> > +\n> > +}; /* namespace libcamera */\n> > +\n> > +#endif /* __LIBCAMERA_BOUND_METHOD_H__ */\n> > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build\n> > index 920eb5fcbfd1..a8a38a9b1db7 100644\n> > --- a/include/libcamera/meson.build\n> > +++ b/include/libcamera/meson.build\n> > @@ -1,4 +1,5 @@\n> >  libcamera_api = files([\n> > +    'bound_method.h',\n> >      'buffer.h',\n> >      'camera.h',\n> >      'camera_manager.h',\n> > diff --git a/include/libcamera/object.h b/include/libcamera/object.h\n> > index 3d08d69a9044..e3b39cf547b0 100644\n> > --- a/include/libcamera/object.h\n> > +++ b/include/libcamera/object.h\n> > @@ -10,13 +10,14 @@\n> >  #include <list>\n> >  #include <memory>\n> >\n> > +#include <libcamera/bound_method.h>\n> > +\n> >  namespace libcamera {\n> >\n> >  class Message;\n> >  template<typename... Args>\n> >  class Signal;\n> >  class SignalBase;\n> > -class SlotBase;\n> >  class Thread;\n> >\n> >  class Object\n> > @@ -36,7 +37,7 @@ protected:\n> >  private:\n> >  \ttemplate<typename... Args>\n> >  \tfriend class Signal;\n> > -\tfriend class SlotBase;\n> > +\tfriend class BoundMethodBase;\n> >  \tfriend class Thread;\n> >\n> >  \tvoid connect(SignalBase *signal);\n> > diff --git a/include/libcamera/signal.h b/include/libcamera/signal.h\n> > index 8f6db700cd80..3b6de30f7d35 100644\n> > --- a/include/libcamera/signal.h\n> > +++ b/include/libcamera/signal.h\n> > @@ -8,127 +8,14 @@\n> >  #define __LIBCAMERA_SIGNAL_H__\n> >\n> >  #include <list>\n> > -#include <tuple>\n> >  #include <type_traits>\n> >  #include <vector>\n> >\n> > +#include <libcamera/bound_method.h>\n> >  #include <libcamera/object.h>\n> >\n> >  namespace libcamera {\n> >\n> > -template<typename... Args>\n> > -class Signal;\n> > -class SignalBase;\n> > -\n> > -class SlotBase\n> > -{\n> > -public:\n> > -\tSlotBase(void *obj, Object *object)\n> > -\t\t: obj_(obj), object_(object) {}\n> > -\tvirtual ~SlotBase() {}\n> > -\n> > -\ttemplate<typename T, typename std::enable_if<!std::is_same<Object, T>::value>::type * = nullptr>\n> > -\tbool match(T *obj) { return obj == obj_; }\n> > -\tbool match(Object *object) { return object == object_; }\n> > -\n> > -\tvoid disconnect(SignalBase *signal);\n> > -\n> > -\tvoid activatePack(void *pack);\n> > -\tvirtual void invokePack(void *pack) = 0;\n> > -\n> > -protected:\n> > -\tvoid *obj_;\n> > -\tObject *object_;\n> > -};\n> > -\n> > -template<typename... Args>\n> > -class SlotArgs : public SlotBase\n> > -{\n> > -private:\n> > -#ifndef __DOXYGEN__\n> > -\t/*\n> > -\t * This is a cheap partial implementation of std::integer_sequence<>\n> > -\t * from C++14.\n> > -\t */\n> > -\ttemplate<int...>\n> > -\tstruct sequence {\n> > -\t};\n> > -\n> > -\ttemplate<int N, int... S>\n> > -\tstruct generator : generator<N-1, N-1, S...> {\n> > -\t};\n> > -\n> > -\ttemplate<int... S>\n> > -\tstruct generator<0, S...> {\n> > -\t\ttypedef sequence<S...> type;\n> > -\t};\n> > -#endif\n> > -\n> > -\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> > -\n> > -\ttemplate<int... S>\n> > -\tvoid invokePack(void *pack, sequence<S...>)\n> > -\t{\n> > -\t\tPackType *args = static_cast<PackType *>(pack);\n> > -\t\tinvoke(std::get<S>(*args)...);\n> > -\t\tdelete args;\n> > -\t}\n> > -\n> > -public:\n> > -\tSlotArgs(void *obj, Object *object)\n> > -\t\t: SlotBase(obj, object) {}\n> > -\n> > -\tvoid invokePack(void *pack) override\n> > -\t{\n> > -\t\tinvokePack(pack, typename generator<sizeof...(Args)>::type());\n> > -\t}\n> > -\n> > -\tvirtual void activate(Args... args) = 0;\n> > -\tvirtual void invoke(Args... args) = 0;\n> > -};\n> > -\n> > -template<typename T, typename... Args>\n> > -class SlotMember : public SlotArgs<Args...>\n> > -{\n> > -public:\n> > -\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> > -\n> > -\tSlotMember(T *obj, Object *object, void (T::*func)(Args...))\n> > -\t\t: SlotArgs<Args...>(obj, object), func_(func) {}\n> > -\n> > -\tvoid activate(Args... args)\n> > -\t{\n> > -\t\tif (this->object_)\n> > -\t\t\tSlotBase::activatePack(new PackType{ args... });\n> > -\t\telse\n> > -\t\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> > -\t}\n> > -\n> > -\tvoid invoke(Args... args)\n> > -\t{\n> > -\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> > -\t}\n> > -\n> > -private:\n> > -\tfriend class Signal<Args...>;\n> > -\tvoid (T::*func_)(Args...);\n> > -};\n> > -\n> > -template<typename... Args>\n> > -class SlotStatic : public SlotArgs<Args...>\n> > -{\n> > -public:\n> > -\tSlotStatic(void (*func)(Args...))\n> > -\t\t: SlotArgs<Args...>(nullptr, nullptr), func_(func) {}\n> > -\n> > -\tvoid activate(Args... args) { (*func_)(args...); }\n> > -\tvoid invoke(Args... args) {}\n> > -\n> > -private:\n> > -\tfriend class Signal<Args...>;\n> > -\tvoid (*func_)(Args...);\n> > -};\n> > -\n> >  class SignalBase\n> >  {\n> >  public:\n> > @@ -136,7 +23,7 @@ public:\n> >  \tvoid disconnect(T *obj)\n> >  \t{\n> >  \t\tfor (auto iter = slots_.begin(); iter != slots_.end(); ) {\n> > -\t\t\tSlotBase *slot = *iter;\n> > +\t\t\tBoundMethodBase *slot = *iter;\n> >  \t\t\tif (slot->match(obj)) {\n> >  \t\t\t\titer = slots_.erase(iter);\n> >  \t\t\t\tdelete slot;\n> > @@ -148,7 +35,7 @@ public:\n> >\n> >  protected:\n> >  \tfriend class Object;\n> > -\tstd::list<SlotBase *> slots_;\n> > +\tstd::list<BoundMethodBase *> slots_;\n> >  };\n> >\n> >  template<typename... Args>\n> > @@ -158,7 +45,7 @@ public:\n> >  \tSignal() {}\n> >  \t~Signal()\n> >  \t{\n> > -\t\tfor (SlotBase *slot : slots_) {\n> > +\t\tfor (BoundMethodBase *slot : slots_) {\n> >  \t\t\tslot->disconnect(this);\n> >  \t\t\tdelete slot;\n> >  \t\t}\n> > @@ -170,7 +57,7 @@ public:\n> >  \t{\n> >  \t\tObject *object = static_cast<Object *>(obj);\n> >  \t\tobject->connect(this);\n> > -\t\tslots_.push_back(new SlotMember<T, Args...>(obj, object, func));\n> > +\t\tslots_.push_back(new BoundMemberMethod<T, Args...>(obj, object, func));\n> >  \t}\n> >\n> >  \ttemplate<typename T, typename std::enable_if<!std::is_base_of<Object, T>::value>::type * = nullptr>\n> > @@ -179,17 +66,17 @@ public:\n> >  #endif\n> >  \tvoid connect(T *obj, void (T::*func)(Args...))\n> >  \t{\n> > -\t\tslots_.push_back(new SlotMember<T, Args...>(obj, nullptr, func));\n> > +\t\tslots_.push_back(new BoundMemberMethod<T, Args...>(obj, nullptr, func));\n> >  \t}\n> >\n> >  \tvoid connect(void (*func)(Args...))\n> >  \t{\n> > -\t\tslots_.push_back(new SlotStatic<Args...>(func));\n> > +\t\tslots_.push_back(new BoundStaticMethod<Args...>(func));\n> >  \t}\n> >\n> >  \tvoid disconnect()\n> >  \t{\n> > -\t\tfor (SlotBase *slot : slots_)\n> > +\t\tfor (BoundMethodBase *slot : slots_)\n> >  \t\t\tdelete slot;\n> >  \t\tslots_.clear();\n> >  \t}\n> > @@ -204,15 +91,15 @@ public:\n> >  \tvoid disconnect(T *obj, void (T::*func)(Args...))\n> >  \t{\n> >  \t\tfor (auto iter = slots_.begin(); iter != slots_.end(); ) {\n> > -\t\t\tSlotArgs<Args...> *slot = static_cast<SlotArgs<Args...> *>(*iter);\n> > +\t\t\tBoundMethodArgs<Args...> *slot = static_cast<BoundMethodArgs<Args...> *>(*iter);\n> >  \t\t\t/*\n> >  \t\t\t * If the object matches the slot, the slot is\n> >  \t\t\t * guaranteed to be a member slot, so we can safely\n> > -\t\t\t * cast it to SlotMember<T, Args...> and access its\n> > +\t\t\t * cast it to BoundMemberMethod<T, Args...> and access its\n> >  \t\t\t * func_ member.\n> >  \t\t\t */\n> >  \t\t\tif (slot->match(obj) &&\n> > -\t\t\t    static_cast<SlotMember<T, Args...> *>(slot)->func_ == func) {\n> > +\t\t\t    static_cast<BoundMemberMethod<T, Args...> *>(slot)->func_ == func) {\n> >  \t\t\t\titer = slots_.erase(iter);\n> >  \t\t\t\tdelete slot;\n> >  \t\t\t} else {\n> > @@ -224,9 +111,9 @@ public:\n> >  \tvoid disconnect(void (*func)(Args...))\n> >  \t{\n> >  \t\tfor (auto iter = slots_.begin(); iter != slots_.end(); ) {\n> > -\t\t\tSlotArgs<Args...> *slot = *iter;\n> > +\t\t\tBoundMethodArgs<Args...> *slot = *iter;\n> >  \t\t\tif (slot->match(nullptr) &&\n> > -\t\t\t    static_cast<SlotStatic<Args...> *>(slot)->func_ == func) {\n> > +\t\t\t    static_cast<BoundStaticMethod<Args...> *>(slot)->func_ == func) {\n> >  \t\t\t\titer = slots_.erase(iter);\n> >  \t\t\t\tdelete slot;\n> >  \t\t\t} else {\n> > @@ -241,9 +128,9 @@ public:\n> >  \t\t * Make a copy of the slots list as the slot could call the\n> >  \t\t * disconnect operation, invalidating the iterator.\n> >  \t\t */\n> > -\t\tstd::vector<SlotBase *> slots{ slots_.begin(), slots_.end() };\n> > -\t\tfor (SlotBase *slot : slots)\n> > -\t\t\tstatic_cast<SlotArgs<Args...> *>(slot)->activate(args...);\n> > +\t\tstd::vector<BoundMethodBase *> slots{ slots_.begin(), slots_.end() };\n> > +\t\tfor (BoundMethodBase *slot : slots)\n> > +\t\t\tstatic_cast<BoundMethodArgs<Args...> *>(slot)->activate(args...);\n> >  \t}\n> >  };\n> >\n> > diff --git a/src/libcamera/bound_method.cpp b/src/libcamera/bound_method.cpp\n> > new file mode 100644\n> > index 000000000000..0a2d61a6c805\n> > --- /dev/null\n> > +++ b/src/libcamera/bound_method.cpp\n> > @@ -0,0 +1,33 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * bound_method.cpp - Method bind and invocation\n> > + */\n> > +\n> > +#include <libcamera/bound_method.h>\n> > +\n> > +#include \"message.h\"\n> > +#include \"thread.h\"\n> > +#include \"utils.h\"\n> > +\n> > +namespace libcamera {\n> > +\n> > +void BoundMethodBase::disconnect(SignalBase *signal)\n> > +{\n> > +\tif (object_)\n> > +\t\tobject_->disconnect(signal);\n> > +}\n> > +\n> > +void BoundMethodBase::activatePack(void *pack)\n> > +{\n> > +\tif (Thread::current() == object_->thread()) {\n> > +\t\tinvokePack(pack);\n> > +\t} else {\n> > +\t\tstd::unique_ptr<Message> msg =\n> > +\t\t\tutils::make_unique<SignalMessage>(this, pack);\n> > +\t\tobject_->postMessage(std::move(msg));\n> > +\t}\n> > +}\n> > +\n> > +} /* namespace libcamera */\n> > diff --git a/src/libcamera/include/message.h b/src/libcamera/include/message.h\n> > index 416fe74b10ad..b4670c0eab76 100644\n> > --- a/src/libcamera/include/message.h\n> > +++ b/src/libcamera/include/message.h\n> > @@ -11,8 +11,8 @@\n> >\n> >  namespace libcamera {\n> >\n> > +class BoundMethodBase;\n> >  class Object;\n> > -class SlotBase;\n> >  class Thread;\n> >\n> >  class Message\n> > @@ -44,12 +44,12 @@ private:\n> >  class SignalMessage : public Message\n> >  {\n> >  public:\n> > -\tSignalMessage(SlotBase *slot, void *pack)\n> > -\t\t: Message(Message::SignalMessage), slot_(slot), pack_(pack)\n> > +\tSignalMessage(BoundMethodBase *method, void *pack)\n> > +\t\t: Message(Message::SignalMessage), method_(method), pack_(pack)\n> >  \t{\n> >  \t}\n> >\n> > -\tSlotBase *slot_;\n> > +\tBoundMethodBase *method_;\n> >  \tvoid *pack_;\n> >  };\n> >\n> > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> > index 7d5d3c04fba0..c5d8f116ffc6 100644\n> > --- a/src/libcamera/meson.build\n> > +++ b/src/libcamera/meson.build\n> > @@ -1,4 +1,5 @@\n> >  libcamera_sources = files([\n> > +    'bound_method.cpp',\n> >      'buffer.cpp',\n> >      'camera.cpp',\n> >      'camera_manager.cpp',\n> > diff --git a/src/libcamera/message.cpp b/src/libcamera/message.cpp\n> > index d44d2a4c73a8..8d3376d8a533 100644\n> > --- a/src/libcamera/message.cpp\n> > +++ b/src/libcamera/message.cpp\n> > @@ -114,12 +114,12 @@ Message::Type Message::registerMessageType()\n> >  /**\n> >   * \\fn SignalMessage::SignalMessage()\n> >   * \\brief Construct a SignalMessage\n> > - * \\param[in] slot The slot that the signal targets\n> > + * \\param[in] method The slot that the signal targets\n> >   * \\param[in] pack The signal arguments\n> >   */\n> >\n> >  /**\n> > - * \\var SignalMessage::slot_\n> > + * \\var SignalMessage::method_\n> >   * \\brief The slot that the signal targets\n> >   */\n> >\n> > diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp\n> > index 61787fadac0b..0adbc203add8 100644\n> > --- a/src/libcamera/object.cpp\n> > +++ b/src/libcamera/object.cpp\n> > @@ -90,7 +90,7 @@ void Object::message(Message *msg)\n> >  \tswitch (msg->type()) {\n> >  \tcase Message::SignalMessage: {\n> >  \t\tSignalMessage *smsg = static_cast<SignalMessage *>(msg);\n> > -\t\tsmsg->slot_->invokePack(smsg->pack_);\n> > +\t\tsmsg->method_->invokePack(smsg->pack_);\n> >  \t\tbreak;\n> >  \t}\n> >\n> > diff --git a/src/libcamera/signal.cpp b/src/libcamera/signal.cpp\n> > index ab7dba508dfb..6ee348acc8d4 100644\n> > --- a/src/libcamera/signal.cpp\n> > +++ b/src/libcamera/signal.cpp\n> > @@ -7,10 +7,6 @@\n> >\n> >  #include <libcamera/signal.h>\n> >\n> > -#include \"message.h\"\n> > -#include \"thread.h\"\n> > -#include \"utils.h\"\n> > -\n> >  /**\n> >   * \\file signal.h\n> >   * \\brief Signal & slot implementation\n> > @@ -57,25 +53,6 @@ namespace libcamera {\n> >   * passed through the signal will remain valid after the signal is emitted.\n> >   */\n> >\n> > -void SlotBase::disconnect(SignalBase *signal)\n> > -{\n> > -\tif (object_)\n> > -\t\tobject_->disconnect(signal);\n> > -}\n> > -\n> > -void SlotBase::activatePack(void *pack)\n> > -{\n> > -\tObject *obj = static_cast<Object *>(object_);\n> > -\n> > -\tif (Thread::current() == obj->thread()) {\n> > -\t\tinvokePack(pack);\n> > -\t} else {\n> > -\t\tstd::unique_ptr<Message> msg =\n> > -\t\t\tutils::make_unique<SignalMessage>(this, pack);\n> > -\t\tobj->postMessage(std::move(msg));\n> > -\t}\n> > -}\n> > -\n> >  /**\n> >   * \\fn Signal::connect(T *object, void(T::*func)(Args...))\n> >   * \\brief Connect the signal to a member function slot\n> > --\n> > Regards,\n> >\n> > Laurent Pinchart\n> >\n> > _______________________________________________\n> > libcamera-devel mailing list\n> > libcamera-devel@lists.libcamera.org\n> > https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 419A660E2C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 15 Aug 2019 11:49:11 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi\n\t[IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id AE8802B2;\n\tThu, 15 Aug 2019 11:49:10 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1565862550;\n\tbh=wqUV99ifVCaj5cgnhNEsouVSqDGETWyxzvNrpYbJKhU=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=ZSqEOxVl979f3sS68nw9NQfjHrBbT2RDoiTQIdh7+sCfcrXqkvezZZuKc5MQ4DWVM\n\tPrSCCwgKUZ9RJEZa3XlKjVLH/W/4QpgJuCbqdHyClcrl/1nCsr5wUihOcl9s50Birp\n\tr6MoUopAO8uGpNeUhBbVmd+GyDRFlAWzH2fA9nNQ=","Date":"Thu, 15 Aug 2019 12:49:07 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190815094907.GB5011@pendragon.ideasonboard.com>","References":"<20190812124642.24287-1-laurent.pinchart@ideasonboard.com>\n\t<20190812124642.24287-5-laurent.pinchart@ideasonboard.com>\n\t<20190815084741.7qurumsza7cglent@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190815084741.7qurumsza7cglent@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH 04/18] libcamera: signal: Split Slot\n\timplementation to reusable classes","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Thu, 15 Aug 2019 09:49:11 -0000"}},{"id":2430,"web_url":"https://patchwork.libcamera.org/comment/2430/","msgid":"<20190817142107.GH16603@wyvern>","date":"2019-08-17T14:21:07","subject":"Re: [libcamera-devel] [PATCH 04/18] libcamera: signal: Split Slot\n\timplementation to reusable classes","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Laurent,\n\nThanks for your work.\n\nOn 2019-08-12 15:46:28 +0300, Laurent Pinchart wrote:\n> Move the Slot* classes to bound_method.{h,cpp} and rename them to\n> Bound*Method*. They will be reused to implement asynchronous method\n> invocation similar to cross-thread signal delivery.\n\nI would clarify that this is *only* a move and rename patch, to ease \nreview as it's a quiet big patch.\n\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\n> ---\n>  Documentation/Doxyfile.in        |  10 +--\n>  include/libcamera/bound_method.h | 131 ++++++++++++++++++++++++++++\n>  include/libcamera/meson.build    |   1 +\n>  include/libcamera/object.h       |   5 +-\n>  include/libcamera/signal.h       | 145 ++++---------------------------\n>  src/libcamera/bound_method.cpp   |  33 +++++++\n>  src/libcamera/include/message.h  |   8 +-\n>  src/libcamera/meson.build        |   1 +\n>  src/libcamera/message.cpp        |   4 +-\n>  src/libcamera/object.cpp         |   2 +-\n>  src/libcamera/signal.cpp         |  23 -----\n>  11 files changed, 197 insertions(+), 166 deletions(-)\n>  create mode 100644 include/libcamera/bound_method.h\n>  create mode 100644 src/libcamera/bound_method.cpp\n> \n> diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in\n> index 3d94623a4b8f..a9596c2a32d8 100644\n> --- a/Documentation/Doxyfile.in\n> +++ b/Documentation/Doxyfile.in\n> @@ -865,11 +865,11 @@ EXCLUDE_PATTERNS       =\n>  # Note that the wildcards are matched against the file with absolute path, so to\n>  # exclude all test directories use the pattern */test/*\n>  \n> -EXCLUDE_SYMBOLS        = libcamera::SignalBase \\\n> -                         libcamera::SlotArgs \\\n> -                         libcamera::SlotBase \\\n> -                         libcamera::SlotMember \\\n> -                         libcamera::SlotStatic \\\n> +EXCLUDE_SYMBOLS        = libcamera::BoundMemberMethod \\\n> +                         libcamera::BoundMethodArgs \\\n> +                         libcamera::BoundMethodBase \\\n> +                         libcamera::BoundStaticMethod \\\n> +                         libcamera::SignalBase \\\n>                           std::*\n>  \n>  # The EXAMPLE_PATH tag can be used to specify one or more files or directories\n> diff --git a/include/libcamera/bound_method.h b/include/libcamera/bound_method.h\n> new file mode 100644\n> index 000000000000..38c44b923ba1\n> --- /dev/null\n> +++ b/include/libcamera/bound_method.h\n> @@ -0,0 +1,131 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * bound_method.h - Method bind and invocation\n> + */\n> +#ifndef __LIBCAMERA_BOUND_METHOD_H__\n> +#define __LIBCAMERA_BOUND_METHOD_H__\n> +\n> +#include <tuple>\n> +#include <type_traits>\n> +\n> +namespace libcamera {\n> +\n> +class Object;\n> +template<typename... Args>\n> +class Signal;\n> +class SignalBase;\n> +\n> +class BoundMethodBase\n> +{\n> +public:\n> +\tBoundMethodBase(void *obj, Object *object)\n> +\t\t: obj_(obj), object_(object) {}\n> +\tvirtual ~BoundMethodBase() {}\n> +\n> +\ttemplate<typename T, typename std::enable_if<!std::is_same<Object, T>::value>::type * = nullptr>\n> +\tbool match(T *obj) { return obj == obj_; }\n> +\tbool match(Object *object) { return object == object_; }\n> +\n> +\tvoid disconnect(SignalBase *signal);\n> +\n> +\tvoid activatePack(void *pack);\n> +\tvirtual void invokePack(void *pack) = 0;\n> +\n> +protected:\n> +\tvoid *obj_;\n> +\tObject *object_;\n> +};\n> +\n> +template<typename... Args>\n> +class BoundMethodArgs : public BoundMethodBase\n> +{\n> +private:\n> +#ifndef __DOXYGEN__\n> +\t/*\n> +\t * This is a cheap partial implementation of std::integer_sequence<>\n> +\t * from C++14.\n> +\t */\n> +\ttemplate<int...>\n> +\tstruct sequence {\n> +\t};\n> +\n> +\ttemplate<int N, int... S>\n> +\tstruct generator : generator<N-1, N-1, S...> {\n> +\t};\n> +\n> +\ttemplate<int... S>\n> +\tstruct generator<0, S...> {\n> +\t\ttypedef sequence<S...> type;\n> +\t};\n> +#endif\n> +\n> +\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> +\n> +\ttemplate<int... S>\n> +\tvoid invokePack(void *pack, sequence<S...>)\n> +\t{\n> +\t\tPackType *args = static_cast<PackType *>(pack);\n> +\t\tinvoke(std::get<S>(*args)...);\n> +\t\tdelete args;\n> +\t}\n> +\n> +public:\n> +\tBoundMethodArgs(void *obj, Object *object)\n> +\t\t: BoundMethodBase(obj, object) {}\n> +\n> +\tvoid invokePack(void *pack) override\n> +\t{\n> +\t\tinvokePack(pack, typename generator<sizeof...(Args)>::type());\n> +\t}\n> +\n> +\tvirtual void activate(Args... args) = 0;\n> +\tvirtual void invoke(Args... args) = 0;\n> +};\n> +\n> +template<typename T, typename... Args>\n> +class BoundMemberMethod : public BoundMethodArgs<Args...>\n> +{\n> +public:\n> +\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> +\n> +\tBoundMemberMethod(T *obj, Object *object, void (T::*func)(Args...))\n> +\t\t: BoundMethodArgs<Args...>(obj, object), func_(func) {}\n> +\n> +\tvoid activate(Args... args)\n> +\t{\n> +\t\tif (this->object_)\n> +\t\t\tBoundMethodBase::activatePack(new PackType{ args... });\n> +\t\telse\n> +\t\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> +\t}\n> +\n> +\tvoid invoke(Args... args)\n> +\t{\n> +\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> +\t}\n> +\n> +private:\n> +\tfriend class Signal<Args...>;\n> +\tvoid (T::*func_)(Args...);\n> +};\n> +\n> +template<typename... Args>\n> +class BoundStaticMethod : public BoundMethodArgs<Args...>\n> +{\n> +public:\n> +\tBoundStaticMethod(void (*func)(Args...))\n> +\t\t: BoundMethodArgs<Args...>(nullptr, nullptr), func_(func) {}\n> +\n> +\tvoid activate(Args... args) { (*func_)(args...); }\n> +\tvoid invoke(Args... args) {}\n> +\n> +private:\n> +\tfriend class Signal<Args...>;\n> +\tvoid (*func_)(Args...);\n> +};\n> +\n> +}; /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_BOUND_METHOD_H__ */\n> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build\n> index 920eb5fcbfd1..a8a38a9b1db7 100644\n> --- a/include/libcamera/meson.build\n> +++ b/include/libcamera/meson.build\n> @@ -1,4 +1,5 @@\n>  libcamera_api = files([\n> +    'bound_method.h',\n>      'buffer.h',\n>      'camera.h',\n>      'camera_manager.h',\n> diff --git a/include/libcamera/object.h b/include/libcamera/object.h\n> index 3d08d69a9044..e3b39cf547b0 100644\n> --- a/include/libcamera/object.h\n> +++ b/include/libcamera/object.h\n> @@ -10,13 +10,14 @@\n>  #include <list>\n>  #include <memory>\n>  \n> +#include <libcamera/bound_method.h>\n> +\n>  namespace libcamera {\n>  \n>  class Message;\n>  template<typename... Args>\n>  class Signal;\n>  class SignalBase;\n> -class SlotBase;\n>  class Thread;\n>  \n>  class Object\n> @@ -36,7 +37,7 @@ protected:\n>  private:\n>  \ttemplate<typename... Args>\n>  \tfriend class Signal;\n> -\tfriend class SlotBase;\n> +\tfriend class BoundMethodBase;\n>  \tfriend class Thread;\n>  \n>  \tvoid connect(SignalBase *signal);\n> diff --git a/include/libcamera/signal.h b/include/libcamera/signal.h\n> index 8f6db700cd80..3b6de30f7d35 100644\n> --- a/include/libcamera/signal.h\n> +++ b/include/libcamera/signal.h\n> @@ -8,127 +8,14 @@\n>  #define __LIBCAMERA_SIGNAL_H__\n>  \n>  #include <list>\n> -#include <tuple>\n>  #include <type_traits>\n>  #include <vector>\n>  \n> +#include <libcamera/bound_method.h>\n>  #include <libcamera/object.h>\n>  \n>  namespace libcamera {\n>  \n> -template<typename... Args>\n> -class Signal;\n> -class SignalBase;\n> -\n> -class SlotBase\n> -{\n> -public:\n> -\tSlotBase(void *obj, Object *object)\n> -\t\t: obj_(obj), object_(object) {}\n> -\tvirtual ~SlotBase() {}\n> -\n> -\ttemplate<typename T, typename std::enable_if<!std::is_same<Object, T>::value>::type * = nullptr>\n> -\tbool match(T *obj) { return obj == obj_; }\n> -\tbool match(Object *object) { return object == object_; }\n> -\n> -\tvoid disconnect(SignalBase *signal);\n> -\n> -\tvoid activatePack(void *pack);\n> -\tvirtual void invokePack(void *pack) = 0;\n> -\n> -protected:\n> -\tvoid *obj_;\n> -\tObject *object_;\n> -};\n> -\n> -template<typename... Args>\n> -class SlotArgs : public SlotBase\n> -{\n> -private:\n> -#ifndef __DOXYGEN__\n> -\t/*\n> -\t * This is a cheap partial implementation of std::integer_sequence<>\n> -\t * from C++14.\n> -\t */\n> -\ttemplate<int...>\n> -\tstruct sequence {\n> -\t};\n> -\n> -\ttemplate<int N, int... S>\n> -\tstruct generator : generator<N-1, N-1, S...> {\n> -\t};\n> -\n> -\ttemplate<int... S>\n> -\tstruct generator<0, S...> {\n> -\t\ttypedef sequence<S...> type;\n> -\t};\n> -#endif\n> -\n> -\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> -\n> -\ttemplate<int... S>\n> -\tvoid invokePack(void *pack, sequence<S...>)\n> -\t{\n> -\t\tPackType *args = static_cast<PackType *>(pack);\n> -\t\tinvoke(std::get<S>(*args)...);\n> -\t\tdelete args;\n> -\t}\n> -\n> -public:\n> -\tSlotArgs(void *obj, Object *object)\n> -\t\t: SlotBase(obj, object) {}\n> -\n> -\tvoid invokePack(void *pack) override\n> -\t{\n> -\t\tinvokePack(pack, typename generator<sizeof...(Args)>::type());\n> -\t}\n> -\n> -\tvirtual void activate(Args... args) = 0;\n> -\tvirtual void invoke(Args... args) = 0;\n> -};\n> -\n> -template<typename T, typename... Args>\n> -class SlotMember : public SlotArgs<Args...>\n> -{\n> -public:\n> -\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n> -\n> -\tSlotMember(T *obj, Object *object, void (T::*func)(Args...))\n> -\t\t: SlotArgs<Args...>(obj, object), func_(func) {}\n> -\n> -\tvoid activate(Args... args)\n> -\t{\n> -\t\tif (this->object_)\n> -\t\t\tSlotBase::activatePack(new PackType{ args... });\n> -\t\telse\n> -\t\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> -\t}\n> -\n> -\tvoid invoke(Args... args)\n> -\t{\n> -\t\t(static_cast<T *>(this->obj_)->*func_)(args...);\n> -\t}\n> -\n> -private:\n> -\tfriend class Signal<Args...>;\n> -\tvoid (T::*func_)(Args...);\n> -};\n> -\n> -template<typename... Args>\n> -class SlotStatic : public SlotArgs<Args...>\n> -{\n> -public:\n> -\tSlotStatic(void (*func)(Args...))\n> -\t\t: SlotArgs<Args...>(nullptr, nullptr), func_(func) {}\n> -\n> -\tvoid activate(Args... args) { (*func_)(args...); }\n> -\tvoid invoke(Args... args) {}\n> -\n> -private:\n> -\tfriend class Signal<Args...>;\n> -\tvoid (*func_)(Args...);\n> -};\n> -\n>  class SignalBase\n>  {\n>  public:\n> @@ -136,7 +23,7 @@ public:\n>  \tvoid disconnect(T *obj)\n>  \t{\n>  \t\tfor (auto iter = slots_.begin(); iter != slots_.end(); ) {\n> -\t\t\tSlotBase *slot = *iter;\n> +\t\t\tBoundMethodBase *slot = *iter;\n>  \t\t\tif (slot->match(obj)) {\n>  \t\t\t\titer = slots_.erase(iter);\n>  \t\t\t\tdelete slot;\n> @@ -148,7 +35,7 @@ public:\n>  \n>  protected:\n>  \tfriend class Object;\n> -\tstd::list<SlotBase *> slots_;\n> +\tstd::list<BoundMethodBase *> slots_;\n>  };\n>  \n>  template<typename... Args>\n> @@ -158,7 +45,7 @@ public:\n>  \tSignal() {}\n>  \t~Signal()\n>  \t{\n> -\t\tfor (SlotBase *slot : slots_) {\n> +\t\tfor (BoundMethodBase *slot : slots_) {\n>  \t\t\tslot->disconnect(this);\n>  \t\t\tdelete slot;\n>  \t\t}\n> @@ -170,7 +57,7 @@ public:\n>  \t{\n>  \t\tObject *object = static_cast<Object *>(obj);\n>  \t\tobject->connect(this);\n> -\t\tslots_.push_back(new SlotMember<T, Args...>(obj, object, func));\n> +\t\tslots_.push_back(new BoundMemberMethod<T, Args...>(obj, object, func));\n>  \t}\n>  \n>  \ttemplate<typename T, typename std::enable_if<!std::is_base_of<Object, T>::value>::type * = nullptr>\n> @@ -179,17 +66,17 @@ public:\n>  #endif\n>  \tvoid connect(T *obj, void (T::*func)(Args...))\n>  \t{\n> -\t\tslots_.push_back(new SlotMember<T, Args...>(obj, nullptr, func));\n> +\t\tslots_.push_back(new BoundMemberMethod<T, Args...>(obj, nullptr, func));\n>  \t}\n>  \n>  \tvoid connect(void (*func)(Args...))\n>  \t{\n> -\t\tslots_.push_back(new SlotStatic<Args...>(func));\n> +\t\tslots_.push_back(new BoundStaticMethod<Args...>(func));\n>  \t}\n>  \n>  \tvoid disconnect()\n>  \t{\n> -\t\tfor (SlotBase *slot : slots_)\n> +\t\tfor (BoundMethodBase *slot : slots_)\n>  \t\t\tdelete slot;\n>  \t\tslots_.clear();\n>  \t}\n> @@ -204,15 +91,15 @@ public:\n>  \tvoid disconnect(T *obj, void (T::*func)(Args...))\n>  \t{\n>  \t\tfor (auto iter = slots_.begin(); iter != slots_.end(); ) {\n> -\t\t\tSlotArgs<Args...> *slot = static_cast<SlotArgs<Args...> *>(*iter);\n> +\t\t\tBoundMethodArgs<Args...> *slot = static_cast<BoundMethodArgs<Args...> *>(*iter);\n>  \t\t\t/*\n>  \t\t\t * If the object matches the slot, the slot is\n>  \t\t\t * guaranteed to be a member slot, so we can safely\n> -\t\t\t * cast it to SlotMember<T, Args...> and access its\n> +\t\t\t * cast it to BoundMemberMethod<T, Args...> and access its\n>  \t\t\t * func_ member.\n>  \t\t\t */\n>  \t\t\tif (slot->match(obj) &&\n> -\t\t\t    static_cast<SlotMember<T, Args...> *>(slot)->func_ == func) {\n> +\t\t\t    static_cast<BoundMemberMethod<T, Args...> *>(slot)->func_ == func) {\n>  \t\t\t\titer = slots_.erase(iter);\n>  \t\t\t\tdelete slot;\n>  \t\t\t} else {\n> @@ -224,9 +111,9 @@ public:\n>  \tvoid disconnect(void (*func)(Args...))\n>  \t{\n>  \t\tfor (auto iter = slots_.begin(); iter != slots_.end(); ) {\n> -\t\t\tSlotArgs<Args...> *slot = *iter;\n> +\t\t\tBoundMethodArgs<Args...> *slot = *iter;\n>  \t\t\tif (slot->match(nullptr) &&\n> -\t\t\t    static_cast<SlotStatic<Args...> *>(slot)->func_ == func) {\n> +\t\t\t    static_cast<BoundStaticMethod<Args...> *>(slot)->func_ == func) {\n>  \t\t\t\titer = slots_.erase(iter);\n>  \t\t\t\tdelete slot;\n>  \t\t\t} else {\n> @@ -241,9 +128,9 @@ public:\n>  \t\t * Make a copy of the slots list as the slot could call the\n>  \t\t * disconnect operation, invalidating the iterator.\n>  \t\t */\n> -\t\tstd::vector<SlotBase *> slots{ slots_.begin(), slots_.end() };\n> -\t\tfor (SlotBase *slot : slots)\n> -\t\t\tstatic_cast<SlotArgs<Args...> *>(slot)->activate(args...);\n> +\t\tstd::vector<BoundMethodBase *> slots{ slots_.begin(), slots_.end() };\n> +\t\tfor (BoundMethodBase *slot : slots)\n> +\t\t\tstatic_cast<BoundMethodArgs<Args...> *>(slot)->activate(args...);\n>  \t}\n>  };\n>  \n> diff --git a/src/libcamera/bound_method.cpp b/src/libcamera/bound_method.cpp\n> new file mode 100644\n> index 000000000000..0a2d61a6c805\n> --- /dev/null\n> +++ b/src/libcamera/bound_method.cpp\n> @@ -0,0 +1,33 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * bound_method.cpp - Method bind and invocation\n> + */\n> +\n> +#include <libcamera/bound_method.h>\n> +\n> +#include \"message.h\"\n> +#include \"thread.h\"\n> +#include \"utils.h\"\n> +\n> +namespace libcamera {\n> +\n> +void BoundMethodBase::disconnect(SignalBase *signal)\n> +{\n> +\tif (object_)\n> +\t\tobject_->disconnect(signal);\n> +}\n> +\n> +void BoundMethodBase::activatePack(void *pack)\n> +{\n> +\tif (Thread::current() == object_->thread()) {\n> +\t\tinvokePack(pack);\n> +\t} else {\n> +\t\tstd::unique_ptr<Message> msg =\n> +\t\t\tutils::make_unique<SignalMessage>(this, pack);\n> +\t\tobject_->postMessage(std::move(msg));\n> +\t}\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/include/message.h b/src/libcamera/include/message.h\n> index 416fe74b10ad..b4670c0eab76 100644\n> --- a/src/libcamera/include/message.h\n> +++ b/src/libcamera/include/message.h\n> @@ -11,8 +11,8 @@\n>  \n>  namespace libcamera {\n>  \n> +class BoundMethodBase;\n>  class Object;\n> -class SlotBase;\n>  class Thread;\n>  \n>  class Message\n> @@ -44,12 +44,12 @@ private:\n>  class SignalMessage : public Message\n>  {\n>  public:\n> -\tSignalMessage(SlotBase *slot, void *pack)\n> -\t\t: Message(Message::SignalMessage), slot_(slot), pack_(pack)\n> +\tSignalMessage(BoundMethodBase *method, void *pack)\n> +\t\t: Message(Message::SignalMessage), method_(method), pack_(pack)\n>  \t{\n>  \t}\n>  \n> -\tSlotBase *slot_;\n> +\tBoundMethodBase *method_;\n>  \tvoid *pack_;\n>  };\n>  \n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index 7d5d3c04fba0..c5d8f116ffc6 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -1,4 +1,5 @@\n>  libcamera_sources = files([\n> +    'bound_method.cpp',\n>      'buffer.cpp',\n>      'camera.cpp',\n>      'camera_manager.cpp',\n> diff --git a/src/libcamera/message.cpp b/src/libcamera/message.cpp\n> index d44d2a4c73a8..8d3376d8a533 100644\n> --- a/src/libcamera/message.cpp\n> +++ b/src/libcamera/message.cpp\n> @@ -114,12 +114,12 @@ Message::Type Message::registerMessageType()\n>  /**\n>   * \\fn SignalMessage::SignalMessage()\n>   * \\brief Construct a SignalMessage\n> - * \\param[in] slot The slot that the signal targets\n> + * \\param[in] method The slot that the signal targets\n>   * \\param[in] pack The signal arguments\n>   */\n>  \n>  /**\n> - * \\var SignalMessage::slot_\n> + * \\var SignalMessage::method_\n>   * \\brief The slot that the signal targets\n>   */\n>  \n> diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp\n> index 61787fadac0b..0adbc203add8 100644\n> --- a/src/libcamera/object.cpp\n> +++ b/src/libcamera/object.cpp\n> @@ -90,7 +90,7 @@ void Object::message(Message *msg)\n>  \tswitch (msg->type()) {\n>  \tcase Message::SignalMessage: {\n>  \t\tSignalMessage *smsg = static_cast<SignalMessage *>(msg);\n> -\t\tsmsg->slot_->invokePack(smsg->pack_);\n> +\t\tsmsg->method_->invokePack(smsg->pack_);\n>  \t\tbreak;\n>  \t}\n>  \n> diff --git a/src/libcamera/signal.cpp b/src/libcamera/signal.cpp\n> index ab7dba508dfb..6ee348acc8d4 100644\n> --- a/src/libcamera/signal.cpp\n> +++ b/src/libcamera/signal.cpp\n> @@ -7,10 +7,6 @@\n>  \n>  #include <libcamera/signal.h>\n>  \n> -#include \"message.h\"\n> -#include \"thread.h\"\n> -#include \"utils.h\"\n> -\n>  /**\n>   * \\file signal.h\n>   * \\brief Signal & slot implementation\n> @@ -57,25 +53,6 @@ namespace libcamera {\n>   * passed through the signal will remain valid after the signal is emitted.\n>   */\n>  \n> -void SlotBase::disconnect(SignalBase *signal)\n> -{\n> -\tif (object_)\n> -\t\tobject_->disconnect(signal);\n> -}\n> -\n> -void SlotBase::activatePack(void *pack)\n> -{\n> -\tObject *obj = static_cast<Object *>(object_);\n> -\n> -\tif (Thread::current() == obj->thread()) {\n> -\t\tinvokePack(pack);\n> -\t} else {\n> -\t\tstd::unique_ptr<Message> msg =\n> -\t\t\tutils::make_unique<SignalMessage>(this, pack);\n> -\t\tobj->postMessage(std::move(msg));\n> -\t}\n> -}\n> -\n>  /**\n>   * \\fn Signal::connect(T *object, void(T::*func)(Args...))\n>   * \\brief Connect the signal to a member function slot\n> -- \n> Regards,\n> \n> Laurent Pinchart\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-ed1-x543.google.com (mail-ed1-x543.google.com\n\t[IPv6:2a00:1450:4864:20::543])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8C793600F9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 17 Aug 2019 16:21:11 +0200 (CEST)","by mail-ed1-x543.google.com with SMTP id s49so7520652edb.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 17 Aug 2019 07:21:11 -0700 (PDT)","from localhost ([185.224.57.161]) by smtp.gmail.com with ESMTPSA id\n\tf15sm1220256ejx.14.2019.08.17.07.21.09\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tSat, 17 Aug 2019 07:21:10 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to\n\t:user-agent; bh=X8Yx4vshgZM8Pd436GULmifWwGI+d1xVWZYuVCFa5+c=;\n\tb=Lma+zDjm8s7mCsdM118DR2Ple9hhtVPeVk6rpCJl6gjAm2vpeuwpQthGm1V1w9rtv5\n\tVDLPyATip7T8ewg/uQWS6e9t5LBfAuTurT7wm7epQy0C9HJv+CnJg1PMybn6PRexFmqY\n\t5nFY9uBRyTYVvnyMA97T2NeKhSHy2DAUVl+TjgQH2CShDMUNYPyXyXqXA0XL8So/krWG\n\tMoXafVcxmj1yQuma/2dhZbnoVTfpbNGQiJM7l0pbEFt64Pew52D9GtiQXUJ9NF3nbGDf\n\tdsK8qAA7bQoMi5BMZWmbEYxVchfyAh8Q9y3Kxs1kjzVwtgLtLVuzfiiBj3cS9UQCGbdI\n\ttqGA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to:user-agent;\n\tbh=X8Yx4vshgZM8Pd436GULmifWwGI+d1xVWZYuVCFa5+c=;\n\tb=GMOcBBx2N44Ywc3QVIg/VzlRQUFsxGGdkwyg5EC5Yhh3P/6qbNRzrAj5WNi3gpbXi9\n\tI/h0CRfi3LWrU+llCSeTLJc3Rs7MK4jRA2Kq/p1+Tv1Yn7lTE2KpWabV99CNO+flc06a\n\tmtjdbzPpScDkh9QXbL3gqiK/pz3eDl/aJ5GvC+zgVOUG9rIT1RbqLHpBswfkSVI76DIl\n\tb3gNdXf0jfahI8OJHMlCSukezAvaG4izXq9vB21LkxW69xvrXCmUSW+Xo4JLUU8zAqZ7\n\t1c+p43ATJ7VaqziJQIw18xCapoS1LAttOwDUL4LTZeauXNdQaIwKhQHY4MaD34af21hn\n\tE0Yw==","X-Gm-Message-State":"APjAAAUgedegdW6eV4qZhZDjAgNZdAvryqV+jUpeT/AsTltvZfD6jnL1\n\tJfmZc0T+Q+cd7uJ3SXQFmwDtRE+qRyU=","X-Google-Smtp-Source":"APXvYqxp7wLhOJkIeQdVx/rb3HI2ffk5DiQ+/QCp6DBf6cj3mM7Qhw14K2+4YGjO8d/vrSMclD225Q==","X-Received":"by 2002:a17:906:6dd7:: with SMTP id\n\tj23mr13650236ejt.269.1566051671006; \n\tSat, 17 Aug 2019 07:21:11 -0700 (PDT)","Date":"Sat, 17 Aug 2019 16:21:07 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190817142107.GH16603@wyvern>","References":"<20190812124642.24287-1-laurent.pinchart@ideasonboard.com>\n\t<20190812124642.24287-5-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190812124642.24287-5-laurent.pinchart@ideasonboard.com>","User-Agent":"Mutt/1.12.1 (2019-06-15)","Subject":"Re: [libcamera-devel] [PATCH 04/18] libcamera: signal: Split Slot\n\timplementation to reusable classes","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Sat, 17 Aug 2019 14:21:11 -0000"}}]