• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GObject - GLib Type, Object, Parameter and Signal Library
2  * Copyright (C) 2000-2001 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 #include "config.h"
21 
22 #include <string.h>
23 
24 #include "gboxed.h"
25 #include "gbsearcharray.h"
26 #include "gvalue.h"
27 #include "gvaluearray.h"
28 #include "gclosure.h"
29 #include "gvaluecollector.h"
30 #include "gobjectalias.h"
31 
32 
33 /**
34  * SECTION:gboxed
35  * @short_description: A mechanism to wrap opaque C structures registered
36  *     by the type system
37  * @see_also: #GParamSpecBoxed, g_param_spec_boxed()
38  * @title: Boxed Types
39  *
40  * GBoxed is a generic wrapper mechanism for arbitrary C structures. The only
41  * thing the type system needs to know about the structures is how to copy and
42  * free them, beyond that they are treated as opaque chunks of memory.
43  *
44  * Boxed types are useful for simple value-holder structures like rectangles or
45  * points. They can also be used for wrapping structures defined in non-GObject
46  * based libraries.
47  */
48 
49 /* --- typedefs & structures --- */
50 typedef struct
51 {
52   GType		 type;
53   GBoxedCopyFunc copy;
54   GBoxedFreeFunc free;
55 } BoxedNode;
56 
57 
58 /* --- prototypes --- */
59 static gint	boxed_nodes_cmp		(gconstpointer	p1,
60 					 gconstpointer	p2);
61 
62 
63 /* --- variables --- */
64 static GBSearchArray *boxed_bsa = NULL;
65 static const GBSearchConfig boxed_bconfig = {
66   sizeof (BoxedNode),
67   boxed_nodes_cmp,
68   0,
69 };
70 
71 
72 /* --- functions --- */
73 static gint
boxed_nodes_cmp(gconstpointer p1,gconstpointer p2)74 boxed_nodes_cmp	(gconstpointer p1,
75 		 gconstpointer p2)
76 {
77   const BoxedNode *node1 = p1, *node2 = p2;
78 
79   return G_BSEARCH_ARRAY_CMP (node1->type, node2->type);
80 }
81 
82 static inline void              /* keep this function in sync with gvalue.c */
value_meminit(GValue * value,GType value_type)83 value_meminit (GValue *value,
84 	       GType   value_type)
85 {
86   value->g_type = value_type;
87   memset (value->data, 0, sizeof (value->data));
88 }
89 
90 static gpointer
value_copy(gpointer boxed)91 value_copy (gpointer boxed)
92 {
93   const GValue *src_value = boxed;
94   GValue *dest_value = g_new0 (GValue, 1);
95 
96   if (G_VALUE_TYPE (src_value))
97     {
98       g_value_init (dest_value, G_VALUE_TYPE (src_value));
99       g_value_copy (src_value, dest_value);
100     }
101   return dest_value;
102 }
103 
104 static void
value_free(gpointer boxed)105 value_free (gpointer boxed)
106 {
107   GValue *value = boxed;
108 
109   if (G_VALUE_TYPE (value))
110     g_value_unset (value);
111   g_free (value);
112 }
113 
114 void
g_boxed_type_init(void)115 g_boxed_type_init (void)
116 {
117   static const GTypeInfo info = {
118     0,                          /* class_size */
119     NULL,                       /* base_init */
120     NULL,                       /* base_destroy */
121     NULL,                       /* class_init */
122     NULL,                       /* class_destroy */
123     NULL,                       /* class_data */
124     0,                          /* instance_size */
125     0,                          /* n_preallocs */
126     NULL,                       /* instance_init */
127     NULL,                       /* value_table */
128   };
129   const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
130   GType type;
131 
132   boxed_bsa = g_bsearch_array_create (&boxed_bconfig);
133 
134   /* G_TYPE_BOXED
135    */
136   type = g_type_register_fundamental (G_TYPE_BOXED, g_intern_static_string ("GBoxed"), &info, &finfo,
137 				      G_TYPE_FLAG_ABSTRACT | G_TYPE_FLAG_VALUE_ABSTRACT);
138   g_assert (type == G_TYPE_BOXED);
139 }
140 
141 GType
g_closure_get_type(void)142 g_closure_get_type (void)
143 {
144   static GType type_id = 0;
145 
146   if (!type_id)
147     type_id = g_boxed_type_register_static (g_intern_static_string ("GClosure"),
148 					    (GBoxedCopyFunc) g_closure_ref,
149 					    (GBoxedFreeFunc) g_closure_unref);
150   return type_id;
151 }
152 
153 GType
g_value_get_type(void)154 g_value_get_type (void)
155 {
156   static GType type_id = 0;
157 
158   if (!type_id)
159     type_id = g_boxed_type_register_static (g_intern_static_string ("GValue"),
160 					    value_copy,
161 					    value_free);
162   return type_id;
163 }
164 
165 GType
g_value_array_get_type(void)166 g_value_array_get_type (void)
167 {
168   static GType type_id = 0;
169 
170   if (!type_id)
171     type_id = g_boxed_type_register_static (g_intern_static_string ("GValueArray"),
172 					    (GBoxedCopyFunc) g_value_array_copy,
173 					    (GBoxedFreeFunc) g_value_array_free);
174   return type_id;
175 }
176 
177 static gpointer
gdate_copy(gpointer boxed)178 gdate_copy (gpointer boxed)
179 {
180   const GDate *date = (const GDate*) boxed;
181 
182   return g_date_new_julian (g_date_get_julian (date));
183 }
184 
185 GType
g_date_get_type(void)186 g_date_get_type (void)
187 {
188   static GType type_id = 0;
189 
190   if (!type_id)
191     type_id = g_boxed_type_register_static (g_intern_static_string ("GDate"),
192 					    (GBoxedCopyFunc) gdate_copy,
193 					    (GBoxedFreeFunc) g_date_free);
194   return type_id;
195 }
196 
197 GType
g_strv_get_type(void)198 g_strv_get_type (void)
199 {
200   static GType type_id = 0;
201 
202   if (!type_id)
203     type_id = g_boxed_type_register_static (g_intern_static_string ("GStrv"),
204 					    (GBoxedCopyFunc) g_strdupv,
205 					    (GBoxedFreeFunc) g_strfreev);
206   return type_id;
207 }
208 
209 static gpointer
gstring_copy(gpointer boxed)210 gstring_copy (gpointer boxed)
211 {
212   const GString *src_gstring = boxed;
213 
214   return g_string_new_len (src_gstring->str, src_gstring->len);
215 }
216 
217 static void
gstring_free(gpointer boxed)218 gstring_free (gpointer boxed)
219 {
220   GString *gstring = boxed;
221 
222   g_string_free (gstring, TRUE);
223 }
224 
225 GType
g_gstring_get_type(void)226 g_gstring_get_type (void)
227 {
228   static GType type_id = 0;
229 
230   if (!type_id)
231     type_id = g_boxed_type_register_static (g_intern_static_string ("GString"),
232                                             /* the naming is a bit odd, but GString is obviously not G_TYPE_STRING */
233 					    gstring_copy,
234 					    gstring_free);
235   return type_id;
236 }
237 
238 static gpointer
hash_table_copy(gpointer boxed)239 hash_table_copy (gpointer boxed)
240 {
241   GHashTable *hash_table = boxed;
242   return g_hash_table_ref (hash_table);
243 }
244 
245 static void
hash_table_free(gpointer boxed)246 hash_table_free (gpointer boxed)
247 {
248   GHashTable *hash_table = boxed;
249   g_hash_table_unref (hash_table);
250 }
251 
252 GType
g_hash_table_get_type(void)253 g_hash_table_get_type (void)
254 {
255   static GType type_id = 0;
256   if (!type_id)
257     type_id = g_boxed_type_register_static (g_intern_static_string ("GHashTable"),
258 					    hash_table_copy, hash_table_free);
259   return type_id;
260 }
261 
262 GType
g_regex_get_type(void)263 g_regex_get_type (void)
264 {
265   static GType type_id = 0;
266 
267 #ifdef ENABLE_REGEX
268   if (!type_id)
269     type_id = g_boxed_type_register_static (g_intern_static_string ("GRegex"),
270 					    (GBoxedCopyFunc) g_regex_ref,
271 					    (GBoxedFreeFunc) g_regex_unref);
272 #endif
273 
274   return type_id;
275 }
276 
277 static void
boxed_proxy_value_init(GValue * value)278 boxed_proxy_value_init (GValue *value)
279 {
280   value->data[0].v_pointer = NULL;
281 }
282 
283 static void
boxed_proxy_value_free(GValue * value)284 boxed_proxy_value_free (GValue *value)
285 {
286   if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
287     {
288       BoxedNode key, *node;
289 
290       key.type = G_VALUE_TYPE (value);
291       node = g_bsearch_array_lookup (boxed_bsa, &boxed_bconfig, &key);
292       node->free (value->data[0].v_pointer);
293     }
294 }
295 
296 static void
boxed_proxy_value_copy(const GValue * src_value,GValue * dest_value)297 boxed_proxy_value_copy (const GValue *src_value,
298 			GValue       *dest_value)
299 {
300   if (src_value->data[0].v_pointer)
301     {
302       BoxedNode key, *node;
303 
304       key.type = G_VALUE_TYPE (src_value);
305       node = g_bsearch_array_lookup (boxed_bsa, &boxed_bconfig, &key);
306       dest_value->data[0].v_pointer = node->copy (src_value->data[0].v_pointer);
307     }
308   else
309     dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
310 }
311 
312 static gpointer
boxed_proxy_value_peek_pointer(const GValue * value)313 boxed_proxy_value_peek_pointer (const GValue *value)
314 {
315   return value->data[0].v_pointer;
316 }
317 
318 static gchar*
boxed_proxy_collect_value(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)319 boxed_proxy_collect_value (GValue      *value,
320 			   guint        n_collect_values,
321 			   GTypeCValue *collect_values,
322 			   guint        collect_flags)
323 {
324   BoxedNode key, *node;
325 
326   key.type = G_VALUE_TYPE (value);
327   node = g_bsearch_array_lookup (boxed_bsa, &boxed_bconfig, &key);
328 
329   if (!collect_values[0].v_pointer)
330     value->data[0].v_pointer = NULL;
331   else
332     {
333       if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
334 	{
335 	  value->data[0].v_pointer = collect_values[0].v_pointer;
336 	  value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
337 	}
338       else
339 	value->data[0].v_pointer = node->copy (collect_values[0].v_pointer);
340     }
341 
342   return NULL;
343 }
344 
345 static gchar*
boxed_proxy_lcopy_value(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)346 boxed_proxy_lcopy_value (const GValue *value,
347 			 guint         n_collect_values,
348 			 GTypeCValue  *collect_values,
349 			 guint         collect_flags)
350 {
351   gpointer *boxed_p = collect_values[0].v_pointer;
352 
353   if (!boxed_p)
354     return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
355 
356   if (!value->data[0].v_pointer)
357     *boxed_p = NULL;
358   else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
359     *boxed_p = value->data[0].v_pointer;
360   else
361     {
362       BoxedNode key, *node;
363 
364       key.type = G_VALUE_TYPE (value);
365       node = g_bsearch_array_lookup (boxed_bsa, &boxed_bconfig, &key);
366       *boxed_p = node->copy (value->data[0].v_pointer);
367     }
368 
369   return NULL;
370 }
371 
372 /**
373  * g_boxed_type_register_static:
374  * @name: Name of the new boxed type.
375  * @boxed_copy: Boxed structure copy function.
376  * @boxed_free: Boxed structure free function.
377  *
378  * This function creates a new %G_TYPE_BOXED derived type id for a new
379  * boxed type with name @name. Boxed type handling functions have to be
380  * provided to copy and free opaque boxed structures of this type.
381  *
382  * Returns: New %G_TYPE_BOXED derived type id for @name.
383  */
384 GType
g_boxed_type_register_static(const gchar * name,GBoxedCopyFunc boxed_copy,GBoxedFreeFunc boxed_free)385 g_boxed_type_register_static (const gchar   *name,
386 			      GBoxedCopyFunc boxed_copy,
387 			      GBoxedFreeFunc boxed_free)
388 {
389   static const GTypeValueTable vtable = {
390     boxed_proxy_value_init,
391     boxed_proxy_value_free,
392     boxed_proxy_value_copy,
393     boxed_proxy_value_peek_pointer,
394     "p",
395     boxed_proxy_collect_value,
396     "p",
397     boxed_proxy_lcopy_value,
398   };
399   static const GTypeInfo type_info = {
400     0,			/* class_size */
401     NULL,		/* base_init */
402     NULL,		/* base_finalize */
403     NULL,		/* class_init */
404     NULL,		/* class_finalize */
405     NULL,		/* class_data */
406     0,			/* instance_size */
407     0,			/* n_preallocs */
408     NULL,		/* instance_init */
409     &vtable,		/* value_table */
410   };
411   GType type;
412 
413   g_return_val_if_fail (name != NULL, 0);
414   g_return_val_if_fail (boxed_copy != NULL, 0);
415   g_return_val_if_fail (boxed_free != NULL, 0);
416   g_return_val_if_fail (g_type_from_name (name) == 0, 0);
417 
418   type = g_type_register_static (G_TYPE_BOXED, name, &type_info, 0);
419 
420   /* install proxy functions upon successfull registration */
421   if (type)
422     {
423       BoxedNode key;
424 
425       key.type = type;
426       key.copy = boxed_copy;
427       key.free = boxed_free;
428       boxed_bsa = g_bsearch_array_insert (boxed_bsa, &boxed_bconfig, &key);
429     }
430 
431   return type;
432 }
433 
434 /**
435  * g_boxed_copy:
436  * @boxed_type: The type of @src_boxed.
437  * @src_boxed: The boxed structure to be copied.
438  *
439  * Provide a copy of a boxed structure @src_boxed which is of type @boxed_type.
440  *
441  * Returns: The newly created copy of the boxed structure.
442  */
443 gpointer
g_boxed_copy(GType boxed_type,gconstpointer src_boxed)444 g_boxed_copy (GType         boxed_type,
445 	      gconstpointer src_boxed)
446 {
447   GTypeValueTable *value_table;
448   gpointer dest_boxed;
449 
450   g_return_val_if_fail (G_TYPE_IS_BOXED (boxed_type), NULL);
451   g_return_val_if_fail (G_TYPE_IS_ABSTRACT (boxed_type) == FALSE, NULL);
452   g_return_val_if_fail (src_boxed != NULL, NULL);
453 
454   value_table = g_type_value_table_peek (boxed_type);
455   if (!value_table)
456     g_return_val_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type), NULL);
457 
458   /* check if our proxying implementation is used, we can short-cut here */
459   if (value_table->value_copy == boxed_proxy_value_copy)
460     {
461       BoxedNode key, *node;
462 
463       key.type = boxed_type;
464       node = g_bsearch_array_lookup (boxed_bsa, &boxed_bconfig, &key);
465       dest_boxed = node->copy ((gpointer) src_boxed);
466     }
467   else
468     {
469       GValue src_value, dest_value;
470 
471       /* we heavily rely on third-party boxed type value vtable
472        * implementations to follow normal boxed value storage
473        * (data[0].v_pointer is the boxed struct, and
474        * data[1].v_uint holds the G_VALUE_NOCOPY_CONTENTS flag,
475        * rest zero).
476        * but then, we can expect that since we layed out the
477        * g_boxed_*() API.
478        * data[1].v_uint&G_VALUE_NOCOPY_CONTENTS shouldn't be set
479        * after a copy.
480        */
481       /* equiv. to g_value_set_static_boxed() */
482       value_meminit (&src_value, boxed_type);
483       src_value.data[0].v_pointer = (gpointer) src_boxed;
484       src_value.data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
485 
486       /* call third-party code copy function, fingers-crossed */
487       value_meminit (&dest_value, boxed_type);
488       value_table->value_copy (&src_value, &dest_value);
489 
490       /* double check and grouse if things went wrong */
491       if (dest_value.data[1].v_ulong)
492 	g_warning ("the copy_value() implementation of type `%s' seems to make use of reserved GValue fields",
493 		   g_type_name (boxed_type));
494 
495       dest_boxed = dest_value.data[0].v_pointer;
496     }
497 
498   return dest_boxed;
499 }
500 
501 /**
502  * g_boxed_free:
503  * @boxed_type: The type of @boxed.
504  * @boxed: The boxed structure to be freed.
505  *
506  * Free the boxed structure @boxed which is of type @boxed_type.
507  */
508 void
g_boxed_free(GType boxed_type,gpointer boxed)509 g_boxed_free (GType    boxed_type,
510 	      gpointer boxed)
511 {
512   GTypeValueTable *value_table;
513 
514   g_return_if_fail (G_TYPE_IS_BOXED (boxed_type));
515   g_return_if_fail (G_TYPE_IS_ABSTRACT (boxed_type) == FALSE);
516   g_return_if_fail (boxed != NULL);
517 
518   value_table = g_type_value_table_peek (boxed_type);
519   if (!value_table)
520     g_return_if_fail (G_TYPE_IS_VALUE_TYPE (boxed_type));
521 
522   /* check if our proxying implementation is used, we can short-cut here */
523   if (value_table->value_free == boxed_proxy_value_free)
524     {
525       BoxedNode key, *node;
526 
527       key.type = boxed_type;
528       node = g_bsearch_array_lookup (boxed_bsa, &boxed_bconfig, &key);
529       node->free (boxed);
530     }
531   else
532     {
533       GValue value;
534 
535       /* see g_boxed_copy() on why we think we can do this */
536       value_meminit (&value, boxed_type);
537       value.data[0].v_pointer = boxed;
538       value_table->value_free (&value);
539     }
540 }
541 
542 /**
543  * g_value_get_boxed:
544  * @value: a valid #GValue of %G_TYPE_BOXED derived type
545  *
546  * Get the contents of a %G_TYPE_BOXED derived #GValue.
547  *
548  * Returns: boxed contents of @value
549  */
550 gpointer
g_value_get_boxed(const GValue * value)551 g_value_get_boxed (const GValue *value)
552 {
553   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), NULL);
554   g_return_val_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)), NULL);
555 
556   return value->data[0].v_pointer;
557 }
558 
559 /**
560  * g_value_dup_boxed:
561  * @value: a valid #GValue of %G_TYPE_BOXED derived type
562  *
563  * Get the contents of a %G_TYPE_BOXED derived #GValue.  Upon getting,
564  * the boxed value is duplicated and needs to be later freed with
565  * g_boxed_free(), e.g. like: g_boxed_free (G_VALUE_TYPE (@value),
566  * return_value);
567  *
568  * Returns: boxed contents of @value
569  */
570 gpointer
g_value_dup_boxed(const GValue * value)571 g_value_dup_boxed (const GValue *value)
572 {
573   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), NULL);
574   g_return_val_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)), NULL);
575 
576   return value->data[0].v_pointer ? g_boxed_copy (G_VALUE_TYPE (value), value->data[0].v_pointer) : NULL;
577 }
578 
579 static inline void
value_set_boxed_internal(GValue * value,gconstpointer const_boxed,gboolean need_copy,gboolean need_free)580 value_set_boxed_internal (GValue       *value,
581 			  gconstpointer const_boxed,
582 			  gboolean      need_copy,
583 			  gboolean      need_free)
584 {
585   BoxedNode key, *node;
586   gpointer boxed = (gpointer) const_boxed;
587 
588   if (!boxed)
589     {
590       /* just resetting to NULL might not be desired, need to
591        * have value reinitialized also (for values defaulting
592        * to other default value states than a NULL data pointer),
593        * g_value_reset() will handle this
594        */
595       g_value_reset (value);
596       return;
597     }
598 
599   key.type = G_VALUE_TYPE (value);
600   node = g_bsearch_array_lookup (boxed_bsa, &boxed_bconfig, &key);
601 
602   if (node)
603     {
604       /* we proxy this type, free contents and copy right away */
605       if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
606 	node->free (value->data[0].v_pointer);
607       value->data[1].v_uint = need_free ? 0 : G_VALUE_NOCOPY_CONTENTS;
608       value->data[0].v_pointer = need_copy ? node->copy (boxed) : boxed;
609     }
610   else
611     {
612       /* we don't handle this type, free contents and let g_boxed_copy()
613        * figure what's required
614        */
615       if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
616 	g_boxed_free (G_VALUE_TYPE (value), value->data[0].v_pointer);
617       value->data[1].v_uint = need_free ? 0 : G_VALUE_NOCOPY_CONTENTS;
618       value->data[0].v_pointer = need_copy ? g_boxed_copy (G_VALUE_TYPE (value), boxed) : boxed;
619     }
620 }
621 
622 /**
623  * g_value_set_boxed:
624  * @value: a valid #GValue of %G_TYPE_BOXED derived type
625  * @v_boxed: boxed value to be set
626  *
627  * Set the contents of a %G_TYPE_BOXED derived #GValue to @v_boxed.
628  */
629 void
g_value_set_boxed(GValue * value,gconstpointer boxed)630 g_value_set_boxed (GValue       *value,
631 		   gconstpointer boxed)
632 {
633   g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
634   g_return_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)));
635 
636   value_set_boxed_internal (value, boxed, TRUE, TRUE);
637 }
638 
639 /**
640  * g_value_set_static_boxed:
641  * @value: a valid #GValue of %G_TYPE_BOXED derived type
642  * @v_boxed: static boxed value to be set
643  *
644  * Set the contents of a %G_TYPE_BOXED derived #GValue to @v_boxed.
645  * The boxed value is assumed to be static, and is thus not duplicated
646  * when setting the #GValue.
647  */
648 void
g_value_set_static_boxed(GValue * value,gconstpointer boxed)649 g_value_set_static_boxed (GValue       *value,
650 			  gconstpointer boxed)
651 {
652   g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
653   g_return_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)));
654 
655   value_set_boxed_internal (value, boxed, FALSE, FALSE);
656 }
657 
658 /**
659  * g_value_set_boxed_take_ownership:
660  * @value: a valid #GValue of %G_TYPE_BOXED derived type
661  * @v_boxed: duplicated unowned boxed value to be set
662  *
663  * This is an internal function introduced mainly for C marshallers.
664  *
665  * Deprecated: 2.4: Use g_value_take_boxed() instead.
666  */
667 void
g_value_set_boxed_take_ownership(GValue * value,gconstpointer boxed)668 g_value_set_boxed_take_ownership (GValue       *value,
669 				  gconstpointer boxed)
670 {
671   g_value_take_boxed (value, boxed);
672 }
673 
674 /**
675  * g_value_take_boxed:
676  * @value: a valid #GValue of %G_TYPE_BOXED derived type
677  * @v_boxed: duplicated unowned boxed value to be set
678  *
679  * Sets the contents of a %G_TYPE_BOXED derived #GValue to @v_boxed
680  * and takes over the ownership of the callers reference to @v_boxed;
681  * the caller doesn't have to unref it any more.
682  *
683  * Since: 2.4
684  */
685 void
g_value_take_boxed(GValue * value,gconstpointer boxed)686 g_value_take_boxed (GValue       *value,
687 		    gconstpointer boxed)
688 {
689   g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
690   g_return_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)));
691 
692   value_set_boxed_internal (value, boxed, FALSE, TRUE);
693 }
694 
695 #define __G_BOXED_C__
696 #include "gobjectaliasdef.c"
697