[HQ](Debian) Package version up
[external/glib2.0.git] / glib / gvarianttypeinfo.c
1 /*
2  * Copyright © 2008 Ryan Lortie
3  * Copyright © 2010 Codethink Limited
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Ryan Lortie <desrt@desrt.ca>
21  */
22
23 #include "config.h"
24
25 #include "gvarianttypeinfo.h"
26
27 #include <glib/gtestutils.h>
28 #include <glib/gthread.h>
29 #include <glib/ghash.h>
30
31 #include "galias.h"
32
33 /* < private >
34  * GVariantTypeInfo:
35  *
36  * This structure contains the necessary information to facilitate the
37  * serialisation and fast deserialisation of a given type of GVariant
38  * value.  A GVariant instance holds a pointer to one of these
39  * structures to provide for efficient operation.
40  *
41  * The GVariantTypeInfo structures for all of the base types, plus the
42  * "variant" type are stored in a read-only static array.
43  *
44  * For container types, a hash table and reference counting is used to
45  * ensure that only one of these structures exists for any given type.
46  * In general, a container GVariantTypeInfo will exist for a given type
47  * only if one or more GVariant instances of that type exist or if
48  * another GVariantTypeInfo has that type as a subtype.  For example, if
49  * a process contains a single GVariant instance with type "(asv)", then
50  * container GVariantTypeInfo structures will exist for "(asv)" and
51  * for "as" (note that "s" and "v" always exist in the static array).
52  *
53  * The trickiest part of GVariantTypeInfo (and in fact, the major reason
54  * for its existance) is the storage of somewhat magical constants that
55  * allow for O(1) lookups of items in tuples.  This is described below.
56  *
57  * 'container_class' is set to 'a' or 'r' if the GVariantTypeInfo is
58  * contained inside of an ArrayInfo or TupleInfo, respectively.  This
59  * allows the storage of the necessary additional information.
60  *
61  * 'fixed_size' is set to the fixed size of the type, if applicable, or
62  * 0 otherwise (since no type has a fixed size of 0).
63  *
64  * 'alignment' is set to one less than the alignment requirement for
65  * this type.  This makes many operations much more convenient.
66  */
67 struct _GVariantTypeInfo
68 {
69   gsize fixed_size;
70   guchar alignment;
71   guchar container_class;
72 };
73
74 /* Container types are reference counted.  They also need to have their
75  * type string stored explicitly since it is not merely a single letter.
76  */
77 typedef struct
78 {
79   GVariantTypeInfo info;
80
81   gchar *type_string;
82   gint ref_count;
83 } ContainerInfo;
84
85 /* For 'array' and 'maybe' types, we store some extra information on the
86  * end of the GVariantTypeInfo struct -- the element type (ie: "s" for
87  * "as").  The container GVariantTypeInfo structure holds a reference to
88  * the element typeinfo.
89  */
90 typedef struct
91 {
92   ContainerInfo container;
93
94   GVariantTypeInfo *element;
95 } ArrayInfo;
96
97 /* For 'tuple' and 'dict entry' types, we store extra information for
98  * each member -- its type and how to find it inside the serialised data
99  * in O(1) time using 4 variables -- 'i', 'a', 'b', and 'c'.  See the
100  * comment on GVariantMemberInfo in gvarianttypeinfo.h.
101  */
102 typedef struct
103 {
104   ContainerInfo container;
105
106   GVariantMemberInfo *members;
107   gsize n_members;
108 } TupleInfo;
109
110
111 /* Hard-code the base types in a constant array */
112 static const GVariantTypeInfo g_variant_type_info_basic_table[24] = {
113 #define fixed_aligned(x)  x, x - 1
114 #define not_a_type             0,
115 #define unaligned         0, 0
116 #define aligned(x)        0, x - 1
117   /* 'b' */ { fixed_aligned(1) },   /* boolean */
118   /* 'c' */ { not_a_type },
119   /* 'd' */ { fixed_aligned(8) },   /* double */
120   /* 'e' */ { not_a_type },
121   /* 'f' */ { not_a_type },
122   /* 'g' */ { unaligned        },   /* signature string */
123   /* 'h' */ { fixed_aligned(4) },   /* file handle (int32) */
124   /* 'i' */ { fixed_aligned(4) },   /* int32 */
125   /* 'j' */ { not_a_type },
126   /* 'k' */ { not_a_type },
127   /* 'l' */ { not_a_type },
128   /* 'm' */ { not_a_type },
129   /* 'n' */ { fixed_aligned(2) },   /* int16 */
130   /* 'o' */ { unaligned        },   /* object path string */
131   /* 'p' */ { not_a_type },
132   /* 'q' */ { fixed_aligned(2) },   /* uint16 */
133   /* 'r' */ { not_a_type },
134   /* 's' */ { unaligned        },   /* string */
135   /* 't' */ { fixed_aligned(8) },   /* uint64 */
136   /* 'u' */ { fixed_aligned(4) },   /* uint32 */
137   /* 'v' */ { aligned(8)       },   /* variant */
138   /* 'w' */ { not_a_type },
139   /* 'x' */ { fixed_aligned(8) },   /* int64 */
140   /* 'y' */ { fixed_aligned(1) },   /* byte */
141 #undef fixed_aligned
142 #undef not_a_type
143 #undef unaligned
144 #undef aligned
145 };
146
147 /* We need to have type strings to return for the base types.  We store
148  * those in another array.  Since all base type strings are single
149  * characters this is easy.  By not storing pointers to strings into the
150  * GVariantTypeInfo itself, we save a bunch of relocations.
151  */
152 static const char g_variant_type_info_basic_chars[24][2] = {
153   "b", " ", "d", " ", " ", "g", "h", "i", " ", " ", " ", " ",
154   "n", "o", " ", "q", " ", "s", "t", "u", "v", " ", "x", "y"
155 };
156
157 /* sanity checks to make debugging easier */
158 static void
159 g_variant_type_info_check (const GVariantTypeInfo *info,
160                            char                    container_class)
161 {
162   g_assert (!container_class || info->container_class == container_class);
163
164   /* alignment can only be one of these */
165   g_assert (info->alignment == 0 || info->alignment == 1 ||
166             info->alignment == 3 || info->alignment == 7);
167
168   if (info->container_class)
169     {
170       ContainerInfo *container = (ContainerInfo *) info;
171
172       /* extra checks for containers */
173       g_assert_cmpint (container->ref_count, >, 0);
174       g_assert (container->type_string != NULL);
175     }
176   else
177     {
178       gint index;
179
180       /* if not a container, then ensure that it is a valid member of
181        * the basic types table
182        */
183       index = info - g_variant_type_info_basic_table;
184
185       g_assert (G_N_ELEMENTS (g_variant_type_info_basic_table) == 24);
186       g_assert (G_N_ELEMENTS (g_variant_type_info_basic_chars) == 24);
187       g_assert (0 <= index && index < 24);
188       g_assert (g_variant_type_info_basic_chars[index][0] != ' ');
189     }
190 }
191
192 /* < private >
193  * g_variant_type_info_get_type_string:
194  * @info: a #GVariantTypeInfo
195  *
196  * Gets the type string for @info.  The string is nul-terminated.
197  */
198 const gchar *
199 g_variant_type_info_get_type_string (GVariantTypeInfo *info)
200 {
201   g_variant_type_info_check (info, 0);
202
203   if (info->container_class)
204     {
205       ContainerInfo *container = (ContainerInfo *) info;
206
207       /* containers have their type string stored inside them */
208       return container->type_string;
209     }
210   else
211     {
212       gint index;
213
214       /* look up the type string in the base type array.  the call to
215        * g_variant_type_info_check() above already ensured validity.
216        */
217       index = info - g_variant_type_info_basic_table;
218
219       return g_variant_type_info_basic_chars[index];
220     }
221 }
222
223 /* < private >
224  * g_variant_type_info_query:
225  * @info: a #GVariantTypeInfo
226  * @alignment: the location to store the alignment, or %NULL
227  * @fixed_size: the location to store the fixed size, or %NULL
228  *
229  * Queries @info to determine the alignment requirements and fixed size
230  * (if any) of the type.
231  *
232  * @fixed_size, if non-%NULL is set to the fixed size of the type, or 0
233  * to indicate that the type is a variable-sized type.  No type has a
234  * fixed size of 0.
235  *
236  * @alignment, if non-%NULL, is set to one less than the required
237  * alignment of the type.  For example, for a 32bit integer, @alignment
238  * would be set to 3.  This allows you to round an integer up to the
239  * proper alignment by performing the following efficient calculation:
240  *
241  *   offset += ((-offset) & alignment);
242  */
243 void
244 g_variant_type_info_query (GVariantTypeInfo *info,
245                            guint            *alignment,
246                            gsize            *fixed_size)
247 {
248   g_variant_type_info_check (info, 0);
249
250   if (alignment)
251     *alignment = info->alignment;
252
253   if (fixed_size)
254     *fixed_size = info->fixed_size;
255 }
256
257 /* == array == */
258 #define ARRAY_INFO_CLASS 'a'
259 static ArrayInfo *
260 ARRAY_INFO (GVariantTypeInfo *info)
261 {
262   g_variant_type_info_check (info, ARRAY_INFO_CLASS);
263
264   return (ArrayInfo *) info;
265 }
266
267 static void
268 array_info_free (GVariantTypeInfo *info)
269 {
270   ArrayInfo *array_info;
271
272   g_assert (info->container_class == ARRAY_INFO_CLASS);
273   array_info = (ArrayInfo *) info;
274
275   g_variant_type_info_unref (array_info->element);
276   g_slice_free (ArrayInfo, array_info);
277 }
278
279 static ContainerInfo *
280 array_info_new (const GVariantType *type)
281 {
282   ArrayInfo *info;
283
284   info = g_slice_new (ArrayInfo);
285   info->container.info.container_class = ARRAY_INFO_CLASS;
286
287   info->element = g_variant_type_info_get (g_variant_type_element (type));
288   info->container.info.alignment = info->element->alignment;
289   info->container.info.fixed_size = 0;
290
291   return (ContainerInfo *) info;
292 }
293
294 /* < private >
295  * g_variant_type_info_element:
296  * @info: a #GVariantTypeInfo for an array or maybe type
297  *
298  * Returns the element type for the array or maybe type.  A reference is
299  * not added, so the caller must add their own.
300  */
301 GVariantTypeInfo *
302 g_variant_type_info_element (GVariantTypeInfo *info)
303 {
304   return ARRAY_INFO (info)->element;
305 }
306
307 /* < private >
308  * g_variant_type_query_element:
309  * @info: a #GVariantTypeInfo for an array or maybe type
310  * @alignment: the location to store the alignment, or %NULL
311  * @fixed_size: the location to store the fixed size, or %NULL
312  *
313  * Returns the alignment requires and fixed size (if any) for the
314  * element type of the array.  This call is a convenience wrapper around
315  * g_variant_type_info_element() and g_variant_type_info_query().
316  */
317 void
318 g_variant_type_info_query_element (GVariantTypeInfo *info,
319                                    guint            *alignment,
320                                    gsize            *fixed_size)
321 {
322   g_variant_type_info_query (ARRAY_INFO (info)->element,
323                              alignment, fixed_size);
324 }
325
326 /* == tuple == */
327 #define TUPLE_INFO_CLASS 'r'
328 static TupleInfo *
329 TUPLE_INFO (GVariantTypeInfo *info)
330 {
331   g_variant_type_info_check (info, TUPLE_INFO_CLASS);
332
333   return (TupleInfo *) info;
334 }
335
336 static void
337 tuple_info_free (GVariantTypeInfo *info)
338 {
339   TupleInfo *tuple_info;
340   gint i;
341
342   g_assert (info->container_class == TUPLE_INFO_CLASS);
343   tuple_info = (TupleInfo *) info;
344
345   for (i = 0; i < tuple_info->n_members; i++)
346     g_variant_type_info_unref (tuple_info->members[i].type_info);
347
348   g_slice_free1 (sizeof (GVariantMemberInfo) * tuple_info->n_members,
349                  tuple_info->members);
350   g_slice_free (TupleInfo, tuple_info);
351 }
352
353 static void
354 tuple_allocate_members (const GVariantType  *type,
355                         GVariantMemberInfo **members,
356                         gsize               *n_members)
357 {
358   const GVariantType *item_type;
359   gsize i = 0;
360
361   *n_members = g_variant_type_n_items (type);
362   *members = g_slice_alloc (sizeof (GVariantMemberInfo) * *n_members);
363
364   item_type = g_variant_type_first (type);
365   while (item_type)
366     {
367       GVariantMemberInfo *member = &(*members)[i++];
368
369       member->type_info = g_variant_type_info_get (item_type);
370       item_type = g_variant_type_next (item_type);
371
372       if (member->type_info->fixed_size)
373         member->ending_type = G_VARIANT_MEMBER_ENDING_FIXED;
374       else if (item_type == NULL)
375         member->ending_type = G_VARIANT_MEMBER_ENDING_LAST;
376       else
377         member->ending_type = G_VARIANT_MEMBER_ENDING_OFFSET;
378     }
379
380   g_assert (i == *n_members);
381 }
382
383 /* this is g_variant_type_info_query for a given member of the tuple.
384  * before the access is done, it is ensured that the item is within
385  * range and %FALSE is returned if not.
386  */
387 static gboolean
388 tuple_get_item (TupleInfo          *info,
389                 GVariantMemberInfo *item,
390                 gsize              *d,
391                 gsize              *e)
392 {
393   if (&info->members[info->n_members] == item)
394     return FALSE;
395
396   *d = item->type_info->alignment;
397   *e = item->type_info->fixed_size;
398   return TRUE;
399 }
400
401 /* Read the documentation for #GVariantMemberInfo in gvarianttype.h
402  * before attempting to understand this.
403  *
404  * This function adds one set of "magic constant" values (for one item
405  * in the tuple) to the table.
406  *
407  * The algorithm in tuple_generate_table() calculates values of 'a', 'b'
408  * and 'c' for each item, such that the procedure for finding the item
409  * is to start at the end of the previous variable-sized item, add 'a',
410  * then round up to the nearest multiple of 'b', then then add 'c'.
411  * Note that 'b' is stored in the usual "one less than" form.  ie:
412  *
413  *   start = ROUND_UP(prev_end + a, (b + 1)) + c;
414  *
415  * We tweak these values a little to allow for a slightly easier
416  * computation and more compact storage.
417  */
418 static void
419 tuple_table_append (GVariantMemberInfo **items,
420                     gsize                i,
421                     gsize                a,
422                     gsize                b,
423                     gsize                c)
424 {
425   GVariantMemberInfo *item = (*items)++;
426
427   /* We can shift multiples of the alignment size from 'c' into 'a'.
428    * As long as we're shifting whole multiples, it won't affect the
429    * result.  This means that we can take the "aligned" portion off of
430    * 'c' and add it into 'a'.
431    *
432    *  Imagine (for sake of clarity) that ROUND_10 rounds up to the
433    *  nearest 10.  It is clear that:
434    *
435    *   ROUND_10(a) + c == ROUND_10(a + 10*(c / 10)) + (c % 10)
436    *
437    * ie: remove the 10s portion of 'c' and add it onto 'a'.
438    *
439    * To put some numbers on it, imagine we start with a = 34 and c = 27:
440    *
441    *  ROUND_10(34) + 27 = 40 + 27 = 67
442    *
443    * but also, we can split 27 up into 20 and 7 and do this:
444    *
445    *  ROUND_10(34 + 20) + 7 = ROUND_10(54) + 7 = 60 + 7 = 67
446    *                ^^    ^
447    * without affecting the result.  We do that here.
448    *
449    * This reduction in the size of 'c' means that we can store it in a
450    * gchar instead of a gsize.  Due to how the structure is packed, this
451    * ends up saving us 'two pointer sizes' per item in each tuple when
452    * allocating using GSlice.
453    */
454   a += ~b & c;    /* take the "aligned" part of 'c' and add to 'a' */
455   c &= b;         /* chop 'c' to contain only the unaligned part */
456
457
458   /* Finally, we made one last adjustment.  Recall:
459    *
460    *   start = ROUND_UP(prev_end + a, (b + 1)) + c;
461    *
462    * Forgetting the '+ c' for the moment:
463    *
464    *   ROUND_UP(prev_end + a, (b + 1));
465    *
466    * we can do a "round up" operation by adding 1 less than the amount
467    * to round up to, then rounding down.  ie:
468    *
469    *   #define ROUND_UP(x, y)    ROUND_DOWN(x + (y-1), y)
470    *
471    * Of course, for rounding down to a power of two, we can just mask
472    * out the appropriate number of low order bits:
473    *
474    *   #define ROUND_DOWN(x, y)  (x & ~(y - 1))
475    *
476    * Which gives us
477    *
478    *   #define ROUND_UP(x, y)    (x + (y - 1) & ~(y - 1))
479    *
480    * but recall that our alignment value 'b' is already "one less".
481    * This means that to round 'prev_end + a' up to 'b' we can just do:
482    *
483    *   ((prev_end + a) + b) & ~b
484    *
485    * Associativity, and putting the 'c' back on:
486    *
487    *   (prev_end + (a + b)) & ~b + c
488    *
489    * Now, since (a + b) is constant, we can just add 'b' to 'a' now and
490    * store that as the number to add to prev_end.  Then we use ~b as the
491    * number to take a bitwise 'and' with.  Finally, 'c' is added on.
492    *
493    * Note, however, that all the low order bits of the 'aligned' value
494    * are masked out and that all of the high order bits of 'c' have been
495    * "moved" to 'a' (in the previous step).  This means that there are
496    * no overlapping bits in the addition -- so we can do a bitwise 'or'
497    * equivalently.
498    *
499    * This means that we can now compute the start address of a given
500    * item in the tuple using the algorithm given in the documentation
501    * for #GVariantMemberInfo:
502    *
503    *   item_start = ((prev_end + a) & b) | c;
504    */
505
506   item->i = i;
507   item->a = a + b;
508   item->b = ~b;
509   item->c = c;
510 }
511
512 static gsize
513 tuple_align (gsize offset,
514              guint alignment)
515 {
516   return offset + ((-offset) & alignment);
517 }
518
519 /* This function is the heart of the algorithm for calculating 'i', 'a',
520  * 'b' and 'c' for each item in the tuple.
521  *
522  * Imagine we want to find the start of the "i" in the type "(su(qx)ni)".
523  * That's a string followed by a uint32, then a tuple containing a
524  * uint16 and a int64, then an int16, then our "i".  In order to get to
525  * our "i" we:
526  *
527  * Start at the end of the string, align to 4 (for the uint32), add 4.
528  * Align to 8, add 16 (for the tuple).  Align to 2, add 2 (for the
529  * int16).  Then we're there.  It turns out that, given 3 simple rules,
530  * we can flatten this iteration into one addition, one alignment, then
531  * one more addition.
532  *
533  * The loop below plays through each item in the tuple, querying its
534  * alignment and fixed_size into 'd' and 'e', respectively.  At all
535  * times the variables 'a', 'b', and 'c' are maintained such that in
536  * order to get to the current point, you add 'a', align to 'b' then add
537  * 'c'.  'b' is kept in "one less than" form.  For each item, the proper
538  * alignment is applied to find the values of 'a', 'b' and 'c' to get to
539  * the start of that item.  Those values are recorded into the table.
540  * The fixed size of the item (if applicable) is then added on.
541  *
542  * These 3 rules are how 'a', 'b' and 'c' are modified for alignment and
543  * addition of fixed size.  They have been proven correct but are
544  * presented here, without proof:
545  *
546  *  1) in order to "align to 'd'" where 'd' is less than or equal to the
547  *     largest level of alignment seen so far ('b'), you align 'c' to
548  *     'd'.
549  *  2) in order to "align to 'd'" where 'd' is greater than the largest
550  *     level of alignment seen so far, you add 'c' aligned to 'b' to the
551  *     value of 'a', set 'b' to 'd' (ie: increase the 'largest alignment
552  *     seen') and reset 'c' to 0.
553  *  3) in order to "add 'e'", just add 'e' to 'c'.
554  */
555 static void
556 tuple_generate_table (TupleInfo *info)
557 {
558   GVariantMemberInfo *items = info->members;
559   gsize i = -1, a = 0, b = 0, c = 0, d, e;
560
561   /* iterate over each item in the tuple.
562    *   'd' will be the alignment of the item (in one-less form)
563    *   'e' will be the fixed size (or 0 for variable-size items)
564    */
565   while (tuple_get_item (info, items, &d, &e))
566     {
567       /* align to 'd' */
568       if (d <= b)
569         c = tuple_align (c, d);                   /* rule 1 */
570       else
571         a += tuple_align (c, b), b = d, c = 0;    /* rule 2 */
572
573       /* the start of the item is at this point (ie: right after we
574        * have aligned for it).  store this information in the table.
575        */
576       tuple_table_append (&items, i, a, b, c);
577
578       /* "move past" the item by adding in its size. */
579       if (e == 0)
580         /* variable size:
581          *
582          * we'll have an offset stored to mark the end of this item, so
583          * just bump the offset index to give us a new starting point
584          * and reset all the counters.
585          */
586         i++, a = b = c = 0;
587       else
588         /* fixed size */
589         c += e;                                   /* rule 3 */
590     }
591 }
592
593 static void
594 tuple_set_base_info (TupleInfo *info)
595 {
596   GVariantTypeInfo *base = &info->container.info;
597
598   if (info->n_members > 0)
599     {
600       GVariantMemberInfo *m;
601
602       /* the alignment requirement of the tuple is the alignment
603        * requirement of its largest item.
604        */
605       base->alignment = 0;
606       for (m = info->members; m < &info->members[info->n_members]; m++)
607         /* can find the max of a list of "one less than" powers of two
608          * by 'or'ing them
609          */
610         base->alignment |= m->type_info->alignment;
611
612       m--; /* take 'm' back to the last item */
613
614       /* the structure only has a fixed size if no variable-size
615        * offsets are stored and the last item is fixed-sized too (since
616        * an offset is never stored for the last item).
617        */
618       if (m->i == -1 && m->type_info->fixed_size)
619         /* in that case, the fixed size can be found by finding the
620          * start of the last item (in the usual way) and adding its
621          * fixed size.
622          *
623          * if a tuple has a fixed size then it is always a multiple of
624          * the alignment requirement (to make packing into arrays
625          * easier) so we round up to that here.
626          */
627         base->fixed_size =
628           tuple_align (((m->a & m->b) | m->c) + m->type_info->fixed_size,
629                        base->alignment);
630       else
631         /* else, the tuple is not fixed size */
632         base->fixed_size = 0;
633     }
634   else
635     {
636       /* the empty tuple: '()'.
637        *
638        * has a size of 1 and an no alignment requirement.
639        *
640        * It has a size of 1 (not 0) for two practical reasons:
641        *
642        *  1) So we can determine how many of them are in an array
643        *     without dividing by zero or without other tricks.
644        *
645        *  2) Even if we had some trick to know the number of items in
646        *     the array (as GVariant did at one time) this would open a
647        *     potential denial of service attack: an attacker could send
648        *     you an extremely small array (in terms of number of bytes)
649        *     containing trillions of zero-sized items.  If you iterated
650        *     over this array you would effectively infinite-loop your
651        *     program.  By forcing a size of at least one, we bound the
652        *     amount of computation done in response to a message to a
653        *     reasonable function of the size of that message.
654        */
655       base->alignment = 0;
656       base->fixed_size = 1;
657     }
658 }
659
660 static ContainerInfo *
661 tuple_info_new (const GVariantType *type)
662 {
663   TupleInfo *info;
664
665   info = g_slice_new (TupleInfo);
666   info->container.info.container_class = TUPLE_INFO_CLASS;
667
668   tuple_allocate_members (type, &info->members, &info->n_members);
669   tuple_generate_table (info);
670   tuple_set_base_info (info);
671
672   return (ContainerInfo *) info;
673 }
674
675 /* < private >
676  * g_variant_type_info_n_members:
677  * @info: a #GVariantTypeInfo for a tuple or dictionary entry type
678  *
679  * Returns the number of members in a tuple or dictionary entry type.
680  * For a dictionary entry this will always be 2.
681  */
682 gsize
683 g_variant_type_info_n_members (GVariantTypeInfo *info)
684 {
685   return TUPLE_INFO (info)->n_members;
686 }
687
688 /* < private >
689  * g_variant_type_info_member_info:
690  * @info: a #GVariantTypeInfo for a tuple or dictionary entry type
691  * @index: the member to fetch information for
692  *
693  * Returns the #GVariantMemberInfo for a given member.  See
694  * documentation for that structure for why you would want this
695  * information.
696  *
697  * @index must refer to a valid child (ie: strictly less than
698  * g_variant_type_info_n_members() returns).
699  */
700 const GVariantMemberInfo *
701 g_variant_type_info_member_info (GVariantTypeInfo *info,
702                                  gsize             index)
703 {
704   TupleInfo *tuple_info = TUPLE_INFO (info);
705
706   if (index < tuple_info->n_members)
707     return &tuple_info->members[index];
708
709   return NULL;
710 }
711
712 /* == new/ref/unref == */
713 static GStaticRecMutex g_variant_type_info_lock = G_STATIC_REC_MUTEX_INIT;
714 static GHashTable *g_variant_type_info_table;
715
716 /* < private >
717  * g_variant_type_info_get:
718  * @type: a #GVariantType
719  *
720  * Returns a reference to a #GVariantTypeInfo for @type.
721  *
722  * If an info structure already exists for this type, a new reference is
723  * returned.  If not, the required calculations are performed and a new
724  * info structure is returned.
725  *
726  * It is appropriate to call g_variant_type_info_unref() on the return
727  * value.
728  */
729 GVariantTypeInfo *
730 g_variant_type_info_get (const GVariantType *type)
731 {
732   char type_char;
733
734   type_char = g_variant_type_peek_string (type)[0];
735
736   if (type_char == G_VARIANT_TYPE_INFO_CHAR_MAYBE ||
737       type_char == G_VARIANT_TYPE_INFO_CHAR_ARRAY ||
738       type_char == G_VARIANT_TYPE_INFO_CHAR_TUPLE ||
739       type_char == G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY)
740     {
741       GVariantTypeInfo *info;
742       gchar *type_string;
743
744       type_string = g_variant_type_dup_string (type);
745
746       g_static_rec_mutex_lock (&g_variant_type_info_lock);
747
748       if (g_variant_type_info_table == NULL)
749         g_variant_type_info_table = g_hash_table_new (g_str_hash,
750                                                       g_str_equal);
751       info = g_hash_table_lookup (g_variant_type_info_table, type_string);
752
753       if (info == NULL)
754         {
755           ContainerInfo *container;
756
757           if (type_char == G_VARIANT_TYPE_INFO_CHAR_MAYBE ||
758               type_char == G_VARIANT_TYPE_INFO_CHAR_ARRAY)
759             {
760               container = array_info_new (type);
761             }
762           else /* tuple or dict entry */
763             {
764               container = tuple_info_new (type);
765             }
766
767           info = (GVariantTypeInfo *) container;
768           container->type_string = type_string;
769           container->ref_count = 1;
770
771           g_hash_table_insert (g_variant_type_info_table, type_string, info);
772           type_string = NULL;
773         }
774       else
775         g_variant_type_info_ref (info);
776
777       g_static_rec_mutex_unlock (&g_variant_type_info_lock);
778       g_variant_type_info_check (info, 0);
779       g_free (type_string);
780
781       return info;
782     }
783   else
784     {
785       const GVariantTypeInfo *info;
786       int index;
787
788       index = type_char - 'b';
789       g_assert (G_N_ELEMENTS (g_variant_type_info_basic_table) == 24);
790       g_assert_cmpint (0, <=, index);
791       g_assert_cmpint (index, <, 24);
792
793       info = g_variant_type_info_basic_table + index;
794       g_variant_type_info_check (info, 0);
795
796       return (GVariantTypeInfo *) info;
797     }
798 }
799
800 /* < private >
801  * g_variant_type_info_ref:
802  * @info: a #GVariantTypeInfo
803  *
804  * Adds a reference to @info.
805  */
806 GVariantTypeInfo *
807 g_variant_type_info_ref (GVariantTypeInfo *info)
808 {
809   g_variant_type_info_check (info, 0);
810
811   if (info->container_class)
812     {
813       ContainerInfo *container = (ContainerInfo *) info;
814
815       g_assert_cmpint (container->ref_count, >, 0);
816       g_atomic_int_inc (&container->ref_count);
817     }
818
819   return info;
820 }
821
822 /* < private >
823  * g_variant_type_info_unref:
824  * @info: a #GVariantTypeInfo
825  *
826  * Releases a reference held on @info.  This may result in @info being
827  * freed.
828  */
829 void
830 g_variant_type_info_unref (GVariantTypeInfo *info)
831 {
832   g_variant_type_info_check (info, 0);
833
834   if (info->container_class)
835     {
836       ContainerInfo *container = (ContainerInfo *) info;
837
838       g_static_rec_mutex_lock (&g_variant_type_info_lock);
839       if (g_atomic_int_dec_and_test (&container->ref_count))
840         {
841           g_hash_table_remove (g_variant_type_info_table,
842                                container->type_string);
843           if (g_hash_table_size (g_variant_type_info_table) == 0)
844             {
845               g_hash_table_unref (g_variant_type_info_table);
846               g_variant_type_info_table = NULL;
847             }
848           g_static_rec_mutex_unlock (&g_variant_type_info_lock);
849
850           g_free (container->type_string);
851
852           if (info->container_class == ARRAY_INFO_CLASS)
853             array_info_free (info);
854
855           else if (info->container_class == TUPLE_INFO_CLASS)
856             tuple_info_free (info);
857
858           else
859             g_assert_not_reached ();
860         }
861       else
862         g_static_rec_mutex_unlock (&g_variant_type_info_lock);
863     }
864 }
865
866 void
867 g_variant_type_info_assert_no_infos (void)
868 {
869   g_assert (g_variant_type_info_table == NULL);
870 }
871
872 #define __G_VARIANT_TYPE_INFO_C__
873 #include "galiasdef.c"