(root)/
glib-2.79.0/
gobject/
gboxed.c
       1  /* GObject - GLib Type, Object, Parameter and Signal Library
       2   * Copyright (C) 2000-2001 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  #include "config.h"
      21  
      22  #include <string.h>
      23  
      24  /* for GValueArray */
      25  #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
      26  #define GLIB_DISABLE_DEPRECATION_WARNINGS
      27  #endif
      28  
      29  #include "gboxed.h"
      30  #include "gclosure.h"
      31  #include "gtype-private.h"
      32  #include "gvalue.h"
      33  #include "gvaluearray.h"
      34  #include "gvaluecollector.h"
      35  
      36  static inline void              /* keep this function in sync with gvalue.c */
      37  value_meminit (GValue *value,
      38  	       GType   value_type)
      39  {
      40    value->g_type = value_type;
      41    memset (value->data, 0, sizeof (value->data));
      42  }
      43  
      44  static GValue *
      45  value_copy (GValue *src_value)
      46  {
      47    GValue *dest_value = g_new0 (GValue, 1);
      48  
      49    if (G_VALUE_TYPE (src_value))
      50      {
      51        g_value_init (dest_value, G_VALUE_TYPE (src_value));
      52        g_value_copy (src_value, dest_value);
      53      }
      54    return dest_value;
      55  }
      56  
      57  static void
      58  value_free (GValue *value)
      59  {
      60    if (G_VALUE_TYPE (value))
      61      g_value_unset (value);
      62    g_free (value);
      63  }
      64  
      65  static GPollFD *
      66  pollfd_copy (GPollFD *src)
      67  {
      68    GPollFD *dest = g_new0 (GPollFD, 1);
      69    /* just a couple of integers */
      70    memcpy (dest, src, sizeof (GPollFD));
      71    return dest;
      72  }
      73  
      74  void
      75  _g_boxed_type_init (void)
      76  {
      77    const GTypeInfo info = {
      78      0,                          /* class_size */
      79      NULL,                       /* base_init */
      80      NULL,                       /* base_destroy */
      81      NULL,                       /* class_init */
      82      NULL,                       /* class_destroy */
      83      NULL,                       /* class_data */
      84      0,                          /* instance_size */
      85      0,                          /* n_preallocs */
      86      NULL,                       /* instance_init */
      87      NULL,                       /* value_table */
      88    };
      89    const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
      90    GType type G_GNUC_UNUSED  /* when compiling with G_DISABLE_ASSERT */;
      91  
      92    /* G_TYPE_BOXED
      93     */
      94    type = g_type_register_fundamental (G_TYPE_BOXED, g_intern_static_string ("GBoxed"), &info, &finfo,
      95  				      G_TYPE_FLAG_ABSTRACT | G_TYPE_FLAG_VALUE_ABSTRACT);
      96    g_assert (type == G_TYPE_BOXED);
      97  }
      98  
      99  static GString *
     100  gstring_copy (GString *src_gstring)
     101  {
     102    return g_string_new_len (src_gstring->str, src_gstring->len);
     103  }
     104  
     105  static void
     106  gstring_free (GString *gstring)
     107  {
     108    g_string_free (gstring, TRUE);
     109  }
     110  
     111  G_DEFINE_BOXED_TYPE (GClosure, g_closure, g_closure_ref, g_closure_unref)
     112  G_DEFINE_BOXED_TYPE (GValue, g_value, value_copy, value_free)
     113  G_DEFINE_BOXED_TYPE (GValueArray, g_value_array, g_value_array_copy, g_value_array_free)
     114  G_DEFINE_BOXED_TYPE (GDate, g_date, g_date_copy, g_date_free)
     115  /* the naming is a bit odd, but GString is obviously not G_TYPE_STRING */
     116  G_DEFINE_BOXED_TYPE (GString, g_gstring, gstring_copy, gstring_free)
     117  G_DEFINE_BOXED_TYPE (GHashTable, g_hash_table, g_hash_table_ref, g_hash_table_unref)
     118  G_DEFINE_BOXED_TYPE (GArray, g_array, g_array_ref, g_array_unref)
     119  G_DEFINE_BOXED_TYPE (GPtrArray, g_ptr_array,g_ptr_array_ref, g_ptr_array_unref)
     120  G_DEFINE_BOXED_TYPE (GByteArray, g_byte_array, g_byte_array_ref, g_byte_array_unref)
     121  G_DEFINE_BOXED_TYPE (GBytes, g_bytes, g_bytes_ref, g_bytes_unref)
     122  G_DEFINE_BOXED_TYPE (GTree, g_tree, g_tree_ref, g_tree_unref)
     123  
     124  G_DEFINE_BOXED_TYPE (GRegex, g_regex, g_regex_ref, g_regex_unref)
     125  G_DEFINE_BOXED_TYPE (GMatchInfo, g_match_info, g_match_info_ref, g_match_info_unref)
     126  
     127  #define g_variant_type_get_type g_variant_type_get_gtype
     128  G_DEFINE_BOXED_TYPE (GVariantType, g_variant_type, g_variant_type_copy, g_variant_type_free)
     129  #undef g_variant_type_get_type
     130  
     131  G_DEFINE_BOXED_TYPE (GVariantBuilder, g_variant_builder, g_variant_builder_ref, g_variant_builder_unref)
     132  G_DEFINE_BOXED_TYPE (GVariantDict, g_variant_dict, g_variant_dict_ref, g_variant_dict_unref)
     133  
     134  G_DEFINE_BOXED_TYPE (GError, g_error, g_error_copy, g_error_free)
     135  
     136  G_DEFINE_BOXED_TYPE (GDateTime, g_date_time, g_date_time_ref, g_date_time_unref)
     137  G_DEFINE_BOXED_TYPE (GTimeZone, g_time_zone, g_time_zone_ref, g_time_zone_unref)
     138  G_DEFINE_BOXED_TYPE (GKeyFile, g_key_file, g_key_file_ref, g_key_file_unref)
     139  G_DEFINE_BOXED_TYPE (GMappedFile, g_mapped_file, g_mapped_file_ref, g_mapped_file_unref)
     140  G_DEFINE_BOXED_TYPE (GBookmarkFile, g_bookmark_file, g_bookmark_file_copy, g_bookmark_file_free)
     141  G_DEFINE_BOXED_TYPE (GHmac, g_hmac, g_hmac_ref, g_hmac_unref)
     142  G_DEFINE_BOXED_TYPE (GDir, g_dir, g_dir_ref, g_dir_unref)
     143  
     144  G_DEFINE_BOXED_TYPE (GMainLoop, g_main_loop, g_main_loop_ref, g_main_loop_unref)
     145  G_DEFINE_BOXED_TYPE (GMainContext, g_main_context, g_main_context_ref, g_main_context_unref)
     146  G_DEFINE_BOXED_TYPE (GSource, g_source, g_source_ref, g_source_unref)
     147  G_DEFINE_BOXED_TYPE (GPollFD, g_pollfd, pollfd_copy, g_free)
     148  G_DEFINE_BOXED_TYPE (GMarkupParseContext, g_markup_parse_context, g_markup_parse_context_ref, g_markup_parse_context_unref)
     149  
     150  G_DEFINE_BOXED_TYPE (GThread, g_thread, g_thread_ref, g_thread_unref)
     151  G_DEFINE_BOXED_TYPE (GChecksum, g_checksum, g_checksum_copy, g_checksum_free)
     152  G_DEFINE_BOXED_TYPE (GUri, g_uri, g_uri_ref, g_uri_unref)
     153  
     154  G_DEFINE_BOXED_TYPE (GOptionGroup, g_option_group, g_option_group_ref, g_option_group_unref)
     155  G_DEFINE_BOXED_TYPE (GPatternSpec, g_pattern_spec, g_pattern_spec_copy, g_pattern_spec_free);
     156  
     157  G_DEFINE_BOXED_TYPE (GStrvBuilder, g_strv_builder, g_strv_builder_ref, g_strv_builder_unref);
     158  
     159  /* This one can't use G_DEFINE_BOXED_TYPE (GStrv, g_strv, g_strdupv, g_strfreev) */
     160  GType
     161  g_strv_get_type (void)
     162  {
     163    static GType static_g_define_type_id = 0;
     164  
     165    if (g_once_init_enter_pointer (&static_g_define_type_id))
     166      {
     167        GType g_define_type_id =
     168          g_boxed_type_register_static (g_intern_static_string ("GStrv"),
     169                                        (GBoxedCopyFunc) g_strdupv,
     170                                        (GBoxedFreeFunc) g_strfreev);
     171  
     172        g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id);
     173      }
     174  
     175    return static_g_define_type_id;
     176  }
     177  
     178  GType
     179  g_variant_get_gtype (void)
     180  {
     181    return G_TYPE_VARIANT;
     182  }
     183  
     184  static void
     185  boxed_proxy_value_init (GValue *value)
     186  {
     187    value->data[0].v_pointer = NULL;
     188  }
     189  
     190  static void
     191  boxed_proxy_value_free (GValue *value)
     192  {
     193    if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
     194      _g_type_boxed_free (G_VALUE_TYPE (value), value->data[0].v_pointer);
     195  }
     196  
     197  static void
     198  boxed_proxy_value_copy (const GValue *src_value,
     199  			GValue       *dest_value)
     200  {
     201    if (src_value->data[0].v_pointer)
     202      dest_value->data[0].v_pointer = _g_type_boxed_copy (G_VALUE_TYPE (src_value), src_value->data[0].v_pointer);
     203    else
     204      dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
     205  }
     206  
     207  static gpointer
     208  boxed_proxy_value_peek_pointer (const GValue *value)
     209  {
     210    return value->data[0].v_pointer;
     211  }
     212  
     213  static gchar*
     214  boxed_proxy_collect_value (GValue      *value,
     215  			   guint        n_collect_values,
     216  			   GTypeCValue *collect_values,
     217  			   guint        collect_flags)
     218  {
     219    if (!collect_values[0].v_pointer)
     220      value->data[0].v_pointer = NULL;
     221    else
     222      {
     223        if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
     224  	{
     225  	  value->data[0].v_pointer = collect_values[0].v_pointer;
     226  	  value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
     227  	}
     228        else
     229  	value->data[0].v_pointer = _g_type_boxed_copy (G_VALUE_TYPE (value), collect_values[0].v_pointer);
     230      }
     231  
     232    return NULL;
     233  }
     234  
     235  static gchar*
     236  boxed_proxy_lcopy_value (const GValue *value,
     237  			 guint         n_collect_values,
     238  			 GTypeCValue  *collect_values,
     239  			 guint         collect_flags)
     240  {
     241    gpointer *boxed_p = collect_values[0].v_pointer;
     242  
     243    g_return_val_if_fail (boxed_p != NULL, g_strdup_printf ("value location for '%s' passed as NULL", G_VALUE_TYPE_NAME (value)));
     244  
     245    if (!value->data[0].v_pointer)
     246      *boxed_p = NULL;
     247    else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
     248      *boxed_p = value->data[0].v_pointer;
     249    else
     250      *boxed_p = _g_type_boxed_copy (G_VALUE_TYPE (value), value->data[0].v_pointer);
     251  
     252    return NULL;
     253  }
     254  
     255  /**
     256   * g_boxed_type_register_static:
     257   * @name: Name of the new boxed type.
     258   * @boxed_copy: (scope forever): Boxed structure copy function.
     259   * @boxed_free: (scope forever): Boxed structure free function.
     260   *
     261   * This function creates a new %G_TYPE_BOXED derived type id for a new
     262   * boxed type with name @name.
     263   *
     264   * Boxed type handling functions have to be provided to copy and free
     265   * opaque boxed structures of this type.
     266   *
     267   * For the general case, it is recommended to use G_DEFINE_BOXED_TYPE()
     268   * instead of calling g_boxed_type_register_static() directly. The macro 
     269   * will create the appropriate `*_get_type()` function for the boxed type.
     270   *
     271   * Returns: New %G_TYPE_BOXED derived type id for @name.
     272   */
     273  GType
     274  g_boxed_type_register_static (const gchar   *name,
     275  			      GBoxedCopyFunc boxed_copy,
     276  			      GBoxedFreeFunc boxed_free)
     277  {
     278    static const GTypeValueTable vtable = {
     279      boxed_proxy_value_init,
     280      boxed_proxy_value_free,
     281      boxed_proxy_value_copy,
     282      boxed_proxy_value_peek_pointer,
     283      "p",
     284      boxed_proxy_collect_value,
     285      "p",
     286      boxed_proxy_lcopy_value,
     287    };
     288    GTypeInfo type_info = {
     289      0,			/* class_size */
     290      NULL,		/* base_init */
     291      NULL,		/* base_finalize */
     292      NULL,		/* class_init */
     293      NULL,		/* class_finalize */
     294      NULL,		/* class_data */
     295      0,			/* instance_size */
     296      0,			/* n_preallocs */
     297      NULL,		/* instance_init */
     298      &vtable,		/* value_table */
     299    };
     300    GType type;
     301  
     302    g_return_val_if_fail (name != NULL, 0);
     303    g_return_val_if_fail (boxed_copy != NULL, 0);
     304    g_return_val_if_fail (boxed_free != NULL, 0);
     305    g_return_val_if_fail (g_type_from_name (name) == 0, 0);
     306  
     307    type = g_type_register_static (G_TYPE_BOXED, name, &type_info, 0);
     308  
     309    /* install proxy functions upon successful registration */
     310    if (type)
     311      _g_type_boxed_init (type, boxed_copy, boxed_free);
     312  
     313    return type;
     314  }
     315  
     316  /**
     317   * g_boxed_copy:
     318   * @boxed_type: The type of @src_boxed.
     319   * @src_boxed: (not nullable): The boxed structure to be copied.
     320   * 
     321   * Provide a copy of a boxed structure @src_boxed which is of type @boxed_type.
     322   * 
     323   * Returns: (transfer full) (not nullable): The newly created copy of the boxed
     324   *    structure.
     325   */
     326  gpointer
     327  g_boxed_copy (GType         boxed_type,
     328  	      gconstpointer src_boxed)
     329  {
     330    GTypeValueTable *value_table;
     331    gpointer dest_boxed;
     332  
     333    g_return_val_if_fail (G_TYPE_IS_BOXED (boxed_type), NULL);
     334    g_return_val_if_fail (G_TYPE_IS_ABSTRACT (boxed_type) == FALSE, NULL);
     335    g_return_val_if_fail (src_boxed != NULL, NULL);
     336  
     337    value_table = g_type_value_table_peek (boxed_type);
     338    g_assert (value_table != NULL);
     339  
     340    /* check if our proxying implementation is used, we can short-cut here */
     341    if (value_table->value_copy == boxed_proxy_value_copy)
     342      dest_boxed = _g_type_boxed_copy (boxed_type, (gpointer) src_boxed);
     343    else
     344      {
     345        GValue src_value, dest_value;
     346  
     347        /* we heavily rely on third-party boxed type value vtable
     348         * implementations to follow normal boxed value storage
     349         * (data[0].v_pointer is the boxed struct, and
     350         * data[1].v_uint holds the G_VALUE_NOCOPY_CONTENTS flag,
     351         * rest zero).
     352         * but then, we can expect that since we laid out the
     353         * g_boxed_*() API.
     354         * data[1].v_uint&G_VALUE_NOCOPY_CONTENTS shouldn't be set
     355         * after a copy.
     356         */
     357        /* equiv. to g_value_set_static_boxed() */
     358        value_meminit (&src_value, boxed_type);
     359        src_value.data[0].v_pointer = (gpointer) src_boxed;
     360        src_value.data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
     361  
     362        /* call third-party code copy function, fingers-crossed */
     363        value_meminit (&dest_value, boxed_type);
     364        value_table->value_copy (&src_value, &dest_value);
     365  
     366        /* double check and grouse if things went wrong */
     367        if (dest_value.data[1].v_ulong)
     368  	g_warning ("the copy_value() implementation of type '%s' seems to make use of reserved GValue fields",
     369  		   g_type_name (boxed_type));
     370  
     371        dest_boxed = dest_value.data[0].v_pointer;
     372      }
     373  
     374    return dest_boxed;
     375  }
     376  
     377  /**
     378   * g_boxed_free:
     379   * @boxed_type: The type of @boxed.
     380   * @boxed: (not nullable): The boxed structure to be freed.
     381   *
     382   * Free the boxed structure @boxed which is of type @boxed_type.
     383   */
     384  void
     385  g_boxed_free (GType    boxed_type,
     386  	      gpointer boxed)
     387  {
     388    GTypeValueTable *value_table;
     389  
     390    g_return_if_fail (G_TYPE_IS_BOXED (boxed_type));
     391    g_return_if_fail (G_TYPE_IS_ABSTRACT (boxed_type) == FALSE);
     392    g_return_if_fail (boxed != NULL);
     393  
     394    value_table = g_type_value_table_peek (boxed_type);
     395    g_assert (value_table != NULL);
     396  
     397    /* check if our proxying implementation is used, we can short-cut here */
     398    if (value_table->value_free == boxed_proxy_value_free)
     399      _g_type_boxed_free (boxed_type, boxed);
     400    else
     401      {
     402        GValue value;
     403  
     404        /* see g_boxed_copy() on why we think we can do this */
     405        value_meminit (&value, boxed_type);
     406        value.data[0].v_pointer = boxed;
     407        value_table->value_free (&value);
     408      }
     409  }
     410  
     411  /**
     412   * g_value_get_boxed:
     413   * @value: a valid #GValue of %G_TYPE_BOXED derived type
     414   *
     415   * Get the contents of a %G_TYPE_BOXED derived #GValue.
     416   *
     417   * Returns: (transfer none) (nullable): boxed contents of @value
     418   */
     419  gpointer
     420  g_value_get_boxed (const GValue *value)
     421  {
     422    g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), NULL);
     423    g_return_val_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)), NULL);
     424  
     425    return value->data[0].v_pointer;
     426  }
     427  
     428  /**
     429   * g_value_dup_boxed: (skip)
     430   * @value: a valid #GValue of %G_TYPE_BOXED derived type
     431   *
     432   * Get the contents of a %G_TYPE_BOXED derived #GValue.  Upon getting,
     433   * the boxed value is duplicated and needs to be later freed with
     434   * g_boxed_free(), e.g. like: g_boxed_free (G_VALUE_TYPE (@value),
     435   * return_value);
     436   *
     437   * Returns: (transfer full) (nullable): boxed contents of @value
     438   */
     439  gpointer
     440  g_value_dup_boxed (const GValue *value)
     441  {
     442    g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), NULL);
     443    g_return_val_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)), NULL);
     444  
     445    return value->data[0].v_pointer ? g_boxed_copy (G_VALUE_TYPE (value), value->data[0].v_pointer) : NULL;
     446  }
     447  
     448  static inline void
     449  value_set_boxed_internal (GValue       *value,
     450  			  gconstpointer boxed,
     451  			  gboolean      need_copy,
     452  			  gboolean      need_free)
     453  {
     454    if (!boxed)
     455      {
     456        /* just resetting to NULL might not be desired, need to
     457         * have value reinitialized also (for values defaulting
     458         * to other default value states than a NULL data pointer),
     459         * g_value_reset() will handle this
     460         */
     461        g_value_reset (value);
     462        return;
     463      }
     464  
     465    if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
     466      g_boxed_free (G_VALUE_TYPE (value), value->data[0].v_pointer);
     467    value->data[1].v_uint = need_free ? 0 : G_VALUE_NOCOPY_CONTENTS;
     468    value->data[0].v_pointer = need_copy ? g_boxed_copy (G_VALUE_TYPE (value), boxed) : (gpointer) boxed;
     469  }
     470  
     471  /**
     472   * g_value_set_boxed:
     473   * @value: a valid #GValue of %G_TYPE_BOXED derived type
     474   * @v_boxed: (nullable): boxed value to be set
     475   *
     476   * Set the contents of a %G_TYPE_BOXED derived #GValue to @v_boxed.
     477   */
     478  void
     479  g_value_set_boxed (GValue       *value,
     480  		   gconstpointer boxed)
     481  {
     482    g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
     483    g_return_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)));
     484  
     485    value_set_boxed_internal (value, boxed, TRUE, TRUE);
     486  }
     487  
     488  /**
     489   * g_value_set_static_boxed:
     490   * @value: a valid #GValue of %G_TYPE_BOXED derived type
     491   * @v_boxed: (nullable): static boxed value to be set
     492   *
     493   * Set the contents of a %G_TYPE_BOXED derived #GValue to @v_boxed.
     494   *
     495   * The boxed value is assumed to be static, and is thus not duplicated
     496   * when setting the #GValue.
     497   */
     498  void
     499  g_value_set_static_boxed (GValue       *value,
     500  			  gconstpointer boxed)
     501  {
     502    g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
     503    g_return_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)));
     504  
     505    value_set_boxed_internal (value, boxed, FALSE, FALSE);
     506  }
     507  
     508  /**
     509   * g_value_set_boxed_take_ownership:
     510   * @value: a valid #GValue of %G_TYPE_BOXED derived type
     511   * @v_boxed: (nullable): duplicated unowned boxed value to be set
     512   *
     513   * This is an internal function introduced mainly for C marshallers.
     514   *
     515   * Deprecated: 2.4: Use g_value_take_boxed() instead.
     516   */
     517  void
     518  g_value_set_boxed_take_ownership (GValue       *value,
     519  				  gconstpointer boxed)
     520  {
     521    g_value_take_boxed (value, boxed);
     522  }
     523  
     524  /**
     525   * g_value_take_boxed:
     526   * @value: a valid #GValue of %G_TYPE_BOXED derived type
     527   * @v_boxed: (nullable): duplicated unowned boxed value to be set
     528   *
     529   * Sets the contents of a %G_TYPE_BOXED derived #GValue to @v_boxed
     530   * and takes over the ownership of the caller’s reference to @v_boxed;
     531   * the caller doesn’t have to unref it any more.
     532   *
     533   * Since: 2.4
     534   */
     535  void
     536  g_value_take_boxed (GValue       *value,
     537  		    gconstpointer boxed)
     538  {
     539    g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
     540    g_return_if_fail (G_TYPE_IS_VALUE (G_VALUE_TYPE (value)));
     541  
     542    value_set_boxed_internal (value, boxed, FALSE, TRUE);
     543  }