glib/gobject/gvalue.c
changeset 18 47c74d1534e1
equal deleted inserted replaced
0:e4d67989cc36 18:47c74d1534e1
       
     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-2009 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 "config.h"
       
    26 
       
    27 #include <string.h>
       
    28 
       
    29 #include "gvalue.h"
       
    30 #include "gvaluecollector.h"
       
    31 #include "gbsearcharray.h"
       
    32 #include "gobjectalias.h"
       
    33 
       
    34 #ifdef __SYMBIAN32__
       
    35 #include "gobject_wsd.h"
       
    36 #endif /* __SYMBIAN32__ */
       
    37 
       
    38 /**
       
    39  * SECTION:generic_values
       
    40  * @short_description: A polymorphic type that can hold values of any
       
    41  *     other type
       
    42  * @see_also: The fundamental types which all support #GValue
       
    43  *     operations and thus can be used as a type initializer for
       
    44  *     g_value_init() are defined by a separate interface.  See the <link
       
    45  *     linkend="gobject-Standard-Parameter-and-Value-Types">Standard
       
    46  *     Values API</link> for details.
       
    47  * @title: Generic values
       
    48  *
       
    49  * The #GValue structure is basically a variable container that consists
       
    50  * of a type identifier and a specific value of that type.
       
    51  * The type identifier within a #GValue structure always determines the
       
    52  * type of the associated value.
       
    53  * To create a undefined #GValue structure, simply create a zero-filled
       
    54  * #GValue structure. To initialize the #GValue, use the g_value_init()
       
    55  * function. A #GValue cannot be used until it is initialized.
       
    56  * The basic type operations (such as freeing and copying) are determined
       
    57  * by the #GTypeValueTable associated with the type ID stored in the #GValue.
       
    58  * Other #GValue operations (such as converting values between types) are
       
    59  * provided by this interface.
       
    60  *
       
    61  * The code in the example program below demonstrates #GValue's
       
    62  * features.
       
    63  *
       
    64  * |[
       
    65  * #include &lt;glib-object.h&gt;
       
    66  *
       
    67  * static void
       
    68  * int2string (const GValue *src_value,
       
    69  *             GValue       *dest_value)
       
    70  * {
       
    71  *   if (g_value_get_int (src_value) == 42)
       
    72  *     g_value_set_static_string (dest_value, "An important number");
       
    73  *   else
       
    74  *     g_value_set_static_string (dest_value, "What's that?");
       
    75  * }
       
    76  *
       
    77  * int
       
    78  * main (int   argc,
       
    79  *       char *argv[])
       
    80  * {
       
    81  *   /&ast; GValues must start zero-filled &ast;/
       
    82  *   GValue a = {0};
       
    83  *   GValue b = {0};
       
    84  *   const gchar *message;
       
    85  *
       
    86  *   g_type_init ();
       
    87  *
       
    88  *   /&ast; The GValue starts empty &ast;/
       
    89  *   g_assert (!G_VALUE_HOLDS_STRING (&amp;a));
       
    90  *
       
    91  *   /&ast; Put a string in it &ast;/
       
    92  *   g_value_init (&amp;a, G_TYPE_STRING);
       
    93  *   g_assert (G_VALUE_HOLDS_STRING (&amp;a));
       
    94  *   g_value_set_static_string (&amp;a, "Hello, world!");
       
    95  *   g_printf ("%s\n", g_value_get_string (&amp;a));
       
    96  *
       
    97  *   /&ast; Reset it to its pristine state &ast;/
       
    98  *   g_value_unset (&amp;a);
       
    99  *
       
   100  *   /&ast; It can then be reused for another type &ast;/
       
   101  *   g_value_init (&amp;a, G_TYPE_INT);
       
   102  *   g_value_set_int (&amp;a, 42);
       
   103  *
       
   104  *   /&ast; Attempt to transform it into a GValue of type STRING &ast;/
       
   105  *   g_value_init (&amp;b, G_TYPE_STRING);
       
   106  *
       
   107  *   /&ast; An INT is transformable to a STRING &ast;/
       
   108  *   g_assert (g_value_type_transformable (G_TYPE_INT, G_TYPE_STRING));
       
   109  *
       
   110  *   g_value_transform (&amp;a, &amp;b);
       
   111  *   g_printf ("%s\n", g_value_get_string (&amp;b));
       
   112  *
       
   113  *   /&ast; Attempt to transform it again using a custom transform function &ast;/
       
   114  *   g_value_register_transform_func (G_TYPE_INT, G_TYPE_STRING, int2string);
       
   115  *   g_value_transform (&amp;a, &amp;b);
       
   116  *   g_printf ("%s\n", g_value_get_string (&amp;b));
       
   117  *   return 0;
       
   118  * }
       
   119  * ]|
       
   120  */
       
   121 
       
   122 
       
   123 /* --- typedefs & structures --- */
       
   124 typedef struct {
       
   125   GType src_type;
       
   126   GType dest_type;
       
   127   GValueTransform func;
       
   128 } TransformEntry;
       
   129 
       
   130 
       
   131 /* --- prototypes --- */
       
   132 static gint	transform_entries_cmp	(gconstpointer bsearch_node1,
       
   133 					 gconstpointer bsearch_node2);
       
   134 
       
   135 
       
   136 /* --- variables --- */
       
   137 #if EMULATOR
       
   138 
       
   139 PLS(transform_array,gvalue,GBSearchArray *) 
       
   140 PLS(transform_bconfig,gvalue,GBSearchConfig )
       
   141 
       
   142 #define transform_array (*FUNCTION_NAME(transform_array,gvalue)())
       
   143 #define transform_bconfig  (*FUNCTION_NAME(transform_bconfig ,gvalue)())
       
   144 
       
   145 const GBSearchConfig temp_transform_bconfig = {
       
   146   sizeof (TransformEntry),
       
   147   transform_entries_cmp,
       
   148   0,
       
   149 };
       
   150 
       
   151 
       
   152 #else
       
   153 
       
   154 static GBSearchArray *transform_array = NULL;
       
   155 static GBSearchConfig transform_bconfig = {
       
   156   sizeof (TransformEntry),
       
   157   transform_entries_cmp,
       
   158   0,
       
   159 };
       
   160 
       
   161 #endif /* EMULATOR */
       
   162 
       
   163 
       
   164 /* --- functions --- */
       
   165 void
       
   166 g_value_c_init (void)
       
   167 {
       
   168   transform_array = g_bsearch_array_create (&transform_bconfig);
       
   169 }
       
   170 
       
   171 static inline void		/* keep this function in sync with gvaluecollector.h and gboxed.c */
       
   172 value_meminit (GValue *value,
       
   173 	       GType   value_type)
       
   174 {
       
   175   value->g_type = value_type;
       
   176   memset (value->data, 0, sizeof (value->data));
       
   177 }
       
   178 
       
   179 /**
       
   180  * g_value_init:
       
   181  * @value: A zero-filled (uninitialized) #GValue structure.
       
   182  * @g_type: Type the #GValue should hold values of.
       
   183  *
       
   184  * Initializes @value with the default value of @type.
       
   185  *
       
   186  * Returns: the #GValue structure that has been passed in
       
   187  */
       
   188 EXPORT_C GValue*
       
   189 g_value_init (GValue *value,
       
   190 	      GType   g_type)
       
   191 {
       
   192   /* g_return_val_if_fail (G_TYPE_IS_VALUE (g_type), NULL);	be more elaborate below */
       
   193   g_return_val_if_fail (value != NULL, NULL);
       
   194   /* g_return_val_if_fail (G_VALUE_TYPE (value) == 0, NULL);	be more elaborate below */
       
   195 
       
   196   if (G_TYPE_IS_VALUE (g_type) && G_VALUE_TYPE (value) == 0)
       
   197     {
       
   198       GTypeValueTable *value_table = g_type_value_table_peek (g_type);
       
   199 
       
   200       /* setup and init */
       
   201       value_meminit (value, g_type);
       
   202       value_table->value_init (value);
       
   203     }
       
   204   else if (G_VALUE_TYPE (value))
       
   205     g_warning ("%s: cannot initialize GValue with type `%s', the value has already been initialized as `%s'",
       
   206 	       G_STRLOC,
       
   207 	       g_type_name (g_type),
       
   208 	       g_type_name (G_VALUE_TYPE (value)));
       
   209   else /* !G_TYPE_IS_VALUE (g_type) */
       
   210     g_warning ("%s: cannot initialize GValue with type `%s', %s",
       
   211 	       G_STRLOC,
       
   212 	       g_type_name (g_type),
       
   213 	       g_type_value_table_peek (g_type) ?
       
   214 	       "this type is abstract with regards to GValue use, use a more specific (derived) type" :
       
   215 	       "this type has no GTypeValueTable implementation");
       
   216   return value;
       
   217 }
       
   218 
       
   219 /**
       
   220  * g_value_copy:
       
   221  * @src_value: An initialized #GValue structure.
       
   222  * @dest_value: An initialized #GValue structure of the same type as @src_value.
       
   223  *
       
   224  * Copies the value of @src_value into @dest_value.
       
   225  */
       
   226 EXPORT_C void
       
   227 g_value_copy (const GValue *src_value,
       
   228 	      GValue       *dest_value)
       
   229 {
       
   230   g_return_if_fail (G_IS_VALUE (src_value));
       
   231   g_return_if_fail (G_IS_VALUE (dest_value));
       
   232   g_return_if_fail (g_value_type_compatible (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)));
       
   233   
       
   234   if (src_value != dest_value)
       
   235     {
       
   236       GType dest_type = G_VALUE_TYPE (dest_value);
       
   237       GTypeValueTable *value_table = g_type_value_table_peek (dest_type);
       
   238 
       
   239       /* make sure dest_value's value is free()d */
       
   240       if (value_table->value_free)
       
   241 	value_table->value_free (dest_value);
       
   242 
       
   243       /* setup and copy */
       
   244       value_meminit (dest_value, dest_type);
       
   245       value_table->value_copy (src_value, dest_value);
       
   246     }
       
   247 }
       
   248 
       
   249 /**
       
   250  * g_value_reset:
       
   251  * @value: An initialized #GValue structure.
       
   252  *
       
   253  * Clears the current value in @value and resets it to the default value
       
   254  * (as if the value had just been initialized).
       
   255  *
       
   256  * Returns: the #GValue structure that has been passed in
       
   257  */
       
   258 EXPORT_C GValue*
       
   259 g_value_reset (GValue *value)
       
   260 {
       
   261   GTypeValueTable *value_table;
       
   262   GType g_type;
       
   263   
       
   264   g_return_val_if_fail (G_IS_VALUE (value), NULL);
       
   265   
       
   266   g_type = G_VALUE_TYPE (value);
       
   267   value_table = g_type_value_table_peek (g_type);
       
   268 
       
   269   /* make sure value's value is free()d */
       
   270   if (value_table->value_free)
       
   271     value_table->value_free (value);
       
   272 
       
   273   /* setup and init */
       
   274   value_meminit (value, g_type);
       
   275   value_table->value_init (value);
       
   276 
       
   277   return value;
       
   278 }
       
   279 
       
   280 /**
       
   281  * g_value_unset:
       
   282  * @value: An initialized #GValue structure.
       
   283  *
       
   284  * Clears the current value in @value and "unsets" the type,
       
   285  * this releases all resources associated with this GValue.
       
   286  * An unset value is the same as an uninitialized (zero-filled)
       
   287  * #GValue structure.
       
   288  */
       
   289 EXPORT_C void
       
   290 g_value_unset (GValue *value)
       
   291 {
       
   292   GTypeValueTable *value_table;
       
   293   
       
   294   g_return_if_fail (G_IS_VALUE (value));
       
   295 
       
   296   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
       
   297 
       
   298   if (value_table->value_free)
       
   299     value_table->value_free (value);
       
   300   memset (value, 0, sizeof (*value));
       
   301 }
       
   302 
       
   303 /**
       
   304  * g_value_fits_pointer:
       
   305  * @value: An initialized #GValue structure.
       
   306  *
       
   307  * Determines if @value will fit inside the size of a pointer value.
       
   308  * This is an internal function introduced mainly for C marshallers.
       
   309  *
       
   310  * Returns: %TRUE if @value will fit inside a pointer value.
       
   311  */
       
   312 EXPORT_C gboolean
       
   313 g_value_fits_pointer (const GValue *value)
       
   314 {
       
   315   GTypeValueTable *value_table;
       
   316 
       
   317   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
       
   318 
       
   319   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
       
   320 
       
   321   return value_table->value_peek_pointer != NULL;
       
   322 }
       
   323 
       
   324 /**
       
   325  * g_value_peek_pointer:
       
   326  * @value: An initialized #GValue structure.
       
   327  *
       
   328  * Return the value contents as pointer. This function asserts that
       
   329  * g_value_fits_pointer() returned %TRUE for the passed in value.
       
   330  * This is an internal function introduced mainly for C marshallers.
       
   331  *
       
   332  * Returns: %TRUE if @value will fit inside a pointer value.
       
   333  */
       
   334 EXPORT_C gpointer
       
   335 g_value_peek_pointer (const GValue *value)
       
   336 {
       
   337   GTypeValueTable *value_table;
       
   338 
       
   339   g_return_val_if_fail (G_IS_VALUE (value), NULL);
       
   340 
       
   341   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
       
   342   if (!value_table->value_peek_pointer)
       
   343     {
       
   344       g_return_val_if_fail (g_value_fits_pointer (value) == TRUE, NULL);
       
   345       return NULL;
       
   346     }
       
   347 
       
   348   return value_table->value_peek_pointer (value);
       
   349 }
       
   350 
       
   351 /**
       
   352  * g_value_set_instance:
       
   353  * @value: An initialized #GValue structure.
       
   354  * @instance: the instance
       
   355  *
       
   356  * Sets @value from an instantiatable type via the
       
   357  * value_table's collect_value() function.
       
   358  */
       
   359 EXPORT_C void
       
   360 g_value_set_instance (GValue  *value,
       
   361 		      gpointer instance)
       
   362 {
       
   363   GType g_type;
       
   364   GTypeValueTable *value_table;
       
   365   GTypeCValue cvalue;
       
   366   gchar *error_msg;
       
   367   
       
   368   g_return_if_fail (G_IS_VALUE (value));
       
   369   if (instance)
       
   370     {
       
   371       g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
       
   372       g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (instance), G_VALUE_TYPE (value)));
       
   373     }
       
   374   
       
   375   g_type = G_VALUE_TYPE (value);
       
   376   value_table = g_type_value_table_peek (g_type);
       
   377   
       
   378   g_return_if_fail (strcmp (value_table->collect_format, "p") == 0);
       
   379   
       
   380   memset (&cvalue, 0, sizeof (cvalue));
       
   381   cvalue.v_pointer = instance;
       
   382   
       
   383   /* make sure value's value is free()d */
       
   384   if (value_table->value_free)
       
   385     value_table->value_free (value);
       
   386 
       
   387   /* setup and collect */
       
   388   value_meminit (value, g_type);
       
   389   error_msg = value_table->collect_value (value, 1, &cvalue, 0);
       
   390   if (error_msg)
       
   391     {
       
   392       g_warning ("%s: %s", G_STRLOC, error_msg);
       
   393       g_free (error_msg);
       
   394       
       
   395       /* we purposely leak the value here, it might not be
       
   396        * in a sane state if an error condition occoured
       
   397        */
       
   398       value_meminit (value, g_type);
       
   399       value_table->value_init (value);
       
   400     }
       
   401 }
       
   402 
       
   403 static GValueTransform
       
   404 transform_func_lookup (GType src_type,
       
   405 		       GType dest_type)
       
   406 {
       
   407   TransformEntry entry;
       
   408 
       
   409   entry.src_type = src_type;
       
   410   do
       
   411     {
       
   412       entry.dest_type = dest_type;
       
   413       do
       
   414 	{
       
   415 	  TransformEntry *e;
       
   416 	  
       
   417 	  e = g_bsearch_array_lookup (transform_array, &transform_bconfig, &entry);
       
   418 	  if (e)
       
   419 	    {
       
   420 	      /* need to check that there hasn't been a change in value handling */
       
   421 	      if (g_type_value_table_peek (entry.dest_type) == g_type_value_table_peek (dest_type) &&
       
   422 		  g_type_value_table_peek (entry.src_type) == g_type_value_table_peek (src_type))
       
   423 		return e->func;
       
   424 	    }
       
   425 	  entry.dest_type = g_type_parent (entry.dest_type);
       
   426 	}
       
   427       while (entry.dest_type);
       
   428       
       
   429       entry.src_type = g_type_parent (entry.src_type);
       
   430     }
       
   431   while (entry.src_type);
       
   432 
       
   433   return NULL;
       
   434 }
       
   435 
       
   436 static gint
       
   437 transform_entries_cmp (gconstpointer bsearch_node1,
       
   438 		       gconstpointer bsearch_node2)
       
   439 {
       
   440   const TransformEntry *e1 = bsearch_node1;
       
   441   const TransformEntry *e2 = bsearch_node2;
       
   442   gint cmp = G_BSEARCH_ARRAY_CMP (e1->src_type, e2->src_type);
       
   443 
       
   444   if (cmp)
       
   445     return cmp;
       
   446   else
       
   447     return G_BSEARCH_ARRAY_CMP (e1->dest_type, e2->dest_type);
       
   448 }
       
   449 
       
   450 /**
       
   451  * g_value_register_transform_func:
       
   452  * @src_type: Source type.
       
   453  * @dest_type: Target type.
       
   454  * @transform_func: a function which transforms values of type @src_type
       
   455  *  into value of type @dest_type
       
   456  *
       
   457  * Registers a value transformation function for use in g_value_transform().
       
   458  * A previously registered transformation function for @src_type and @dest_type
       
   459  * will be replaced.
       
   460  */
       
   461 EXPORT_C void
       
   462 g_value_register_transform_func (GType           src_type,
       
   463 				 GType           dest_type,
       
   464 				 GValueTransform transform_func)
       
   465 {
       
   466   TransformEntry entry;
       
   467 
       
   468   /* these checks won't pass for dynamic types.
       
   469    * g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (src_type));
       
   470    * g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (dest_type));
       
   471    */
       
   472   g_return_if_fail (transform_func != NULL);
       
   473 
       
   474   entry.src_type = src_type;
       
   475   entry.dest_type = dest_type;
       
   476 
       
   477 #if 0 /* let transform function replacement be a valid operation */
       
   478   if (g_bsearch_array_lookup (transform_array, &transform_bconfig, &entry))
       
   479     g_warning ("reregistering value transformation function (%p) for `%s' to `%s'",
       
   480 	       transform_func,
       
   481 	       g_type_name (src_type),
       
   482 	       g_type_name (dest_type));
       
   483 #endif
       
   484 
       
   485   entry.func = transform_func;
       
   486   transform_array = g_bsearch_array_replace (transform_array, &transform_bconfig, &entry);
       
   487 }
       
   488 
       
   489 /**
       
   490  * g_value_type_transformable:
       
   491  * @src_type: Source type.
       
   492  * @dest_type: Target type.
       
   493  *
       
   494  * Check whether g_value_transform() is able to transform values
       
   495  * of type @src_type into values of type @dest_type.
       
   496  *
       
   497  * Returns: %TRUE if the transformation is possible, %FALSE otherwise.
       
   498  */
       
   499 EXPORT_C gboolean
       
   500 g_value_type_transformable (GType src_type,
       
   501 			    GType dest_type)
       
   502 {
       
   503   g_return_val_if_fail (G_TYPE_IS_VALUE (src_type), FALSE);
       
   504   g_return_val_if_fail (G_TYPE_IS_VALUE (dest_type), FALSE);
       
   505 
       
   506   return (g_value_type_compatible (src_type, dest_type) ||
       
   507 	  transform_func_lookup (src_type, dest_type) != NULL);
       
   508 }
       
   509 
       
   510 /**
       
   511  * g_value_type_compatible:
       
   512  * @src_type: source type to be copied.
       
   513  * @dest_type: destination type for copying.
       
   514  *
       
   515  * Returns whether a #GValue of type @src_type can be copied into
       
   516  * a #GValue of type @dest_type.
       
   517  *
       
   518  * Returns: %TRUE if g_value_copy() is possible with @src_type and @dest_type.
       
   519  */
       
   520 EXPORT_C gboolean
       
   521 g_value_type_compatible (GType src_type,
       
   522 			 GType dest_type)
       
   523 {
       
   524   g_return_val_if_fail (G_TYPE_IS_VALUE (src_type), FALSE);
       
   525   g_return_val_if_fail (G_TYPE_IS_VALUE (dest_type), FALSE);
       
   526 
       
   527   return (g_type_is_a (src_type, dest_type) &&
       
   528 	  g_type_value_table_peek (dest_type) == g_type_value_table_peek (src_type));
       
   529 }
       
   530 
       
   531 /**
       
   532  * g_value_transform:
       
   533  * @src_value: Source value.
       
   534  * @dest_value: Target value.
       
   535  *
       
   536  * Tries to cast the contents of @src_value into a type appropriate
       
   537  * to store in @dest_value, e.g. to transform a %G_TYPE_INT value
       
   538  * into a %G_TYPE_FLOAT value. Performing transformations between
       
   539  * value types might incur precision lossage. Especially
       
   540  * transformations into strings might reveal seemingly arbitrary
       
   541  * results and shouldn't be relied upon for production code (such
       
   542  * as rcfile value or object property serialization).
       
   543  *
       
   544  * Returns: Whether a transformation rule was found and could be applied.
       
   545  *  Upon failing transformations, @dest_value is left untouched.
       
   546  */
       
   547 EXPORT_C gboolean
       
   548 g_value_transform (const GValue *src_value,
       
   549 		   GValue       *dest_value)
       
   550 {
       
   551   GType dest_type;
       
   552 
       
   553   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
       
   554   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
       
   555 
       
   556   dest_type = G_VALUE_TYPE (dest_value);
       
   557   if (g_value_type_compatible (G_VALUE_TYPE (src_value), dest_type))
       
   558     {
       
   559       g_value_copy (src_value, dest_value);
       
   560       
       
   561       return TRUE;
       
   562     }
       
   563   else
       
   564     {
       
   565       GValueTransform transform = transform_func_lookup (G_VALUE_TYPE (src_value), dest_type);
       
   566 
       
   567       if (transform)
       
   568 	{
       
   569 	  g_value_unset (dest_value);
       
   570 	  
       
   571 	  /* setup and transform */
       
   572 	  value_meminit (dest_value, dest_type);
       
   573 	  transform (src_value, dest_value);
       
   574 	  
       
   575 	  return TRUE;
       
   576 	}
       
   577     }
       
   578   return FALSE;
       
   579 }
       
   580 
       
   581 #define __G_VALUE_C__
       
   582 #include "gobjectaliasdef.c"