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