[glib] gvalue: New g_value_init_from_instance



commit c5c3c320a2eb32aa9bde5d412ce5bee0fc215ead
Author: Edward Hervey <bilboed bilboed com>
Date:   Thu Jun 19 11:28:48 2014 +0200

    gvalue: New g_value_init_from_instance
    
    Used for the commonly used case (in signal emission) where we
    initialize and set a GValue for an instance
    
    Includes a fast-path for GObject
    
    Overall makes it 6 times faster than the previous combination
    of g_value_init + g_value_set_instance
    
    Makes signal emission around 10% faster
    
    https://bugzilla.gnome.org/show_bug.cgi?id=731950

 docs/reference/gobject/gobject-sections.txt |    1 +
 gobject/gsignal.c                           |    6 +--
 gobject/gvalue.c                            |   65 +++++++++++++++++++++++++++
 gobject/gvalue.h                            |    3 +
 4 files changed, 71 insertions(+), 4 deletions(-)
---
diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt
index 5a78278..50f1a4c 100644
--- a/docs/reference/gobject/gobject-sections.txt
+++ b/docs/reference/gobject/gobject-sections.txt
@@ -438,6 +438,7 @@ g_value_init
 g_value_copy
 g_value_reset
 g_value_unset
+g_value_init_from_instance
 g_value_set_instance
 g_value_fits_pointer
 g_value_peek_pointer
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index 6c57f69..3cc06fc 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -2157,8 +2157,7 @@ g_signal_chain_from_overridden_handler (gpointer instance,
 
       SIGNAL_UNLOCK ();
       instance_and_params->g_type = 0;
-      g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (instance));
-      g_value_set_instance (instance_and_params, instance);
+      g_value_init_from_instance (instance_and_params, instance);
       SIGNAL_LOCK ();
 
       emission->chain_type = chain_type;
@@ -3305,8 +3304,7 @@ g_signal_emit_valist (gpointer instance,
     }
 
   instance_and_params->g_type = 0;
-  g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (instance));
-  g_value_set_instance (instance_and_params, instance);
+  g_value_init_from_instance (instance_and_params, instance);
   if (signal_return_type == G_TYPE_NONE)
     signal_emit_unlocked_R (node, detail, instance, NULL, instance_and_params);
   else
diff --git a/gobject/gvalue.c b/gobject/gvalue.c
index c229ce8..5277b77 100644
--- a/gobject/gvalue.c
+++ b/gobject/gvalue.c
@@ -373,6 +373,71 @@ g_value_set_instance (GValue  *value,
     }
 }
 
+/**
+ * g_value_init_from_instance:
+ * @value: An uninitialized #GValue structure.
+ * @instance: the instance
+ *
+ * Initializes and sets @value from an instantiatable type via the
+ * value_table's collect_value() function.
+ *
+ * Note: The @value will be initialised with the exact type of
+ * @instance.  If you wish to set the @value's type to a different GType
+ * (such as a parent class GType), you need to manually call
+ * g_value_init() and g_value_set_instance().
+ *
+ * Since: 2.42
+ */
+void
+g_value_init_from_instance (GValue  *value,
+                            gpointer instance)
+{
+  g_return_if_fail (value != NULL && G_VALUE_TYPE(value) == 0);
+
+  if (G_IS_OBJECT (instance))
+    {
+      /* Fast-path.
+       * If G_IS_OBJECT() succeeds we know:
+       * * that instance is present and valid
+       * * that it is a GObject, and therefore we can directly
+       *   use the collect implementation (g_object_ref) */
+      value_meminit (value, G_TYPE_FROM_INSTANCE (instance));
+      value->data[0].v_pointer = g_object_ref (instance);
+    }
+  else
+    {  
+      GType g_type;
+      GTypeValueTable *value_table;
+      GTypeCValue cvalue;
+      gchar *error_msg;
+
+      g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
+
+      g_type = G_TYPE_FROM_INSTANCE (instance);
+      value_table = g_type_value_table_peek (g_type);
+      g_return_if_fail (strcmp (value_table->collect_format, "p") == 0);
+
+      memset (&cvalue, 0, sizeof (cvalue));
+      cvalue.v_pointer = instance;
+
+      /* setup and collect */
+      value_meminit (value, g_type);
+      value_table->value_init (value);
+      error_msg = value_table->collect_value (value, 1, &cvalue, 0);
+      if (error_msg)
+        {
+          g_warning ("%s: %s", G_STRLOC, error_msg);
+          g_free (error_msg);
+
+          /* we purposely leak the value here, it might not be
+           * in a sane state if an error condition occoured
+           */
+          value_meminit (value, g_type);
+          value_table->value_init (value);
+        }
+    }
+}
+
 static GValueTransform
 transform_func_lookup (GType src_type,
                       GType dest_type)
diff --git a/gobject/gvalue.h b/gobject/gvalue.h
index 9f9bfaf..fd924f6 100644
--- a/gobject/gvalue.h
+++ b/gobject/gvalue.h
@@ -137,6 +137,9 @@ void            g_value_unset       (GValue       *value);
 GLIB_AVAILABLE_IN_ALL
 void           g_value_set_instance    (GValue       *value,
                                         gpointer      instance);
+GLIB_AVAILABLE_IN_2_42
+void            g_value_init_from_instance   (GValue       *value,
+                                              gpointer      instance);
 
 
 /* --- private --- */


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