fixed dealing with collection/lcopy of NULL values.
[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 #include "gvaluecollector.h"
24
25
26 /* --- typedefs & structures --- */
27 typedef struct
28 {
29   GType          value_type1;
30   GType          value_type2;
31   GValueExchange func;
32   GType          first_type;
33 } ExchangeEntry;
34
35
36 /* --- variables --- */
37 static GHashTable *param_exchange_ht = NULL;
38
39
40 /* --- functions --- */
41 void
42 g_value_init (GValue *value,
43               GType   g_type)
44 {
45   GTypeValueTable *value_table = g_type_value_table_peek (g_type);
46   
47   g_return_if_fail (value != NULL);
48   g_return_if_fail (G_VALUE_TYPE (value) == 0);
49   
50   if (value_table)
51     {
52       memset (value, 0, sizeof (*value));
53       value->g_type = g_type;
54       value_table->value_init (value);
55     }
56   else
57     g_warning (G_STRLOC ": cannot initialize value of type `%s' which has no GTypeValueTable",
58                g_type_name (g_type));
59 }
60
61 void
62 g_value_copy (const GValue *src_value,
63               GValue       *dest_value)
64 {
65   GTypeValueTable *value_table;
66   
67   g_return_if_fail (G_IS_VALUE (src_value));
68   g_return_if_fail (G_IS_VALUE (dest_value));
69   g_return_if_fail (g_type_is_a (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)));
70   
71   value_table = g_type_value_table_peek (G_VALUE_TYPE (dest_value));
72   if (!value_table)
73     g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (dest_value)) != NULL);
74   
75   if (src_value != dest_value)
76     {
77       /* make sure dest_value's value is free()d and zero initialized */
78       g_value_reset (dest_value);
79       
80       value_table->value_copy (src_value, dest_value);
81     }
82 }
83
84 gboolean
85 g_value_fits_pointer (const GValue *value)
86 {
87   GTypeValueTable *value_table;
88
89   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
90
91   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
92   if (!value_table)
93     g_return_val_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL, FALSE);
94
95   return value_table->value_peek_pointer != NULL;
96 }
97
98 gpointer
99 g_value_get_as_pointer (const GValue *value)
100 {
101   GTypeValueTable *value_table;
102
103   g_return_val_if_fail (G_IS_VALUE (value), NULL);
104
105   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
106   if (!value_table)
107     g_return_val_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL, NULL);
108   if (!value_table->value_peek_pointer)
109     g_return_val_if_fail (g_value_fits_pointer (value) == TRUE, NULL);
110
111   return value_table->value_peek_pointer (value);
112 }
113
114 void
115 g_value_set_instance (GValue  *value,
116                       gpointer instance)
117 {
118   g_return_if_fail (G_IS_VALUE (value));
119   
120   g_value_reset (value);
121   if (instance)
122     {
123       GType g_type = G_VALUE_TYPE (value);
124       GTypeValueTable *value_table = g_type_value_table_peek (g_type);
125       GTypeCValue cvalue = { 0, };
126       guint nth_value = 0;
127       guint collect_type = value_table->collect_type;
128       gchar *error_msg;
129       
130       g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
131       g_return_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (instance), G_VALUE_TYPE (value)));
132       g_return_if_fail (value_table->collect_type == G_VALUE_COLLECT_POINTER);
133       
134       cvalue.v_pointer = instance;
135       error_msg = value_table->collect_value (value, nth_value++, &collect_type, &cvalue);
136       
137       /* this shouldn't be triggered, instance types should collect just one pointer,
138        * but since we have to follow the calling conventions for collect_value(),
139        * we can attempt to feed them with 0s if they insist on extra args.
140        */
141       while (collect_type && !error_msg)
142         {
143           memset (&cvalue, 0, sizeof (cvalue));
144           error_msg = value_table->collect_value (value, nth_value++, &collect_type, &cvalue);
145         }
146       
147       if (error_msg)
148         {
149           g_warning ("%s: %s", G_STRLOC, error_msg);
150           g_free (error_msg);
151           
152           /* we purposely leak the value here, it might not be
153            * in a sane state if an error condition occoured
154            */
155           memset (value, 0, sizeof (*value));
156           value->g_type = g_type;
157           value_table->value_init (value);
158         }
159     }
160 }
161
162 void
163 g_value_unset (GValue *value)
164 {
165   GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
166   
167   g_return_if_fail (G_IS_VALUE (value));
168   if (!value_table)
169     g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL);
170   
171   if (value_table->value_free)
172     value_table->value_free (value);
173   memset (value, 0, sizeof (*value));
174 }
175
176 void
177 g_value_reset (GValue *value)
178 {
179   GTypeValueTable *value_table;
180   GType g_type;
181   
182   g_return_if_fail (G_IS_VALUE (value));
183   
184   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
185   g_type = G_VALUE_TYPE (value);
186   
187   if (value_table->value_free)
188     value_table->value_free (value);
189   memset (value, 0, sizeof (*value));
190   
191   value->g_type = g_type;
192   value_table->value_init (value);
193 }
194
195 static gboolean
196 exchange_entries_equal (gconstpointer v1,
197                         gconstpointer v2)
198 {
199   const ExchangeEntry *entry1 = v1;
200   const ExchangeEntry *entry2 = v2;
201   
202   return (entry1->value_type1 == entry2->value_type1 &&
203           entry1->value_type2 == entry2->value_type2);
204 }
205
206 static guint
207 exchange_entry_hash (gconstpointer key)
208 {
209   const ExchangeEntry *entry = key;
210   
211   return entry->value_type1 ^ entry->value_type2;
212 }
213
214 static void
215 value_exchange_memcpy (GValue *value1,
216                        GValue *value2)
217 {
218   GValue tmp_value;
219   
220   memcpy (&tmp_value.data, &value1->data, sizeof (value1->data));
221   memcpy (&value1->data, &value2->data, sizeof (value1->data));
222   memcpy (&value2->data, &tmp_value.data, sizeof (value2->data));
223 }
224
225 static inline GValueExchange
226 exchange_func_lookup (GType     value_type1,
227                       GType     value_type2,
228                       gboolean *need_swap)
229 {
230   if (value_type1 == value_type2)
231     return value_exchange_memcpy;
232   else
233     {
234       GType type1 = value_type1;
235       
236       do
237         {
238           GType type2 = value_type2;
239           
240           do
241             {
242               ExchangeEntry entry, *ret;
243               
244               entry.value_type1 = MIN (type1, type2);
245               entry.value_type2 = MAX (type1, type2);
246               ret = g_hash_table_lookup (param_exchange_ht, &entry);
247               if (ret)
248                 {
249                   if (need_swap)
250                     *need_swap = ret->first_type == type2;
251                   
252                   return ret->func;
253                 }
254               
255               type2 = g_type_parent (type2);
256             }
257           while (type2);
258           
259           type1 = g_type_parent (type1);
260         }
261       while (type1);
262     }
263   
264   return NULL;
265 }
266
267 void
268 g_value_register_exchange_func (GType          value_type1,
269                                 GType          value_type2,
270                                 GValueExchange func)
271 {
272   ExchangeEntry entry;
273   
274   g_return_if_fail (g_type_name (value_type1) != NULL);
275   g_return_if_fail (g_type_name (value_type2) != NULL);
276   g_return_if_fail (func != NULL);
277   
278   entry.value_type1 = MIN (value_type1, value_type2);
279   entry.value_type2 = MAX (value_type1, value_type2);
280   if (param_exchange_ht && g_hash_table_lookup (param_exchange_ht, &entry))
281     g_warning (G_STRLOC ": cannot re-register param value exchange function "
282                "for `%s' and `%s'",
283                g_type_name (value_type1),
284                g_type_name (value_type2));
285   else
286     {
287       ExchangeEntry *entry = g_new (ExchangeEntry, 1);
288       
289       if (!param_exchange_ht)
290         param_exchange_ht = g_hash_table_new (exchange_entry_hash, exchange_entries_equal);
291       entry->value_type1 = MIN (value_type1, value_type2);
292       entry->value_type2 = MAX (value_type1, value_type2);
293       entry->func = func;
294       entry->first_type = value_type1;
295       g_hash_table_insert (param_exchange_ht, entry, entry);
296     }
297 }
298
299 gboolean
300 g_value_types_exchangable (GType value_type1,
301                            GType value_type2)
302 {
303   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE); /* these might bite us, think G_TYPE_ENUM */
304   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type2), FALSE);
305   
306   return exchange_func_lookup (value_type1, value_type2, NULL) != NULL;
307 }
308
309 gboolean
310 g_values_exchange (GValue *value1,
311                    GValue *value2)
312 {
313   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
314   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
315   
316   if (value1 != value2)
317     {
318       gboolean need_swap;
319       GValueExchange value_exchange = exchange_func_lookup (G_VALUE_TYPE (value1),
320                                                             G_VALUE_TYPE (value2),
321                                                             &need_swap);
322       if (value_exchange)
323         {
324           if (need_swap)
325             value_exchange (value2, value1);
326           else
327             value_exchange (value1, value2);
328         }
329       
330       return value_exchange != NULL;
331     }
332   
333   return TRUE;
334 }
335
336 gboolean
337 g_value_convert (const GValue *src_value,
338                  GValue       *dest_value)
339 {
340   gboolean success = TRUE;
341   
342   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
343   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
344   
345   if (src_value != dest_value)
346     {
347       GValue tmp_value = { 0, };
348       
349       g_value_init (&tmp_value, G_VALUE_TYPE (src_value));
350       g_value_copy (src_value, &tmp_value);
351       
352       success = g_values_exchange (&tmp_value, dest_value);
353       g_value_unset (&tmp_value);
354     }
355   
356   return success;
357 }