Branch data Line data Source code
1 : : /* GObject - GLib Type, Object, Parameter and Signal Library
2 : : * Copyright (C) 1997-1999, 2000-2001 Tim Janik and Red Hat, Inc.
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General
17 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
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 "gtype-private.h"
32 : :
33 : :
34 : : /* --- typedefs & structures --- */
35 : : typedef struct {
36 : : GType src_type;
37 : : GType dest_type;
38 : : GValueTransform func;
39 : : } TransformEntry;
40 : :
41 : :
42 : : /* --- prototypes --- */
43 : : static gint transform_entries_cmp (gconstpointer bsearch_node1,
44 : : gconstpointer bsearch_node2);
45 : :
46 : :
47 : : /* --- variables --- */
48 : : static GBSearchArray *transform_array = NULL;
49 : : static GBSearchConfig transform_bconfig = {
50 : : sizeof (TransformEntry),
51 : : transform_entries_cmp,
52 : : G_BSEARCH_ARRAY_ALIGN_POWER2,
53 : : };
54 : :
55 : :
56 : : /* --- functions --- */
57 : : void
58 : 580 : _g_value_c_init (void)
59 : : {
60 : 580 : transform_array = g_bsearch_array_create (&transform_bconfig);
61 : 580 : }
62 : :
63 : : static inline void /* keep this function in sync with gvaluecollector.h and gboxed.c */
64 : 18802583 : value_meminit (GValue *value,
65 : : GType value_type)
66 : : {
67 : 18802583 : value->g_type = value_type;
68 : 18802583 : memset (value->data, 0, sizeof (value->data));
69 : 18802583 : }
70 : :
71 : : /**
72 : : * g_value_init:
73 : : * @value: a zero-filled (cleared) [struct@GObject.Value] structure
74 : : * @g_type: type the [struct@GObject.Value] should hold values of
75 : : *
76 : : * Initializes @value to store values of the given @type, and sets its value
77 : : * to the default for @type.
78 : : *
79 : : * This must be called before any other methods on a [struct@GObject.Value], so
80 : : * the value knows what type it’s meant to store.
81 : : *
82 : : * ```c
83 : : * GValue value = G_VALUE_INIT;
84 : : *
85 : : * g_value_init (&value, SOME_G_TYPE);
86 : : * …
87 : : * g_value_unset (&value);
88 : : * ```
89 : : *
90 : : * Returns: (transfer none): the [struct@GObject.Value] structure that has been
91 : : * passed in
92 : : */
93 : : GValue*
94 : 10256761 : g_value_init (GValue *value,
95 : : GType g_type)
96 : : {
97 : : GTypeValueTable *value_table;
98 : : /* g_return_val_if_fail (G_TYPE_IS_VALUE (g_type), NULL); be more elaborate below */
99 : 10256761 : g_return_val_if_fail (value != NULL, NULL);
100 : : /* g_return_val_if_fail (G_VALUE_TYPE (value) == 0, NULL); be more elaborate below */
101 : :
102 : 10256761 : value_table = g_type_value_table_peek (g_type);
103 : :
104 : 10256761 : if (value_table && G_VALUE_TYPE (value) == 0)
105 : : {
106 : : /* setup and init */
107 : 10256761 : value_meminit (value, g_type);
108 : 10256761 : value_table->value_init (value);
109 : : }
110 : 0 : else if (G_VALUE_TYPE (value))
111 : 0 : g_critical ("%s: cannot initialize GValue with type '%s', the value has already been initialized as '%s'",
112 : : G_STRLOC,
113 : : g_type_name (g_type),
114 : : g_type_name (G_VALUE_TYPE (value)));
115 : : else /* !G_TYPE_IS_VALUE (g_type) */
116 : 0 : g_critical ("%s: cannot initialize GValue with type '%s', %s",
117 : : G_STRLOC,
118 : : g_type_name (g_type),
119 : : value_table ? "this type is abstract with regards to GValue use, use a more specific (derived) type" : "this type has no GTypeValueTable implementation");
120 : 10256761 : return value;
121 : : }
122 : :
123 : : /**
124 : : * g_value_copy:
125 : : * @src_value: an initialized [struct@GObject.Value] structure
126 : : * @dest_value: an initialized [struct@GObject.Value] structure of the same type
127 : : * as @src_value
128 : : *
129 : : * Copies the value of @src_value into @dest_value.
130 : : */
131 : : void
132 : 14361 : g_value_copy (const GValue *src_value,
133 : : GValue *dest_value)
134 : : {
135 : 14361 : g_return_if_fail (src_value);
136 : 14361 : g_return_if_fail (dest_value);
137 : 14361 : g_return_if_fail (g_value_type_compatible (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)));
138 : :
139 : 14361 : if (src_value != dest_value)
140 : : {
141 : 14361 : GType dest_type = G_VALUE_TYPE (dest_value);
142 : 14361 : GTypeValueTable *value_table = g_type_value_table_peek (dest_type);
143 : :
144 : 14361 : g_return_if_fail (value_table);
145 : :
146 : : /* make sure dest_value's value is free()d */
147 : 14361 : if (value_table->value_free)
148 : 13523 : value_table->value_free (dest_value);
149 : :
150 : : /* setup and copy */
151 : 14361 : value_meminit (dest_value, dest_type);
152 : 14361 : value_table->value_copy (src_value, dest_value);
153 : : }
154 : : }
155 : :
156 : : /**
157 : : * g_value_reset:
158 : : * @value: an initialized [struct@GObject.Value] structure
159 : : *
160 : : * Clears the current value in @value and resets it to the default value
161 : : * (as if the value had just been initialized using
162 : : * [method@GObject.Value.init]).
163 : : *
164 : : * Returns: the [struct@GObject.Value] structure that has been passed in
165 : : */
166 : : GValue*
167 : 6378 : g_value_reset (GValue *value)
168 : : {
169 : : GTypeValueTable *value_table;
170 : : GType g_type;
171 : :
172 : 6378 : g_return_val_if_fail (value, NULL);
173 : 6378 : g_type = G_VALUE_TYPE (value);
174 : :
175 : 6378 : value_table = g_type_value_table_peek (g_type);
176 : 6378 : g_return_val_if_fail (value_table, NULL);
177 : :
178 : : /* make sure value's value is free()d */
179 : 6378 : if (value_table->value_free)
180 : 1633 : value_table->value_free (value);
181 : :
182 : : /* setup and init */
183 : 6378 : value_meminit (value, g_type);
184 : 6378 : value_table->value_init (value);
185 : :
186 : 6378 : return value;
187 : : }
188 : :
189 : : /**
190 : : * g_value_unset:
191 : : * @value: an initialized [struct@GObject.Value] structure
192 : : *
193 : : * Clears the current value in @value (if any) and ‘unsets’ the type.
194 : : *
195 : : * This releases all resources associated with this [struct@GObject.Value]. An
196 : : * unset value is the same as a cleared (zero-filled)
197 : : * [struct@GObject.Value] structure set to `G_VALUE_INIT`.
198 : : */
199 : : void
200 : 26875942 : g_value_unset (GValue *value)
201 : : {
202 : : GTypeValueTable *value_table;
203 : :
204 : 26875942 : if (value->g_type == 0)
205 : 1 : return;
206 : :
207 : 26875941 : g_return_if_fail (value);
208 : :
209 : 26875941 : value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
210 : 26875941 : g_return_if_fail (value_table);
211 : :
212 : 26875941 : if (value_table->value_free)
213 : 12139592 : value_table->value_free (value);
214 : 26875941 : memset (value, 0, sizeof (*value));
215 : : }
216 : :
217 : : /**
218 : : * g_value_fits_pointer:
219 : : * @value: an initialized [struct@GObject.Value] structure
220 : : *
221 : : * Determines if @value will fit inside the size of a pointer value.
222 : : *
223 : : * This is an internal function introduced mainly for C marshallers.
224 : : *
225 : : * Returns: true if @value will fit inside a pointer value; false otherwise
226 : : */
227 : : gboolean
228 : 0 : g_value_fits_pointer (const GValue *value)
229 : : {
230 : : GTypeValueTable *value_table;
231 : :
232 : 0 : g_return_val_if_fail (value, FALSE);
233 : :
234 : 0 : value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
235 : 0 : g_return_val_if_fail (value_table, FALSE);
236 : :
237 : 0 : return value_table->value_peek_pointer != NULL;
238 : : }
239 : :
240 : : /**
241 : : * g_value_peek_pointer:
242 : : * @value: an initialized [struct@GObject.Value] structure
243 : : *
244 : : * Returns the value contents as a pointer.
245 : : *
246 : : * This function asserts that [method@GObject.Value.fits_pointer] returned true
247 : : * for the passed in value.
248 : : *
249 : : * This is an internal function introduced mainly for C marshallers.
250 : : *
251 : : * Returns: (transfer none): the value contents as a pointer
252 : : */
253 : : gpointer
254 : 18187177 : g_value_peek_pointer (const GValue *value)
255 : : {
256 : : GTypeValueTable *value_table;
257 : :
258 : 18187177 : g_return_val_if_fail (value, NULL);
259 : :
260 : 18187177 : value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
261 : 18187177 : g_return_val_if_fail (value_table, NULL);
262 : :
263 : 18187177 : if (!value_table->value_peek_pointer)
264 : : {
265 : 0 : g_return_val_if_fail (g_value_fits_pointer (value) == TRUE, NULL);
266 : 0 : return NULL;
267 : : }
268 : :
269 : 18187177 : return value_table->value_peek_pointer (value);
270 : : }
271 : :
272 : : /**
273 : : * g_value_set_instance:
274 : : * @value: an initialized [struct@GObject.Value] structure
275 : : * @instance: (nullable): the instance
276 : : *
277 : : * Sets @value from an instantiatable type.
278 : : *
279 : : * This calls the [callback@GObject.TypeValueCollectFunc] function for the type
280 : : * the [struct@GObject.Value] contains.
281 : : */
282 : : void
283 : 0 : g_value_set_instance (GValue *value,
284 : : gpointer instance)
285 : : {
286 : : GType g_type;
287 : : GTypeValueTable *value_table;
288 : : GTypeCValue cvalue;
289 : : gchar *error_msg;
290 : :
291 : 0 : g_return_if_fail (value);
292 : 0 : g_type = G_VALUE_TYPE (value);
293 : 0 : value_table = g_type_value_table_peek (g_type);
294 : 0 : g_return_if_fail (value_table);
295 : :
296 : 0 : if (instance)
297 : : {
298 : 0 : g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
299 : 0 : g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (instance), G_VALUE_TYPE (value)));
300 : : }
301 : :
302 : 0 : g_return_if_fail (strcmp (value_table->collect_format, "p") == 0);
303 : :
304 : 0 : memset (&cvalue, 0, sizeof (cvalue));
305 : 0 : cvalue.v_pointer = instance;
306 : :
307 : : /* make sure value's value is free()d */
308 : 0 : if (value_table->value_free)
309 : 0 : value_table->value_free (value);
310 : :
311 : : /* setup and collect */
312 : 0 : value_meminit (value, g_type);
313 : 0 : error_msg = value_table->collect_value (value, 1, &cvalue, 0);
314 : 0 : if (error_msg)
315 : : {
316 : 0 : g_critical ("%s: %s", G_STRLOC, error_msg);
317 : 0 : g_free (error_msg);
318 : :
319 : : /* we purposely leak the value here, it might not be
320 : : * in a correct state if an error condition occurred
321 : : */
322 : 0 : value_meminit (value, g_type);
323 : 0 : value_table->value_init (value);
324 : : }
325 : : }
326 : :
327 : : /**
328 : : * g_value_init_from_instance:
329 : : * @value: a zero-filled (cleared) [struct@GObject.Value] structure
330 : : * @instance: (type GObject.TypeInstance): the instance
331 : : *
332 : : * Initializes and sets @value from an instantiatable type.
333 : : *
334 : : * This calls the [callback@GObject.TypeValueCollectFunc] function for the type
335 : : * the [struct@GObject.Value] contains.
336 : : *
337 : : * Note: The @value will be initialised with the exact type of
338 : : * @instance. If you wish to set the @value’s type to a different
339 : : * [type@GObject.Type] (such as a parent class type), you need to manually call
340 : : * [method@GObject.Value.init] and [method@GObject.Value.set_instance].
341 : : *
342 : : * Since: 2.42
343 : : */
344 : : void
345 : 8524759 : g_value_init_from_instance (GValue *value,
346 : : gpointer instance)
347 : : {
348 : 8524759 : g_return_if_fail (value != NULL && G_VALUE_TYPE(value) == 0);
349 : :
350 : 8524759 : if (G_IS_OBJECT (instance))
351 : : {
352 : : /* Fast-path.
353 : : * If G_IS_OBJECT() succeeds we know:
354 : : * * that instance is present and valid
355 : : * * that it is a GObject, and therefore we can directly
356 : : * use the collect implementation (g_object_ref) */
357 : 8524759 : value_meminit (value, G_TYPE_FROM_INSTANCE (instance));
358 : 8524759 : value->data[0].v_pointer = g_object_ref (instance);
359 : : }
360 : : else
361 : : {
362 : : GType g_type;
363 : : GTypeValueTable *value_table;
364 : : GTypeCValue cvalue;
365 : : gchar *error_msg;
366 : :
367 : 0 : g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
368 : :
369 : 0 : g_type = G_TYPE_FROM_INSTANCE (instance);
370 : 0 : value_table = g_type_value_table_peek (g_type);
371 : 0 : g_return_if_fail (strcmp (value_table->collect_format, "p") == 0);
372 : :
373 : 0 : memset (&cvalue, 0, sizeof (cvalue));
374 : 0 : cvalue.v_pointer = instance;
375 : :
376 : : /* setup and collect */
377 : 0 : value_meminit (value, g_type);
378 : 0 : value_table->value_init (value);
379 : 0 : error_msg = value_table->collect_value (value, 1, &cvalue, 0);
380 : 0 : if (error_msg)
381 : : {
382 : 0 : g_critical ("%s: %s", G_STRLOC, error_msg);
383 : 0 : g_free (error_msg);
384 : :
385 : : /* we purposely leak the value here, it might not be
386 : : * in a correct state if an error condition occurred
387 : : */
388 : 0 : value_meminit (value, g_type);
389 : 0 : value_table->value_init (value);
390 : : }
391 : : }
392 : : }
393 : :
394 : : static GType
395 : 558 : transform_lookup_get_parent_type (GType type)
396 : : {
397 : 558 : if (g_type_fundamental (type) == G_TYPE_INTERFACE)
398 : 60 : return g_type_interface_instantiatable_prerequisite (type);
399 : :
400 : 498 : return g_type_parent (type);
401 : : }
402 : :
403 : : static GValueTransform
404 : 520 : transform_func_lookup (GType src_type,
405 : : GType dest_type)
406 : : {
407 : : TransformEntry entry;
408 : :
409 : 520 : entry.src_type = src_type;
410 : : do
411 : : {
412 : 650 : entry.dest_type = dest_type;
413 : : do
414 : : {
415 : : TransformEntry *e;
416 : :
417 : 906 : e = g_bsearch_array_lookup (transform_array, &transform_bconfig, &entry);
418 : 906 : if (e)
419 : : {
420 : : /* need to check that there hasn't been a change in value handling */
421 : 998 : if (g_type_value_table_peek (entry.dest_type) == g_type_value_table_peek (dest_type) &&
422 : 499 : g_type_value_table_peek (entry.src_type) == g_type_value_table_peek (src_type))
423 : 499 : return e->func;
424 : : }
425 : 407 : entry.dest_type = transform_lookup_get_parent_type (entry.dest_type);
426 : : }
427 : 407 : while (entry.dest_type);
428 : :
429 : 151 : entry.src_type = transform_lookup_get_parent_type (entry.src_type);
430 : : }
431 : 151 : while (entry.src_type);
432 : :
433 : 21 : return NULL;
434 : : }
435 : :
436 : : static gint
437 : 1173053 : transform_entries_cmp (gconstpointer bsearch_node1,
438 : : gconstpointer bsearch_node2)
439 : : {
440 : 1173053 : const TransformEntry *e1 = bsearch_node1;
441 : 1173053 : const TransformEntry *e2 = bsearch_node2;
442 : 1173053 : gint cmp = G_BSEARCH_ARRAY_CMP (e1->src_type, e2->src_type);
443 : :
444 : 1173053 : if (cmp)
445 : 788750 : return cmp;
446 : : else
447 : 384303 : return G_BSEARCH_ARRAY_CMP (e1->dest_type, e2->dest_type);
448 : : }
449 : :
450 : : /**
451 : : * g_value_register_transform_func: (skip)
452 : : * @src_type: source type
453 : : * @dest_type: target type
454 : : * @transform_func: a function which transforms values of type @src_type
455 : : * into values of type @dest_type
456 : : *
457 : : * Registers a value transformation function for use in
458 : : * [method@GObject.Value.transform].
459 : : *
460 : : * Any previously registered transformation function for @src_type and
461 : : * @dest_type will be replaced.
462 : : */
463 : : void
464 : 98600 : g_value_register_transform_func (GType src_type,
465 : : GType dest_type,
466 : : GValueTransform transform_func)
467 : : {
468 : : TransformEntry entry;
469 : :
470 : : /* these checks won't pass for dynamic types.
471 : : * g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (src_type));
472 : : * g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (dest_type));
473 : : */
474 : 98600 : g_return_if_fail (transform_func != NULL);
475 : :
476 : 98600 : entry.src_type = src_type;
477 : 98600 : entry.dest_type = dest_type;
478 : :
479 : : #if 0 /* let transform function replacement be a valid operation */
480 : : if (g_bsearch_array_lookup (transform_array, &transform_bconfig, &entry))
481 : : g_warning ("reregistering value transformation function (%p) for '%s' to '%s'",
482 : : transform_func,
483 : : g_type_name (src_type),
484 : : g_type_name (dest_type));
485 : : #endif
486 : :
487 : 98600 : entry.func = transform_func;
488 : 98600 : transform_array = g_bsearch_array_replace (transform_array, &transform_bconfig, &entry);
489 : : }
490 : :
491 : : /**
492 : : * g_value_type_transformable:
493 : : * @src_type: source type
494 : : * @dest_type: target type
495 : : *
496 : : * Checks whether [method@GObject.Value.transform] is able to transform values
497 : : * of type @src_type into values of type @dest_type.
498 : : *
499 : : * Note that for the types to be transformable, they must be compatible or a
500 : : * transformation function must be registered using
501 : : * [func@GObject.Value.register_transform_func].
502 : : *
503 : : * Returns: true if the transformation is possible; false otherwise
504 : : */
505 : : gboolean
506 : 212 : g_value_type_transformable (GType src_type,
507 : : GType dest_type)
508 : : {
509 : 212 : g_return_val_if_fail (src_type, FALSE);
510 : 212 : g_return_val_if_fail (dest_type, FALSE);
511 : :
512 : 389 : return (g_value_type_compatible (src_type, dest_type) ||
513 : 177 : transform_func_lookup (src_type, dest_type) != NULL);
514 : : }
515 : :
516 : : /**
517 : : * g_value_type_compatible:
518 : : * @src_type: source type to be copied
519 : : * @dest_type: destination type for copying
520 : : *
521 : : * Checks whether a [method@GObject.Value.copy] is able to copy values of type
522 : : * @src_type into values of type @dest_type.
523 : : *
524 : : * Returns: true if the copy is possible; false otherwise
525 : : */
526 : : gboolean
527 : 15658443 : g_value_type_compatible (GType src_type,
528 : : GType dest_type)
529 : : {
530 : 15658443 : g_return_val_if_fail (src_type, FALSE);
531 : 15658443 : g_return_val_if_fail (dest_type, FALSE);
532 : :
533 : : /* Fast path */
534 : 15658443 : if (src_type == dest_type)
535 : 12965618 : return TRUE;
536 : :
537 : 5385125 : return (g_type_is_a (src_type, dest_type) &&
538 : 2692300 : g_type_value_table_peek (dest_type) == g_type_value_table_peek (src_type));
539 : : }
540 : :
541 : : /**
542 : : * g_value_transform:
543 : : * @src_value: source value
544 : : * @dest_value: target value
545 : : *
546 : : * Tries to cast the contents of @src_value into a type appropriate
547 : : * to store in @dest_value.
548 : : *
549 : : * If a transformation is not possible, @dest_value is not modified.
550 : : *
551 : : * For example, this could transform a `G_TYPE_INT` value into a `G_TYPE_FLOAT`
552 : : * value.
553 : : *
554 : : * Performing transformations between value types might incur precision loss.
555 : : * Especially transformations into strings might reveal seemingly arbitrary
556 : : * results and the format of particular transformations to strings is not
557 : : * guaranteed over time.
558 : : *
559 : : * Returns: true on success; false otherwise
560 : : */
561 : : gboolean
562 : 13242 : g_value_transform (const GValue *src_value,
563 : : GValue *dest_value)
564 : : {
565 : : GType dest_type;
566 : :
567 : 13242 : g_return_val_if_fail (src_value, FALSE);
568 : 13242 : g_return_val_if_fail (dest_value, FALSE);
569 : :
570 : 13242 : dest_type = G_VALUE_TYPE (dest_value);
571 : 13242 : if (g_value_type_compatible (G_VALUE_TYPE (src_value), dest_type))
572 : : {
573 : 12899 : g_value_copy (src_value, dest_value);
574 : :
575 : 12899 : return TRUE;
576 : : }
577 : : else
578 : : {
579 : 343 : GValueTransform transform = transform_func_lookup (G_VALUE_TYPE (src_value), dest_type);
580 : :
581 : 343 : if (transform)
582 : : {
583 : 324 : g_value_unset (dest_value);
584 : :
585 : : /* setup and transform */
586 : 324 : value_meminit (dest_value, dest_type);
587 : 324 : transform (src_value, dest_value);
588 : :
589 : 324 : return TRUE;
590 : : }
591 : : }
592 : 19 : return FALSE;
593 : : }
|