[glib/gobject-speedups4: 20/20] gobject: Speed up property lookup
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/gobject-speedups4: 20/20] gobject: Speed up property lookup
- Date: Mon, 30 May 2022 16:06:42 +0000 (UTC)
commit 7842920128852ff3bdd32eb56813242bed8b4e7b
Author: Matthias Clasen <mclasen redhat com>
Date: Fri May 20 20:49:05 2022 -0400
gobject: Speed up property lookup
When the param specs are provided as an array
with g_object_class_install_properties, keep
a copy of that array around and use it for
looking up properties without the param spec
pool.
gobject/gobject.c | 127 +++++++++++++++++++++++++++++++++++++++++-------------
gobject/gobject.h | 6 ++-
2 files changed, 103 insertions(+), 30 deletions(-)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index bbf5164570..269dc5cbc6 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -483,6 +483,8 @@ g_object_base_class_init (GObjectClass *class)
class->n_construct_properties = g_slist_length (class->construct_properties);
class->get_property = NULL;
class->set_property = NULL;
+ class->pspecs = NULL;
+ class->n_pspecs = 0;
}
static void
@@ -694,6 +696,61 @@ g_object_class_install_property (GObjectClass *class,
pspec);
}
+typedef struct {
+ const char *name;
+ GParamSpec *pspec;
+} PspecEntry;
+
+static int
+compare_pspec_entry (const void *a,
+ const void *b)
+{
+ const PspecEntry *ae = a;
+ const PspecEntry *be = b;
+
+ return ae->name < be->name ? -1 : (ae->name > be->name ? 1 : 0);
+}
+
+static inline GParamSpec *
+find_pspec (GObjectClass *class,
+ const char *property_name)
+{
+ PspecEntry *pspecs = (PspecEntry *)class->pspecs;
+ guint n_pspecs = class->n_pspecs;
+
+ if (n_pspecs < 10)
+ {
+ for (guint i = 0; i < n_pspecs; i++)
+ {
+ if (pspecs[i].name == property_name)
+ return pspecs[i].pspec;
+ }
+ }
+ else
+ {
+ int lower = 0;
+ int upper = (int)class->n_pspecs - 1;
+ int mid;
+
+ while (lower <= upper)
+ {
+ mid = (lower + upper) / 2;
+
+ if (property_name < pspecs[mid].name)
+ upper = mid - 1;
+ else if (property_name > pspecs[mid].name)
+ lower = mid + 1;
+ else
+ return pspecs[mid].pspec;
+ }
+ }
+
+ return g_param_spec_pool_lookup (pspec_pool,
+ property_name,
+ ((GTypeClass *)class)->g_type,
+ TRUE);
+}
+
/**
* g_object_class_install_properties:
* @oclass: a #GObjectClass
@@ -800,6 +857,21 @@ g_object_class_install_properties (GObjectClass *oclass,
break;
}
}
+
+ if (oclass->pspecs == NULL)
+ {
+ PspecEntry *entries = g_new (PspecEntry, n_pspecs - 1);
+ for (i = 1; i < n_pspecs; i++)
+ {
+ entries[i - 1].name = pspecs[i]->name;
+ entries[i - 1].pspec = pspecs[i];
+ }
+
+ qsort (entries, n_pspecs - 1, sizeof (PspecEntry), compare_pspec_entry);
+
+ oclass->pspecs = entries;
+ oclass->n_pspecs = n_pspecs - 1;
+ }
}
/**
@@ -2198,8 +2270,8 @@ g_object_new_with_properties (GType object_type,
params = g_newa (GObjectConstructParam, n_properties);
for (i = 0; i < n_properties; i++)
{
- GParamSpec *pspec;
- pspec = g_param_spec_pool_lookup (pspec_pool, names[i], object_type, TRUE);
+ GParamSpec *pspec = find_pspec (class, names[i]);
+
if (!g_object_new_is_valid_property (object_type, pspec, names[i], params, count))
continue;
params[count].pspec = pspec;
@@ -2264,9 +2336,8 @@ g_object_newv (GType object_type,
for (i = 0; i < n_parameters; i++)
{
- GParamSpec *pspec;
+ GParamSpec *pspec = find_pspec (class, parameters[i].name);
- pspec = g_param_spec_pool_lookup (pspec_pool, parameters[i].name, object_type, TRUE);
if (!g_object_new_is_valid_property (object_type, pspec, parameters[i].name, cparams, j))
continue;
@@ -2337,9 +2408,7 @@ g_object_new_valist (GType object_type,
do
{
gchar *error = NULL;
- GParamSpec *pspec;
-
- pspec = g_param_spec_pool_lookup (pspec_pool, name, object_type, TRUE);
+ GParamSpec *pspec = find_pspec (class, name);
if (!g_object_new_is_valid_property (object_type, pspec, name, params, n_params))
break;
@@ -2505,7 +2574,7 @@ g_object_setv (GObject *object,
guint i;
GObjectNotifyQueue *nqueue = NULL;
GParamSpec *pspec;
- GType obj_type;
+ GObjectClass *class;
g_return_if_fail (G_IS_OBJECT (object));
@@ -2513,14 +2582,15 @@ g_object_setv (GObject *object,
return;
g_object_ref (object);
- obj_type = G_OBJECT_TYPE (object);
+
+ class = G_OBJECT_GET_CLASS (object);
if (_g_object_has_notify_handler (object))
nqueue = g_object_notify_queue_freeze (object, FALSE);
for (i = 0; i < n_properties; i++)
{
- pspec = g_param_spec_pool_lookup (pspec_pool, names[i], obj_type, TRUE);
+ pspec = find_pspec (class, names[i]);
if (!g_object_set_is_valid_property (object, pspec, names[i]))
break;
@@ -2550,6 +2620,7 @@ g_object_set_valist (GObject *object,
{
GObjectNotifyQueue *nqueue = NULL;
const gchar *name;
+ GObjectClass *class;
g_return_if_fail (G_IS_OBJECT (object));
@@ -2557,7 +2628,9 @@ g_object_set_valist (GObject *object,
if (_g_object_has_notify_handler (object))
nqueue = g_object_notify_queue_freeze (object, FALSE);
-
+
+ class = G_OBJECT_GET_CLASS (object);
+
name = first_property_name;
while (name)
{
@@ -2566,10 +2639,7 @@ g_object_set_valist (GObject *object,
gchar *error = NULL;
GTypeValueTable *vtab;
- pspec = g_param_spec_pool_lookup (pspec_pool,
- name,
- G_OBJECT_TYPE (object),
- TRUE);
+ pspec = find_pspec (class, name);
if (!g_object_set_is_valid_property (object, pspec, name))
break;
@@ -2642,7 +2712,7 @@ g_object_getv (GObject *object,
{
guint i;
GParamSpec *pspec;
- GType obj_type;
+ GObjectClass *class;
g_return_if_fail (G_IS_OBJECT (object));
@@ -2651,12 +2721,14 @@ g_object_getv (GObject *object,
g_object_ref (object);
+ class = G_OBJECT_GET_CLASS (object);
+
memset (values, 0, n_properties * sizeof (GValue));
- obj_type = G_OBJECT_TYPE (object);
for (i = 0; i < n_properties; i++)
{
- pspec = g_param_spec_pool_lookup (pspec_pool, names[i], obj_type, TRUE);
+ pspec = find_pspec (class, names[i]);
+
if (!g_object_get_is_valid_property (object, pspec, names[i]))
break;
g_value_init (&values[i], pspec->value_type);
@@ -2686,23 +2758,23 @@ g_object_get_valist (GObject *object,
va_list var_args)
{
const gchar *name;
+ GObjectClass *class;
g_return_if_fail (G_IS_OBJECT (object));
g_object_ref (object);
-
+
+ class = G_OBJECT_GET_CLASS (object);
+
name = first_property_name;
-
+
while (name)
{
GValue value = G_VALUE_INIT;
GParamSpec *pspec;
gchar *error;
-
- pspec = g_param_spec_pool_lookup (pspec_pool,
- name,
- G_OBJECT_TYPE (object),
- TRUE);
+
+ pspec = find_pspec (class, name);
if (!g_object_get_is_valid_property (object, pspec, name))
break;
@@ -2862,10 +2934,7 @@ g_object_get_property (GObject *object,
g_object_ref (object);
- pspec = g_param_spec_pool_lookup (pspec_pool,
- property_name,
- G_OBJECT_TYPE (object),
- TRUE);
+ pspec = find_pspec (G_OBJECT_GET_CLASS (object), property_name);
if (g_object_get_is_valid_property (object, pspec, property_name))
{
diff --git a/gobject/gobject.h b/gobject/gobject.h
index c67794ae50..93502b01d6 100644
--- a/gobject/gobject.h
+++ b/gobject/gobject.h
@@ -370,8 +370,12 @@ struct _GObjectClass
gsize flags;
gsize n_construct_properties;
+
+ gpointer pspecs;
+ guint n_pspecs;
+
/* padding */
- gpointer pdummy[5];
+ gpointer pdummy[3];
};
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]