Coverage Report

Created: 2025-07-01 07:09

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