[I'm dropping dbus@ from the CC; however I just sent an updated patch there which may be interesting context for this] On Mon, 2005-05-16 at 15:22 +0200, Tim Janik wrote: > is this type meant to be abstract (i.e. you'd only use boxed instances > which are truly parameterized)? Yeah. > > 1) Type names can't contain < or > > > extending the charset for typenames s no problem. it's an arbitrary > limitation made inside gtype.c. Ok, that'd be nice. Currently I'm generating type names like "GArray+guint" and "GHashTable+gchararray+gchararray". I'd like to be able to use "GArray<guint>" and "GHashTable<gchararray,gchararray>". > > 2) We can't "deep" derive from G_TYPE_BOXED > > we didn't see a use for that until now. it can be switched on, the glib code > should just be checked for occourances of dependance on flat derivation of > boxed types. (i don't expect them to exist though) Right. I am hacking around this at the moment by using qdata on the types. > > #define DBUS_G_TYPE_STR_STR_HASHTABLE (g_type_build_parameterized ("GHashTable<gchararray,gchararray>")) > > could you outline what exactly you need besides tearing down the two > artifical limitations you described above? (e.g. present code for > g_type_build_parameterized(), etc.) Indeed. I've attached the "generic" part of the dbus work here. There's dbus-gtype-specialized.[hc], which define an interface for both registering and manipulating "specialized" types of collections (GArray, GPtrArray, GList), and maps (GHashTable). This is neat because now the dbus glib marshalling code can e.g. accept any kind of registered collection, instead of just GArray. For example you could send a GList<gchararray> and that would be marshalled as a D-BUS array, just like GArray<gchararray>. I've also attached dbus-gvalue-utils.[hc], which register specialization vtables for GArray, GPtrArray, and GHashTable. To understand this, I'd look at dbus-gtype-specialized.h and get a feel for the interface, then dbus-gvalue-utils.c:dbus_g_type_specialized_builtins_init to see how it's used.
/* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-gtype-specialized.h: Non-DBus-specific functions for specialized GTypes * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef DBUS_GOBJECT_TYPE_SPECIALIZED_H #define DBUS_GOBJECT_TYPE_SPECIALIZED_H #include <glib.h> #include <glib-object.h> G_BEGIN_DECLS GType dbus_g_type_get_collection (const char *container, GType specialization); GType dbus_g_type_get_map (const char *container, GType key_specialization, GType value_specialization); gboolean dbus_g_type_is_collection (GType gtype); gboolean dbus_g_type_is_map (GType gtype); GType dbus_g_type_get_collection_specialization (GType gtype); GType dbus_g_type_get_map_key_specialization (GType gtype); GType dbus_g_type_get_map_value_specialization (GType gtype); typedef void (*DBusGTypeSpecializedCollectionIterator) (const GValue *val, gpointer user_data); typedef void (*DBusGTypeSpecializedMapIterator) (const GValue *key_val, const GValue *value_val, gpointer user_data); gpointer dbus_g_type_specialized_construct (GType type); gboolean dbus_g_type_collection_get_fixed (GValue *value, gpointer *data, guint *len); void dbus_g_type_collection_value_iterate (GValue *value, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data); void dbus_g_type_map_value_iterate (GValue *value, DBusGTypeSpecializedMapIterator iterator, gpointer user_data); typedef gpointer (*DBusGTypeSpecializedConstructor) (GType type); typedef void (*DBusGTypeSpecializedFreeFunc) (GType type, gpointer val); typedef gpointer (*DBusGTypeSpecializedCopyFunc) (GType type, gpointer src); typedef struct { DBusGTypeSpecializedConstructor constructor; DBusGTypeSpecializedFreeFunc free_func; DBusGTypeSpecializedCopyFunc copy_func; gpointer padding1; gpointer padding2; gpointer padding3; } DBusGTypeSpecializedVtable; typedef gboolean (*DBusGTypeSpecializedCollectionFixedAccessorFunc) (GType type, gpointer instance, gpointer *values, guint *len); typedef void (*DBusGTypeSpecializedCollectionIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data); typedef struct { DBusGTypeSpecializedVtable base_vtable; DBusGTypeSpecializedCollectionFixedAccessorFunc fixed_accessor; DBusGTypeSpecializedCollectionIteratorFunc iterator; } DBusGTypeSpecializedCollectionVtable; typedef void (*DBusGTypeSpecializedMapIteratorFunc) (GType type, gpointer instance, DBusGTypeSpecializedMapIterator iterator, gpointer user_data); typedef struct { DBusGTypeSpecializedVtable base_vtable; DBusGTypeSpecializedMapIteratorFunc iterator; } DBusGTypeSpecializedMapVtable; void dbus_g_type_specialized_init (void); void dbus_g_type_register_collection (const char *name, const DBusGTypeSpecializedCollectionVtable *vtable, guint flags); void dbus_g_type_register_map (const char *name, const DBusGTypeSpecializedMapVtable *vtable, guint flags); G_END_DECLS #endif
/* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-gtype-specialized.c: Non-DBus-specific functions for specialized GTypes * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "dbus-gtype-specialized.h" #include <glib.h> #include <string.h> #include <gobject/gvaluecollector.h> typedef enum { DBUS_G_SPECTYPE_COLLECTION, DBUS_G_SPECTYPE_MAP } DBusGTypeSpecializedType; typedef struct { DBusGTypeSpecializedType type; const DBusGTypeSpecializedVtable *vtable; } DBusGTypeSpecializedContainer; typedef struct { GType types[6]; const DBusGTypeSpecializedContainer *klass; } DBusGTypeSpecializedData; static GHashTable /* char * -> data* */ *specialized_containers; static GQuark specialized_type_data_quark () { static GQuark quark; if (!quark) quark = g_quark_from_static_string ("DBusGTypeSpecializedData"); return quark; } void dbus_g_type_specialized_init (void) { specialized_containers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } static gboolean specialized_types_is_initialized (void) { return specialized_containers != NULL; } static DBusGTypeSpecializedData * lookup_specialization_data (GType type) { return g_type_get_qdata (type, specialized_type_data_quark ()); } /* Copied from gboxed.c */ static void proxy_value_init (GValue *value) { value->data[0].v_pointer = NULL; } /* Adapted from gboxed.c */ static void proxy_value_free (GValue *value) { if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS)) { DBusGTypeSpecializedData *data; GType type; type = G_VALUE_TYPE (value); data = lookup_specialization_data (type); g_assert (data != NULL); data->klass->vtable->free_func (type, value->data[0].v_pointer); } } /* Adapted from gboxed.c */ static void proxy_value_copy (const GValue *src_value, GValue *dest_value) { if (src_value->data[0].v_pointer) { DBusGTypeSpecializedData *data; GType type; type = G_VALUE_TYPE (src_value); data = lookup_specialization_data (type); g_assert (data != NULL); dest_value->data[0].v_pointer = data->klass->vtable->copy_func (type, src_value->data[0].v_pointer); } else dest_value->data[0].v_pointer = src_value->data[0].v_pointer; } /* Copied from gboxed.c */ static gpointer proxy_value_peek_pointer (const GValue *value) { return value->data[0].v_pointer; } /* Adapted from gboxed.c */ static gchar* proxy_collect_value (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { DBusGTypeSpecializedData *data; GType type; type = G_VALUE_TYPE (value); data = lookup_specialization_data (type); if (!collect_values[0].v_pointer) value->data[0].v_pointer = NULL; else { if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { value->data[0].v_pointer = collect_values[0].v_pointer; value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS; } else value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer); } return NULL; } /* Adapted from gboxed.c */ static gchar* proxy_lcopy_value (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gpointer *boxed_p = collect_values[0].v_pointer; if (!boxed_p) return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); if (!value->data[0].v_pointer) *boxed_p = NULL; else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) *boxed_p = value->data[0].v_pointer; else { DBusGTypeSpecializedData *data; GType type; type = G_VALUE_TYPE (value); data = lookup_specialization_data (type); *boxed_p = data->klass->vtable->copy_func (type, value->data[0].v_pointer); } return NULL; } static char * build_specialization_name (const char *prefix, GType first_type, GType second_type) { GString *fullname; fullname = g_string_new (prefix); g_string_append_c (fullname, '+'); g_string_append (fullname, g_type_name (first_type)); if (second_type != G_TYPE_INVALID) { g_string_append_c (fullname, '+'); g_string_append (fullname, g_type_name (second_type)); } return g_string_free (fullname, FALSE); } static void register_container (const char *name, DBusGTypeSpecializedType type, const DBusGTypeSpecializedVtable *vtable) { DBusGTypeSpecializedContainer *klass; klass = g_new0 (DBusGTypeSpecializedContainer, 1); klass->type = type; klass->vtable = vtable; g_hash_table_insert (specialized_containers, g_strdup (name), klass); } void dbus_g_type_register_collection (const char *name, const DBusGTypeSpecializedCollectionVtable *vtable, guint flags) { g_return_if_fail (specialized_types_is_initialized ()); register_container (name, DBUS_G_SPECTYPE_COLLECTION, (const DBusGTypeSpecializedVtable*) vtable); } void dbus_g_type_register_map (const char *name, const DBusGTypeSpecializedMapVtable *vtable, guint flags) { g_return_if_fail (specialized_types_is_initialized ()); register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable); } static GType register_specialized_instance (const DBusGTypeSpecializedContainer *klass, char *name, GType first_type, GType second_type) { GType ret; static const GTypeValueTable vtable = { proxy_value_init, proxy_value_free, proxy_value_copy, proxy_value_peek_pointer, "p", proxy_collect_value, "p", proxy_lcopy_value, }; static const GTypeInfo derived_info = { 0, /* class_size */ NULL, /* base_init */ NULL, /* base_finalize */ NULL, /* class_init */ NULL, /* class_finalize */ NULL, /* class_data */ 0, /* instance_size */ 0, /* n_preallocs */ NULL, /* instance_init */ &vtable, /* value_table */ }; ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0); /* install proxy functions upon successfull registration */ if (ret != G_TYPE_INVALID) { DBusGTypeSpecializedData *data; data = g_new0 (DBusGTypeSpecializedData, 1); data->types[0] = first_type; data->types[1] = second_type; data->klass = klass; g_type_set_qdata (ret, specialized_type_data_quark (), data); } return ret; } static GType lookup_or_register_specialized (const char *container, GType first_type, GType second_type) { GType ret; char *name; const DBusGTypeSpecializedContainer *klass; g_return_val_if_fail (specialized_types_is_initialized (), G_TYPE_INVALID); klass = g_hash_table_lookup (specialized_containers, container); g_return_val_if_fail (klass != NULL, G_TYPE_INVALID); name = build_specialization_name (container, first_type, second_type); ret = g_type_from_name (name); if (ret == G_TYPE_INVALID) { /* Take ownership of name */ ret = register_specialized_instance (klass, name, first_type, second_type); } else g_free (name); return ret; } GType dbus_g_type_get_collection (const char *container, GType specialization) { return lookup_or_register_specialized (container, specialization, G_TYPE_INVALID); } GType dbus_g_type_get_map (const char *container, GType key_specialization, GType value_specialization) { return lookup_or_register_specialized (container, key_specialization, value_specialization); } gboolean dbus_g_type_is_collection (GType gtype) { DBusGTypeSpecializedData *data; data = lookup_specialization_data (gtype); if (data == NULL) return FALSE; return data->klass->type == DBUS_G_SPECTYPE_COLLECTION; } gboolean dbus_g_type_is_map (GType gtype) { DBusGTypeSpecializedData *data; data = lookup_specialization_data (gtype); if (data == NULL) return FALSE; return data->klass->type == DBUS_G_SPECTYPE_MAP; } static GType get_specialization_index (GType gtype, guint i) { DBusGTypeSpecializedData *data; data = lookup_specialization_data (gtype); return data->types[i]; } GType dbus_g_type_get_collection_specialization (GType gtype) { g_return_val_if_fail (dbus_g_type_is_collection (gtype), G_TYPE_INVALID); return get_specialization_index (gtype, 0); } GType dbus_g_type_get_map_key_specialization (GType gtype) { g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID); return get_specialization_index (gtype, 0); } GType dbus_g_type_get_map_value_specialization (GType gtype) { g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID); return get_specialization_index (gtype, 1); } gpointer dbus_g_type_specialized_construct (GType type) { DBusGTypeSpecializedData *data; g_return_val_if_fail (specialized_types_is_initialized (), FALSE); data = lookup_specialization_data (type); g_return_val_if_fail (data != NULL, FALSE); return data->klass->vtable->constructor (type); } gboolean dbus_g_type_collection_get_fixed (GValue *value, gpointer *data_ret, guint *len_ret) { DBusGTypeSpecializedData *data; GType gtype; g_return_val_if_fail (specialized_types_is_initialized (), FALSE); g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE); gtype = G_VALUE_TYPE (value); data = lookup_specialization_data (gtype); g_return_val_if_fail (data != NULL, FALSE); return ((DBusGTypeSpecializedCollectionVtable *) (data->klass->vtable))->fixed_accessor (gtype, g_value_get_boxed (value), data_ret, len_ret); } void dbus_g_type_collection_value_iterate (GValue *value, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data) { DBusGTypeSpecializedData *data; GType gtype; g_return_if_fail (specialized_types_is_initialized ()); g_return_if_fail (G_VALUE_HOLDS_BOXED (value)); gtype = G_VALUE_TYPE (value); data = lookup_specialization_data (gtype); g_return_if_fail (data != NULL); ((DBusGTypeSpecializedCollectionVtable *) data->klass->vtable)->iterator (gtype, g_value_get_boxed (value), iterator, user_data); } void dbus_g_type_map_value_iterate (GValue *value, DBusGTypeSpecializedMapIterator iterator, gpointer user_data) { DBusGTypeSpecializedData *data; GType gtype; g_return_if_fail (specialized_types_is_initialized ()); g_return_if_fail (G_VALUE_HOLDS_BOXED (value)); gtype = G_VALUE_TYPE (value); data = lookup_specialization_data (gtype); g_return_if_fail (data != NULL); ((DBusGTypeSpecializedMapVtable *) data->klass->vtable)->iterator (gtype, g_value_get_boxed (value), iterator, user_data); }
/* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-gvalue-utils.h: Non-DBus-specific functions related to GType/GValue * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef DBUS_GOBJECT_VALUE_UTILS_H #define DBUS_GOBJECT_VALUE_UTILS_H #include <glib.h> #include <glib-object.h> G_BEGIN_DECLS void dbus_g_type_specialized_builtins_init (void); gboolean dbus_g_type_is_fixed (GType gtype); guint dbus_g_type_fixed_get_size (GType gtype); gboolean dbus_gvalue_set_from_pointer (GValue *value, gconstpointer storage); typedef void (*DBusGHashValueForeachFunc) (GValue * key, GValue *val, gpointer data); void dbus_g_hash_table_value_foreach (GHashTable *table, GType hash_type, DBusGHashValueForeachFunc func, gpointer data); void dbus_g_hash_table_insert_values (GHashTable *table, GValue *key_val, GValue *value_val); void dbus_g_hash_table_insert_steal_values (GHashTable *table, GValue *key_val, GValue *value_val); gboolean dbus_gtype_is_valid_hash_key (GType type); gboolean dbus_gtype_is_valid_hash_value (GType type); GHashFunc dbus_g_hash_func_from_gtype (GType gtype); GEqualFunc dbus_g_hash_equal_from_gtype (GType gtype); GDestroyNotify dbus_g_hash_free_from_gtype (GType gtype); gboolean dbus_gvalue_store (GValue *value, gpointer storage); gboolean dbus_gvalue_take (GValue *value, GTypeCValue *cvalue); G_END_DECLS #endif
/* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-gvalue-utils.c: Non-DBus-specific functions related to GType/GValue * * Copyright (C) 2005 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "dbus/dbus-glib.h" #include "dbus-gvalue-utils.h" #include <glib.h> #include <string.h> #include <gobject/gvaluecollector.h> static guint fixed_type_get_size (GType type) { switch (type) { case G_TYPE_CHAR: case G_TYPE_UCHAR: return sizeof (gchar); case G_TYPE_BOOLEAN: return sizeof (gboolean); case G_TYPE_LONG: case G_TYPE_ULONG: return sizeof (glong); case G_TYPE_INT: case G_TYPE_UINT: return sizeof (gint); case G_TYPE_INT64: case G_TYPE_UINT64: return sizeof (gint64); case G_TYPE_FLOAT: return sizeof (gfloat); case G_TYPE_DOUBLE: return sizeof (gdouble); default: return 0; } } gboolean dbus_g_type_is_fixed (GType type) { return fixed_type_get_size (type) > 0; } guint dbus_g_type_fixed_get_size (GType type) { g_assert (dbus_g_type_is_fixed (type)); return fixed_type_get_size (type); } gboolean dbus_gvalue_store (GValue *value, gpointer storage) { /* FIXME - can we use the GValue lcopy_value method * to do this in a cleaner way? */ switch (g_type_fundamental (G_VALUE_TYPE (value))) { case G_TYPE_CHAR: *((gchar *) storage) = g_value_get_char (value); return TRUE; case G_TYPE_UCHAR: *((guchar *) storage) = g_value_get_uchar (value); return TRUE; case G_TYPE_BOOLEAN: *((gboolean *) storage) = g_value_get_boolean (value); return TRUE; case G_TYPE_LONG: *((glong *) storage) = g_value_get_long (value); return TRUE; case G_TYPE_ULONG: *((gulong *) storage) = g_value_get_ulong (value); return TRUE; case G_TYPE_INT: *((gint *) storage) = g_value_get_int (value); return TRUE; case G_TYPE_UINT: *((guint *) storage) = g_value_get_uint (value); return TRUE; case G_TYPE_INT64: *((gint64 *) storage) = g_value_get_int64 (value); return TRUE; case G_TYPE_UINT64: *((guint64 *) storage) = g_value_get_uint64 (value); return TRUE; case G_TYPE_DOUBLE: *((gdouble *) storage) = g_value_get_double (value); return TRUE; case G_TYPE_STRING: *((gchar **) storage) = (char*) g_value_get_string (value); return TRUE; case G_TYPE_POINTER: *((gpointer *) storage) = g_value_get_pointer (value); return TRUE; case G_TYPE_OBJECT: *((gpointer *) storage) = g_value_get_object (value); return TRUE; case G_TYPE_BOXED: *((gpointer *) storage) = g_value_get_boxed (value); return TRUE; default: return FALSE; } } gboolean dbus_gvalue_set_from_pointer (GValue *value, gconstpointer storage) { /* FIXME - is there a better way to do this? */ switch (g_type_fundamental (G_VALUE_TYPE (value))) { case G_TYPE_CHAR: g_value_set_char (value, *((gchar *) storage)); return TRUE; case G_TYPE_UCHAR: g_value_set_uchar (value, *((guchar *) storage)); return TRUE; case G_TYPE_BOOLEAN: g_value_set_boolean (value, *((gboolean *) storage)); return TRUE; case G_TYPE_LONG: g_value_set_long (value, *((glong *) storage)); return TRUE; case G_TYPE_ULONG: g_value_set_ulong (value, *((gulong *) storage)); return TRUE; case G_TYPE_INT: g_value_set_int (value, *((gint *) storage)); return TRUE; case G_TYPE_UINT: g_value_set_uint (value, *((guint *) storage)); return TRUE; case G_TYPE_INT64: g_value_set_int64 (value, *((gint64 *) storage)); return TRUE; case G_TYPE_UINT64: g_value_set_uint64 (value, *((guint64 *) storage)); return TRUE; case G_TYPE_DOUBLE: g_value_set_double (value, *((gdouble *) storage)); return TRUE; case G_TYPE_STRING: g_value_set_string (value, *((gchar **) storage)); return TRUE; case G_TYPE_POINTER: g_value_set_pointer (value, *((gpointer *) storage)); return TRUE; case G_TYPE_OBJECT: g_value_set_object (value, *((gpointer *) storage)); return TRUE; case G_TYPE_BOXED: g_value_set_boxed (value, *((gpointer *) storage)); return TRUE; default: return FALSE; } } gboolean dbus_gvalue_take (GValue *value, GTypeCValue *cvalue) { GType g_type; GTypeValueTable *value_table; char *error_msg; g_type = G_VALUE_TYPE (value); value_table = g_type_value_table_peek (g_type); error_msg = value_table->collect_value (value, 1, cvalue, G_VALUE_NOCOPY_CONTENTS); if (error_msg) { g_warning ("%s: %s", G_STRLOC, error_msg); g_free (error_msg); return FALSE; } /* Clear the NOCOPY_CONTENTS flag; we want to take ownership * of the value. */ value->data[1].v_uint &= ~(G_VALUE_NOCOPY_CONTENTS); return TRUE; } static gboolean hash_func_from_gtype (GType gtype, GHashFunc *func) { switch (gtype) { case G_TYPE_CHAR: case G_TYPE_UCHAR: case G_TYPE_BOOLEAN: case G_TYPE_INT: case G_TYPE_UINT: *func = NULL; return TRUE; case G_TYPE_STRING: *func = g_str_hash; return TRUE; default: return FALSE; } } static gboolean hash_free_from_gtype (GType gtype, GDestroyNotify *func) { switch (gtype) { case G_TYPE_CHAR: case G_TYPE_UCHAR: case G_TYPE_BOOLEAN: case G_TYPE_INT: case G_TYPE_UINT: *func = NULL; return TRUE; case G_TYPE_STRING: *func = g_free; return TRUE; default: if (gtype == G_TYPE_VALUE) { *func = (GDestroyNotify) g_value_unset; return TRUE; } return FALSE; } } gboolean dbus_gtype_is_valid_hash_key (GType type) { GHashFunc func; return hash_func_from_gtype (type, &func); } gboolean dbus_gtype_is_valid_hash_value (GType type) { GDestroyNotify func; return hash_free_from_gtype (type, &func); } GHashFunc dbus_g_hash_func_from_gtype (GType gtype) { GHashFunc func; gboolean ret; ret = hash_func_from_gtype (gtype, &func); g_assert (ret != FALSE); return func; } GEqualFunc dbus_g_hash_equal_from_gtype (GType gtype) { g_assert (dbus_gtype_is_valid_hash_key (gtype)); switch (gtype) { case G_TYPE_CHAR: case G_TYPE_UCHAR: case G_TYPE_BOOLEAN: case G_TYPE_INT: case G_TYPE_UINT: return NULL; case G_TYPE_STRING: return g_str_equal; default: g_assert_not_reached (); return NULL; } } GDestroyNotify dbus_g_hash_free_from_gtype (GType gtype) { GDestroyNotify func; gboolean ret; ret = hash_free_from_gtype (gtype, &func); g_assert (ret != FALSE); return func; } static void gvalue_from_hash_value (GValue *value, gpointer instance) { switch (g_type_fundamental (G_VALUE_TYPE (value))) { case G_TYPE_CHAR: g_value_set_char (value, (gchar) GPOINTER_TO_INT (instance)); break; case G_TYPE_UCHAR: g_value_set_uchar (value, (guchar) GPOINTER_TO_UINT (instance)); break; case G_TYPE_BOOLEAN: g_value_set_boolean (value, (gboolean) GPOINTER_TO_UINT (instance)); break; case G_TYPE_INT: g_value_set_int (value, GPOINTER_TO_INT (instance)); break; case G_TYPE_UINT: g_value_set_uint (value, GPOINTER_TO_UINT (instance)); break; case G_TYPE_STRING: g_value_set_static_string (value, instance); break; case G_TYPE_POINTER: g_value_set_pointer (value, instance); break; case G_TYPE_BOXED: g_value_set_static_boxed (value, instance); break; case G_TYPE_OBJECT: g_value_set_object (value, instance); g_object_unref (g_value_get_object (value)); break; default: g_assert_not_reached (); break; } } static gpointer hash_value_from_gvalue (GValue *value) { switch (g_type_fundamental (G_VALUE_TYPE (value))) { case G_TYPE_CHAR: return GINT_TO_POINTER ((int) g_value_get_char (value)); break; case G_TYPE_UCHAR: return GUINT_TO_POINTER ((guint) g_value_get_uchar (value)); break; case G_TYPE_BOOLEAN: return GUINT_TO_POINTER ((guint) g_value_get_boolean (value)); break; case G_TYPE_INT: return GINT_TO_POINTER (g_value_get_int (value)); break; case G_TYPE_UINT: return GUINT_TO_POINTER (g_value_get_uint (value)); break; case G_TYPE_STRING: return (gpointer) g_value_get_string (value); break; case G_TYPE_POINTER: return g_value_get_pointer (value); break; case G_TYPE_BOXED: return g_value_get_boxed (value); break; case G_TYPE_OBJECT: return g_value_get_object (value); break; default: g_assert_not_reached (); return NULL; } } struct DBusGHashTableValueForeachData { DBusGTypeSpecializedMapIterator func; GType key_type; GType value_type; gpointer data; }; static void hashtable_foreach_with_values (gpointer key, gpointer value, gpointer user_data) { GValue key_val = {0, }; GValue value_val = {0, }; struct DBusGHashTableValueForeachData *data = user_data; g_value_init (&key_val, data->key_type); g_value_init (&value_val, data->value_type); gvalue_from_hash_value (&key_val, key); gvalue_from_hash_value (&value_val, value); data->func (&key_val, &value_val, data->data); } static void hashtable_iterator (GType hash_type, gpointer instance, DBusGTypeSpecializedMapIterator iterator, gpointer user_data) { struct DBusGHashTableValueForeachData data; GType key_gtype; GType value_gtype; key_gtype = dbus_g_type_get_map_key_specialization (hash_type); value_gtype = dbus_g_type_get_map_value_specialization (hash_type); data.func = iterator; data.key_type = key_gtype; data.value_type = value_gtype; data.data = user_data; g_hash_table_foreach (instance, hashtable_foreach_with_values, &data); } void dbus_g_hash_table_insert_steal_values (GHashTable *table, GValue *key_val, GValue *value_val) { gpointer key, val; key = hash_value_from_gvalue (key_val); val = hash_value_from_gvalue (value_val); g_hash_table_insert (table, key, val); } static gpointer hashtable_constructor (GType type) { GHashTable *ret; GType key_gtype; GType value_gtype; key_gtype = dbus_g_type_get_map_key_specialization (type); value_gtype = dbus_g_type_get_map_value_specialization (type); ret = g_hash_table_new_full (dbus_g_hash_func_from_gtype (key_gtype), dbus_g_hash_equal_from_gtype (key_gtype), dbus_g_hash_free_from_gtype (key_gtype), dbus_g_hash_free_from_gtype (value_gtype)); return ret; } static void hashtable_insert_values (GHashTable *table, const GValue *key_val, const GValue *value_val) { GValue key_copy = {0, }; GValue value_copy = {0, }; g_value_init (&key_copy, G_VALUE_TYPE (key_val)); g_value_copy (key_val, &key_copy); g_value_init (&value_copy, G_VALUE_TYPE (value_val)); g_value_copy (value_val, &value_copy); dbus_g_hash_table_insert_steal_values (table, &key_copy, &value_copy); } static void hashtable_foreach_copy (const GValue *key, const GValue *val, gpointer data) { hashtable_insert_values ((GHashTable *) data, key, val); } static gpointer hashtable_copy (GType type, gpointer src) { GHashTable *ghash; GHashTable *ret; GValue hashval = {0,}; ghash = src; ret = hashtable_constructor (type); g_value_init (&hashval, type); g_value_set_static_boxed (&hashval, ghash); dbus_g_type_map_value_iterate (&hashval, hashtable_foreach_copy, ret); return ret; } static void hashtable_free (GType type, gpointer val) { g_hash_table_destroy (val); } static gpointer array_constructor (GType type) { GArray *array; guint elt_size; GType elt_type; gboolean zero_terminated; gboolean clear; elt_type = dbus_g_type_get_collection_specialization (type); g_assert (elt_type != G_TYPE_INVALID); elt_size = dbus_g_type_fixed_get_size (elt_type); /* These are "safe" defaults */ zero_terminated = TRUE; /* ((struct _DBusGRealArray*) garray)->zero_terminated; */ clear = TRUE; /* ((struct _DBusGRealArray*) garray)->clear; */ array = g_array_new (zero_terminated, clear, elt_size); return array; } static gpointer array_copy (GType type, gpointer src) { GArray *garray; GArray *new; garray = src; new = array_constructor (type); g_array_append_vals (new, garray->data, garray->len); return new; } static void array_free (GType type, gpointer val) { GArray *array; array = val; g_array_free (array, TRUE); } static gboolean array_fixed_accessor (GType type, gpointer instance, gpointer *values, guint *len) { GType elt_type; GArray *array = instance; elt_type = dbus_g_type_get_collection_specialization (type); if (!dbus_g_type_is_fixed (elt_type)) return FALSE; *values = array->data; *len = array->len; return TRUE; } static gpointer ptrarray_constructor (GType type) { /* Later we should determine a destructor, need g_ptr_array_destroy */ return g_ptr_array_new (); } static void gvalue_from_ptrarray_value (GValue *value, gpointer instance) { switch (g_type_fundamental (G_VALUE_TYPE (value))) { case G_TYPE_POINTER: g_value_set_pointer (value, instance); break; case G_TYPE_BOXED: g_value_set_static_boxed (value, instance); break; case G_TYPE_OBJECT: g_value_set_object (value, instance); g_object_unref (g_value_get_object (value)); break; default: g_assert_not_reached (); break; } } static gpointer ptrarray_value_from_gvalue (const GValue *value) { switch (g_type_fundamental (G_VALUE_TYPE (value))) { case G_TYPE_POINTER: return g_value_get_pointer (value); break; case G_TYPE_BOXED: return g_value_get_boxed (value); break; case G_TYPE_OBJECT: return g_value_get_object (value); break; default: g_assert_not_reached (); return NULL; } } static void ptrarray_iterator (GType hash_type, gpointer instance, DBusGTypeSpecializedCollectionIterator iterator, gpointer user_data) { GPtrArray *ptrarray; GType elt_gtype; guint i; ptrarray = instance; elt_gtype = dbus_g_type_get_collection_specialization (hash_type); for (i = 0; i < ptrarray->len; i++) { GValue val = {0, }; g_value_init (&val, elt_gtype); gvalue_from_ptrarray_value (&val, g_ptr_array_index (ptrarray, i)); iterator (&val, user_data); } } static void ptrarray_copy_elt (const GValue *val, gpointer user_data) { GPtrArray *dest = user_data; GValue val_copy = {0, }; g_value_init (&val_copy, G_VALUE_TYPE (val)); g_value_copy (val, &val_copy); g_ptr_array_add (dest, ptrarray_value_from_gvalue (&val_copy)); } static gpointer ptrarray_copy (GType type, gpointer src) { GPtrArray *new; GValue array_val = {0, }; g_value_init (&array_val, type); g_value_set_static_boxed (&array_val, src); new = ptrarray_constructor (type); dbus_g_type_collection_value_iterate (&array_val, ptrarray_copy_elt, new); return new; } static void ptrarray_free (GType type, gpointer val) { GArray *array; array = val; g_array_free (array, TRUE); } void dbus_g_type_specialized_builtins_init (void) { static const DBusGTypeSpecializedCollectionVtable array_vtable = { { array_constructor, array_free, array_copy, NULL, NULL, NULL }, array_fixed_accessor, NULL }; dbus_g_type_register_collection ("GArray", &array_vtable, 0); static const DBusGTypeSpecializedCollectionVtable ptrarray_vtable = { { ptrarray_constructor, ptrarray_free, ptrarray_copy, NULL, NULL, NULL }, NULL, ptrarray_iterator }; dbus_g_type_register_collection ("GPtrArray", &ptrarray_vtable, 0); static const DBusGTypeSpecializedMapVtable hashtable_vtable = { { hashtable_constructor, hashtable_free, hashtable_copy, NULL, NULL, NULL }, hashtable_iterator }; dbus_g_type_register_map ("GHashTable", &hashtable_vtable, 0); }
Attachment:
signature.asc
Description: This is a digitally signed message part