include string.h for memset include string.h for strcpy include string.h
[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 = g_type_value_table_peek (G_VALUE_TYPE (dest_value));
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   if (!value_table)
70     g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (dest_value)) != NULL);
71   
72   if (src_value != dest_value)
73     {
74       /* make sure dest_value's value is free()d and zero initialized */
75       g_value_reset (dest_value);
76       
77       value_table->value_copy (src_value, dest_value);
78     }
79 }
80
81 void
82 g_value_unset (GValue *value)
83 {
84   GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
85   
86   g_return_if_fail (G_IS_VALUE (value));
87   if (!value_table)
88     g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (value)) != NULL);
89   
90   if (value_table->value_free)
91     value_table->value_free (value);
92   memset (value, 0, sizeof (*value));
93 }
94
95 void
96 g_value_reset (GValue *value)
97 {
98   GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
99   GType g_type;
100   
101   g_return_if_fail (G_IS_VALUE (value));
102   
103   g_type = G_VALUE_TYPE (value);
104   
105   if (value_table->value_free)
106     value_table->value_free (value);
107   memset (value, 0, sizeof (*value));
108   
109   value->g_type = g_type;
110   value_table->value_init (value);
111 }
112
113 static gint
114 exchange_entries_equal (gconstpointer v1,
115                         gconstpointer v2)
116 {
117   const ExchangeEntry *entry1 = v1;
118   const ExchangeEntry *entry2 = v2;
119   
120   return (entry1->value_type1 == entry2->value_type1 &&
121           entry1->value_type2 == entry2->value_type2);
122 }
123
124 static guint
125 exchange_entry_hash (gconstpointer key)
126 {
127   const ExchangeEntry *entry = key;
128   
129   return entry->value_type1 ^ entry->value_type2;
130 }
131
132 static void
133 value_exchange_memcpy (GValue *value1,
134                        GValue *value2)
135 {
136   GValue tmp_value;
137   
138   memcpy (&tmp_value.data, &value1->data, sizeof (value1->data));
139   memcpy (&value1->data, &value2->data, sizeof (value1->data));
140   memcpy (&value2->data, &tmp_value.data, sizeof (value2->data));
141 }
142
143 static inline GValueExchange
144 exchange_func_lookup (GType     value_type1,
145                       GType     value_type2,
146                       gboolean *need_swap)
147 {
148   if (value_type1 == value_type2)
149     return value_exchange_memcpy;
150   else
151     {
152       GType type1 = value_type1;
153       
154       do
155         {
156           GType type2 = value_type2;
157           
158           do
159             {
160               ExchangeEntry entry, *ret;
161               
162               entry.value_type1 = MIN (type1, type2);
163               entry.value_type2 = MAX (type1, type2);
164               ret = g_hash_table_lookup (param_exchange_ht, &entry);
165               if (ret)
166                 {
167                   if (need_swap)
168                     *need_swap = ret->first_type == type2;
169                   
170                   return ret->func;
171                 }
172               
173               type2 = g_type_parent (type2);
174             }
175           while (type2);
176           
177           type1 = g_type_parent (type1);
178         }
179       while (type1);
180     }
181   
182   return NULL;
183 }
184
185 void
186 g_value_register_exchange_func (GType          value_type1,
187                                 GType          value_type2,
188                                 GValueExchange func)
189 {
190   ExchangeEntry entry;
191   
192   g_return_if_fail (G_TYPE_IS_VALUE (value_type1));
193   g_return_if_fail (G_TYPE_IS_VALUE (value_type2));
194   g_return_if_fail (func != NULL);
195   
196   entry.value_type1 = MIN (value_type1, value_type2);
197   entry.value_type2 = MAX (value_type1, value_type2);
198   if (param_exchange_ht && g_hash_table_lookup (param_exchange_ht, &entry))
199     g_warning (G_STRLOC ": cannot re-register param value exchange function "
200                "for `%s' and `%s'",
201                g_type_name (value_type1),
202                g_type_name (value_type2));
203   else
204     {
205       ExchangeEntry *entry = g_new (ExchangeEntry, 1);
206       
207       if (!param_exchange_ht)
208         param_exchange_ht = g_hash_table_new (exchange_entry_hash, exchange_entries_equal);
209       entry->value_type1 = MIN (value_type1, value_type2);
210       entry->value_type2 = MAX (value_type1, value_type2);
211       entry->func = func;
212       entry->first_type = value_type1;
213       g_hash_table_insert (param_exchange_ht, entry, entry);
214     }
215 }
216
217 gboolean
218 g_value_types_exchangable (GType value_type1,
219                            GType value_type2)
220 {
221   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type1), FALSE);
222   g_return_val_if_fail (G_TYPE_IS_VALUE (value_type2), FALSE);
223   
224   return exchange_func_lookup (value_type1, value_type2, NULL) != NULL;
225 }
226
227 gboolean
228 g_values_exchange (GValue *value1,
229                    GValue *value2)
230 {
231   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
232   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
233   
234   if (value1 != value2)
235     {
236       gboolean need_swap;
237       GValueExchange value_exchange = exchange_func_lookup (G_VALUE_TYPE (value1),
238                                                             G_VALUE_TYPE (value2),
239                                                             &need_swap);
240       if (value_exchange)
241         {
242           if (need_swap)
243             value_exchange (value2, value1);
244           else
245             value_exchange (value1, value2);
246         }
247       
248       return value_exchange != NULL;
249     }
250   
251   return TRUE;
252 }
253
254 gboolean
255 g_value_convert (const GValue *src_value,
256                  GValue       *dest_value)
257 {
258   gboolean success = TRUE;
259   
260   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
261   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
262   
263   if (src_value != dest_value)
264     {
265       GValue tmp_value = { 0, };
266       
267       g_value_init (&tmp_value, G_VALUE_TYPE (src_value));
268       g_value_copy (src_value, &tmp_value);
269       
270       success = g_values_exchange (&tmp_value, dest_value);
271       g_value_unset (&tmp_value);
272     }
273   
274   return success;
275 }