From c5c3c320a2eb32aa9bde5d412ce5bee0fc215ead Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 19 Jun 2014 11:28:48 +0200 Subject: [PATCH] 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 5a782788f..50f1a4c19 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 6c57f69e9..3cc06fc4d 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 c229ce867..5277b777e 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 9f9bfafca..fd924f67c 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 --- */