[gnumeric] Derivative: use a GnmFunc signal instead of ad-hoc handlers.



commit 03f01e3833a5ba3e4839a34c45a787de1af3bfc5
Author: Morten Welinder <terra gnome org>
Date:   Sat May 26 22:55:29 2018 -0400

    Derivative: use a GnmFunc signal instead of ad-hoc handlers.

 plugins/fn-math/functions.c |  40 +++++++--------
 src/expr-deriv.c            | 119 +++++++++++++++-----------------------------
 src/expr-deriv.h            |  24 +++------
 src/func-builtin.c          |  20 +++-----
 src/func.c                  |  67 ++++++++++++++++++++++++-
 src/func.h                  |   7 +++
 src/gnm-marshalers.list     |   1 +
 src/gnumeric-fwd.h          |   1 +
 8 files changed, 146 insertions(+), 133 deletions(-)
---
diff --git a/plugins/fn-math/functions.c b/plugins/fn-math/functions.c
index 333dfb089..4963c7f53 100644
--- a/plugins/fn-math/functions.c
+++ b/plugins/fn-math/functions.c
@@ -968,10 +968,10 @@ gnumeric_exp (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
 }
 
 static GnmExpr const *
-gnumeric_exp_deriv (GnmExpr const *expr, GnmEvalPos const *ep,
-                   GnmExprDeriv *info, gpointer data)
+gnumeric_exp_deriv (GnmFunc *func, GnmExpr const *expr, GnmEvalPos const *ep,
+                   GnmExprDeriv *info)
 {
-       return gnm_expr_copy (expr);
+       return gnm_expr_deriv_chain (expr, gnm_expr_copy (expr), ep, info);
 }
 
 /***************************************************************************/
@@ -1318,9 +1318,11 @@ static GnmExpr const *
 gnumeric_ln_deriv (GnmExpr const *expr, GnmEvalPos const *ep,
                   GnmExprDeriv *info, gpointer data)
 {
-       return gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (1)),
-                                   GNM_EXPR_OP_DIV,
-                                   gnm_expr_copy (gnm_expr_get_func_arg (expr, 0)));
+       GnmExpr const *deriv =
+               gnm_expr_new_binary (gnm_expr_new_constant (value_new_int (1)),
+                                    GNM_EXPR_OP_DIV,
+                                    gnm_expr_copy (gnm_expr_get_func_arg (expr, 0)));
+       return gnm_expr_deriv_chain (expr, deriv, ep, info);
 }
 
 /***************************************************************************/
@@ -1750,8 +1752,9 @@ gnumeric_sumsq (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
 }
 
 static GnmExpr const *
-gnumeric_sumsq_deriv (GnmExpr const *expr, GnmEvalPos const *ep,
-                     GnmExprDeriv *info, gpointer data)
+gnumeric_sumsq_deriv (GnmFunc *func,
+                     GnmExpr const *expr, GnmEvalPos const *ep,
+                     GnmExprDeriv *info)
 {
        GnmExprList *l, *args = gnm_expr_deriv_collect (expr, ep, info);
        GnmExpr const *res;
@@ -3742,24 +3745,15 @@ GnmFuncDescriptor const math_functions[] = {
 G_MODULE_EXPORT void
 go_plugin_init (GOPlugin *plugin, GOCmdContext *cc)
 {
-       gnm_expr_deriv_install_handler (gnm_func_lookup ("sumsq", NULL),
-                                       gnumeric_sumsq_deriv,
-                                       GNM_EXPR_DERIV_NO_CHAIN | GNM_EXPR_DERIV_OPTIMIZE,
-                                       NULL, NULL);
-       gnm_expr_deriv_install_handler (gnm_func_lookup ("exp", NULL),
-                                       gnumeric_exp_deriv,
-                                       GNM_EXPR_DERIV_CHAIN,
-                                       NULL, NULL);
-       gnm_expr_deriv_install_handler (gnm_func_lookup ("ln", NULL),
-                                       gnumeric_ln_deriv,
-                                       GNM_EXPR_DERIV_CHAIN,
-                                       NULL, NULL);
+       g_signal_connect (gnm_func_lookup ("sumsq", NULL),
+                         "derivative", G_CALLBACK (gnumeric_sumsq_deriv), NULL);
+       g_signal_connect (gnm_func_lookup ("exp", NULL),
+                         "derivative", G_CALLBACK (gnumeric_exp_deriv), NULL);
+       g_signal_connect (gnm_func_lookup ("ln", NULL),
+                         "derivative", G_CALLBACK (gnumeric_ln_deriv), NULL);
 }
 
 G_MODULE_EXPORT void
 go_plugin_shutdown (GOPlugin *plugin, GOCmdContext *cc)
 {
-       gnm_expr_deriv_uninstall_handler (gnm_func_lookup ("sumsq", NULL));
-       gnm_expr_deriv_uninstall_handler (gnm_func_lookup ("exp", NULL));
-       gnm_expr_deriv_uninstall_handler (gnm_func_lookup ("ln", NULL));
 }
diff --git a/src/expr-deriv.c b/src/expr-deriv.c
index 347496bdc..981ccbed5 100644
--- a/src/expr-deriv.c
+++ b/src/expr-deriv.c
@@ -32,25 +32,6 @@
 
 /* ------------------------------------------------------------------------- */
 
-static GHashTable *deriv_handlers;
-
-struct DerivHandler {
-       GnmExprDerivHandler handler;
-       GnmExprDerivFlags flags;
-       gpointer data;
-       GDestroyNotify notify;
-};
-
-static void
-deriv_handler_free (struct DerivHandler *di)
-{
-       if (di->notify)
-               di->notify (di->data);
-       g_free (di);
-}
-
-/* ------------------------------------------------------------------------- */
-
 struct GnmExprDeriv_ {
        unsigned ref_count;
        GnmEvalPos var;
@@ -474,7 +455,7 @@ gnm_expr_deriv_collect (GnmExpr const *expr,
                                                &user);
        }
 
-       return user.args;
+       return g_slist_reverse (user.args);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -494,7 +475,15 @@ gnm_expr_deriv_collect (GnmExpr const *expr,
 
 #define COMMON_BINARY_END }
 
-
+/**
+ * gnm_expr_deriv:
+ * @expr: #GnmExpr
+ * @ep: position for @expr
+ * @info: Derivative information
+ *
+ * Returns: (transfer full) (nullable): the derivative of @expr with respect
+ * to @info.
+ */
 GnmExpr const *
 gnm_expr_deriv (GnmExpr const *expr,
                GnmEvalPos const *ep,
@@ -585,33 +574,12 @@ gnm_expr_deriv (GnmExpr const *expr,
 
        case GNM_EXPR_OP_FUNCALL: {
                GnmFunc *f = gnm_expr_get_func_def (expr);
-               struct DerivHandler const *di = deriv_handlers
-                       ? g_hash_table_lookup (deriv_handlers, f)
-                       : NULL;
-               GnmExpr const *res = di
-                       ? di->handler (expr, ep, info, di->data)
-                       : NULL;
-               if (!res)
-                       return NULL;
-
-               if (di->flags & GNM_EXPR_DERIV_CHAIN) {
-                       GnmExpr const *e2 =
-                               gnm_expr_deriv (gnm_expr_get_func_arg (expr, 0), ep, info);
-                       if (!e2) {
-                               gnm_expr_free (res);
-                               return NULL;
-                       }
-                       res = mmul (res, 0, e2, 0);
+               GnmExpr const *res = gnm_func_derivative (f, expr, ep, info);
+               GnmExpr const *opt = optimize (res);
+               if (opt) {
+                       gnm_expr_free (res);
+                       res = opt;
                }
-
-               if (di->flags & GNM_EXPR_DERIV_OPTIMIZE) {
-                       GnmExpr const *opt = optimize (res);
-                       if (opt) {
-                               gnm_expr_free (res);
-                               res = opt;
-                       }
-               }
-
                return res;
        }
 
@@ -794,40 +762,35 @@ gnm_expr_cell_deriv_value (GnmCell *y, GnmCell *x)
 /* ------------------------------------------------------------------------- */
 
 /**
- * gnm_expr_deriv_install_handler:
- * @func: the function being given a handler
- * @h: (scope notified): #GnmExprDerivHandler
- * @flags:
- * @data: user data for @h
- * @notify: destroy notification for @data
+ * gnm_expr_deriv_chain:
+ * @expr: #GnmExpr for a function call with one argument
+ * @deriv: (transfer full) (nullable): Derivative of @expr's function.
+ * @ep: position for @expr
+ * @info: Derivative information
+ *
+ * Applies the chain rule to @expr.
+ *
+ * Returns: (transfer full) (nullable): the derivative of @expr with respect
+ * to @info.
  */
-void
-gnm_expr_deriv_install_handler (GnmFunc *func, GnmExprDerivHandler h,
-                               GnmExprDerivFlags flags,
-                               gpointer data,
-                               GDestroyNotify notify)
+GnmExpr const *
+gnm_expr_deriv_chain (GnmExpr const *expr,
+                     GnmExpr const *deriv,
+                     GnmEvalPos const *ep,
+                     GnmExprDeriv *info)
 {
-       struct DerivHandler *hdata;
-
-       if (!deriv_handlers) {
-               deriv_handlers = g_hash_table_new_full
-                       (g_direct_hash, g_direct_equal,
-                        NULL, (GDestroyNotify)deriv_handler_free);
-       }
+       GnmExpr const *deriv2;
 
-       hdata = g_new (struct DerivHandler, 1);
-       hdata->handler = h;
-       hdata->flags = flags;
-       hdata->data = data;
-       hdata->notify = notify;
+       if (!deriv)
+               return NULL;
 
-       g_hash_table_replace (deriv_handlers, func, hdata);
-}
+       deriv2 = gnm_expr_deriv (gnm_expr_get_func_arg (expr, 0), ep, info);
+       if (!deriv2) {
+               gnm_expr_free (deriv);
+               return NULL;
+       }
 
-void
-gnm_expr_deriv_uninstall_handler (GnmFunc *func)
-{
-       g_hash_table_remove (deriv_handlers, func);
+       return mmul (deriv, 0, deriv2, 0);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -835,10 +798,6 @@ gnm_expr_deriv_uninstall_handler (GnmFunc *func)
 void
 _gnm_expr_deriv_shutdown (void)
 {
-       if (deriv_handlers) {
-               g_hash_table_destroy (deriv_handlers);
-               deriv_handlers = NULL;
-       }
 }
 
 /* ------------------------------------------------------------------------- */
diff --git a/src/expr-deriv.h b/src/expr-deriv.h
index 0b9c0c9e6..5e30826a8 100644
--- a/src/expr-deriv.h
+++ b/src/expr-deriv.h
@@ -3,13 +3,12 @@
 
 G_BEGIN_DECLS
 
+#include <gnumeric-fwd.h>
 #include <expr.h>
 #include <numbers.h>
 
 /* ------------------------------------------------------------------------- */
 
-typedef struct GnmExprDeriv_ GnmExprDeriv;
-
 GType gnm_expr_deriv_info_get_type (void);
 
 GnmExprDeriv *gnm_expr_deriv_info_new (void);
@@ -33,26 +32,17 @@ GnmExprTop const *gnm_expr_cell_deriv (GnmCell *y, GnmCell *x);
 
 gnm_float gnm_expr_cell_deriv_value (GnmCell *y, GnmCell *x);
 
-/* ------------------------------------------------------------------------- */
+GnmExpr const *gnm_expr_deriv_chain (GnmExpr const *expr,
+                                    GnmExpr const *deriv,
+                                    GnmEvalPos const *ep,
+                                    GnmExprDeriv *info);
 
 GnmExprList *gnm_expr_deriv_collect (GnmExpr const *expr,
                                     GnmEvalPos const *ep,
                                     GnmExprDeriv *info);
 
-typedef GnmExpr const * (*GnmExprDerivHandler) (GnmExpr const *expr,
-                                               GnmEvalPos const *ep,
-                                               GnmExprDeriv *info,
-                                               gpointer user);
-typedef enum {
-       GNM_EXPR_DERIV_NO_CHAIN = 0x0,
-       GNM_EXPR_DERIV_CHAIN = 0x1,
-       GNM_EXPR_DERIV_OPTIMIZE = 0x2
-} GnmExprDerivFlags;
-
-void gnm_expr_deriv_install_handler (GnmFunc *func, GnmExprDerivHandler h,
-                                    GnmExprDerivFlags flags,
-                                    gpointer data, GDestroyNotify notify);
-void gnm_expr_deriv_uninstall_handler (GnmFunc *func);
+/* ------------------------------------------------------------------------- */
+
 void _gnm_expr_deriv_shutdown (void);
 
 /* ------------------------------------------------------------------------- */
diff --git a/src/func-builtin.c b/src/func-builtin.c
index 3043bcc30..3b2c89304 100644
--- a/src/func-builtin.c
+++ b/src/func-builtin.c
@@ -63,13 +63,12 @@ gnumeric_sum (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
 }
 
 static GnmExpr const *
-gnumeric_sum_deriv (GnmExpr const *expr,
+gnumeric_sum_deriv (GnmFunc *func,
+                   GnmExpr const *expr,
                    GnmEvalPos const *ep,
-                   GnmExprDeriv *info,
-                   gpointer data)
+                   GnmExprDeriv *info)
 {
        GnmExprList *l, *args = gnm_expr_deriv_collect (expr, ep, info);
-       GnmFunc *fsum = gnm_expr_get_func_def (expr);
        gboolean bad = FALSE;
 
        for (l = args; l; l = l->next) {
@@ -90,7 +89,7 @@ gnumeric_sum_deriv (GnmExpr const *expr,
                gnm_expr_list_free (args);
                return NULL;
        } else
-               return gnm_expr_new_funcall (fsum, args);
+               return gnm_expr_new_funcall (func, args);
 }
 
 /***************************************************************************/
@@ -541,7 +540,6 @@ func_builtin_init (void)
        const char *gname;
        const char *tdomain = GETTEXT_PACKAGE;
        int i = 0;
-       GnmFunc *table_func;
 
        gname = N_("Mathematics");
        math_group = gnm_func_group_fetch (gname, _(gname));
@@ -562,13 +560,11 @@ func_builtin_init (void)
        logic_group = gnm_func_group_fetch (gname, _(gname));
        gnm_func_add (logic_group, builtins + i++, tdomain);
 
-       table_func = gnm_func_lookup ("table", NULL);
-       g_signal_connect (table_func, "link-dep", G_CALLBACK (gnumeric_table_link), NULL);
+       g_signal_connect (gnm_func_lookup ("table", NULL),
+                         "link-dep", G_CALLBACK (gnumeric_table_link), NULL);
 
-       gnm_expr_deriv_install_handler (gnm_func_lookup ("sum", NULL),
-                                       gnumeric_sum_deriv,
-                                       GNM_EXPR_DERIV_NO_CHAIN | GNM_EXPR_DERIV_OPTIMIZE,
-                                       NULL, NULL);
+       g_signal_connect (gnm_func_lookup ("sum", NULL),
+                         "derivative", G_CALLBACK (gnumeric_sum_deriv), NULL);
 }
 
 void
diff --git a/src/func.c b/src/func.c
index b5382bba4..f2d07b92a 100644
--- a/src/func.c
+++ b/src/func.c
@@ -30,6 +30,7 @@
 #include <gnm-plugin.h>
 #include <gutils.h>
 #include <gui-util.h>
+#include <expr-deriv.h>
 #include <gnm-marshalers.h>
 
 #include <goffice/goffice.h>
@@ -47,6 +48,7 @@ enum {
 enum {
        SIG_LOAD_STUB,
        SIG_LINK_DEP,
+       SIG_DERIVATIVE,
        LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -1782,6 +1784,27 @@ gnm_func_link_dep (GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink)
        return (GnmDependentFlags)res;
 }
 
+/**
+ * gnm_func_derivative:
+ * @func: #GnmFunc
+ * @expr: expression that calls @func
+ * @ep: position of @expr
+ * @info: #GnmExprDeriv
+ *
+ * Returns: (transfer full) (nullable): the derivative of @expr with respect to
+ * @info.
+ */
+GnmExpr const *
+gnm_func_derivative (GnmFunc *func, GnmExpr const *expr, GnmEvalPos const *ep,
+                    GnmExprDeriv *info)
+{
+       GnmExpr *res = NULL;
+
+       g_return_val_if_fail (GNM_IS_FUNC (func), NULL);
+       g_signal_emit (func, signals[SIG_DERIVATIVE], 0, expr, ep, info, &res);
+       return res;
+}
+
 /* ------------------------------------------------------------------------- */
 
 static GObjectClass *parent_class;
@@ -1791,6 +1814,7 @@ typedef struct {
 
        void (*load_stub) (GnmFunc *func);
        int (*link_dep) (GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink);
+       GnmExpr* (*derivative) (GnmFunc *func, GnmExpr const *expr, GnmEvalPos *ep, GnmExprDeriv *info);
 } GnmFuncClass;
 
 static void
@@ -1925,6 +1949,14 @@ gnm_func_class_init (GObjectClass *gobject_class)
                                       GSF_PARAM_STATIC |
                                       G_PARAM_READABLE));
 
+       /**
+        * GnmFunc::load-stub:
+        * @func: the #GnmFunc that needs to be loaded
+        *
+        * Signals that @func, which is a stub, needs to be loaded now.  Anyone
+        * creating a stub function should arrange for this signal to be caught
+        * and the function to be properly instantiated.
+        */
        signals[SIG_LOAD_STUB] = g_signal_new
                ("load-stub",
                 GNM_FUNC_TYPE,
@@ -1934,7 +1966,18 @@ gnm_func_class_init (GObjectClass *gobject_class)
                 g_cclosure_marshal_VOID__VOID,
                 G_TYPE_NONE, 0);
 
-
+       /**
+        * GnmFunc::link-dep:
+        * @func: the #GnmFunc that is being linked or unlinked
+        * @ei: #GnmFuncEvalInfo for the call initiating the link or unlink.
+        * @qlink: %TRUE for link, %FALSE for unlink
+        *
+        * Signals that an expressions that is a call to @func is being linked
+        * or unlinked.  Most functions do not need this.
+        *
+        * Returns: A #GnmDependentFlags allowing arguments not be be linked if
+        * that is appropriate.
+        */
        signals[SIG_LINK_DEP] = g_signal_new
                ("link-dep",
                 GNM_FUNC_TYPE,
@@ -1944,6 +1987,28 @@ gnm_func_class_init (GObjectClass *gobject_class)
                 gnm__INT__POINTER_BOOLEAN,
                 // GnmDependentFlags ... GnmFuncEvalInfo
                 G_TYPE_INT, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
+
+       /**
+        * GnmFunc::derivative:
+        * @func: #GnmFunc
+        * @expr: #GnmExpr for the call for which the derivative is sought
+        * @ep: position f @expr
+        * @info: #GnmExprDeriv telling which derivative is sought
+        *
+        * Signals that a function call's derivative should be calculatted
+        *
+        * Returns: (transfer full) (nullable): #GnmExpr representing the
+        * derivative, %NULL for error.
+        */
+       signals[SIG_DERIVATIVE] = g_signal_new
+               ("derivative",
+                GNM_FUNC_TYPE,
+                G_SIGNAL_RUN_LAST,
+                G_STRUCT_OFFSET (GnmFuncClass, derivative),
+                NULL, NULL,
+                gnm__BOXED__BOXED_BOXED_BOXED,
+                gnm_expr_get_type(),
+                3, gnm_expr_get_type(), gnm_eval_pos_get_type(), gnm_expr_deriv_info_get_type());
 }
 
 GSF_CLASS (GnmFunc, gnm_func,
diff --git a/src/func.h b/src/func.h
index 5a00e7744..d1f33b9ec 100644
--- a/src/func.h
+++ b/src/func.h
@@ -306,6 +306,13 @@ struct _GnmFuncEvalInfo {
 GnmFunc const *gnm_eval_info_get_func (GnmFuncEvalInfo const *ei);
 int gnm_eval_info_get_arg_count (GnmFuncEvalInfo const *ei);
 
+/*************************************************************************/
+
+GnmExpr const *gnm_func_derivative (GnmFunc *func,
+                                   GnmExpr const *expr, GnmEvalPos const *ep,
+                                   GnmExprDeriv *info);
+
+
 G_END_DECLS
 
 #endif /* _GNM_FUNC_H_ */
diff --git a/src/gnm-marshalers.list b/src/gnm-marshalers.list
index 2655e605e..45b633477 100644
--- a/src/gnm-marshalers.list
+++ b/src/gnm-marshalers.list
@@ -25,3 +25,4 @@ BOOLEAN:OBJECT,POINTER
 VOID:BOOLEAN,INT
 BOOLEAN:VOID
 INT:POINTER,BOOLEAN
+BOXED:BOXED,BOXED,BOXED
diff --git a/src/gnumeric-fwd.h b/src/gnumeric-fwd.h
index c1a83c265..92a99e88d 100644
--- a/src/gnumeric-fwd.h
+++ b/src/gnumeric-fwd.h
@@ -104,6 +104,7 @@ typedef struct _WorkbookView                WorkbookView;
 typedef union  _GnmExpr                        GnmExpr;
 typedef union  _GnmValue               GnmValue;
 typedef struct _GenericToolState       GnmGenericToolState;
+typedef struct GnmExprDeriv_            GnmExprDeriv;
 
 typedef GList                          ColRowIndexList;
 typedef GSList                         ColRowStateGroup;


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