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 <glib-object.h> 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 * /* GValues must start zero-filled */ 78 * GValue a = {0}; 79 * GValue b = {0}; 80 * const gchar *message; 81 * 82 * g_type_init (); 83 * 84 * /* The GValue starts empty */ 85 * g_assert (!G_VALUE_HOLDS_STRING (&a)); 86 * 87 * /* Put a string in it */ 88 * g_value_init (&a, G_TYPE_STRING); 89 * g_assert (G_VALUE_HOLDS_STRING (&a)); 90 * g_value_set_static_string (&a, "Hello, world!"); 91 * g_printf ("%s\n", g_value_get_string (&a)); 92 * 93 * /* Reset it to its pristine state */ 94 * g_value_unset (&a); 95 * 96 * /* It can then be reused for another type */ 97 * g_value_init (&a, G_TYPE_INT); 98 * g_value_set_int (&a, 42); 99 * 100 * /* Attempt to transform it into a GValue of type STRING */ 101 * g_value_init (&b, G_TYPE_STRING); 102 * 103 * /* An INT is transformable to a STRING */ 104 * g_assert (g_value_type_transformable (G_TYPE_INT, G_TYPE_STRING)); 105 * 106 * g_value_transform (&a, &b); 107 * g_printf ("%s\n", g_value_get_string (&b)); 108 * 109 * /* Attempt to transform it again using a custom transform function */ 110 * g_value_register_transform_func (G_TYPE_INT, G_TYPE_STRING, int2string); 111 * g_value_transform (&a, &b); 112 * g_printf ("%s\n", g_value_get_string (&b)); 113 * return 0; 114 * } 115 * ]| 116 */ 117 118 119/* --- typedefs & structures --- */ 120typedef struct { 121 GType src_type; 122 GType dest_type; 123 GValueTransform func; 124} TransformEntry; 125 126 127/* --- prototypes --- */ 128static gint transform_entries_cmp (gconstpointer bsearch_node1, 129 gconstpointer bsearch_node2); 130 131 132/* --- variables --- */ 133static GBSearchArray *transform_array = NULL; 134static GBSearchConfig transform_bconfig = { 135 sizeof (TransformEntry), 136 transform_entries_cmp, 137 0, 138}; 139 140 141/* --- functions --- */ 142void 143g_value_c_init (void) 144{ 145 transform_array = g_bsearch_array_create (&transform_bconfig); 146} 147 148static inline void /* keep this function in sync with gvaluecollector.h and gboxed.c */ 149value_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 */ 165GValue* 166g_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 */ 203void 204g_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 */ 235GValue* 236g_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 */ 266void 267g_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 */ 289gboolean 290g_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 */ 311gpointer 312g_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 */ 336void 337g_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 380static GValueTransform 381transform_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 413static gint 414transform_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 */ 438void 439g_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 */ 476gboolean 477g_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 */ 497gboolean 498g_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 */ 524gboolean 525g_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