|
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 <glib-object.h> |
|
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 * /* GValues must start zero-filled */ |
|
82 * GValue a = {0}; |
|
83 * GValue b = {0}; |
|
84 * const gchar *message; |
|
85 * |
|
86 * g_type_init (); |
|
87 * |
|
88 * /* The GValue starts empty */ |
|
89 * g_assert (!G_VALUE_HOLDS_STRING (&a)); |
|
90 * |
|
91 * /* Put a string in it */ |
|
92 * g_value_init (&a, G_TYPE_STRING); |
|
93 * g_assert (G_VALUE_HOLDS_STRING (&a)); |
|
94 * g_value_set_static_string (&a, "Hello, world!"); |
|
95 * g_printf ("%s\n", g_value_get_string (&a)); |
|
96 * |
|
97 * /* Reset it to its pristine state */ |
|
98 * g_value_unset (&a); |
|
99 * |
|
100 * /* It can then be reused for another type */ |
|
101 * g_value_init (&a, G_TYPE_INT); |
|
102 * g_value_set_int (&a, 42); |
|
103 * |
|
104 * /* Attempt to transform it into a GValue of type STRING */ |
|
105 * g_value_init (&b, G_TYPE_STRING); |
|
106 * |
|
107 * /* An INT is transformable to a STRING */ |
|
108 * g_assert (g_value_type_transformable (G_TYPE_INT, G_TYPE_STRING)); |
|
109 * |
|
110 * g_value_transform (&a, &b); |
|
111 * g_printf ("%s\n", g_value_get_string (&b)); |
|
112 * |
|
113 * /* Attempt to transform it again using a custom transform function */ |
|
114 * g_value_register_transform_func (G_TYPE_INT, G_TYPE_STRING, int2string); |
|
115 * g_value_transform (&a, &b); |
|
116 * g_printf ("%s\n", g_value_get_string (&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" |