Home | History | Annotate | Download | only in gobject
      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
     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 */
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    218 gstring_free (gpointer boxed)
    219 {
    220   GString *gstring = boxed;
    221 
    222   g_string_free (gstring, TRUE);
    223 }
    224 
    225 GType
    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
    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
    246 hash_table_free (gpointer boxed)
    247 {
    248   GHashTable *hash_table = boxed;
    249   g_hash_table_unref (hash_table);
    250 }
    251 
    252 GType
    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
    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
    278 boxed_proxy_value_init (GValue *value)
    279 {
    280   value->data[0].v_pointer = NULL;
    281 }
    282 
    283 static void
    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
    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
    313 boxed_proxy_value_peek_pointer (const GValue *value)
    314 {
    315   return value->data[0].v_pointer;
    316 }
    317 
    318 static gchar*
    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*
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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