📄 gparam.c
字号:
else if (!g_value_type_compatible (G_PARAM_SPEC_TYPE (param), G_VALUE_TYPE (value))) return g_strconcat ("invalid param spec type `", G_PARAM_SPEC_TYPE_NAME (param), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); value->data[0].v_pointer = g_param_spec_ref (param); } else value->data[0].v_pointer = NULL; return NULL;}static gchar*value_param_lcopy_value (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags){ GParamSpec **param_p = collect_values[0].v_pointer; if (!param_p) return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); if (!value->data[0].v_pointer) *param_p = NULL; else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) *param_p = value->data[0].v_pointer; else *param_p = g_param_spec_ref (value->data[0].v_pointer); return NULL;}/* --- param spec pool --- */struct _GParamSpecPool{ GStaticMutex smutex; gboolean type_prefixing; GHashTable *hash_table;};static guintparam_spec_pool_hash (gconstpointer key_spec){ const GParamSpec *key = key_spec; const gchar *p; guint h = key->owner_type; for (p = key->name; *p; p++) h = (h << 5) - h + *p; return h;}static gbooleanparam_spec_pool_equals (gconstpointer key_spec_1, gconstpointer key_spec_2){ const GParamSpec *key1 = key_spec_1; const GParamSpec *key2 = key_spec_2; return (key1->owner_type == key2->owner_type && strcmp (key1->name, key2->name) == 0);}GParamSpecPool*g_param_spec_pool_new (gboolean type_prefixing){ static GStaticMutex init_smutex = G_STATIC_MUTEX_INIT; GParamSpecPool *pool = g_new (GParamSpecPool, 1); memcpy (&pool->smutex, &init_smutex, sizeof (init_smutex)); pool->type_prefixing = type_prefixing != FALSE; pool->hash_table = g_hash_table_new (param_spec_pool_hash, param_spec_pool_equals); return pool;}voidg_param_spec_pool_insert (GParamSpecPool *pool, GParamSpec *pspec, GType owner_type){ gchar *p; if (pool && pspec && owner_type > 0 && pspec->owner_type == 0) { G_SLOCK (&pool->smutex); for (p = pspec->name; *p; p++) { 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); G_SUNLOCK (&pool->smutex); return; } } pspec->owner_type = owner_type; g_param_spec_ref (pspec); g_hash_table_insert (pool->hash_table, pspec, pspec); G_SUNLOCK (&pool->smutex); } 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); }}voidg_param_spec_pool_remove (GParamSpecPool *pool, GParamSpec *pspec){ if (pool && pspec) { G_SLOCK (&pool->smutex); 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_SUNLOCK (&pool->smutex); } else { g_return_if_fail (pool != NULL); g_return_if_fail (pspec); }}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) { /* try canonicalized form */ key.name = g_strdup (param_name); key.owner_type = owner_type; canonalize_key (key.name); 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_pool_lookup (GParamSpecPool *pool, const gchar *param_name, GType owner_type, gboolean walk_ancestors){ GParamSpec *pspec; gchar *delim; if (!pool || !param_name) { g_return_val_if_fail (pool != NULL, NULL); g_return_val_if_fail (param_name != NULL, NULL); } G_SLOCK (&pool->smutex); delim = pool->type_prefixing ? strchr (param_name, ':') : NULL; /* try quick and away, i.e. without prefix */ if (!delim) { pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors); G_SUNLOCK (&pool->smutex); return pspec; } /* 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 */ { /* 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)) { G_SUNLOCK (&pool->smutex); return NULL; } owner_type = type; param_name += l + 2; pspec = param_spec_ht_lookup (pool->hash_table, param_name, owner_type, walk_ancestors); G_SUNLOCK (&pool->smutex); return pspec; } } /* malformed param_name */ G_SUNLOCK (&pool->smutex); return NULL;}static voidpool_list (gpointer key, gpointer value, gpointer user_data){ GParamSpec *pspec = value; gpointer *data = user_data; GType owner_type = (GType) data[1]; if (owner_type == pspec->owner_type) data[0] = g_list_prepend (data[0], pspec);}GList*g_param_spec_pool_list_owned (GParamSpecPool *pool, GType owner_type){ gpointer data[2]; g_return_val_if_fail (pool != NULL, NULL); g_return_val_if_fail (owner_type > 0, NULL); G_SLOCK (&pool->smutex); data[0] = NULL; data[1] = (gpointer) owner_type; g_hash_table_foreach (pool->hash_table, pool_list, &data); G_SUNLOCK (&pool->smutex); return data[0];}static gintpspec_compare_id (gconstpointer a, gconstpointer b){ const GParamSpec *pspec1 = a, *pspec2 = b; return pspec1->param_id < pspec2->param_id ? -1 : pspec1->param_id > pspec2->param_id;}static inline GSList*pspec_list_remove_overridden (GSList *plist, GHashTable *ht, GType owner_type, guint *n_p){ GSList *rlist = NULL; while (plist) { GSList *tmp = plist->next; GParamSpec *pspec = plist->data; if (param_spec_ht_lookup (ht, pspec->name, owner_type, TRUE) != pspec) g_slist_free_1 (plist); else { plist->next = rlist; rlist = plist; *n_p += 1; } plist = tmp; } return rlist;}static voidpool_depth_list (gpointer key, gpointer value, gpointer user_data){ GParamSpec *pspec = value; gpointer *data = user_data; GSList **slists = data[0]; GType owner_type = (GType) data[1]; if (g_type_is_a (owner_type, pspec->owner_type)) { guint d = g_type_depth (pspec->owner_type); slists[d - 1] = g_slist_prepend (slists[d - 1], pspec); }}GParamSpec** /* free result */g_param_spec_pool_list (GParamSpecPool *pool, GType owner_type, guint *n_pspecs_p){ GParamSpec **pspecs, **p; GSList **slists, *node; gpointer data[2]; guint d, i; g_return_val_if_fail (pool != NULL, NULL); g_return_val_if_fail (owner_type > 0, NULL); g_return_val_if_fail (n_pspecs_p != NULL, NULL); G_SLOCK (&pool->smutex); *n_pspecs_p = 0; d = g_type_depth (owner_type); slists = g_new0 (GSList*, d); data[0] = slists; data[1] = (gpointer) owner_type; g_hash_table_foreach (pool->hash_table, pool_depth_list, &data); for (i = 0; i < d - 1; i++) slists[i] = pspec_list_remove_overridden (slists[i], pool->hash_table, owner_type, n_pspecs_p); *n_pspecs_p += g_slist_length (slists[i]); pspecs = g_new (GParamSpec*, *n_pspecs_p + 1); p = pspecs; for (i = 0; i < d; i++) { slists[i] = g_slist_sort (slists[i], pspec_compare_id); for (node = slists[i]; node; node = node->next) *p++ = node->data; g_slist_free (slists[i]); } *p++ = NULL; g_free (slists); G_SUNLOCK (&pool->smutex); return pspecs;}/* --- auxillary functions --- */typedef struct{ /* class portion */ GType value_type; void (*finalize) (GParamSpec *pspec); void (*value_set_default) (GParamSpec *pspec, GValue *value); gboolean (*value_validate) (GParamSpec *pspec, GValue *value); gint (*values_cmp) (GParamSpec *pspec, const GValue *value1, const GValue *value2);} ParamSpecClassInfo;static voidparam_spec_generic_class_init (gpointer g_class, gpointer class_data){ GParamSpecClass *class = g_class; ParamSpecClassInfo *info = class_data; class->value_type = info->value_type; if (info->finalize) class->finalize = info->finalize; /* optional */ class->value_set_default = info->value_set_default; if (info->value_validate) class->value_validate = info->value_validate; /* optional */ class->values_cmp = info->values_cmp; g_free (class_data);}static voiddefault_value_set_default (GParamSpec *pspec, GValue *value){ /* value is already zero initialized */}static gintdefault_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2){ return memcmp (&value1->data, &value2->data, sizeof (value1->data));}GTypeg_param_type_register_static (const gchar *name, const GParamSpecTypeInfo *pspec_info){ GTypeInfo info = { sizeof (GParamSpecClass), /* class_size */ NULL, /* base_init */ NULL, /* base_destroy */ param_spec_generic_class_init, /* class_init */ NULL, /* class_destroy */ NULL, /* class_data */ 0, /* instance_size */ 16, /* n_preallocs */ NULL, /* instance_init */ }; ParamSpecClassInfo *cinfo; g_return_val_if_fail (name != NULL, 0); g_return_val_if_fail (pspec_info != NULL, 0); g_return_val_if_fail (g_type_from_name (name) == 0, 0); g_return_val_if_fail (pspec_info->instance_size >= sizeof (GParamSpec), 0); g_return_val_if_fail (g_type_name (pspec_info->value_type) != NULL, 0); /* default: g_return_val_if_fail (pspec_info->value_set_default != NULL, 0); */ /* optional: g_return_val_if_fail (pspec_info->value_validate != NULL, 0); */ /* default: g_return_val_if_fail (pspec_info->values_cmp != NULL, 0); */ info.instance_size = pspec_info->instance_size; info.n_preallocs = pspec_info->n_preallocs; info.instance_init = (GInstanceInitFunc) pspec_info->instance_init; cinfo = g_new (ParamSpecClassInfo, 1); cinfo->value_type = pspec_info->value_type; cinfo->finalize = pspec_info->finalize; cinfo->value_set_default = pspec_info->value_set_default ? pspec_info->value_set_default : default_value_set_default; cinfo->value_validate = pspec_info->value_validate; cinfo->values_cmp = pspec_info->values_cmp ? pspec_info->values_cmp : default_values_cmp; info.class_data = cinfo; return g_type_register_static (G_TYPE_PARAM, name, &info, 0);}voidg_value_set_param (GValue *value, GParamSpec *param){ g_return_if_fail (G_VALUE_HOLDS_PARAM (value)); if (param) g_return_if_fail (G_IS_PARAM_SPEC (param)); if (value->data[0].v_pointer) g_param_spec_unref (value->data[0].v_pointer); value->data[0].v_pointer = param; if (value->data[0].v_pointer) g_param_spec_ref (value->data[0].v_pointer);}voidg_value_set_param_take_ownership (GValue *value, GParamSpec *param){ g_return_if_fail (G_VALUE_HOLDS_PARAM (value)); if (param) g_return_if_fail (G_IS_PARAM_SPEC (param)); if (value->data[0].v_pointer) g_param_spec_unref (value->data[0].v_pointer); value->data[0].v_pointer = param; /* we take over the reference count */}GParamSpec*g_value_get_param (const GValue *value){ g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value), NULL); return value->data[0].v_pointer;}GParamSpec*g_value_dup_param (const GValue *value){ g_return_val_if_fail (G_VALUE_HOLDS_PARAM (value), NULL); return value->data[0].v_pointer ? g_param_spec_ref (value->data[0].v_pointer) : NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -