glib/libgobject/src/gvalue.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 /* GObject - GLib Type, Object, Parameter and Signal Library
       
     2  * Copyright (C) 1997-1999, 2000-2001 Tim Janik and Red Hat, Inc.
       
     3  * Portions copyright (c) 2006 Nokia Corporation.  All rights reserved.
       
     4  *
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Lesser General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Lesser General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Lesser General
       
    16  * Public License along with this library; if not, write to the
       
    17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
       
    18  * Boston, MA 02111-1307, USA.
       
    19  */
       
    20 
       
    21 /*
       
    22  * FIXME: MT-safety
       
    23  */
       
    24 
       
    25 #include <string.h>
       
    26 
       
    27 #include "gvalue.h"
       
    28 #include "gvaluecollector.h"
       
    29 #include "gbsearcharray.h"
       
    30 #include "gobjectalias.h"
       
    31 
       
    32 #ifdef __SYMBIAN32__
       
    33 #include <gobject_wsd.h>
       
    34 #endif /* __SYMBIAN32__ */
       
    35 
       
    36 
       
    37 /* --- typedefs & structures --- */
       
    38 typedef struct {
       
    39   GType src_type;
       
    40   GType dest_type;
       
    41   GValueTransform func;
       
    42 } TransformEntry;
       
    43 
       
    44 
       
    45 /* --- prototypes --- */
       
    46 static gint	transform_entries_cmp	(gconstpointer bsearch_node1,
       
    47 					 gconstpointer bsearch_node2);
       
    48 
       
    49 
       
    50 /* --- variables --- */
       
    51 #if EMULATOR
       
    52 
       
    53 PLS(transform_array,gvalue,GBSearchArray *) 
       
    54 PLS(transform_bconfig,gvalue,GBSearchConfig )
       
    55 
       
    56 #define transform_array (*FUNCTION_NAME(transform_array,gvalue)())
       
    57 #define transform_bconfig  (*FUNCTION_NAME(transform_bconfig ,gvalue)())
       
    58 
       
    59 const GBSearchConfig temp_transform_bconfig = {
       
    60   sizeof (TransformEntry),
       
    61   transform_entries_cmp,
       
    62   0,
       
    63 };
       
    64 
       
    65 
       
    66 #else
       
    67 
       
    68 static GBSearchArray *transform_array = NULL;
       
    69 static GBSearchConfig transform_bconfig = {
       
    70   sizeof (TransformEntry),
       
    71   transform_entries_cmp,
       
    72   0,
       
    73 };
       
    74 
       
    75 #endif /* EMULATOR */
       
    76 
       
    77 
       
    78 /* --- functions --- */
       
    79 void
       
    80 g_value_c_init (void)
       
    81 {
       
    82   transform_array = g_bsearch_array_create (&transform_bconfig);
       
    83 }
       
    84 
       
    85 static inline void		/* keep this function in sync with gvaluecollector.h and gboxed.c */
       
    86 value_meminit (GValue *value,
       
    87 	       GType   value_type)
       
    88 {
       
    89   value->g_type = value_type;
       
    90   memset (value->data, 0, sizeof (value->data));
       
    91 }
       
    92 
       
    93 EXPORT_C GValue*
       
    94 g_value_init (GValue *value,
       
    95 	      GType   g_type)
       
    96 {
       
    97   /* g_return_val_if_fail (G_TYPE_IS_VALUE (g_type), NULL);	be more elaborate below */
       
    98   g_return_val_if_fail (value != NULL, NULL);
       
    99   /* g_return_val_if_fail (G_VALUE_TYPE (value) == 0, NULL);	be more elaborate below */
       
   100 
       
   101   if (G_TYPE_IS_VALUE (g_type) && G_VALUE_TYPE (value) == 0)
       
   102     {
       
   103       GTypeValueTable *value_table = g_type_value_table_peek (g_type);
       
   104 
       
   105       /* setup and init */
       
   106       value_meminit (value, g_type);
       
   107       value_table->value_init (value);
       
   108     }
       
   109   else if (G_VALUE_TYPE (value))
       
   110     g_warning ("%s: cannot initialize GValue with type `%s', the value has already been initialized as `%s'",
       
   111 	       G_STRLOC,
       
   112 	       g_type_name (g_type),
       
   113 	       g_type_name (G_VALUE_TYPE (value)));
       
   114   else /* !G_TYPE_IS_VALUE (g_type) */
       
   115     g_warning ("%s: cannot initialize GValue with type `%s', %s",
       
   116 	       G_STRLOC,
       
   117 	       g_type_name (g_type),
       
   118 	       g_type_value_table_peek (g_type) ?
       
   119 	       "this type is abstract with regards to GValue use, use a more specific (derived) type" :
       
   120 	       "this type has no GTypeValueTable implementation");
       
   121   return value;
       
   122 }
       
   123 
       
   124 EXPORT_C void
       
   125 g_value_copy (const GValue *src_value,
       
   126 	      GValue       *dest_value)
       
   127 {
       
   128   g_return_if_fail (G_IS_VALUE (src_value));
       
   129   g_return_if_fail (G_IS_VALUE (dest_value));
       
   130   g_return_if_fail (g_value_type_compatible (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)));
       
   131   
       
   132   if (src_value != dest_value)
       
   133     {
       
   134       GType dest_type = G_VALUE_TYPE (dest_value);
       
   135       GTypeValueTable *value_table = g_type_value_table_peek (dest_type);
       
   136 
       
   137       /* make sure dest_value's value is free()d */
       
   138       if (value_table->value_free)
       
   139 	value_table->value_free (dest_value);
       
   140 
       
   141       /* setup and copy */
       
   142       value_meminit (dest_value, dest_type);
       
   143       value_table->value_copy (src_value, dest_value);
       
   144     }
       
   145 }
       
   146 
       
   147 EXPORT_C GValue*
       
   148 g_value_reset (GValue *value)
       
   149 {
       
   150   GTypeValueTable *value_table;
       
   151   GType g_type;
       
   152   
       
   153   g_return_val_if_fail (G_IS_VALUE (value), NULL);
       
   154   
       
   155   g_type = G_VALUE_TYPE (value);
       
   156   value_table = g_type_value_table_peek (g_type);
       
   157 
       
   158   /* make sure value's value is free()d */
       
   159   if (value_table->value_free)
       
   160     value_table->value_free (value);
       
   161 
       
   162   /* setup and init */
       
   163   value_meminit (value, g_type);
       
   164   value_table->value_init (value);
       
   165 
       
   166   return value;
       
   167 }
       
   168 
       
   169 EXPORT_C void
       
   170 g_value_unset (GValue *value)
       
   171 {
       
   172   GTypeValueTable *value_table;
       
   173   
       
   174   g_return_if_fail (G_IS_VALUE (value));
       
   175 
       
   176   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
       
   177 
       
   178   if (value_table->value_free)
       
   179     value_table->value_free (value);
       
   180   memset (value, 0, sizeof (*value));
       
   181 }
       
   182 
       
   183 EXPORT_C gboolean
       
   184 g_value_fits_pointer (const GValue *value)
       
   185 {
       
   186   GTypeValueTable *value_table;
       
   187 
       
   188   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
       
   189 
       
   190   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
       
   191 
       
   192   return value_table->value_peek_pointer != NULL;
       
   193 }
       
   194 
       
   195 EXPORT_C gpointer
       
   196 g_value_peek_pointer (const GValue *value)
       
   197 {
       
   198   GTypeValueTable *value_table;
       
   199 
       
   200   g_return_val_if_fail (G_IS_VALUE (value), NULL);
       
   201 
       
   202   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
       
   203   if (!value_table->value_peek_pointer)
       
   204     {
       
   205       g_assert (g_value_fits_pointer (value) == TRUE);
       
   206       return NULL;
       
   207     }
       
   208 
       
   209   return value_table->value_peek_pointer (value);
       
   210 }
       
   211 
       
   212 EXPORT_C void
       
   213 g_value_set_instance (GValue  *value,
       
   214 		      gpointer instance)
       
   215 {
       
   216   GType g_type;
       
   217   GTypeValueTable *value_table;
       
   218   GTypeCValue cvalue;
       
   219   gchar *error_msg;
       
   220   
       
   221   g_return_if_fail (G_IS_VALUE (value));
       
   222   if (instance)
       
   223     {
       
   224       g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
       
   225       g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (instance), G_VALUE_TYPE (value)));
       
   226     }
       
   227   
       
   228   g_type = G_VALUE_TYPE (value);
       
   229   value_table = g_type_value_table_peek (g_type);
       
   230   
       
   231   g_return_if_fail (strcmp (value_table->collect_format, "p") == 0);
       
   232   
       
   233   memset (&cvalue, 0, sizeof (cvalue));
       
   234   cvalue.v_pointer = instance;
       
   235   
       
   236   /* make sure value's value is free()d */
       
   237   if (value_table->value_free)
       
   238     value_table->value_free (value);
       
   239 
       
   240   /* setup and collect */
       
   241   value_meminit (value, g_type);
       
   242   error_msg = value_table->collect_value (value, 1, &cvalue, 0);
       
   243   if (error_msg)
       
   244     {
       
   245       g_warning ("%s: %s", G_STRLOC, error_msg);
       
   246       g_free (error_msg);
       
   247       
       
   248       /* we purposely leak the value here, it might not be
       
   249        * in a sane state if an error condition occoured
       
   250        */
       
   251       value_meminit (value, g_type);
       
   252       value_table->value_init (value);
       
   253     }
       
   254 }
       
   255 
       
   256 static GValueTransform
       
   257 transform_func_lookup (GType src_type,
       
   258 		       GType dest_type)
       
   259 {
       
   260   TransformEntry entry;
       
   261 
       
   262   entry.src_type = src_type;
       
   263   do
       
   264     {
       
   265       entry.dest_type = dest_type;
       
   266       do
       
   267 	{
       
   268 	  TransformEntry *e;
       
   269 	  
       
   270 	  e = g_bsearch_array_lookup (transform_array, &transform_bconfig, &entry);
       
   271 	  if (e)
       
   272 	    {
       
   273 	      /* need to check that there hasn't been a change in value handling */
       
   274 	      if (g_type_value_table_peek (entry.dest_type) == g_type_value_table_peek (dest_type) &&
       
   275 		  g_type_value_table_peek (entry.src_type) == g_type_value_table_peek (src_type))
       
   276 		return e->func;
       
   277 	    }
       
   278 	  entry.dest_type = g_type_parent (entry.dest_type);
       
   279 	}
       
   280       while (entry.dest_type);
       
   281       
       
   282       entry.src_type = g_type_parent (entry.src_type);
       
   283     }
       
   284   while (entry.src_type);
       
   285 
       
   286   return NULL;
       
   287 }
       
   288 
       
   289 static gint
       
   290 transform_entries_cmp (gconstpointer bsearch_node1,
       
   291 		       gconstpointer bsearch_node2)
       
   292 {
       
   293   const TransformEntry *e1 = bsearch_node1;
       
   294   const TransformEntry *e2 = bsearch_node2;
       
   295   gint cmp = G_BSEARCH_ARRAY_CMP (e1->src_type, e2->src_type);
       
   296 
       
   297   if (cmp)
       
   298     return cmp;
       
   299   else
       
   300     return G_BSEARCH_ARRAY_CMP (e1->dest_type, e2->dest_type);
       
   301 }
       
   302 
       
   303 EXPORT_C void
       
   304 g_value_register_transform_func (GType           src_type,
       
   305 				 GType           dest_type,
       
   306 				 GValueTransform transform_func)
       
   307 {
       
   308   TransformEntry entry;
       
   309 
       
   310   /* these checks won't pass for dynamic types.
       
   311    * g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (src_type));
       
   312    * g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (dest_type));
       
   313    */
       
   314   g_return_if_fail (transform_func != NULL);
       
   315 
       
   316   entry.src_type = src_type;
       
   317   entry.dest_type = dest_type;
       
   318 
       
   319 #if 0 /* let transform function replacement be a valid operation */
       
   320   if (g_bsearch_array_lookup (transform_array, &transform_bconfig, &entry))
       
   321     g_warning ("reregistering value transformation function (%p) for `%s' to `%s'",
       
   322 	       transform_func,
       
   323 	       g_type_name (src_type),
       
   324 	       g_type_name (dest_type));
       
   325 #endif
       
   326 
       
   327   entry.func = transform_func;
       
   328   transform_array = g_bsearch_array_replace (transform_array, &transform_bconfig, &entry);
       
   329 }
       
   330 
       
   331 EXPORT_C gboolean
       
   332 g_value_type_transformable (GType src_type,
       
   333 			    GType dest_type)
       
   334 {
       
   335   g_return_val_if_fail (G_TYPE_IS_VALUE (src_type), FALSE);
       
   336   g_return_val_if_fail (G_TYPE_IS_VALUE (dest_type), FALSE);
       
   337 
       
   338   return (g_value_type_compatible (src_type, dest_type) ||
       
   339 	  transform_func_lookup (src_type, dest_type) != NULL);
       
   340 }
       
   341 
       
   342 EXPORT_C gboolean
       
   343 g_value_type_compatible (GType src_type,
       
   344 			 GType dest_type)
       
   345 {
       
   346   g_return_val_if_fail (G_TYPE_IS_VALUE (src_type), FALSE);
       
   347   g_return_val_if_fail (G_TYPE_IS_VALUE (dest_type), FALSE);
       
   348 
       
   349   return (g_type_is_a (src_type, dest_type) &&
       
   350 	  g_type_value_table_peek (dest_type) == g_type_value_table_peek (src_type));
       
   351 }
       
   352 
       
   353 EXPORT_C gboolean
       
   354 g_value_transform (const GValue *src_value,
       
   355 		   GValue       *dest_value)
       
   356 {
       
   357   GType dest_type;
       
   358 
       
   359   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
       
   360   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
       
   361 
       
   362   dest_type = G_VALUE_TYPE (dest_value);
       
   363   if (g_value_type_compatible (G_VALUE_TYPE (src_value), dest_type))
       
   364     {
       
   365       g_value_copy (src_value, dest_value);
       
   366       
       
   367       return TRUE;
       
   368     }
       
   369   else
       
   370     {
       
   371       GValueTransform transform = transform_func_lookup (G_VALUE_TYPE (src_value), dest_type);
       
   372 
       
   373       if (transform)
       
   374 	{
       
   375 	  g_value_unset (dest_value);
       
   376 	  
       
   377 	  /* setup and transform */
       
   378 	  value_meminit (dest_value, dest_type);
       
   379 	  transform (src_value, dest_value);
       
   380 	  
       
   381 	  return TRUE;
       
   382 	}
       
   383     }
       
   384   return FALSE;
       
   385 }
       
   386 
       
   387 #define __G_VALUE_C__
       
   388 #include "gobjectaliasdef.c"