(root)/
glib-2.79.0/
gobject/
gvalue.c
       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  _g_value_c_init (void)
      59  {
      60    transform_array = g_bsearch_array_create (&transform_bconfig);
      61  }
      62  
      63  static inline void		/* keep this function in sync with gvaluecollector.h and gboxed.c */
      64  value_meminit (GValue *value,
      65  	       GType   value_type)
      66  {
      67    value->g_type = value_type;
      68    memset (value->data, 0, sizeof (value->data));
      69  }
      70  
      71  /**
      72   * g_value_init:
      73   * @value: A zero-filled (uninitialized) #GValue structure.
      74   * @g_type: Type the #GValue should hold values of.
      75   *
      76   * Initializes @value with the default value of @type.
      77   *
      78   * Returns: (transfer none): the #GValue structure that has been passed in
      79   */
      80  GValue*
      81  g_value_init (GValue *value,
      82  	      GType   g_type)
      83  {
      84    GTypeValueTable *value_table;
      85    /* g_return_val_if_fail (G_TYPE_IS_VALUE (g_type), NULL);	be more elaborate below */
      86    g_return_val_if_fail (value != NULL, NULL);
      87    /* g_return_val_if_fail (G_VALUE_TYPE (value) == 0, NULL);	be more elaborate below */
      88  
      89    value_table = g_type_value_table_peek (g_type);
      90  
      91    if (value_table && G_VALUE_TYPE (value) == 0)
      92      {
      93        /* setup and init */
      94        value_meminit (value, g_type);
      95        value_table->value_init (value);
      96      }
      97    else if (G_VALUE_TYPE (value))
      98      g_critical ("%s: cannot initialize GValue with type '%s', the value has already been initialized as '%s'",
      99  	        G_STRLOC,
     100  	        g_type_name (g_type),
     101  	        g_type_name (G_VALUE_TYPE (value)));
     102    else /* !G_TYPE_IS_VALUE (g_type) */
     103      g_critical ("%s: cannot initialize GValue with type '%s', %s",
     104                  G_STRLOC,
     105                  g_type_name (g_type),
     106                  value_table ? "this type is abstract with regards to GValue use, use a more specific (derived) type" : "this type has no GTypeValueTable implementation");
     107    return value;
     108  }
     109  
     110  /**
     111   * g_value_copy:
     112   * @src_value: An initialized #GValue structure.
     113   * @dest_value: An initialized #GValue structure of the same type as @src_value.
     114   *
     115   * Copies the value of @src_value into @dest_value.
     116   */
     117  void
     118  g_value_copy (const GValue *src_value,
     119  	      GValue       *dest_value)
     120  {
     121    g_return_if_fail (src_value);
     122    g_return_if_fail (dest_value);
     123    g_return_if_fail (g_value_type_compatible (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)));
     124    
     125    if (src_value != dest_value)
     126      {
     127        GType dest_type = G_VALUE_TYPE (dest_value);
     128        GTypeValueTable *value_table = g_type_value_table_peek (dest_type);
     129  
     130        g_return_if_fail (value_table);
     131  
     132        /* make sure dest_value's value is free()d */
     133        if (value_table->value_free)
     134  	value_table->value_free (dest_value);
     135  
     136        /* setup and copy */
     137        value_meminit (dest_value, dest_type);
     138        value_table->value_copy (src_value, dest_value);
     139      }
     140  }
     141  
     142  /**
     143   * g_value_reset:
     144   * @value: An initialized #GValue structure.
     145   *
     146   * Clears the current value in @value and resets it to the default value
     147   * (as if the value had just been initialized).
     148   *
     149   * Returns: the #GValue structure that has been passed in
     150   */
     151  GValue*
     152  g_value_reset (GValue *value)
     153  {
     154    GTypeValueTable *value_table;
     155    GType g_type;
     156  
     157    g_return_val_if_fail (value, NULL);
     158    g_type = G_VALUE_TYPE (value);
     159  
     160    value_table = g_type_value_table_peek (g_type);
     161    g_return_val_if_fail (value_table, NULL);
     162  
     163    /* make sure value's value is free()d */
     164    if (value_table->value_free)
     165      value_table->value_free (value);
     166  
     167    /* setup and init */
     168    value_meminit (value, g_type);
     169    value_table->value_init (value);
     170  
     171    return value;
     172  }
     173  
     174  /**
     175   * g_value_unset:
     176   * @value: An initialized #GValue structure.
     177   *
     178   * Clears the current value in @value (if any) and "unsets" the type,
     179   * this releases all resources associated with this GValue. An unset
     180   * value is the same as an uninitialized (zero-filled) #GValue
     181   * structure.
     182   */
     183  void
     184  g_value_unset (GValue *value)
     185  {
     186    GTypeValueTable *value_table;
     187    
     188    if (value->g_type == 0)
     189      return;
     190  
     191    g_return_if_fail (value);
     192  
     193    value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
     194    g_return_if_fail (value_table);
     195  
     196    if (value_table->value_free)
     197      value_table->value_free (value);
     198    memset (value, 0, sizeof (*value));
     199  }
     200  
     201  /**
     202   * g_value_fits_pointer:
     203   * @value: An initialized #GValue structure.
     204   *
     205   * Determines if @value will fit inside the size of a pointer value.
     206   * This is an internal function introduced mainly for C marshallers.
     207   *
     208   * Returns: %TRUE if @value will fit inside a pointer value.
     209   */
     210  gboolean
     211  g_value_fits_pointer (const GValue *value)
     212  {
     213    GTypeValueTable *value_table;
     214  
     215    g_return_val_if_fail (value, FALSE);
     216  
     217    value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
     218    g_return_val_if_fail (value_table, FALSE);
     219  
     220    return value_table->value_peek_pointer != NULL;
     221  }
     222  
     223  /**
     224   * g_value_peek_pointer:
     225   * @value: An initialized #GValue structure
     226   *
     227   * Returns the value contents as pointer. This function asserts that
     228   * g_value_fits_pointer() returned %TRUE for the passed in value.
     229   * This is an internal function introduced mainly for C marshallers.
     230   *
     231   * Returns: (transfer none): the value contents as pointer
     232   */
     233  gpointer
     234  g_value_peek_pointer (const GValue *value)
     235  {
     236    GTypeValueTable *value_table;
     237  
     238    g_return_val_if_fail (value, NULL);
     239  
     240    value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
     241    g_return_val_if_fail (value_table, NULL);
     242  
     243    if (!value_table->value_peek_pointer)
     244      {
     245        g_return_val_if_fail (g_value_fits_pointer (value) == TRUE, NULL);
     246        return NULL;
     247      }
     248  
     249    return value_table->value_peek_pointer (value);
     250  }
     251  
     252  /**
     253   * g_value_set_instance:
     254   * @value: An initialized #GValue structure.
     255   * @instance: (nullable): the instance
     256   *
     257   * Sets @value from an instantiatable type via the
     258   * value_table's collect_value() function.
     259   */
     260  void
     261  g_value_set_instance (GValue  *value,
     262  		      gpointer instance)
     263  {
     264    GType g_type;
     265    GTypeValueTable *value_table;
     266    GTypeCValue cvalue;
     267    gchar *error_msg;
     268  
     269    g_return_if_fail (value);
     270    g_type = G_VALUE_TYPE (value);
     271    value_table = g_type_value_table_peek (g_type);
     272    g_return_if_fail (value_table);
     273  
     274    if (instance)
     275      {
     276        g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
     277        g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (instance), G_VALUE_TYPE (value)));
     278      }
     279    
     280    g_return_if_fail (strcmp (value_table->collect_format, "p") == 0);
     281    
     282    memset (&cvalue, 0, sizeof (cvalue));
     283    cvalue.v_pointer = instance;
     284    
     285    /* make sure value's value is free()d */
     286    if (value_table->value_free)
     287      value_table->value_free (value);
     288  
     289    /* setup and collect */
     290    value_meminit (value, g_type);
     291    error_msg = value_table->collect_value (value, 1, &cvalue, 0);
     292    if (error_msg)
     293      {
     294        g_critical ("%s: %s", G_STRLOC, error_msg);
     295        g_free (error_msg);
     296        
     297        /* we purposely leak the value here, it might not be
     298         * in a correct state if an error condition occurred
     299         */
     300        value_meminit (value, g_type);
     301        value_table->value_init (value);
     302      }
     303  }
     304  
     305  /**
     306   * g_value_init_from_instance:
     307   * @value: An uninitialized #GValue structure.
     308   * @instance: (type GObject.TypeInstance): the instance
     309   *
     310   * Initializes and sets @value from an instantiatable type via the
     311   * value_table's collect_value() function.
     312   *
     313   * Note: The @value will be initialised with the exact type of
     314   * @instance.  If you wish to set the @value's type to a different GType
     315   * (such as a parent class GType), you need to manually call
     316   * g_value_init() and g_value_set_instance().
     317   *
     318   * Since: 2.42
     319   */
     320  void
     321  g_value_init_from_instance (GValue  *value,
     322                              gpointer instance)
     323  {
     324    g_return_if_fail (value != NULL && G_VALUE_TYPE(value) == 0);
     325  
     326    if (G_IS_OBJECT (instance))
     327      {
     328        /* Fast-path.
     329         * If G_IS_OBJECT() succeeds we know:
     330         * * that instance is present and valid
     331         * * that it is a GObject, and therefore we can directly
     332         *   use the collect implementation (g_object_ref) */
     333        value_meminit (value, G_TYPE_FROM_INSTANCE (instance));
     334        value->data[0].v_pointer = g_object_ref (instance);
     335      }
     336    else
     337      {  
     338        GType g_type;
     339        GTypeValueTable *value_table;
     340        GTypeCValue cvalue;
     341        gchar *error_msg;
     342  
     343        g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
     344  
     345        g_type = G_TYPE_FROM_INSTANCE (instance);
     346        value_table = g_type_value_table_peek (g_type);
     347        g_return_if_fail (strcmp (value_table->collect_format, "p") == 0);
     348  
     349        memset (&cvalue, 0, sizeof (cvalue));
     350        cvalue.v_pointer = instance;
     351  
     352        /* setup and collect */
     353        value_meminit (value, g_type);
     354        value_table->value_init (value);
     355        error_msg = value_table->collect_value (value, 1, &cvalue, 0);
     356        if (error_msg)
     357          {
     358            g_critical ("%s: %s", G_STRLOC, error_msg);
     359            g_free (error_msg);
     360  
     361            /* we purposely leak the value here, it might not be
     362             * in a correct state if an error condition occurred
     363             */
     364            value_meminit (value, g_type);
     365            value_table->value_init (value);
     366          }
     367      }
     368  }
     369  
     370  static GType
     371  transform_lookup_get_parent_type (GType type)
     372  {
     373    if (g_type_fundamental (type) == G_TYPE_INTERFACE)
     374      return g_type_interface_instantiatable_prerequisite (type);
     375  
     376    return g_type_parent (type);
     377  }
     378  
     379  static GValueTransform
     380  transform_func_lookup (GType src_type,
     381  		       GType dest_type)
     382  {
     383    TransformEntry entry;
     384  
     385    entry.src_type = src_type;
     386    do
     387      {
     388        entry.dest_type = dest_type;
     389        do
     390  	{
     391  	  TransformEntry *e;
     392  	  
     393  	  e = g_bsearch_array_lookup (transform_array, &transform_bconfig, &entry);
     394  	  if (e)
     395  	    {
     396  	      /* need to check that there hasn't been a change in value handling */
     397  	      if (g_type_value_table_peek (entry.dest_type) == g_type_value_table_peek (dest_type) &&
     398  		  g_type_value_table_peek (entry.src_type) == g_type_value_table_peek (src_type))
     399  		return e->func;
     400  	    }
     401  	  entry.dest_type = transform_lookup_get_parent_type (entry.dest_type);
     402  	}
     403        while (entry.dest_type);
     404        
     405        entry.src_type = transform_lookup_get_parent_type (entry.src_type);
     406      }
     407    while (entry.src_type);
     408  
     409    return NULL;
     410  }
     411  
     412  static gint
     413  transform_entries_cmp (gconstpointer bsearch_node1,
     414  		       gconstpointer bsearch_node2)
     415  {
     416    const TransformEntry *e1 = bsearch_node1;
     417    const TransformEntry *e2 = bsearch_node2;
     418    gint cmp = G_BSEARCH_ARRAY_CMP (e1->src_type, e2->src_type);
     419  
     420    if (cmp)
     421      return cmp;
     422    else
     423      return G_BSEARCH_ARRAY_CMP (e1->dest_type, e2->dest_type);
     424  }
     425  
     426  /**
     427   * g_value_register_transform_func: (skip)
     428   * @src_type: Source type.
     429   * @dest_type: Target type.
     430   * @transform_func: a function which transforms values of type @src_type
     431   *  into value of type @dest_type
     432   *
     433   * Registers a value transformation function for use in g_value_transform().
     434   * A previously registered transformation function for @src_type and @dest_type
     435   * will be replaced.
     436   */
     437  void
     438  g_value_register_transform_func (GType           src_type,
     439  				 GType           dest_type,
     440  				 GValueTransform transform_func)
     441  {
     442    TransformEntry entry;
     443  
     444    /* these checks won't pass for dynamic types.
     445     * g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (src_type));
     446     * g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (dest_type));
     447     */
     448    g_return_if_fail (transform_func != NULL);
     449  
     450    entry.src_type = src_type;
     451    entry.dest_type = dest_type;
     452  
     453  #if 0 /* let transform function replacement be a valid operation */
     454    if (g_bsearch_array_lookup (transform_array, &transform_bconfig, &entry))
     455      g_warning ("reregistering value transformation function (%p) for '%s' to '%s'",
     456  	       transform_func,
     457  	       g_type_name (src_type),
     458  	       g_type_name (dest_type));
     459  #endif
     460  
     461    entry.func = transform_func;
     462    transform_array = g_bsearch_array_replace (transform_array, &transform_bconfig, &entry);
     463  }
     464  
     465  /**
     466   * g_value_type_transformable:
     467   * @src_type: Source type.
     468   * @dest_type: Target type.
     469   *
     470   * Check whether g_value_transform() is able to transform values
     471   * of type @src_type into values of type @dest_type. Note that for
     472   * the types to be transformable, they must be compatible or a
     473   * transformation function must be registered.
     474   *
     475   * Returns: %TRUE if the transformation is possible, %FALSE otherwise.
     476   */
     477  gboolean
     478  g_value_type_transformable (GType src_type,
     479  			    GType dest_type)
     480  {
     481    g_return_val_if_fail (src_type, FALSE);
     482    g_return_val_if_fail (dest_type, FALSE);
     483  
     484    return (g_value_type_compatible (src_type, dest_type) ||
     485  	  transform_func_lookup (src_type, dest_type) != NULL);
     486  }
     487  
     488  /**
     489   * g_value_type_compatible:
     490   * @src_type: source type to be copied.
     491   * @dest_type: destination type for copying.
     492   *
     493   * Returns whether a #GValue of type @src_type can be copied into
     494   * a #GValue of type @dest_type.
     495   *
     496   * Returns: %TRUE if g_value_copy() is possible with @src_type and @dest_type.
     497   */
     498  gboolean
     499  g_value_type_compatible (GType src_type,
     500  			 GType dest_type)
     501  {
     502    g_return_val_if_fail (src_type, FALSE);
     503    g_return_val_if_fail (dest_type, FALSE);
     504  
     505    /* Fast path */
     506    if (src_type == dest_type)
     507      return TRUE;
     508  
     509    return (g_type_is_a (src_type, dest_type) &&
     510  	  g_type_value_table_peek (dest_type) == g_type_value_table_peek (src_type));
     511  }
     512  
     513  /**
     514   * g_value_transform:
     515   * @src_value: Source value.
     516   * @dest_value: Target value.
     517   *
     518   * Tries to cast the contents of @src_value into a type appropriate
     519   * to store in @dest_value, e.g. to transform a %G_TYPE_INT value
     520   * into a %G_TYPE_FLOAT value. Performing transformations between
     521   * value types might incur precision lossage. Especially
     522   * transformations into strings might reveal seemingly arbitrary
     523   * results and shouldn't be relied upon for production code (such
     524   * as rcfile value or object property serialization).
     525   *
     526   * Returns: Whether a transformation rule was found and could be applied.
     527   *  Upon failing transformations, @dest_value is left untouched.
     528   */
     529  gboolean
     530  g_value_transform (const GValue *src_value,
     531  		   GValue       *dest_value)
     532  {
     533    GType dest_type;
     534  
     535    g_return_val_if_fail (src_value, FALSE);
     536    g_return_val_if_fail (dest_value, FALSE);
     537  
     538    dest_type = G_VALUE_TYPE (dest_value);
     539    if (g_value_type_compatible (G_VALUE_TYPE (src_value), dest_type))
     540      {
     541        g_value_copy (src_value, dest_value);
     542        
     543        return TRUE;
     544      }
     545    else
     546      {
     547        GValueTransform transform = transform_func_lookup (G_VALUE_TYPE (src_value), dest_type);
     548  
     549        if (transform)
     550  	{
     551  	  g_value_unset (dest_value);
     552  	  
     553  	  /* setup and transform */
     554  	  value_meminit (dest_value, dest_type);
     555  	  transform (src_value, dest_value);
     556  	  
     557  	  return TRUE;
     558  	}
     559      }
     560    return FALSE;
     561  }