Update.
[platform/upstream/glib.git] / gobject / gvalue.c
1 /* GObject - GLib Type, Object, Parameter and Signal Library
2  * Copyright (C) 1997-1999, 2000-2001 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 #include "gbsearcharray.h"
29
30
31 /* --- typedefs & structures --- */
32 typedef struct {
33   GType src_type;
34   GType dest_type;
35   GValueTransform func;
36 } TransformEntry;
37
38
39 /* --- prototypes --- */
40 static gint     transform_entries_cmp   (gconstpointer bsearch_node1,
41                                          gconstpointer bsearch_node2);
42
43
44 /* --- variables --- */
45 static GBSearchArray transform_array = G_STATIC_BSEARCH_ARRAY_INIT (sizeof (TransformEntry),
46                                                                     transform_entries_cmp,
47                                                                     0);
48
49
50 /* --- functions --- */
51 static inline void              /* keep this function in sync with gvaluecollector.h and gboxed.c */
52 value_meminit (GValue *value,
53                GType   value_type)
54 {
55   value->g_type = value_type;
56   memset (value->data, 0, sizeof (value->data));
57 }
58
59 GValue*
60 g_value_init (GValue *value,
61               GType   g_type)
62 {
63   /* g_return_val_if_fail (G_TYPE_IS_VALUE (g_type), NULL);     be more elaborate below */
64   g_return_val_if_fail (value != NULL, NULL);
65   /* g_return_val_if_fail (G_VALUE_TYPE (value) == 0, NULL);    be more elaborate below */
66
67   if (G_TYPE_IS_VALUE (g_type) && G_VALUE_TYPE (value) == 0)
68     {
69       GTypeValueTable *value_table = g_type_value_table_peek (g_type);
70
71       /* setup and init */
72       value_meminit (value, g_type);
73       value_table->value_init (value);
74     }
75   else if (G_VALUE_TYPE (value))
76     g_warning ("%s: cannot initialize GValue with type `%s', the value has already been initialized as `%s'",
77                G_STRLOC,
78                g_type_name (g_type),
79                g_type_name (G_VALUE_TYPE (value)));
80   else /* !G_TYPE_IS_VALUE (g_type) */
81     g_warning ("%s: cannot initialize GValue with type `%s', %s",
82                G_STRLOC,
83                g_type_name (g_type),
84                g_type_value_table_peek (g_type) ?
85                "this type is abstract with regards to GValue use, use a more specific (derived) type" :
86                "this type has no GTypeValueTable implementation");
87   return value;
88 }
89
90 void
91 g_value_copy (const GValue *src_value,
92               GValue       *dest_value)
93 {
94   g_return_if_fail (G_IS_VALUE (src_value));
95   g_return_if_fail (G_IS_VALUE (dest_value));
96   g_return_if_fail (g_value_type_compatible (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)));
97   
98   if (src_value != dest_value)
99     {
100       GType dest_type = G_VALUE_TYPE (dest_value);
101       GTypeValueTable *value_table = g_type_value_table_peek (dest_type);
102
103       /* make sure dest_value's value is free()d */
104       if (value_table->value_free)
105         value_table->value_free (dest_value);
106
107       /* setup and copy */
108       value_meminit (dest_value, dest_type);
109       value_table->value_copy (src_value, dest_value);
110     }
111 }
112
113 GValue*
114 g_value_reset (GValue *value)
115 {
116   GTypeValueTable *value_table;
117   GType g_type;
118   
119   g_return_val_if_fail (G_IS_VALUE (value), NULL);
120   
121   g_type = G_VALUE_TYPE (value);
122   value_table = g_type_value_table_peek (g_type);
123
124   /* make sure value's value is free()d */
125   if (value_table->value_free)
126     value_table->value_free (value);
127
128   /* setup and init */
129   value_meminit (value, g_type);
130   value_table->value_init (value);
131
132   return value;
133 }
134
135 void
136 g_value_unset (GValue *value)
137 {
138   GTypeValueTable *value_table;
139   
140   g_return_if_fail (G_IS_VALUE (value));
141
142   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
143
144   if (value_table->value_free)
145     value_table->value_free (value);
146   memset (value, 0, sizeof (*value));
147 }
148
149 gboolean
150 g_value_fits_pointer (const GValue *value)
151 {
152   GTypeValueTable *value_table;
153
154   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
155
156   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
157
158   return value_table->value_peek_pointer != NULL;
159 }
160
161 gpointer
162 g_value_peek_pointer (const GValue *value)
163 {
164   GTypeValueTable *value_table;
165
166   g_return_val_if_fail (G_IS_VALUE (value), NULL);
167
168   value_table = g_type_value_table_peek (G_VALUE_TYPE (value));
169   if (!value_table->value_peek_pointer)
170     g_return_val_if_fail (g_value_fits_pointer (value) == TRUE, NULL);
171
172   return value_table->value_peek_pointer (value);
173 }
174
175 void
176 g_value_set_instance (GValue  *value,
177                       gpointer instance)
178 {
179   GType g_type;
180   GTypeValueTable *value_table;
181   GTypeCValue cvalue;
182   gchar *error_msg;
183   
184   g_return_if_fail (G_IS_VALUE (value));
185   if (instance)
186     {
187       g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
188       g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (instance), G_VALUE_TYPE (value)));
189     }
190   
191   g_type = G_VALUE_TYPE (value);
192   value_table = g_type_value_table_peek (g_type);
193   
194   g_return_if_fail (strcmp (value_table->collect_format, "p") == 0);
195   
196   memset (&cvalue, 0, sizeof (cvalue));
197   cvalue.v_pointer = instance;
198   
199   /* make sure value's value is free()d */
200   if (value_table->value_free)
201     value_table->value_free (value);
202
203   /* setup and collect */
204   value_meminit (value, g_type);
205   error_msg = value_table->collect_value (value, 1, &cvalue, 0);
206   if (error_msg)
207     {
208       g_warning ("%s: %s", G_STRLOC, error_msg);
209       g_free (error_msg);
210       
211       /* we purposely leak the value here, it might not be
212        * in a sane state if an error condition occoured
213        */
214       value_meminit (value, g_type);
215       value_table->value_init (value);
216     }
217 }
218
219 static GValueTransform
220 transform_func_lookup (GType src_type,
221                        GType dest_type)
222 {
223   TransformEntry entry;
224
225   entry.src_type = src_type;
226   do
227     {
228       entry.dest_type = dest_type;
229       do
230         {
231           TransformEntry *e;
232           
233           e = g_bsearch_array_lookup (&transform_array, &entry);
234           if (e)
235             {
236               /* need to check that there hasn't been a change in value handling */
237               if (g_type_value_table_peek (entry.dest_type) == g_type_value_table_peek (dest_type) &&
238                   g_type_value_table_peek (entry.src_type) == g_type_value_table_peek (src_type))
239                 return e->func;
240             }
241           entry.dest_type = g_type_parent (entry.dest_type);
242         }
243       while (entry.dest_type);
244       
245       entry.src_type = g_type_parent (entry.src_type);
246     }
247   while (entry.src_type);
248
249   return NULL;
250 }
251
252 static gint
253 transform_entries_cmp (gconstpointer bsearch_node1,
254                        gconstpointer bsearch_node2)
255 {
256   const TransformEntry *e1 = bsearch_node1;
257   const TransformEntry *e2 = bsearch_node2;
258   gint cmp = G_BSEARCH_ARRAY_CMP (e1->src_type, e2->src_type);
259
260   if (cmp)
261     return cmp;
262   else
263     return G_BSEARCH_ARRAY_CMP (e1->dest_type, e2->dest_type);
264 }
265
266 void
267 g_value_register_transform_func (GType           src_type,
268                                  GType           dest_type,
269                                  GValueTransform transform_func)
270 {
271   TransformEntry entry;
272
273   g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (src_type));
274   g_return_if_fail (G_TYPE_HAS_VALUE_TABLE (dest_type));
275   g_return_if_fail (transform_func != NULL);
276
277   if (transform_func_lookup (src_type, dest_type))
278     g_warning ("reregistering value transformation function (%p) for `%s' to `%s'",
279                transform_func,
280                g_type_name (src_type),
281                g_type_name (dest_type));
282   entry.src_type = src_type;
283   entry.dest_type = dest_type;
284   entry.func = transform_func;
285   g_bsearch_array_insert (&transform_array, &entry, TRUE);
286 }
287
288 gboolean
289 g_value_type_transformable (GType src_type,
290                             GType dest_type)
291 {
292   g_return_val_if_fail (G_TYPE_IS_VALUE (src_type), FALSE);
293   g_return_val_if_fail (G_TYPE_IS_VALUE (dest_type), FALSE);
294
295   return (g_value_type_compatible (src_type, dest_type) ||
296           transform_func_lookup (src_type, dest_type) != NULL);
297 }
298
299 gboolean
300 g_value_type_compatible (GType src_type,
301                          GType dest_type)
302 {
303   g_return_val_if_fail (G_TYPE_IS_VALUE (src_type), FALSE);
304   g_return_val_if_fail (G_TYPE_IS_VALUE (dest_type), FALSE);
305
306   return (g_type_is_a (src_type, dest_type) &&
307           g_type_value_table_peek (dest_type) == g_type_value_table_peek (src_type));
308 }
309
310 gboolean
311 g_value_transform (const GValue *src_value,
312                    GValue       *dest_value)
313 {
314   GType dest_type;
315
316   g_return_val_if_fail (G_IS_VALUE (src_value), FALSE);
317   g_return_val_if_fail (G_IS_VALUE (dest_value), FALSE);
318
319   dest_type = G_VALUE_TYPE (dest_value);
320   if (g_value_type_compatible (G_VALUE_TYPE (src_value), dest_type))
321     {
322       g_value_copy (src_value, dest_value);
323       
324       return TRUE;
325     }
326   else
327     {
328       GValueTransform transform = transform_func_lookup (G_VALUE_TYPE (src_value), dest_type);
329
330       if (transform)
331         {
332           g_value_unset (dest_value);
333           
334           /* setup and transform */
335           value_meminit (dest_value, dest_type);
336           transform (src_value, dest_value);
337           
338           return TRUE;
339         }
340     }
341   return FALSE;
342 }