diff --git a/ChangeLog b/ChangeLog index 4dcd87590..4dca3db4f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Tue Dec 12 18:58:22 2000 Tim Janik + + * ghash.c (g_hash_table_remove): return whether a value + got removed. + Tue Dec 12 15:18:10 2000 Owen Taylor * gmain.[ch]: Revert unauthorized changes. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 4dcd87590..4dca3db4f 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,8 @@ +Tue Dec 12 18:58:22 2000 Tim Janik + + * ghash.c (g_hash_table_remove): return whether a value + got removed. + Tue Dec 12 15:18:10 2000 Owen Taylor * gmain.[ch]: Revert unauthorized changes. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 4dcd87590..4dca3db4f 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,8 @@ +Tue Dec 12 18:58:22 2000 Tim Janik + + * ghash.c (g_hash_table_remove): return whether a value + got removed. + Tue Dec 12 15:18:10 2000 Owen Taylor * gmain.[ch]: Revert unauthorized changes. diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 4dcd87590..4dca3db4f 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,8 @@ +Tue Dec 12 18:58:22 2000 Tim Janik + + * ghash.c (g_hash_table_remove): return whether a value + got removed. + Tue Dec 12 15:18:10 2000 Owen Taylor * gmain.[ch]: Revert unauthorized changes. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 4dcd87590..4dca3db4f 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,8 @@ +Tue Dec 12 18:58:22 2000 Tim Janik + + * ghash.c (g_hash_table_remove): return whether a value + got removed. + Tue Dec 12 15:18:10 2000 Owen Taylor * gmain.[ch]: Revert unauthorized changes. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 4dcd87590..4dca3db4f 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,8 @@ +Tue Dec 12 18:58:22 2000 Tim Janik + + * ghash.c (g_hash_table_remove): return whether a value + got removed. + Tue Dec 12 15:18:10 2000 Owen Taylor * gmain.[ch]: Revert unauthorized changes. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 4dcd87590..4dca3db4f 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,8 @@ +Tue Dec 12 18:58:22 2000 Tim Janik + + * ghash.c (g_hash_table_remove): return whether a value + got removed. + Tue Dec 12 15:18:10 2000 Owen Taylor * gmain.[ch]: Revert unauthorized changes. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 4dcd87590..4dca3db4f 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,8 @@ +Tue Dec 12 18:58:22 2000 Tim Janik + + * ghash.c (g_hash_table_remove): return whether a value + got removed. + Tue Dec 12 15:18:10 2000 Owen Taylor * gmain.[ch]: Revert unauthorized changes. diff --git a/ghash.c b/ghash.c index d35df1843..52427ce5f 100644 --- a/ghash.c +++ b/ghash.c @@ -169,16 +169,15 @@ g_hash_table_insert (GHashTable *hash_table, } } -void -g_hash_table_remove (GHashTable *hash_table, - gconstpointer key) +gboolean +g_hash_table_remove (GHashTable *hash_table, + gconstpointer key) { GHashNode **node, *dest; - g_return_if_fail (hash_table != NULL); + g_return_val_if_fail (hash_table != NULL, FALSE); node = g_hash_table_lookup_node (hash_table, key); - if (*node) { dest = *node; @@ -187,7 +186,11 @@ g_hash_table_remove (GHashTable *hash_table, hash_table->nnodes--; g_hash_table_resize (hash_table); + + return TRUE; } + + return FALSE; } gboolean diff --git a/ghash.h b/ghash.h index 2f6413151..ce0d1eda5 100644 --- a/ghash.h +++ b/ghash.h @@ -45,7 +45,7 @@ void g_hash_table_destroy (GHashTable *hash_table); void g_hash_table_insert (GHashTable *hash_table, gpointer key, gpointer value); -void g_hash_table_remove (GHashTable *hash_table, +gboolean g_hash_table_remove (GHashTable *hash_table, gconstpointer key); gpointer g_hash_table_lookup (GHashTable *hash_table, gconstpointer key); diff --git a/glib/ghash.c b/glib/ghash.c index d35df1843..52427ce5f 100644 --- a/glib/ghash.c +++ b/glib/ghash.c @@ -169,16 +169,15 @@ g_hash_table_insert (GHashTable *hash_table, } } -void -g_hash_table_remove (GHashTable *hash_table, - gconstpointer key) +gboolean +g_hash_table_remove (GHashTable *hash_table, + gconstpointer key) { GHashNode **node, *dest; - g_return_if_fail (hash_table != NULL); + g_return_val_if_fail (hash_table != NULL, FALSE); node = g_hash_table_lookup_node (hash_table, key); - if (*node) { dest = *node; @@ -187,7 +186,11 @@ g_hash_table_remove (GHashTable *hash_table, hash_table->nnodes--; g_hash_table_resize (hash_table); + + return TRUE; } + + return FALSE; } gboolean diff --git a/glib/ghash.h b/glib/ghash.h index 2f6413151..ce0d1eda5 100644 --- a/glib/ghash.h +++ b/glib/ghash.h @@ -45,7 +45,7 @@ void g_hash_table_destroy (GHashTable *hash_table); void g_hash_table_insert (GHashTable *hash_table, gpointer key, gpointer value); -void g_hash_table_remove (GHashTable *hash_table, +gboolean g_hash_table_remove (GHashTable *hash_table, gconstpointer key); gpointer g_hash_table_lookup (GHashTable *hash_table, gconstpointer key); diff --git a/gobject/ChangeLog b/gobject/ChangeLog index ab686b4fc..928ac3a7f 100644 --- a/gobject/ChangeLog +++ b/gobject/ChangeLog @@ -1,3 +1,14 @@ +Tue Dec 12 23:38:02 2000 Tim Janik + + * Makefile.am: _never_ touch oldest-source-stamp. + + * gobject.[hc]: construct property handling fixes/improvements. + fixed trailer handling in get/set property. + + * gparam.[hc]: implement param spec pool, got rid of param spec + hashtable. the most prominent change is that e deal with type + prefixes here. + 2000-12-12 Elliot Lee * Makefile.am: diff --git a/gobject/gobject.c b/gobject/gobject.c index f1be1607c..50e68a0d5 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -126,11 +126,11 @@ struct _NotifyQueue /* --- variables --- */ -static GQuark quark_notify_queue = 0; -static GQuark quark_property_id = 0; -static GQuark quark_closure_array = 0; -static GHashTable *pspec_hash_table = NULL; -static gulong gobject_signals[LAST_SIGNAL] = { 0, }; +static GQuark quark_notify_queue = 0; +static GQuark quark_property_id = 0; +static GQuark quark_closure_array = 0; +static GParamSpecPool *pspec_pool = NULL; +static gulong gobject_signals[LAST_SIGNAL] = { 0, }; /* --- functions --- */ @@ -218,9 +218,12 @@ g_object_type_init (void) /* sync with gtype.c */ static void g_object_base_class_init (GObjectClass *class) { + GObjectClass *pclass = g_type_class_peek_parent (class); + /* reset instance specific fields and methods that don't get inherited */ class->n_property_specs = 0; class->property_specs = NULL; + class->construct_properties = pclass ? g_slist_copy (pclass->construct_properties) : NULL; class->get_property = NULL; class->set_property = NULL; } @@ -233,12 +236,14 @@ g_object_base_class_finalize (GObjectClass *class) g_message ("finallizing base class of %s", G_OBJECT_CLASS_NAME (class)); _g_signals_destroy (G_OBJECT_CLASS_TYPE (class)); - + + g_slist_free (class->construct_properties); + class->construct_properties = NULL; for (i = 0; i < class->n_property_specs; i++) { GParamSpec *pspec = class->property_specs[i]; - g_param_spec_hash_table_remove (pspec_hash_table, pspec); + g_param_spec_pool_remove (pspec_pool, pspec); g_param_spec_set_qdata (pspec, quark_property_id, NULL); g_param_spec_unref (pspec); } @@ -253,7 +258,7 @@ g_object_do_class_init (GObjectClass *class) quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue"); quark_property_id = g_quark_from_static_string ("GObject-property-id"); quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); - pspec_hash_table = g_param_spec_hash_table_new (); + pspec_pool = g_param_spec_pool_new (TRUE); class->constructor = g_object_constructor; class->set_property = g_object_do_set_property; @@ -332,7 +337,7 @@ g_object_class_install_property (GObjectClass *class, g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ if (pspec->flags & G_PARAM_CONSTRUCT) g_return_if_fail ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); - if (pspec->flags & (G_PARAM_CONSTRUCT || G_PARAM_CONSTRUCT_ONLY)) + if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) g_return_if_fail (pspec->flags & G_PARAM_WRITABLE); /* expensive paranoia checks ;( */ @@ -347,7 +352,7 @@ g_object_class_install_property (GObjectClass *class, pspec->name); return; } - if (g_object_class_find_property (class, pspec->name)) + if (g_param_spec_pool_lookup (pspec_pool, pspec->name, G_OBJECT_CLASS_TYPE (class), FALSE, NULL)) { g_warning (G_STRLOC ": class `%s' already contains a property named `%s'", G_OBJECT_CLASS_NAME (class), @@ -358,10 +363,19 @@ g_object_class_install_property (GObjectClass *class, g_param_spec_ref (pspec); g_param_spec_sink (pspec); g_param_spec_set_qdata (pspec, quark_property_id, GUINT_TO_POINTER (property_id)); - g_param_spec_hash_table_insert (pspec_hash_table, pspec, G_OBJECT_CLASS_TYPE (class)); + g_param_spec_pool_insert (pspec_pool, pspec, G_OBJECT_CLASS_TYPE (class)); i = class->n_property_specs++; class->property_specs = g_renew (GParamSpec*, class->property_specs, class->n_property_specs); class->property_specs[i] = pspec; + if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) + class->construct_properties = g_slist_prepend (class->construct_properties, pspec); + + /* for property overrides of construct poperties, we have to get rid + * of the overidden inherited construct property + */ + pspec = g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type_parent (G_OBJECT_CLASS_TYPE (class)), TRUE, NULL); + if (pspec && pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) + class->construct_properties = g_slist_remove (class->construct_properties, pspec); } GParamSpec* @@ -371,10 +385,10 @@ g_object_class_find_property (GObjectClass *class, g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL); g_return_val_if_fail (property_name != NULL, NULL); - return g_param_spec_hash_table_lookup (pspec_hash_table, - property_name, - G_OBJECT_CLASS_TYPE (class), - TRUE, NULL); + return g_param_spec_pool_lookup (pspec_pool, + property_name, + G_OBJECT_CLASS_TYPE (class), + TRUE, NULL); } static void @@ -446,9 +460,9 @@ g_object_do_set_property (GObject *object, gboolean swapped, after; gpointer callback, data; case PROP_DATA: - g_return_if_fail (trailer[0] == ':' && trailer[1] == ':'); + g_return_if_fail (trailer != NULL); - g_object_set_data (object, trailer + 2, g_value_get_pointer (value)); + g_object_set_data (object, trailer, g_value_get_pointer (value)); break; case PROP_SWAPPED_SIGNAL_AFTER: i++; @@ -459,10 +473,10 @@ g_object_do_set_property (GObject *object, case PROP_SIGNAL: after = i > 2; swapped = i & 1; - g_return_if_fail (trailer[0] == ':' && trailer[1] == ':'); + g_return_if_fail (trailer != NULL); g_value_get_ccallback (value, &callback, &data); - g_signal_connect_data (object, trailer + 2, + g_signal_connect_data (object, trailer, callback, data, NULL, swapped, after); break; @@ -482,9 +496,9 @@ g_object_do_get_property (GObject *object, switch (property_id) { case PROP_DATA: - g_return_if_fail (trailer[0] == ':' && trailer[1] == ':'); + g_return_if_fail (trailer != NULL); - g_value_set_pointer (value, g_object_get_data (object, trailer + 2)); + g_value_set_pointer (value, g_object_get_data (object, trailer)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -598,9 +612,10 @@ static void g_object_notify_property_changed (GObject *object, GParamSpec *pspec) { - g_message ("NOTIFICATION: %s property changed on object `%s'", - pspec->name, - G_OBJECT_TYPE_NAME (object)); + if (0) /* FIXME */ + g_message ("NOTIFICATION: property `%s' changed on object `%s'", + pspec->name, + G_OBJECT_TYPE_NAME (object)); } void @@ -627,10 +642,10 @@ g_object_notify (GObject *object, return; g_object_ref (object); - pspec = g_param_spec_hash_table_lookup (pspec_hash_table, - property_name, - G_OBJECT_TYPE (object), - TRUE, NULL); + pspec = g_param_spec_pool_lookup (pspec_pool, + property_name, + G_OBJECT_TYPE (object), + TRUE, NULL); if (!pspec) g_warning ("%s: object class `%s' has no property named `%s'", G_STRLOC, @@ -725,9 +740,13 @@ g_object_new_valist (GType object_type, const gchar *name; GObjectConstructParam *cparams = NULL, *nparams = NULL; guint n_cparams = 0, n_nparams = 0; + GSList *clist; g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); + class = g_type_class_ref (object_type); + clist = g_slist_copy (class->construct_properties); + /* collect parameters, sort into construction and normal ones */ name = first_property_name; while (name) @@ -736,12 +755,12 @@ g_object_new_valist (GType object_type, GValue *value; GParamSpec *pspec; gchar *error = NULL; - - pspec = g_param_spec_hash_table_lookup (pspec_hash_table, - name, - object_type, - TRUE, - &trailer); + + pspec = g_param_spec_pool_lookup (pspec_pool, + name, + object_type, + TRUE, + &trailer); if (!pspec) { g_warning ("%s: object class `%s' has no property named `%s'", @@ -775,17 +794,24 @@ g_object_new_valist (GType object_type, } if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) { + guint i; + if (!n_cparams || n_cparams >= PREALLOC_CPARAMS) - cparams = g_renew (GObjectConstructParam, cparams, n_cparams + 1); + cparams = g_renew (GObjectConstructParam, cparams, MAX (n_cparams + 1, PREALLOC_CPARAMS)); cparams[n_cparams].pspec = pspec; cparams[n_cparams].value = value; cparams[n_cparams].trailer = trailer; + for (i = 0; i < n_cparams; i++) /* picky, aren't we? ;) */ + if (cparams[i].pspec == pspec) + g_warning (G_STRLOC ": construct property \"%s\" for object `%s' is being set twice", + pspec->name, g_type_name (object_type)); n_cparams++; + clist = g_slist_remove (clist, pspec); /* FIXME: unique */ } else { if (!n_nparams || n_nparams >= PREALLOC_CPARAMS) - nparams = g_renew (GObjectConstructParam, nparams, n_nparams + 1); + nparams = g_renew (GObjectConstructParam, nparams, MAX (n_nparams + 1, PREALLOC_CPARAMS)); nparams[n_nparams].pspec = pspec; nparams[n_nparams].value = value; nparams[n_nparams].trailer = trailer; @@ -796,9 +822,27 @@ g_object_new_valist (GType object_type, } /* construct object from construction parameters */ - class = g_type_class_ref (object_type); + while (clist) + { + GSList *tmp = clist->next; + GParamSpec *pspec = clist->data; + GValue *value = g_new (GValue, 1); + + value->g_type = 0; + g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + g_param_value_set_default (pspec, value); + + if (!n_cparams || n_cparams >= PREALLOC_CPARAMS) + cparams = g_renew (GObjectConstructParam, cparams, MAX (n_cparams + 1, PREALLOC_CPARAMS)); + cparams[n_cparams].pspec = pspec; + cparams[n_cparams].value = value; + cparams[n_cparams].trailer = NULL; + n_cparams++; + + g_slist_free_1 (clist); + clist = tmp; + } object = class->constructor (object_type, n_cparams, cparams); - g_type_class_unref (class); /* free construction values */ while (n_cparams--) @@ -807,17 +851,18 @@ g_object_new_valist (GType object_type, g_free (cparams[n_cparams].value); } g_free (cparams); - + /* release g_object_init() notification queue freeze_count */ nqueue = object_freeze_notifies (object); nqueue->freeze_count--; /* set remaining properties */ + cparams = nparams; while (n_nparams--) { - GValue *value = nparams[n_nparams].value; - GParamSpec *pspec = nparams[n_nparams].pspec; - const gchar *trailer = nparams[n_nparams].trailer; + GValue *value = nparams->value; + GParamSpec *pspec = nparams->pspec; + const gchar *trailer = nparams++->trailer; /* convert if necessary */ if (!g_type_is_a (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (pspec))) @@ -842,7 +887,9 @@ g_object_new_valist (GType object_type, g_value_unset (value); g_free (value); } - g_free (nparams); + g_free (cparams); + + g_type_class_unref (class); /* release our own freeze count and handle notifications */ object_thaw_notifies (object, nqueue); @@ -868,9 +915,9 @@ g_object_constructor (GType type, /* set construct properties */ while (n_construct_properties--) { - GValue *value = construct_params[n_construct_properties].value; - GParamSpec *pspec = construct_params[n_construct_properties].pspec; - const gchar *trailer = construct_params[n_construct_properties].trailer; + GValue *value = construct_params->value; + GParamSpec *pspec = construct_params->pspec; + const gchar *trailer = construct_params++->trailer; /* convert if necessary */ if (!g_type_is_a (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (pspec))) @@ -923,11 +970,11 @@ g_object_set_valist (GObject *object, GParamSpec *pspec; gchar *error = NULL; - pspec = g_param_spec_hash_table_lookup (pspec_hash_table, - name, - G_OBJECT_TYPE (object), - TRUE, - &trailer); + pspec = g_param_spec_pool_lookup (pspec_pool, + name, + G_OBJECT_TYPE (object), + TRUE, + &trailer); if (!pspec) { g_warning ("%s: object class `%s' has no property named `%s'", @@ -990,11 +1037,11 @@ g_object_get_valist (GObject *object, GParamSpec *pspec; gchar *error; - pspec = g_param_spec_hash_table_lookup (pspec_hash_table, - name, - G_OBJECT_TYPE (object), - TRUE, - &trailer); + pspec = g_param_spec_pool_lookup (pspec_pool, + name, + G_OBJECT_TYPE (object), + TRUE, + &trailer); if (!pspec) { g_warning ("%s: object class `%s' has no property named `%s'", @@ -1037,10 +1084,11 @@ g_object_get_valist (GObject *object, } void -g_object_set (GObject *object, +g_object_set (gpointer _object, const gchar *first_property_name, ...) { + GObject *object = _object; va_list var_args; g_return_if_fail (G_IS_OBJECT (object)); @@ -1051,10 +1099,11 @@ g_object_set (GObject *object, } void -g_object_get (GObject *object, +g_object_get (gpointer _object, const gchar *first_property_name, ...) { + GObject *object = _object; va_list var_args; g_return_if_fail (G_IS_OBJECT (object)); @@ -1080,11 +1129,11 @@ g_object_set_property (GObject *object, g_object_ref (object); nqueue = object_freeze_notifies (object); - pspec = g_param_spec_hash_table_lookup (pspec_hash_table, - property_name, - G_OBJECT_TYPE (object), - TRUE, - &trailer); + pspec = g_param_spec_pool_lookup (pspec_pool, + property_name, + G_OBJECT_TYPE (object), + TRUE, + &trailer); if (!pspec) g_warning ("%s: object class `%s' has no property named `%s'", G_STRLOC, @@ -1128,11 +1177,11 @@ g_object_get_property (GObject *object, g_object_ref (object); - pspec = g_param_spec_hash_table_lookup (pspec_hash_table, - property_name, - G_OBJECT_TYPE (object), - TRUE, - &trailer); + pspec = g_param_spec_pool_lookup (pspec_pool, + property_name, + G_OBJECT_TYPE (object), + TRUE, + &trailer); if (!pspec) g_warning ("%s: object class `%s' has no property named `%s'", G_STRLOC, @@ -1169,9 +1218,11 @@ g_object_get_property (GObject *object, g_object_unref (object); } -GObject* -g_object_ref (GObject *object) +gpointer +g_object_ref (gpointer _object) { + GObject *object = _object; + g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (object->ref_count > 0, NULL); @@ -1181,8 +1232,10 @@ g_object_ref (GObject *object) } void -g_object_unref (GObject *object) +g_object_unref (gpointer _object) { + GObject *object = _object; + g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (object->ref_count > 0); diff --git a/gobject/gobject.h b/gobject/gobject.h index 462583094..2d4bff6f7 100644 --- a/gobject/gobject.h +++ b/gobject/gobject.h @@ -74,11 +74,12 @@ struct _GObjectClass /* private, these fields might vanish */ guint n_property_specs; GParamSpec **property_specs; + GSList *construct_properties; /* public overridable methods */ GObject* (*constructor) (GType type, guint n_construct_properties, - GObjectConstructParam *construct_params); + GObjectConstructParam *construct_properties); void (*get_property) (GObject *object, guint property_id, GValue *value, @@ -124,10 +125,10 @@ gpointer g_object_new (GType object_type, gpointer g_object_new_valist (GType object_type, const gchar *first_property_name, va_list var_args); -void g_object_set (GObject *object, +void g_object_set (gpointer object, const gchar *first_property_name, ...); -void g_object_get (GObject *object, +void g_object_get (gpointer object, const gchar *first_property_name, ...); void g_object_set_valist (GObject *object, @@ -146,8 +147,8 @@ void g_object_freeze_notify (GObject *object); void g_object_notify (GObject *object, const gchar *property_name); void g_object_thaw_notify (GObject *object); -GObject* g_object_ref (GObject *object); -void g_object_unref (GObject *object); +gpointer g_object_ref (gpointer object); +void g_object_unref (gpointer object); gpointer g_object_get_qdata (GObject *object, GQuark quark); void g_object_set_qdata (GObject *object, diff --git a/gobject/gparam.c b/gobject/gparam.c index fdb150855..92882b8fd 100644 --- a/gobject/gparam.c +++ b/gobject/gparam.c @@ -398,8 +398,16 @@ value_param_lcopy_value (const GValue *value, return NULL; } + +/* --- param spec pool --- */ +struct _GParamSpecPool +{ + gboolean type_prefixing; + GHashTable *hash_table; +}; + static guint -param_spec_hash (gconstpointer key_spec) +param_spec_pool_hash (gconstpointer key_spec) { const GParamSpec *key = key_spec; const gchar *p; @@ -412,8 +420,8 @@ param_spec_hash (gconstpointer key_spec) } static gboolean -param_spec_equals (gconstpointer key_spec_1, - gconstpointer key_spec_2) +param_spec_pool_equals (gconstpointer key_spec_1, + gconstpointer key_spec_2) { const GParamSpec *key1 = key_spec_1; const GParamSpec *key2 = key_spec_2; @@ -422,88 +430,181 @@ param_spec_equals (gconstpointer key_spec_1, strcmp (key1->name, key2->name) == 0); } -GHashTable* -g_param_spec_hash_table_new (void) +GParamSpecPool* +g_param_spec_pool_new (gboolean type_prefixing) { - return g_hash_table_new (param_spec_hash, param_spec_equals); + GParamSpecPool *pool = g_new (GParamSpecPool, 1); + + pool->type_prefixing = type_prefixing != FALSE; + pool->hash_table = g_hash_table_new (param_spec_pool_hash, param_spec_pool_equals); + + return pool; } void -g_param_spec_hash_table_insert (GHashTable *hash_table, - GParamSpec *pspec, - GType owner_type) +g_param_spec_pool_insert (GParamSpecPool *pool, + GParamSpec *pspec, + GType owner_type) { - g_return_if_fail (hash_table != NULL); - g_return_if_fail (G_IS_PARAM_SPEC (pspec)); - g_return_if_fail (pspec->name != NULL); - if (pspec->owner_type != owner_type) - g_return_if_fail (pspec->owner_type == 0); + gchar *p; - if (strchr (pspec->name, ':')) - g_warning (G_STRLOC ": parameter name `%s' contains field-delimeter", - pspec->name); - else + g_return_if_fail (pool != NULL); + g_return_if_fail (pspec); + g_return_if_fail (owner_type > 0); + g_return_if_fail (pspec->owner_type == 0); + + for (p = pspec->name; *p; p++) { - pspec->owner_type = owner_type; - g_hash_table_insert (hash_table, pspec, pspec); + if (!strchr (G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-_", *p)) + { + g_warning (G_STRLOC ": pspec name \"%s\" contains invalid characters", pspec->name); + return; + } } + + pspec->owner_type = owner_type; + g_param_spec_ref (pspec); + g_hash_table_insert (pool->hash_table, pspec, pspec); } void -g_param_spec_hash_table_remove (GHashTable *hash_table, - GParamSpec *pspec) +g_param_spec_pool_remove (GParamSpecPool *pool, + GParamSpec *pspec) { - g_return_if_fail (hash_table != NULL); - g_return_if_fail (G_IS_PARAM_SPEC (pspec)); + g_return_if_fail (pool != NULL); + g_return_if_fail (pspec); - g_assert (g_param_spec_hash_table_lookup (hash_table, pspec->name, pspec->owner_type, FALSE, NULL) != NULL); /* FIXME: paranoid */ + if (g_hash_table_remove (pool->hash_table, pspec)) + g_param_spec_unref (pspec); + else + g_warning (G_STRLOC ": attempt to remove unknown pspec `%s' from pool", pspec->name); +} - g_hash_table_remove (hash_table, pspec); - g_assert (g_param_spec_hash_table_lookup (hash_table, pspec->name, pspec->owner_type, FALSE, NULL) == NULL); /* FIXME: paranoid */ - pspec->owner_type = 0; +static inline GParamSpec* +param_spec_ht_lookup (GHashTable *hash_table, + const gchar *param_name, + GType owner_type, + gboolean walk_ancestors) +{ + GParamSpec key, *pspec; + + key.owner_type = owner_type; + key.name = (gchar*) param_name; + if (walk_ancestors) + do + { + pspec = g_hash_table_lookup (hash_table, &key); + if (pspec) + return pspec; + key.owner_type = g_type_parent (key.owner_type); + } + while (key.owner_type); + else + pspec = g_hash_table_lookup (hash_table, &key); + + if (!pspec) + { + /* sigh, try canonicalization */ + key.name = g_strdup (param_name); + key.owner_type = owner_type; + + g_strcanon (key.name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-'); + if (walk_ancestors) + do + { + pspec = g_hash_table_lookup (hash_table, &key); + if (pspec) + { + g_free (key.name); + return pspec; + } + key.owner_type = g_type_parent (key.owner_type); + } + while (key.owner_type); + else + pspec = g_hash_table_lookup (hash_table, &key); + g_free (key.name); + } + + return pspec; } GParamSpec* -g_param_spec_hash_table_lookup (GHashTable *hash_table, - const gchar *param_name, - GType owner_type, - gboolean try_ancestors, - const gchar **trailer) +g_param_spec_pool_lookup (GParamSpecPool *pool, + const gchar *param_name, + GType owner_type, + gboolean walk_ancestors, + const gchar **trailer_p) { GParamSpec *pspec; - GParamSpec key; gchar *delim; - - g_return_val_if_fail (hash_table != NULL, NULL); - g_return_val_if_fail (param_name != NULL, NULL); - - key.owner_type = owner_type; - delim = strchr (param_name, ':'); - if (delim) - key.name = g_strndup (param_name, delim - param_name); - else - key.name = g_strdup (param_name); - g_strcanon (key.name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-'); - if (trailer) - *trailer = delim; - - pspec = g_hash_table_lookup (hash_table, &key); - if (!pspec && try_ancestors) + g_return_val_if_fail (pool != NULL, NULL); + g_return_val_if_fail (param_name, NULL); + + delim = strchr (param_name, ':'); + + /* try quick and away, i.e. no prefix, no trailer */ + if (!delim) { - key.owner_type = g_type_parent (key.owner_type); - while (key.owner_type) + if (trailer_p) + *trailer_p = NULL; + return param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors); + } + + /* strip type prefix */ + if (pool->type_prefixing && delim[1] == ':') + { + guint l = delim - param_name; + gchar stack_buffer[32], *buffer = l < 32 ? stack_buffer : g_new (gchar, l + 1); + GType type; + + strncpy (buffer, param_name, delim - param_name); + buffer[l] = 0; + type = g_type_from_name (buffer); + if (l >= 32) + g_free (buffer); + if (type) /* type==0 isn't a valid type pefix */ { - pspec = g_hash_table_lookup (hash_table, &key); - if (pspec) - break; - key.owner_type = g_type_parent (key.owner_type); + /* sanity check, these cases don't make a whole lot of sense */ + if ((!walk_ancestors && type != owner_type) || !g_type_is_a (owner_type, type)) + { + if (trailer_p) + *trailer_p = NULL; + return NULL; + } + owner_type = type; + param_name += l + 2; + delim = strchr (param_name, ':'); + if (!delim) /* good, can still forget about trailer */ + { + if (trailer_p) + *trailer_p = NULL; + return param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors); + } } } - - g_free (key.name); - - return pspec; + + /* ok, no prefix, handle trailer */ + if (delim[1] == ':') + { + guint l = delim - param_name; + gchar stack_buffer[32], *buffer = l < 32 ? stack_buffer : g_new (gchar, l + 1); + + strncpy (buffer, param_name, delim - param_name); + buffer[l] = 0; + pspec = param_spec_ht_lookup (pool->hash_table, buffer, owner_type, walk_ancestors); + if (l >= 32) + g_free (buffer); + if (trailer_p) + *trailer_p = pspec ? delim + 2 : NULL; + return pspec; + } + + /* malformed param_name */ + if (trailer_p) + *trailer_p = NULL; + return NULL; } diff --git a/gobject/gparam.h b/gobject/gparam.h index ec33fbcf8..59c942c07 100644 --- a/gobject/gparam.h +++ b/gobject/gparam.h @@ -48,15 +48,17 @@ typedef enum G_PARAM_WRITABLE = 1 << 1, G_PARAM_CONSTRUCT = 1 << 2, G_PARAM_CONSTRUCT_ONLY = 1 << 3, -#define G_PARAM_MASK (0x000f) - /* bits in the range 0xfff0 are reserved for 3rd party usage */ -#define G_PARAM_USER_MASK (0xfff0) + G_PARAM_PRIVATE = 1 << 4, +#define G_PARAM_MASK (0x000000ff) + /* bits in the range 0xffffff00 are reserved for 3rd party usage */ +#define G_PARAM_USER_MASK (0xffffff00) } GParamFlags; /* --- typedefs & structures --- */ typedef struct _GParamSpec GParamSpec; typedef struct _GParamSpecClass GParamSpecClass; +typedef struct _GParamSpecPool GParamSpecPool; struct _GParamSpec { GTypeInstance g_type_instance; @@ -144,23 +146,23 @@ GType g_param_type_register_static (const gchar *name, const GParamSpecTypeInfo *pspec_info); -/* --- private --- */ +/* --- protected --- */ gpointer g_param_spec_internal (GType param_type, const gchar *name, const gchar *nick, const gchar *blurb, GParamFlags flags); -GHashTable* g_param_spec_hash_table_new (void); -void g_param_spec_hash_table_insert (GHashTable *hash_table, - GParamSpec *pspec, - GType owner_type); -void g_param_spec_hash_table_remove (GHashTable *hash_table, - GParamSpec *pspec); -GParamSpec* g_param_spec_hash_table_lookup (GHashTable *hash_table, - const gchar *param_name, - GType owner_type, - gboolean try_ancestors, - const gchar **trailer); +GParamSpecPool* g_param_spec_pool_new (gboolean type_prefixing); +void g_param_spec_pool_insert (GParamSpecPool *pool, + GParamSpec *pspec, + GType owner_type); +void g_param_spec_pool_remove (GParamSpecPool *pool, + GParamSpec *pspec); +GParamSpec* g_param_spec_pool_lookup (GParamSpecPool *pool, + const gchar *param_name, + GType owner_type, + gboolean walk_ancestors, + const gchar **trailer_p); /* contracts: diff --git a/gobject/gtype.c b/gobject/gtype.c index 42842ddaa..6f9aed300 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -345,7 +345,7 @@ type_lookup_iface_entry (TypeNode *node, guint n_ifaces = node->n_ifaces; GType iface_type = NODE_TYPE (iface); - do /* FIXME: should optimize iface lookups for <= 4 */ + do { guint i; IFaceEntry *check;