changed collect_format, collect_value() and lcopy_format, lcopy_value() in
[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       gchar *error_msg;
131       
132       g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
133       g_return_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (instance), G_VALUE_TYPE (value)));
134       g_return_if_fail (strcmp (value_table->collect_format, "p") == 0);
135       
136       cvalue.v_pointer = instance;
137       error_msg = value_table->collect_value (value, 1, &cvalue, 0);
138       
139       if (error_msg)
140         {
141           g_warning ("%s: %s", G_STRLOC, error_msg);
142           g_free (error_msg);
143           
144           /* we purposely leak the value here, it might not be
145            * in a sane state if an error condition occoured
146            */
147           memset (value, 0, sizeof (*value));
148           value->g_type = g_type;
149           value_table->value_init (value);
150         }
151     }
152 }
153
154 void
155 g_value_unset (GValue *value)
156 {
157   GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
158   
159   g_return_if_fail (G_IS_VALUE (value));
160   if (!value_table)
161     g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL);
162   
163   if (value_table->value_free)
164     value_table->value_free (value);
165   memset (value, 0, sizeof (*value));
166 }
167
168 void
169 g_value_reset (GValue *value)
170 {
171   GTypeValueTable *value_table;
172   GType g_type;
173   
174   g_return_if_fail (G_IS_VALUE (value));
175   
176   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
177   g_type = G_VALUE_TYPE (value);
178   
179   if (value_table->value_free)
180     value_table->value_free (value);
181   memset (value, 0, sizeof (*value));
182   
183   value->g_type = g_type;
184   value_table->value_init (value);
185 }
186
187 static gboolean
188 exchange_entries_equal (gconstpointer v1,
189                         gconstpointer v2)
190 {
191   const ExchangeEntry *entry1 = v1;
192   const ExchangeEntry *entry2 = v2;
193   
194   return (entry1->value_type1 == entry2->value_type1 &&
195           entry1->value_type2 == entry2->value_type2);
196 }
197
198 static guint
199 exchange_entry_hash (gconstpointer key)
200 {
201   const ExchangeEntry *entry = key;
202   
203   return entry->value_type1 ^ entry->value_type2;
204 }
205
206 static void
207 value_exchange_memcpy (GValue *value1,
208                        GValue *value2)
209 {
210   GValue tmp_value;
211   
212   memcpy (&tmp_value.data, &value1->data, sizeof (value1->data));
213   memcpy (&value1->data, &value2->data, sizeof (value1->data));
214   memcpy (&value2->data, &tmp_value.data, sizeof (value2->data));
215 }
216
217 static inline GValueExchange
218 exchange_func_lookup (GType     value_type1,
219                       GType     value_type2,
220                       gboolean *need_swap)
221 {
222   if (value_type1 == value_type2)
223     return value_exchange_memcpy;
224   else
225     {
226       GType type1 = value_type1;
227       
228       do
229         {
230           GType type2 = value_type2;
231           
232           do
233             {
234               ExchangeEntry entry, *ret;
235               
236               entry.value_type1 = MIN (type1, type2);
237               entry.value_type2 = MAX (type1, type2);
238               ret = g_hash_table_lookup (param_exchange_ht, &entry);
239               if (ret)
240                 {
241                   if (need_swap)
242                     *need_swap = ret->first_type == type2;
243                   
244                   return ret->func;
245                 }
246               
247               type2 = g_type_parent (type2);
248             }
249           while (type2);
250           
251           type1 = g_type_parent (type1);
252         }
253       while (type1);
254     }
255   
256   return NULL;
257 }
258
259 void
260 g_value_register_exchange_func (GType          value_type1,
261                                 GType          value_type2,
262                                 GValueExchange func)
263 {
264   ExchangeEntry entry;
265   
266   g_return_if_fail (g_type_name (value_type1) != NULL);
267   g_return_if_fail (g_type_name (value_type2) != NULL);
268   g_return_if_fail (func != NULL);
269   
270   entry.value_type1 = MIN (value_type1, value_type2);
271   entry.value_type2 = MAX (value_type1, value_type2);
272   if (param_exchange_ht && g_hash_table_lookup (param_exchange_ht, &entry))
273     g_warning (G_STRLOC ": cannot re-register param value exchange function "
274                "for `%s' and `%s'",
275                g_type_name (value_type1),
276                g_type_name (value_type2));
277   else
278     {
279       ExchangeEntry *entry = g_new (ExchangeEntry, 1);
280       
281       if (!param_exchange_ht)
282         param_exchange_ht = g_hash_table_new (exchange_entry_hash, exchange_entries_equal);
283       entry->value_type1 = MIN (value_type1, value_type2);
284       entry->value_type2 = MAX (value_type1, value_type2);
285       entry->func = func;
286       entry->first_type = value_type1;
287       g_hash_table_insert (param_exchange_ht, entry, entry);
288     }
289 }
290
291 gboolean
292 g_value_types_exchangable (GType value_type1,
293                            GType value_type2)
294 {
295   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE); /* these might bite us, think G_TYPE_ENUM */
296   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type2), FALSE);
297   
298   return exchange_func_lookup (value_type1, value_type2, NULL) != NULL;
299 }
300
301 gboolean
302 g_values_exchange (GValue *value1,
303                    GValue *value2)
304 {
305   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
306   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
307   
308   if (value1 != value2)
309     {
310       gboolean need_swap;
311       GValueExchange value_exchange = exchange_func_lookup (G_VALUE_TYPE (value1),
312                                                             G_VALUE_TYPE (value2),
313                                                             &need_swap);
314       if (value_exchange)
315         {
316           if (need_swap)
317             value_exchange (value2, value1);
318           else
319             value_exchange (value1, value2);
320         }
321       
322       return value_exchange != NULL;
323     }
324   
325   return TRUE;
326 }
327
328 gboolean
329 g_value_convert (const GValue *src_value,
330                  GValue       *dest_value)
331 {
332   gboolean success = TRUE;
333   
334   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
335   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
336   
337   if (src_value != dest_value)
338     {
339       GValue tmp_value = { 0, };
340       
341       g_value_init (&tmp_value, G_VALUE_TYPE (src_value));
342       g_value_copy (src_value, &tmp_value);
343       
344       success = g_values_exchange (&tmp_value, dest_value);
345       g_value_unset (&tmp_value);
346     }
347   
348   return success;
349 }