00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "dbus-gtype-specialized.h"
00025 #include <glib.h>
00026 #include <string.h>
00027 #include <gobject/gvaluecollector.h>
00028
00029 typedef enum {
00030 DBUS_G_SPECTYPE_COLLECTION,
00031 DBUS_G_SPECTYPE_MAP
00032 } DBusGTypeSpecializedType;
00033
00034 typedef struct {
00035 DBusGTypeSpecializedType type;
00036 const DBusGTypeSpecializedVtable *vtable;
00037 } DBusGTypeSpecializedContainer;
00038
00039 typedef struct {
00040 GType types[6];
00041 const DBusGTypeSpecializedContainer *klass;
00042 } DBusGTypeSpecializedData;
00043
00044 static GHashTable *specialized_containers;
00045
00046 static GQuark
00047 specialized_type_data_quark ()
00048 {
00049 static GQuark quark;
00050 if (!quark)
00051 quark = g_quark_from_static_string ("DBusGTypeSpecializedData");
00052
00053 return quark;
00054 }
00055
00056 void
00057 dbus_g_type_specialized_init (void)
00058 {
00059 specialized_containers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
00060 }
00061
00062 static gboolean
00063 specialized_types_is_initialized (void)
00064 {
00065 return specialized_containers != NULL;
00066 }
00067
00068 static DBusGTypeSpecializedData *
00069 lookup_specialization_data (GType type)
00070 {
00071 return g_type_get_qdata (type, specialized_type_data_quark ());
00072 }
00073
00074
00075 static void
00076 proxy_value_init (GValue *value)
00077 {
00078 value->data[0].v_pointer = NULL;
00079 }
00080
00081
00082 static void
00083 proxy_value_free (GValue *value)
00084 {
00085 if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
00086 {
00087 DBusGTypeSpecializedData *data;
00088 GType type;
00089
00090 type = G_VALUE_TYPE (value);
00091 data = lookup_specialization_data (type);
00092 g_assert (data != NULL);
00093
00094 data->klass->vtable->free_func (type, value->data[0].v_pointer);
00095 }
00096 }
00097
00098
00099 static void
00100 proxy_value_copy (const GValue *src_value,
00101 GValue *dest_value)
00102 {
00103 if (src_value->data[0].v_pointer)
00104 {
00105 DBusGTypeSpecializedData *data;
00106 GType type;
00107 type = G_VALUE_TYPE (src_value);
00108 data = lookup_specialization_data (type);
00109 g_assert (data != NULL);
00110 dest_value->data[0].v_pointer = data->klass->vtable->copy_func (type, src_value->data[0].v_pointer);
00111 }
00112 else
00113 dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
00114 }
00115
00116
00117 static gpointer
00118 proxy_value_peek_pointer (const GValue *value)
00119 {
00120 return value->data[0].v_pointer;
00121 }
00122
00123
00124 static gchar*
00125 proxy_collect_value (GValue *value,
00126 guint n_collect_values,
00127 GTypeCValue *collect_values,
00128 guint collect_flags)
00129 {
00130 DBusGTypeSpecializedData *data;
00131 GType type;
00132
00133 type = G_VALUE_TYPE (value);
00134 data = lookup_specialization_data (type);
00135
00136 if (!collect_values[0].v_pointer)
00137 value->data[0].v_pointer = NULL;
00138 else
00139 {
00140 if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
00141 {
00142 value->data[0].v_pointer = collect_values[0].v_pointer;
00143 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
00144 }
00145 else
00146 value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer);
00147 }
00148
00149 return NULL;
00150 }
00151
00152
00153 static gchar*
00154 proxy_lcopy_value (const GValue *value,
00155 guint n_collect_values,
00156 GTypeCValue *collect_values,
00157 guint collect_flags)
00158 {
00159 gpointer *boxed_p = collect_values[0].v_pointer;
00160
00161 if (!boxed_p)
00162 return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
00163
00164 if (!value->data[0].v_pointer)
00165 *boxed_p = NULL;
00166 else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
00167 *boxed_p = value->data[0].v_pointer;
00168 else
00169 {
00170 DBusGTypeSpecializedData *data;
00171 GType type;
00172
00173 type = G_VALUE_TYPE (value);
00174 data = lookup_specialization_data (type);
00175
00176 *boxed_p = data->klass->vtable->copy_func (type, value->data[0].v_pointer);
00177 }
00178
00179 return NULL;
00180 }
00181
00182 static char *
00183 build_specialization_name (const char *prefix, GType first_type, GType second_type)
00184 {
00185 GString *fullname;
00186
00187 fullname = g_string_new (prefix);
00188 g_string_append_c (fullname, '+');
00189 g_string_append (fullname, g_type_name (first_type));
00190 if (second_type != G_TYPE_INVALID)
00191 {
00192 g_string_append_c (fullname, '+');
00193 g_string_append (fullname, g_type_name (second_type));
00194 }
00195 return g_string_free (fullname, FALSE);
00196 }
00197
00198 static void
00199 register_container (const char *name,
00200 DBusGTypeSpecializedType type,
00201 const DBusGTypeSpecializedVtable *vtable)
00202 {
00203 DBusGTypeSpecializedContainer *klass;
00204
00205 klass = g_new0 (DBusGTypeSpecializedContainer, 1);
00206 klass->type = type;
00207 klass->vtable = vtable;
00208
00209 g_hash_table_insert (specialized_containers, g_strdup (name), klass);
00210 }
00211
00212 void
00213 dbus_g_type_register_collection (const char *name,
00214 const DBusGTypeSpecializedCollectionVtable *vtable,
00215 guint flags)
00216 {
00217 g_return_if_fail (specialized_types_is_initialized ());
00218 register_container (name, DBUS_G_SPECTYPE_COLLECTION, (const DBusGTypeSpecializedVtable*) vtable);
00219 }
00220
00221 void
00222 dbus_g_type_register_map (const char *name,
00223 const DBusGTypeSpecializedMapVtable *vtable,
00224 guint flags)
00225 {
00226 g_return_if_fail (specialized_types_is_initialized ());
00227 register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable);
00228 }
00229
00230 static GType
00231 register_specialized_instance (const DBusGTypeSpecializedContainer *klass,
00232 char *name,
00233 GType first_type,
00234 GType second_type)
00235 {
00236 GType ret;
00237
00238 static const GTypeValueTable vtable =
00239 {
00240 proxy_value_init,
00241 proxy_value_free,
00242 proxy_value_copy,
00243 proxy_value_peek_pointer,
00244 "p",
00245 proxy_collect_value,
00246 "p",
00247 proxy_lcopy_value,
00248 };
00249 static const GTypeInfo derived_info =
00250 {
00251 0,
00252 NULL,
00253 NULL,
00254 NULL,
00255 NULL,
00256 NULL,
00257 0,
00258 0,
00259 NULL,
00260 &vtable,
00261 };
00262
00263 ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0);
00264
00265 if (ret != G_TYPE_INVALID)
00266 {
00267 DBusGTypeSpecializedData *data;
00268 data = g_new0 (DBusGTypeSpecializedData, 1);
00269 data->types[0] = first_type;
00270 data->types[1] = second_type;
00271 data->klass = klass;
00272 g_type_set_qdata (ret, specialized_type_data_quark (), data);
00273 }
00274
00275 return ret;
00276 }
00277
00278 static GType
00279 lookup_or_register_specialized (const char *container,
00280 GType first_type,
00281 GType second_type)
00282 {
00283 GType ret;
00284 char *name;
00285 const DBusGTypeSpecializedContainer *klass;
00286
00287 g_return_val_if_fail (specialized_types_is_initialized (), G_TYPE_INVALID);
00288
00289 klass = g_hash_table_lookup (specialized_containers, container);
00290 g_return_val_if_fail (klass != NULL, G_TYPE_INVALID);
00291
00292 name = build_specialization_name (container, first_type, second_type);
00293 ret = g_type_from_name (name);
00294 if (ret == G_TYPE_INVALID)
00295 {
00296
00297 ret = register_specialized_instance (klass, name,
00298 first_type,
00299 second_type);
00300 }
00301 else
00302 g_free (name);
00303 return ret;
00304 }
00305
00306 GType
00307 dbus_g_type_get_collection (const char *container,
00308 GType specialization)
00309 {
00310 return lookup_or_register_specialized (container, specialization, G_TYPE_INVALID);
00311 }
00312
00313 GType
00314 dbus_g_type_get_map (const char *container,
00315 GType key_specialization,
00316 GType value_specialization)
00317 {
00318 return lookup_or_register_specialized (container, key_specialization, value_specialization);
00319 }
00320
00321 gboolean
00322 dbus_g_type_is_collection (GType gtype)
00323 {
00324 DBusGTypeSpecializedData *data;
00325 data = lookup_specialization_data (gtype);
00326 if (data == NULL)
00327 return FALSE;
00328 return data->klass->type == DBUS_G_SPECTYPE_COLLECTION;
00329 }
00330
00331 gboolean
00332 dbus_g_type_is_map (GType gtype)
00333 {
00334 DBusGTypeSpecializedData *data;
00335 data = lookup_specialization_data (gtype);
00336 if (data == NULL)
00337 return FALSE;
00338 return data->klass->type == DBUS_G_SPECTYPE_MAP;
00339 }
00340
00341 static GType
00342 get_specialization_index (GType gtype, guint i)
00343 {
00344 DBusGTypeSpecializedData *data;
00345
00346 data = lookup_specialization_data (gtype);
00347 return data->types[i];
00348 }
00349
00350 GType
00351 dbus_g_type_get_collection_specialization (GType gtype)
00352 {
00353 g_return_val_if_fail (dbus_g_type_is_collection (gtype), G_TYPE_INVALID);
00354 return get_specialization_index (gtype, 0);
00355 }
00356
00357 GType
00358 dbus_g_type_get_map_key_specialization (GType gtype)
00359 {
00360 g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
00361 return get_specialization_index (gtype, 0);
00362 }
00363
00364 GType
00365 dbus_g_type_get_map_value_specialization (GType gtype)
00366 {
00367 g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
00368 return get_specialization_index (gtype, 1);
00369 }
00370
00371 gpointer
00372 dbus_g_type_specialized_construct (GType type)
00373 {
00374 DBusGTypeSpecializedData *data;
00375 g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
00376
00377 data = lookup_specialization_data (type);
00378 g_return_val_if_fail (data != NULL, FALSE);
00379
00380 return data->klass->vtable->constructor (type);
00381 }
00382
00383 gboolean
00384 dbus_g_type_collection_get_fixed (GValue *value,
00385 gpointer *data_ret,
00386 guint *len_ret)
00387 {
00388 DBusGTypeSpecializedData *data;
00389 GType gtype;
00390
00391 g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
00392 g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
00393
00394 gtype = G_VALUE_TYPE (value);
00395 data = lookup_specialization_data (gtype);
00396 g_return_val_if_fail (data != NULL, FALSE);
00397
00398 return ((DBusGTypeSpecializedCollectionVtable *) (data->klass->vtable))->fixed_accessor (gtype,
00399 g_value_get_boxed (value),
00400 data_ret, len_ret);
00401 }
00402
00403 void
00404 dbus_g_type_collection_value_iterate (const GValue *value,
00405 DBusGTypeSpecializedCollectionIterator iterator,
00406 gpointer user_data)
00407 {
00408 DBusGTypeSpecializedData *data;
00409 GType gtype;
00410
00411 g_return_if_fail (specialized_types_is_initialized ());
00412 g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
00413
00414 gtype = G_VALUE_TYPE (value);
00415 data = lookup_specialization_data (gtype);
00416 g_return_if_fail (data != NULL);
00417
00418 ((DBusGTypeSpecializedCollectionVtable *) data->klass->vtable)->iterator (gtype,
00419 g_value_get_boxed (value),
00420 iterator, user_data);
00421 }
00422
00423 typedef struct {
00424 GValue *val;
00425 GType specialization_type;
00426 DBusGTypeSpecializedData *specdata;
00427 } DBusGTypeSpecializedAppendContextReal;
00428
00429 void
00430 dbus_g_type_specialized_init_append (GValue *value, DBusGTypeSpecializedAppendContext *ctx)
00431 {
00432 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
00433 GType gtype;
00434 DBusGTypeSpecializedData *specdata;
00435
00436 g_return_if_fail (specialized_types_is_initialized ());
00437 g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
00438 gtype = G_VALUE_TYPE (value);
00439 specdata = lookup_specialization_data (gtype);
00440 g_return_if_fail (specdata != NULL);
00441
00442 realctx->val = value;
00443 realctx->specialization_type = specdata->types[0];
00444 realctx->specdata = specdata;
00445 }
00446
00447 void
00448 dbus_g_type_specialized_collection_append (DBusGTypeSpecializedAppendContext *ctx,
00449 GValue *elt)
00450 {
00451 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
00452 ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->append_func (ctx, elt);
00453 }
00454
00455 void
00456 dbus_g_type_specialized_collection_end_append (DBusGTypeSpecializedAppendContext *ctx)
00457 {
00458 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
00459 if (((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func != NULL)
00460 ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func (ctx);
00461 }
00462
00463 void
00464 dbus_g_type_specialized_map_append (DBusGTypeSpecializedAppendContext *ctx,
00465 GValue *key,
00466 GValue *val)
00467 {
00468 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
00469 ((DBusGTypeSpecializedMapVtable *) realctx->specdata->klass->vtable)->append_func (ctx, key, val);
00470 }
00471
00472 void
00473 dbus_g_type_map_value_iterate (const GValue *value,
00474 DBusGTypeSpecializedMapIterator iterator,
00475 gpointer user_data)
00476 {
00477 DBusGTypeSpecializedData *data;
00478 GType gtype;
00479
00480 g_return_if_fail (specialized_types_is_initialized ());
00481 g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
00482
00483 gtype = G_VALUE_TYPE (value);
00484 data = lookup_specialization_data (gtype);
00485 g_return_if_fail (data != NULL);
00486
00487 ((DBusGTypeSpecializedMapVtable *) data->klass->vtable)->iterator (gtype,
00488 g_value_get_boxed (value),
00489 iterator, user_data);
00490 }