added newly added gobject/ headers.
[platform/upstream/glib.git] / gobject / gvalue.c
1 /* GObject - GLib Type, Object, Parameter and Signal Library
2  * Copyright (C) 1997, 1998, 1999, 2000 Tim Janik and 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 <string.h>
21
22 #include "gvalue.h"
23
24
25 /* --- typedefs & structures --- */
26 typedef struct
27 {
28   GType          value_type1;
29   GType          value_type2;
30   GValueExchange func;
31   GType          first_type;
32 } ExchangeEntry;
33
34
35 /* --- variables --- */
36 static GHashTable *param_exchange_ht = NULL;
37
38
39 /* --- functions --- */
40 void
41 g_value_init (GValue *value,
42               GType   g_type)
43 {
44   GTypeValueTable *value_table = g_type_value_table_peek (g_type);
45   
46   g_return_if_fail (value != NULL);
47   g_return_if_fail (G_VALUE_TYPE (value) == 0);
48   
49   if (value_table)
50     {
51       memset (value, 0, sizeof (*value));
52       value->g_type = g_type;
53       value_table->value_init (value);
54     }
55   else
56     g_warning (G_STRLOC ": cannot initialize value of type `%s' which has no GTypeValueTable",
57                g_type_name (g_type));
58 }
59
60 void
61 g_value_copy (const GValue *src_value,
62               GValue       *dest_value)
63 {
64   GTypeValueTable *value_table;
65   
66   g_return_if_fail (G_IS_VALUE (src_value));
67   g_return_if_fail (G_IS_VALUE (dest_value));
68   g_return_if_fail (g_type_is_a (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)));
69
70   value_table = g_type_value_table_peek (G_VALUE_TYPE (dest_value));
71   if (!value_table)
72     g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (dest_value)) != NULL);
73   
74   if (src_value != dest_value)
75     {
76       /* make sure dest_value's value is free()d and zero initialized */
77       g_value_reset (dest_value);
78       
79       value_table->value_copy (src_value, dest_value);
80     }
81 }
82
83 gboolean
84 g_value_fits_pointer (const GValue *value)
85 {
86   GTypeValueTable *value_table;
87
88   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
89
90   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
91   if (!value_table)
92     g_return_val_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL, FALSE);
93
94   return value_table->value_peek_pointer != NULL;
95 }
96
97 gpointer
98 g_value_get_as_pointer (const GValue *value)
99 {
100   GTypeValueTable *value_table;
101
102   g_return_val_if_fail (G_IS_VALUE (value), NULL);
103
104   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
105   if (!value_table)
106     g_return_val_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL, NULL);
107   if (!value_table->value_peek_pointer)
108     g_return_val_if_fail (g_value_fits_pointer (value) == TRUE, NULL);
109
110   return value_table->value_peek_pointer (value);
111 }
112
113 void
114 g_value_unset (GValue *value)
115 {
116   GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
117   
118   g_return_if_fail (G_IS_VALUE (value));
119   if (!value_table)
120     g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL);
121   
122   if (value_table->value_free)
123     value_table->value_free (value);
124   memset (value, 0, sizeof (*value));
125 }
126
127 void
128 g_value_reset (GValue *value)
129 {
130   GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
131   GType g_type;
132   
133   g_return_if_fail (G_IS_VALUE (value));
134   
135   g_type = G_VALUE_TYPE (value);
136   
137   if (value_table->value_free)
138     value_table->value_free (value);
139   memset (value, 0, sizeof (*value));
140   
141   value->g_type = g_type;
142   value_table->value_init (value);
143 }
144
145 static gint
146 exchange_entries_equal (gconstpointer v1,
147                         gconstpointer v2)
148 {
149   const ExchangeEntry *entry1 = v1;
150   const ExchangeEntry *entry2 = v2;
151   
152   return (entry1->value_type1 == entry2->value_type1 &&
153           entry1->value_type2 == entry2->value_type2);
154 }
155
156 static guint
157 exchange_entry_hash (gconstpointer key)
158 {
159   const ExchangeEntry *entry = key;
160   
161   return entry->value_type1 ^ entry->value_type2;
162 }
163
164 static void
165 value_exchange_memcpy (GValue *value1,
166                        GValue *value2)
167 {
168   GValue tmp_value;
169   
170   memcpy (&tmp_value.data, &value1->data, sizeof (value1->data));
171   memcpy (&value1->data, &value2->data, sizeof (value1->data));
172   memcpy (&value2->data, &tmp_value.data, sizeof (value2->data));
173 }
174
175 static inline GValueExchange
176 exchange_func_lookup (GType     value_type1,
177                       GType     value_type2,
178                       gboolean *need_swap)
179 {
180   if (value_type1 == value_type2)
181     return value_exchange_memcpy;
182   else
183     {
184       GType type1 = value_type1;
185       
186       do
187         {
188           GType type2 = value_type2;
189           
190           do
191             {
192               ExchangeEntry entry, *ret;
193               
194               entry.value_type1 = MIN (type1, type2);
195               entry.value_type2 = MAX (type1, type2);
196               ret = g_hash_table_lookup (param_exchange_ht, &entry);
197               if (ret)
198                 {
199                   if (need_swap)
200                     *need_swap = ret->first_type == type2;
201                   
202                   return ret->func;
203                 }
204               
205               type2 = g_type_parent (type2);
206             }
207           while (type2);
208           
209           type1 = g_type_parent (type1);
210         }
211       while (type1);
212     }
213   
214   return NULL;
215 }
216
217 void
218 g_value_register_exchange_func (GType          value_type1,
219                                 GType          value_type2,
220                                 GValueExchange func)
221 {
222   ExchangeEntry entry;
223   
224   g_return_if_fail (g_type_name (value_type1) != NULL);
225   g_return_if_fail (g_type_name (value_type2) != NULL);
226   g_return_if_fail (func != NULL);
227   
228   entry.value_type1 = MIN (value_type1, value_type2);
229   entry.value_type2 = MAX (value_type1, value_type2);
230   if (param_exchange_ht && g_hash_table_lookup (param_exchange_ht, &entry))
231     g_warning (G_STRLOC ": cannot re-register param value exchange function "
232                "for `%s' and `%s'",
233                g_type_name (value_type1),
234                g_type_name (value_type2));
235   else
236     {
237       ExchangeEntry *entry = g_new (ExchangeEntry, 1);
238       
239       if (!param_exchange_ht)
240         param_exchange_ht = g_hash_table_new (exchange_entry_hash, exchange_entries_equal);
241       entry->value_type1 = MIN (value_type1, value_type2);
242       entry->value_type2 = MAX (value_type1, value_type2);
243       entry->func = func;
244       entry->first_type = value_type1;
245       g_hash_table_insert (param_exchange_ht, entry, entry);
246     }
247 }
248
249 gboolean
250 g_value_types_exchangable (GType value_type1,
251                            GType value_type2)
252 {
253   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE); /* these might bite us, think G_TYPE_ENUM */
254   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type2), FALSE);
255   
256   return exchange_func_lookup (value_type1, value_type2, NULL) != NULL;
257 }
258
259 gboolean
260 g_values_exchange (GValue *value1,
261                    GValue *value2)
262 {
263   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
264   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
265   
266   if (value1 != value2)
267     {
268       gboolean need_swap;
269       GValueExchange value_exchange = exchange_func_lookup (G_VALUE_TYPE (value1),
270                                                             G_VALUE_TYPE (value2),
271                                                             &need_swap);
272       if (value_exchange)
273         {
274           if (need_swap)
275             value_exchange (value2, value1);
276           else
277             value_exchange (value1, value2);
278         }
279       
280       return value_exchange != NULL;
281     }
282   
283   return TRUE;
284 }
285
286 gboolean
287 g_value_convert (const GValue *src_value,
288                  GValue       *dest_value)
289 {
290   gboolean success = TRUE;
291   
292   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
293   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
294   
295   if (src_value != dest_value)
296     {
297       GValue tmp_value = { 0, };
298       
299       g_value_init (&tmp_value, G_VALUE_TYPE (src_value));
300       g_value_copy (src_value, &tmp_value);
301       
302       success = g_values_exchange (&tmp_value, dest_value);
303       g_value_unset (&tmp_value);
304     }
305   
306   return success;
307 }