[gjs] object: Use template-based definitions for signal action functions



commit 388609bc9e2cbd5b4db47aa56a62b51e1292f469
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Mon May 11 18:34:31 2020 +0200

    object: Use template-based definitions for signal action functions
    
    We've quite a lot of code generated via a macro to just repeat the same
    actions actions for signals, where the only difference is the match
    function used (and some debugging data), reduce the number of functions
    by just using two template-functions that do the same thing but that use
    a different match function, passed via template.
    
    Use the match function also to compute the debugging string

 gi/object.cpp | 151 +++++++++++++++++++++++++++++++++-------------------------
 gi/object.h   |  21 ++++----
 2 files changed, 94 insertions(+), 78 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index d9a946cd..c8fcad74 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -2103,64 +2103,80 @@ bool ObjectInstance::signal_find_impl(JSContext* cx, const JS::CallArgs& args) {
     return true;
 }
 
-#define DEFINE_SIGNAL_MATCH_METHOD(action)                                    \
-    bool ObjectBase::signals_##action(JSContext* cx, unsigned argc,           \
-                                      JS::Value* vp) {                        \
-        GJS_GET_WRAPPER_PRIV(cx, argc, vp, args, obj, ObjectBase, priv);      \
-        if (!priv->check_is_instance(cx, #action " signal")) {                \
-            return false;                                                     \
-        }                                                                     \
-        return priv->to_instance()->signals_##action##_impl(cx, args);        \
-    }                                                                         \
-                                                                              \
-    bool ObjectInstance::signals_##action##_impl(JSContext* cx,               \
-                                                 const JS::CallArgs& args) {  \
-        gjs_debug_gsignal("[Gi.signals_" #action                              \
-                          "_symbol]() obj %p priv %p argc %d",                \
-                          m_wrapper.get(), this, args.length());              \
-                                                                              \
-        if (!check_gobject_disposed(#action " any signal on")) {              \
-            return true;                                                      \
-        }                                                                     \
-        JS::RootedObject match(cx);                                           \
-        if (!gjs_parse_call_args(cx, "[Gi.signals_" #action "_symbol]", args, \
-                                 "o", "match", &match)) {                     \
-            return false;                                                     \
-        }                                                                     \
-        GSignalMatchType mask;                                                \
-        unsigned signal_id;                                                   \
-        GQuark detail;                                                        \
-        JS::RootedFunction func(cx);                                          \
-        if (!signal_match_arguments_from_object(cx, match, &mask, &signal_id, \
-                                                &detail, &func)) {            \
-            return false;                                                     \
-        }                                                                     \
-        unsigned n_matched = 0;                                               \
-        if (!func) {                                                          \
-            n_matched = g_signal_handlers_##action##_matched(                 \
-                m_ptr, mask, signal_id, detail, nullptr, nullptr, nullptr);   \
-        } else {                                                              \
-            std::vector<GClosure*> candidates;                                \
-            for (GClosure* candidate : m_closures) {                          \
-                if (gjs_closure_get_callable(candidate) == func)              \
-                    candidates.push_back(candidate);                          \
-            }                                                                 \
-            for (GClosure* candidate : candidates) {                          \
-                n_matched += g_signal_handlers_##action##_matched(            \
-                    m_ptr, mask, signal_id, detail, candidate, nullptr,       \
-                    nullptr);                                                 \
-            }                                                                 \
-        }                                                                     \
-                                                                              \
-        args.rval().setNumber(n_matched);                                     \
-        return true;                                                          \
-    }
-
-DEFINE_SIGNAL_MATCH_METHOD(block)
-DEFINE_SIGNAL_MATCH_METHOD(unblock)
-DEFINE_SIGNAL_MATCH_METHOD(disconnect)
-
-#undef DEFINE_SIGNAL_MATCH_METHOD
+template <ObjectBase::SignalMatchFunc(*MatchFunc)>
+static inline const char* signal_match_to_action_name();
+
+template <>
+inline const char*
+signal_match_to_action_name<&g_signal_handlers_block_matched>() {
+    return "block";
+}
+
+template <>
+inline const char*
+signal_match_to_action_name<&g_signal_handlers_unblock_matched>() {
+    return "unblock";
+}
+
+template <>
+inline const char*
+signal_match_to_action_name<&g_signal_handlers_disconnect_matched>() {
+    return "disconnect";
+}
+
+template <ObjectBase::SignalMatchFunc(*MatchFunc)>
+bool ObjectBase::signals_action(JSContext* cx, unsigned argc, JS::Value* vp) {
+    GJS_GET_WRAPPER_PRIV(cx, argc, vp, args, obj, ObjectBase, priv);
+    const std::string action_name = signal_match_to_action_name<MatchFunc>();
+    if (!priv->check_is_instance(cx, (action_name + " signal").c_str()))
+        return false;
+
+    return priv->to_instance()->signals_action_impl<MatchFunc>(cx, args);
+}
+
+template <ObjectBase::SignalMatchFunc(*MatchFunc)>
+bool ObjectInstance::signals_action_impl(JSContext* cx,
+                                         const JS::CallArgs& args) {
+    const std::string action_name = signal_match_to_action_name<MatchFunc>();
+    const std::string action_tag = "[Gi.signals_" + action_name + "_symbol]";
+    gjs_debug_gsignal("[%s]() obj %p priv %p argc %d", action_tag.c_str(),
+                      m_wrapper.get(), this, args.length());
+
+    if (!check_gobject_disposed((action_name + " any signal on").c_str())) {
+        return true;
+    }
+    JS::RootedObject match(cx);
+    if (!gjs_parse_call_args(cx, action_tag.c_str(), args, "o", "match",
+                             &match)) {
+        return false;
+    }
+    GSignalMatchType mask;
+    unsigned signal_id;
+    GQuark detail;
+    JS::RootedFunction func(cx);
+    if (!signal_match_arguments_from_object(cx, match, &mask, &signal_id,
+                                            &detail, &func)) {
+        return false;
+    }
+    unsigned n_matched = 0;
+    if (!func) {
+        n_matched = MatchFunc(m_ptr, mask, signal_id, detail, nullptr, nullptr,
+                              nullptr);
+    } else {
+        std::vector<GClosure*> candidates;
+        for (GClosure* candidate : m_closures) {
+            if (gjs_closure_get_callable(candidate) == func)
+                candidates.push_back(candidate);
+        }
+        for (GClosure* candidate : candidates) {
+            n_matched += MatchFunc(m_ptr, mask, signal_id, detail, candidate,
+                                   nullptr, nullptr);
+        }
+    }
+
+    args.rval().setNumber(n_matched);
+    return true;
+}
 
 bool ObjectBase::to_string(JSContext* cx, unsigned argc, JS::Value* vp) {
     GJS_GET_WRAPPER_PRIV(cx, argc, vp, args, obj, ObjectBase, priv);
@@ -2282,15 +2298,18 @@ bool ObjectPrototype::define_class(JSContext* context,
            JS_DefineFunctionById(context, prototype, atoms.signal_find(),
                                  &ObjectBase::signal_find, 1,
                                  GJS_MODULE_PROP_FLAGS) &&
-           JS_DefineFunctionById(context, prototype, atoms.signals_block(),
-                                 &ObjectBase::signals_block, 1,
-                                 GJS_MODULE_PROP_FLAGS) &&
-           JS_DefineFunctionById(context, prototype, atoms.signals_unblock(),
-                                 &ObjectBase::signals_unblock, 1,
-                                 GJS_MODULE_PROP_FLAGS) &&
+           JS_DefineFunctionById(
+               context, prototype, atoms.signals_block(),
+               &ObjectBase::signals_action<&g_signal_handlers_block_matched>, 1,
+               GJS_MODULE_PROP_FLAGS) &&
+           JS_DefineFunctionById(
+               context, prototype, atoms.signals_unblock(),
+               &ObjectBase::signals_action<&g_signal_handlers_unblock_matched>,
+               1, GJS_MODULE_PROP_FLAGS) &&
            JS_DefineFunctionById(context, prototype, atoms.signals_disconnect(),
-                                 &ObjectBase::signals_disconnect, 1,
-                                 GJS_MODULE_PROP_FLAGS);
+                                 &ObjectBase::signals_action<
+                                     &g_signal_handlers_disconnect_matched>,
+                                 1, GJS_MODULE_PROP_FLAGS);
 }
 
 /*
diff --git a/gi/object.h b/gi/object.h
index 81648ddd..d865c9c4 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -105,6 +105,8 @@ class ObjectBase
         : GIWrapperBase(proto) {}
 
  public:
+    using SignalMatchFunc = guint(gpointer, GSignalMatchType, guint, GQuark,
+                                  GClosure*, gpointer, gpointer);
     static const GjsDebugTopic debug_topic = GJS_DEBUG_GOBJECT;
     static constexpr const char* debug_tag = "GObject";
 
@@ -179,12 +181,10 @@ class ObjectBase
     static bool emit(JSContext* cx, unsigned argc, JS::Value* vp);
     GJS_JSAPI_RETURN_CONVENTION
     static bool signal_find(JSContext* cx, unsigned argc, JS::Value* vp);
-    GJS_JSAPI_RETURN_CONVENTION
-    static bool signals_block(JSContext* cx, unsigned argc, JS::Value* vp);
-    GJS_JSAPI_RETURN_CONVENTION
-    static bool signals_unblock(JSContext* cx, unsigned argc, JS::Value* vp);
-    GJS_JSAPI_RETURN_CONVENTION
-    static bool signals_disconnect(JSContext* cx, unsigned argc, JS::Value* vp);
+    template <SignalMatchFunc(*MATCH_FUNC)>
+    GJS_JSAPI_RETURN_CONVENTION static bool signals_action(JSContext* cx,
+                                                           unsigned argc,
+                                                           JS::Value* vp);
     GJS_JSAPI_RETURN_CONVENTION
     static bool to_string(JSContext* cx, unsigned argc, JS::Value* vp);
     [[nodiscard]] const char* to_string_kind() const;
@@ -476,12 +476,9 @@ class ObjectInstance : public GIWrapperInstance<ObjectBase, ObjectPrototype,
     bool emit_impl(JSContext* cx, const JS::CallArgs& args);
     GJS_JSAPI_RETURN_CONVENTION
     bool signal_find_impl(JSContext* cx, const JS::CallArgs& args);
-    GJS_JSAPI_RETURN_CONVENTION
-    bool signals_block_impl(JSContext* cx, const JS::CallArgs& args);
-    GJS_JSAPI_RETURN_CONVENTION
-    bool signals_unblock_impl(JSContext* cx, const JS::CallArgs& args);
-    GJS_JSAPI_RETURN_CONVENTION
-    bool signals_disconnect_impl(JSContext* cx, const JS::CallArgs& args);
+    template <SignalMatchFunc(*MATCH_FUNC)>
+    GJS_JSAPI_RETURN_CONVENTION bool signals_action_impl(
+        JSContext* cx, const JS::CallArgs& args);
     GJS_JSAPI_RETURN_CONVENTION
     bool init_impl(JSContext* cx, const JS::CallArgs& args,
                    JS::MutableHandleObject obj);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]