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