Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

dbus-gtype-specialized.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-gtype-specialized.c: Non-DBus-specific functions for specialized GTypes
00003  *
00004  * Copyright (C) 2005 Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 /* char * -> data* */ *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 /* Copied from gboxed.c */
00075 static void
00076 proxy_value_init (GValue *value)
00077 {
00078   value->data[0].v_pointer = NULL;
00079 }
00080 
00081 /* Adapted from gboxed.c */
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 /* Adapted from gboxed.c */
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 /* Copied from gboxed.c */
00117 static gpointer
00118 proxy_value_peek_pointer (const GValue *value)
00119 {
00120   return value->data[0].v_pointer;
00121 }
00122 
00123 /* Adapted from gboxed.c */
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 /* Adapted from gboxed.c */
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,                /* class_size */
00252       NULL,             /* base_init */
00253       NULL,             /* base_finalize */
00254       NULL,             /* class_init */
00255       NULL,             /* class_finalize */
00256       NULL,             /* class_data */
00257       0,                /* instance_size */
00258       0,                /* n_preallocs */
00259       NULL,             /* instance_init */
00260       &vtable,          /* value_table */
00261     };
00262 
00263   ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0);
00264   /* install proxy functions upon successfull registration */
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       /* Take ownership of name */
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 }

Generated on Tue Aug 30 16:35:50 2005 for D-BUS by  doxygen 1.4.3