source: trunk/third/glib2/gobject/gtype.c @ 21369

Revision 21369, 102.9 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21368, which included commits to RCS files with non-trunk default branches.
Line 
1/* GObject - GLib Type, Object, Parameter and Signal Library
2 * Copyright (C) 1998-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#include        <config.h>
20#include        "gtype.h"
21
22/*
23 * MT safe
24 */
25
26#include        "gtypeplugin.h"
27#include        "gvaluecollector.h"
28#include        "gbsearcharray.h"
29#include        <string.h>
30
31
32/* NOTE: some functions (some internal variants and exported ones)
33 * invalidate data portions of the TypeNodes. if external functions/callbacks
34 * are called, pointers to memory maintained by TypeNodes have to be looked up
35 * again. this affects most of the struct TypeNode fields, e.g. ->children or
36 * CLASSED_NODE_IFACES_ENTRIES() respectively IFACE_NODE_PREREQUISITES() (but
37 * not ->supers[]), as all those memory portions can get realloc()ed during
38 * callback invocation.
39 *
40 * TODO:
41 * - g_type_from_name() should do an ordered array lookup after fetching the
42 *   the quark, instead of a second hashtable lookup.
43 *
44 * LOCKING:
45 * lock handling issues when calling static functions are indicated by
46 * uppercase letter postfixes, all static functions have to have
47 * one of the below postfixes:
48 * - _I:        [Indifferent about locking]
49 *   function doesn't care about locks at all
50 * - _U:        [Unlocked invocation]
51 *   no read or write lock has to be held across function invocation
52 *   (locks may be acquired and released during invocation though)
53 * - _L:        [Locked invocation]
54 *   a write lock or more than 0 read locks have to be held across
55 *   function invocation
56 * - _W:        [Write-locked invocation]
57 *   a write lock has to be held across function invokation
58 * - _Wm:       [Write-locked invocation, mutatable]
59 *   like _W, but the write lock might be released and reacquired
60 *   during invocation, watch your pointers
61 */
62
63static GStaticRWLock            type_rw_lock = G_STATIC_RW_LOCK_INIT;
64#ifdef LOCK_DEBUG
65#define G_READ_LOCK(rw_lock)    do { g_printerr (G_STRLOC ": readL++\n"); g_static_rw_lock_reader_lock (rw_lock); } while (0)
66#define G_READ_UNLOCK(rw_lock)  do { g_printerr (G_STRLOC ": readL--\n"); g_static_rw_lock_reader_unlock (rw_lock); } while (0)
67#define G_WRITE_LOCK(rw_lock)   do { g_printerr (G_STRLOC ": writeL++\n"); g_static_rw_lock_writer_lock (rw_lock); } while (0)
68#define G_WRITE_UNLOCK(rw_lock) do { g_printerr (G_STRLOC ": writeL--\n"); g_static_rw_lock_writer_unlock (rw_lock); } while (0)
69#else
70#define G_READ_LOCK(rw_lock)    g_static_rw_lock_reader_lock (rw_lock)
71#define G_READ_UNLOCK(rw_lock)  g_static_rw_lock_reader_unlock (rw_lock)
72#define G_WRITE_LOCK(rw_lock)   g_static_rw_lock_writer_lock (rw_lock)
73#define G_WRITE_UNLOCK(rw_lock) g_static_rw_lock_writer_unlock (rw_lock)
74#endif
75#define INVALID_RECURSION(func, arg, type_name) G_STMT_START{ \
76    static const gchar *_action = " invalidly modified type "; \
77    gpointer _arg = (gpointer) (arg); const gchar *_tname = (type_name), *_fname = (func); \
78    if (_arg) \
79      g_error ("%s(%p)%s`%s'", _fname, _arg, _action, _tname); \
80    else \
81      g_error ("%s()%s`%s'", _fname, _action, _tname); \
82}G_STMT_END
83#define g_return_val_if_uninitialized(condition, init_function, return_value) G_STMT_START{     \
84  if (!(condition))                                                                             \
85    {                                                                                           \
86      g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,                                                \
87             "%s: initialization assertion failed, use %s() prior to this function",            \
88             G_STRLOC, G_STRINGIFY (init_function));                                            \
89      return (return_value);                                                                    \
90    }                                                                                           \
91}G_STMT_END
92
93#ifdef  G_ENABLE_DEBUG
94#define DEBUG_CODE(debug_type, code_block)  G_STMT_START {    \
95    if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) \
96      { code_block; }                                     \
97} G_STMT_END
98#else /* !G_ENABLE_DEBUG */
99#define DEBUG_CODE(debug_type, code_block)  /* code_block */
100#endif  /* G_ENABLE_DEBUG */
101
102#define TYPE_FUNDAMENTAL_FLAG_MASK (G_TYPE_FLAG_CLASSED | \
103                                    G_TYPE_FLAG_INSTANTIATABLE | \
104                                    G_TYPE_FLAG_DERIVABLE | \
105                                    G_TYPE_FLAG_DEEP_DERIVABLE)
106#define TYPE_FLAG_MASK             (G_TYPE_FLAG_ABSTRACT | G_TYPE_FLAG_VALUE_ABSTRACT)
107#define SIZEOF_FUNDAMENTAL_INFO    ((gssize) MAX (MAX (sizeof (GTypeFundamentalInfo), \
108                                                       sizeof (gpointer)), \
109                                                  sizeof (glong)))
110
111/* The 2*sizeof(size_t) alignment here is borrowed from
112 * GNU libc, so it should be good most everywhere.
113 * It is more conservative than is needed on some 64-bit
114 * platforms, but ia64 does require a 16-byte alignment.
115 * The SIMD extensions for x86 and ppc32 would want a
116 * larger alignment than this, but we don't need to
117 * do better than malloc.
118 */
119#define STRUCT_ALIGNMENT (2 * sizeof (gsize))
120#define ALIGN_STRUCT(offset) \
121      ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT)
122
123
124/* --- typedefs --- */
125typedef struct _TypeNode        TypeNode;
126typedef struct _CommonData      CommonData;
127typedef struct _IFaceData       IFaceData;
128typedef struct _ClassData       ClassData;
129typedef struct _InstanceData    InstanceData;
130typedef union  _TypeData        TypeData;
131typedef struct _IFaceEntry      IFaceEntry;
132typedef struct _IFaceHolder     IFaceHolder;
133
134
135/* --- prototypes --- */
136static inline GTypeFundamentalInfo*     type_node_fundamental_info_I    (TypeNode               *node);
137static        void                      type_add_flags_W                (TypeNode               *node,
138                                                                         GTypeFlags              flags);
139static        void                      type_data_make_W                (TypeNode               *node,
140                                                                         const GTypeInfo        *info,
141                                                                         const GTypeValueTable  *value_table);
142static inline void                      type_data_ref_Wm                (TypeNode               *node);
143static inline void                      type_data_unref_Wm              (TypeNode               *node,
144                                                                         gboolean                uncached);
145static void                             type_data_last_unref_Wm         (GType                   type,
146                                                                         gboolean                uncached);
147static inline gpointer                  type_get_qdata_L                (TypeNode               *node,
148                                                                         GQuark                  quark);
149static inline void                      type_set_qdata_W                (TypeNode               *node,
150                                                                         GQuark                  quark,
151                                                                         gpointer                data);
152static IFaceHolder*                     type_iface_peek_holder_L        (TypeNode               *iface,
153                                                                         GType                   instance_type);
154static gboolean                         type_iface_vtable_base_init_Wm  (TypeNode               *iface,
155                                                                         TypeNode               *node);
156static void                             type_iface_vtable_iface_init_Wm (TypeNode               *iface,
157                                                                         TypeNode               *node);
158static gboolean                         type_node_is_a_L                (TypeNode               *node,
159                                                                         TypeNode               *iface_node);
160
161
162/* --- enumeration --- */
163
164/* The InitState enumeration is used to track the progress of initializing
165 * both classes and interface vtables. Keeping the state of initialization
166 * is necessary to handle new interfaces being added while we are initializing
167 * the class or other interfaces.
168 */
169typedef enum
170{
171  UNINITIALIZED,
172  BASE_CLASS_INIT,
173  BASE_IFACE_INIT,
174  CLASS_INIT,
175  IFACE_INIT,
176  INITIALIZED
177} InitState;
178
179/* --- structures --- */
180struct _TypeNode
181{
182  GTypePlugin *plugin;
183  guint        n_children : 12;
184  guint        n_supers : 8;
185  guint        _prot_n_ifaces_prerequisites : 9;
186  guint        is_classed : 1;
187  guint        is_instantiatable : 1;
188  guint        mutatable_check_cache : 1;       /* combines some common path checks */
189  GType       *children;
190  TypeData * volatile data;
191  GQuark       qname;
192  GData       *global_gdata;
193  union {
194    IFaceEntry  *iface_entries;         /* for !iface types */
195    GType       *prerequisistes;
196  } _prot;
197  GType        supers[1]; /* flexible array */
198};
199#define SIZEOF_BASE_TYPE_NODE()                 (G_STRUCT_OFFSET (TypeNode, supers))
200#define MAX_N_SUPERS                            (255)
201#define MAX_N_CHILDREN                          (4095)
202#define MAX_N_IFACES                            (511)
203#define MAX_N_PREREQUISITES                     (MAX_N_IFACES)
204#define NODE_TYPE(node)                         (node->supers[0])
205#define NODE_PARENT_TYPE(node)                  (node->supers[1])
206#define NODE_FUNDAMENTAL_TYPE(node)             (node->supers[node->n_supers])
207#define NODE_NAME(node)                         (g_quark_to_string (node->qname))
208#define NODE_IS_IFACE(node)                     (NODE_FUNDAMENTAL_TYPE (node) == G_TYPE_INTERFACE)
209#define CLASSED_NODE_N_IFACES(node)             ((node)->_prot_n_ifaces_prerequisites)
210#define CLASSED_NODE_IFACES_ENTRIES(node)       ((node)->_prot.iface_entries)
211#define IFACE_NODE_N_PREREQUISITES(node)        ((node)->_prot_n_ifaces_prerequisites)
212#define IFACE_NODE_PREREQUISITES(node)          ((node)->_prot.prerequisistes)
213#define iface_node_get_holders_L(node)          ((IFaceHolder*) type_get_qdata_L ((node), static_quark_iface_holder))
214#define iface_node_set_holders_W(node, holders) (type_set_qdata_W ((node), static_quark_iface_holder, (holders)))
215#define iface_node_get_dependants_array_L(n)    ((GType*) type_get_qdata_L ((n), static_quark_dependants_array))
216#define iface_node_set_dependants_array_W(n,d)  (type_set_qdata_W ((n), static_quark_dependants_array, (d)))
217#define TYPE_ID_MASK                            ((GType) ((1 << G_TYPE_FUNDAMENTAL_SHIFT) - 1))
218
219#define NODE_IS_ANCESTOR(ancestor, node)                                                    \
220        ((ancestor)->n_supers <= (node)->n_supers &&                                        \
221         (node)->supers[(node)->n_supers - (ancestor)->n_supers] == NODE_TYPE (ancestor))
222
223
224struct _IFaceHolder
225{
226  GType           instance_type;
227  GInterfaceInfo *info;
228  GTypePlugin    *plugin;
229  IFaceHolder    *next;
230};
231struct _IFaceEntry
232{
233  GType           iface_type;
234  GTypeInterface *vtable;
235  InitState       init_state;
236};
237struct _CommonData
238{
239  guint             ref_count;
240  GTypeValueTable  *value_table;
241};
242struct _IFaceData
243{
244  CommonData         common;
245  guint16            vtable_size;
246  GBaseInitFunc      vtable_init_base;
247  GBaseFinalizeFunc  vtable_finalize_base;
248  GClassInitFunc     dflt_init;
249  GClassFinalizeFunc dflt_finalize;
250  gconstpointer      dflt_data;
251  gpointer           dflt_vtable;
252};
253struct _ClassData
254{
255  CommonData         common;
256  guint16            class_size;
257  guint              init_state : 4;
258  GBaseInitFunc      class_init_base;
259  GBaseFinalizeFunc  class_finalize_base;
260  GClassInitFunc     class_init;
261  GClassFinalizeFunc class_finalize;
262  gconstpointer      class_data;
263  gpointer           class;
264};
265struct _InstanceData
266{
267  CommonData         common;
268  guint16            class_size;
269  guint              init_state : 4;
270  GBaseInitFunc      class_init_base;
271  GBaseFinalizeFunc  class_finalize_base;
272  GClassInitFunc     class_init;
273  GClassFinalizeFunc class_finalize;
274  gconstpointer      class_data;
275  gpointer           class;
276  guint16            instance_size;
277  guint16            private_size;
278  guint16            n_preallocs;
279  GInstanceInitFunc  instance_init;
280  GMemChunk        *mem_chunk;
281};
282union _TypeData
283{
284  CommonData         common;
285  IFaceData          iface;
286  ClassData          class;
287  InstanceData       instance;
288};
289typedef struct {
290  gpointer            cache_data;
291  GTypeClassCacheFunc cache_func;
292} ClassCacheFunc;
293typedef struct {
294  gpointer                check_data;
295  GTypeInterfaceCheckFunc check_func;
296} IFaceCheckFunc;
297
298
299/* --- variables --- */
300static guint           static_n_class_cache_funcs = 0;
301static ClassCacheFunc *static_class_cache_funcs = NULL;
302static guint           static_n_iface_check_funcs = 0;
303static IFaceCheckFunc *static_iface_check_funcs = NULL;
304static GQuark          static_quark_type_flags = 0;
305static GQuark          static_quark_iface_holder = 0;
306static GQuark          static_quark_dependants_array = 0;
307GTypeDebugFlags        _g_type_debug_flags = 0;
308
309
310/* --- type nodes --- */
311static GHashTable       *static_type_nodes_ht = NULL;
312static TypeNode         *static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { 0, };
313static GType             static_fundamental_next = G_TYPE_RESERVED_USER_FIRST;
314
315static inline TypeNode*
316lookup_type_node_I (register GType utype)
317{
318  if (utype > G_TYPE_FUNDAMENTAL_MAX)
319    return (TypeNode*) (utype & ~TYPE_ID_MASK);
320  else
321    return static_fundamental_type_nodes[utype >> G_TYPE_FUNDAMENTAL_SHIFT];
322}
323
324static TypeNode*
325type_node_any_new_W (TypeNode             *pnode,
326                     GType                 ftype,
327                     const gchar          *name,
328                     GTypePlugin          *plugin,
329                     GTypeFundamentalFlags type_flags)
330{
331  guint n_supers;
332  GType type;
333  TypeNode *node;
334  guint i, node_size = 0;
335 
336  n_supers = pnode ? pnode->n_supers + 1 : 0;
337 
338  if (!pnode)
339    node_size += SIZEOF_FUNDAMENTAL_INFO;             /* fundamental type info */
340  node_size += SIZEOF_BASE_TYPE_NODE ();              /* TypeNode structure */
341  node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + (0) for ->supers[] */
342  node = g_malloc0 (node_size);
343  if (!pnode)                                         /* offset fundamental types */
344    {
345      node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO);
346      static_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node;
347      type = ftype;
348    }
349  else
350    type = (GType) node;
351 
352  g_assert ((type & TYPE_ID_MASK) == 0);
353 
354  node->n_supers = n_supers;
355  if (!pnode)
356    {
357      node->supers[0] = type;
358      node->supers[1] = 0;
359     
360      node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0;
361      node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0;
362     
363      if (NODE_IS_IFACE (node))
364        {
365          IFACE_NODE_N_PREREQUISITES (node) = 0;
366          IFACE_NODE_PREREQUISITES (node) = NULL;
367        }
368      else
369        {
370          CLASSED_NODE_N_IFACES (node) = 0;
371          CLASSED_NODE_IFACES_ENTRIES (node) = NULL;
372        }
373    }
374  else
375    {
376      node->supers[0] = type;
377      memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1));
378     
379      node->is_classed = pnode->is_classed;
380      node->is_instantiatable = pnode->is_instantiatable;
381     
382      if (NODE_IS_IFACE (node))
383        {
384          IFACE_NODE_N_PREREQUISITES (node) = 0;
385          IFACE_NODE_PREREQUISITES (node) = NULL;
386        }
387      else
388        {
389          guint j;
390         
391          CLASSED_NODE_N_IFACES (node) = CLASSED_NODE_N_IFACES (pnode);
392          CLASSED_NODE_IFACES_ENTRIES (node) = g_memdup (CLASSED_NODE_IFACES_ENTRIES (pnode),
393                                                         sizeof (CLASSED_NODE_IFACES_ENTRIES (pnode)[0]) *
394                                                         CLASSED_NODE_N_IFACES (node));
395          for (j = 0; j < CLASSED_NODE_N_IFACES (node); j++)
396            {
397              CLASSED_NODE_IFACES_ENTRIES (node)[j].vtable = NULL;
398              CLASSED_NODE_IFACES_ENTRIES (node)[j].init_state = UNINITIALIZED;
399            }
400        }
401     
402      i = pnode->n_children++;
403      pnode->children = g_renew (GType, pnode->children, pnode->n_children);
404      pnode->children[i] = type;
405    }
406 
407  node->plugin = plugin;
408  node->n_children = 0;
409  node->children = NULL;
410  node->data = NULL;
411  node->qname = g_quark_from_string (name);
412  node->global_gdata = NULL;
413 
414  g_hash_table_insert (static_type_nodes_ht,
415                       GUINT_TO_POINTER (node->qname),
416                       (gpointer) type);
417  return node;
418}
419
420static inline GTypeFundamentalInfo*
421type_node_fundamental_info_I (TypeNode *node)
422{
423  GType ftype = NODE_FUNDAMENTAL_TYPE (node);
424 
425  if (ftype != NODE_TYPE (node))
426    node = lookup_type_node_I (ftype);
427 
428  return node ? G_STRUCT_MEMBER_P (node, -SIZEOF_FUNDAMENTAL_INFO) : NULL;
429}
430
431static TypeNode*
432type_node_fundamental_new_W (GType                 ftype,
433                             const gchar          *name,
434                             GTypeFundamentalFlags type_flags)
435{
436  GTypeFundamentalInfo *finfo;
437  TypeNode *node;
438 
439  g_assert ((ftype & TYPE_ID_MASK) == 0);
440  g_assert (ftype <= G_TYPE_FUNDAMENTAL_MAX);
441 
442  if (ftype >> G_TYPE_FUNDAMENTAL_SHIFT == static_fundamental_next)
443    static_fundamental_next++;
444 
445  type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK;
446 
447  node = type_node_any_new_W (NULL, ftype, name, NULL, type_flags);
448 
449  finfo = type_node_fundamental_info_I (node);
450  finfo->type_flags = type_flags;
451 
452  return node;
453}
454
455static TypeNode*
456type_node_new_W (TypeNode    *pnode,
457                 const gchar *name,
458                 GTypePlugin *plugin)
459     
460{
461  g_assert (pnode);
462  g_assert (pnode->n_supers < MAX_N_SUPERS);
463  g_assert (pnode->n_children < MAX_N_CHILDREN);
464 
465  return type_node_any_new_W (pnode, NODE_FUNDAMENTAL_TYPE (pnode), name, plugin, 0);
466}
467
468static inline IFaceEntry*
469type_lookup_iface_entry_L (TypeNode *node,
470                           TypeNode *iface_node)
471{
472  if (NODE_IS_IFACE (iface_node) && CLASSED_NODE_N_IFACES (node))
473    {
474      IFaceEntry *ifaces = CLASSED_NODE_IFACES_ENTRIES (node) - 1;
475      guint n_ifaces = CLASSED_NODE_N_IFACES (node);
476      GType iface_type = NODE_TYPE (iface_node);
477     
478      do
479        {
480          guint i;
481          IFaceEntry *check;
482         
483          i = (n_ifaces + 1) >> 1;
484          check = ifaces + i;
485          if (iface_type == check->iface_type)
486            return check;
487          else if (iface_type > check->iface_type)
488            {
489              n_ifaces -= i;
490              ifaces = check;
491            }
492          else /* if (iface_type < check->iface_type) */
493            n_ifaces = i - 1;
494        }
495      while (n_ifaces);
496    }
497 
498  return NULL;
499}
500
501static inline gboolean
502type_lookup_prerequisite_L (TypeNode *iface,
503                            GType     prerequisite_type)
504{
505  if (NODE_IS_IFACE (iface) && IFACE_NODE_N_PREREQUISITES (iface))
506    {
507      GType *prerequisites = IFACE_NODE_PREREQUISITES (iface) - 1;
508      guint n_prerequisites = IFACE_NODE_N_PREREQUISITES (iface);
509     
510      do
511        {
512          guint i;
513          GType *check;
514         
515          i = (n_prerequisites + 1) >> 1;
516          check = prerequisites + i;
517          if (prerequisite_type == *check)
518            return TRUE;
519          else if (prerequisite_type > *check)
520            {
521              n_prerequisites -= i;
522              prerequisites = check;
523            }
524          else /* if (prerequisite_type < *check) */
525            n_prerequisites = i - 1;
526        }
527      while (n_prerequisites);
528    }
529  return FALSE;
530}
531
532static gchar*
533type_descriptive_name_I (GType type)
534{
535  if (type)
536    {
537      TypeNode *node = lookup_type_node_I (type);
538     
539      return node ? NODE_NAME (node) : "<unknown>";
540    }
541  else
542    return "<invalid>";
543}
544
545
546/* --- type consistency checks --- */
547static gboolean
548check_plugin_U (GTypePlugin *plugin,
549                gboolean     need_complete_type_info,
550                gboolean     need_complete_interface_info,
551                const gchar *type_name)
552{
553  /* G_IS_TYPE_PLUGIN() and G_TYPE_PLUGIN_GET_CLASS() are external calls: _U
554   */
555  if (!plugin)
556    {
557      g_warning ("plugin handle for type `%s' is NULL",
558                 type_name);
559      return FALSE;
560    }
561  if (!G_IS_TYPE_PLUGIN (plugin))
562    {
563      g_warning ("plugin pointer (%p) for type `%s' is invalid",
564                 plugin, type_name);
565      return FALSE;
566    }
567  if (need_complete_type_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_type_info)
568    {
569      g_warning ("plugin for type `%s' has no complete_type_info() implementation",
570                 type_name);
571      return FALSE;
572    }
573  if (need_complete_interface_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_interface_info)
574    {
575      g_warning ("plugin for type `%s' has no complete_interface_info() implementation",
576                 type_name);
577      return FALSE;
578    }
579  return TRUE;
580}
581
582static gboolean
583check_type_name_I (const gchar *type_name)
584{
585  static const gchar *extra_chars = "-_+";
586  const gchar *p = type_name;
587  gboolean name_valid;
588 
589  if (!type_name[0] || !type_name[1] || !type_name[2])
590    {
591      g_warning ("type name `%s' is too short", type_name);
592      return FALSE;
593    }
594  /* check the first letter */
595  name_valid = (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || p[0] == '_';
596  for (p = type_name + 1; *p; p++)
597    name_valid &= ((p[0] >= 'A' && p[0] <= 'Z') ||
598                   (p[0] >= 'a' && p[0] <= 'z') ||
599                   (p[0] >= '0' && p[0] <= '9') ||
600                   strchr (extra_chars, p[0]));
601  if (!name_valid)
602    {
603      g_warning ("type name `%s' contains invalid characters", type_name);
604      return FALSE;
605    }
606  if (g_type_from_name (type_name))
607    {
608      g_warning ("cannot register existing type `%s'", type_name);
609      return FALSE;
610    }
611 
612  return TRUE;
613}
614
615static gboolean
616check_derivation_I (GType        parent_type,
617                    const gchar *type_name)
618{
619  TypeNode *pnode;
620  GTypeFundamentalInfo* finfo;
621 
622  pnode = lookup_type_node_I (parent_type);
623  if (!pnode)
624    {
625      g_warning ("cannot derive type `%s' from invalid parent type `%s'",
626                 type_name,
627                 type_descriptive_name_I (parent_type));
628      return FALSE;
629    }
630  finfo = type_node_fundamental_info_I (pnode);
631  /* ensure flat derivability */
632  if (!(finfo->type_flags & G_TYPE_FLAG_DERIVABLE))
633    {
634      g_warning ("cannot derive `%s' from non-derivable parent type `%s'",
635                 type_name,
636                 NODE_NAME (pnode));
637      return FALSE;
638    }
639  /* ensure deep derivability */
640  if (parent_type != NODE_FUNDAMENTAL_TYPE (pnode) &&
641      !(finfo->type_flags & G_TYPE_FLAG_DEEP_DERIVABLE))
642    {
643      g_warning ("cannot derive `%s' from non-fundamental parent type `%s'",
644                 type_name,
645                 NODE_NAME (pnode));
646      return FALSE;
647    }
648 
649  return TRUE;
650}
651
652static gboolean
653check_collect_format_I (const gchar *collect_format)
654{
655  const gchar *p = collect_format;
656  gchar valid_format[] = { G_VALUE_COLLECT_INT, G_VALUE_COLLECT_LONG,
657                           G_VALUE_COLLECT_INT64, G_VALUE_COLLECT_DOUBLE,
658                           G_VALUE_COLLECT_POINTER, 0 };
659 
660  while (*p)
661    if (!strchr (valid_format, *p++))
662      return FALSE;
663  return p - collect_format <= G_VALUE_COLLECT_FORMAT_MAX_LENGTH;
664}
665
666static gboolean
667check_value_table_I (const gchar           *type_name,
668                     const GTypeValueTable *value_table)
669{
670  if (!value_table)
671    return FALSE;
672  else if (value_table->value_init == NULL)
673    {
674      if (value_table->value_free || value_table->value_copy ||
675          value_table->value_peek_pointer ||
676          value_table->collect_format || value_table->collect_value ||
677          value_table->lcopy_format || value_table->lcopy_value)
678        g_warning ("cannot handle uninitializable values of type `%s'",
679                   type_name);
680      return FALSE;
681    }
682  else /* value_table->value_init != NULL */
683    {
684      if (!value_table->value_free)
685        {
686          /* +++ optional +++
687           * g_warning ("missing `value_free()' for type `%s'", type_name);
688           * return FALSE;
689           */
690        }
691      if (!value_table->value_copy)
692        {
693          g_warning ("missing `value_copy()' for type `%s'", type_name);
694          return FALSE;
695        }
696      if ((value_table->collect_format || value_table->collect_value) &&
697          (!value_table->collect_format || !value_table->collect_value))
698        {
699          g_warning ("one of `collect_format' and `collect_value()' is unspecified for type `%s'",
700                     type_name);
701          return FALSE;
702        }
703      if (value_table->collect_format && !check_collect_format_I (value_table->collect_format))
704        {
705          g_warning ("the `%s' specification for type `%s' is too long or invalid",
706                     "collect_format",
707                     type_name);
708          return FALSE;
709        }
710      if ((value_table->lcopy_format || value_table->lcopy_value) &&
711          (!value_table->lcopy_format || !value_table->lcopy_value))
712        {
713          g_warning ("one of `lcopy_format' and `lcopy_value()' is unspecified for type `%s'",
714                     type_name);
715          return FALSE;
716        }
717      if (value_table->lcopy_format && !check_collect_format_I (value_table->lcopy_format))
718        {
719          g_warning ("the `%s' specification for type `%s' is too long or invalid",
720                     "lcopy_format",
721                     type_name);
722          return FALSE;
723        }
724    }
725  return TRUE;
726}
727
728static gboolean
729check_type_info_I (TypeNode        *pnode,
730                   GType            ftype,
731                   const gchar     *type_name,
732                   const GTypeInfo *info)
733{
734  GTypeFundamentalInfo *finfo = type_node_fundamental_info_I (lookup_type_node_I (ftype));
735  gboolean is_interface = ftype == G_TYPE_INTERFACE;
736 
737  g_assert (ftype <= G_TYPE_FUNDAMENTAL_MAX && !(ftype & TYPE_ID_MASK));
738 
739  /* check instance members */
740  if (!(finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
741      (info->instance_size || info->n_preallocs || info->instance_init))
742    {
743      if (pnode)
744        g_warning ("cannot instantiate `%s', derived from non-instantiatable parent type `%s'",
745                   type_name,
746                   NODE_NAME (pnode));
747      else
748        g_warning ("cannot instantiate `%s' as non-instantiatable fundamental",
749                   type_name);
750      return FALSE;
751    }
752  /* check class & interface members */
753  if (!((finfo->type_flags & G_TYPE_FLAG_CLASSED) || is_interface) &&
754      (info->class_init || info->class_finalize || info->class_data ||
755       info->class_size || info->base_init || info->base_finalize))
756    {
757      if (pnode)
758        g_warning ("cannot create class for `%s', derived from non-classed parent type `%s'",
759                   type_name,
760                   NODE_NAME (pnode));
761      else
762        g_warning ("cannot create class for `%s' as non-classed fundamental",
763                   type_name);
764      return FALSE;
765    }
766  /* check interface size */
767  if (is_interface && info->class_size < sizeof (GTypeInterface))
768    {
769      g_warning ("specified interface size for type `%s' is smaller than `GTypeInterface' size",
770                 type_name);
771      return FALSE;
772    }
773  /* check class size */
774  if (finfo->type_flags & G_TYPE_FLAG_CLASSED)
775    {
776      if (info->class_size < sizeof (GTypeClass))
777        {
778          g_warning ("specified class size for type `%s' is smaller than `GTypeClass' size",
779                     type_name);
780          return FALSE;
781        }
782      if (pnode && info->class_size < pnode->data->class.class_size)
783        {
784          g_warning ("specified class size for type `%s' is smaller "
785                     "than the parent type's `%s' class size",
786                     type_name,
787                     NODE_NAME (pnode));
788          return FALSE;
789        }
790    }
791  /* check instance size */
792  if (finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE)
793    {
794      if (info->instance_size < sizeof (GTypeInstance))
795        {
796          g_warning ("specified instance size for type `%s' is smaller than `GTypeInstance' size",
797                     type_name);
798          return FALSE;
799        }
800      if (pnode && info->instance_size < pnode->data->instance.instance_size)
801        {
802          g_warning ("specified instance size for type `%s' is smaller "
803                     "than the parent type's `%s' instance size",
804                     type_name,
805                     NODE_NAME (pnode));
806          return FALSE;
807        }
808    }
809 
810  return TRUE;
811}
812
813static TypeNode*
814find_conforming_child_type_L (TypeNode *pnode,
815                              TypeNode *iface)
816{
817  TypeNode *node = NULL;
818  guint i;
819 
820  if (type_lookup_iface_entry_L (pnode, iface))
821    return pnode;
822 
823  for (i = 0; i < pnode->n_children && !node; i++)
824    node = find_conforming_child_type_L (lookup_type_node_I (pnode->children[i]), iface);
825 
826  return node;
827}
828
829static gboolean
830check_add_interface_L (GType instance_type,
831                       GType iface_type)
832{
833  TypeNode *node = lookup_type_node_I (instance_type);
834  TypeNode *iface = lookup_type_node_I (iface_type);
835  IFaceEntry *entry;
836  TypeNode *tnode;
837  GType *prerequisites;
838  guint i;
839
840 
841  if (!node || !node->is_instantiatable)
842    {
843      g_warning ("cannot add interfaces to invalid (non-instantiatable) type `%s'",
844                 type_descriptive_name_I (instance_type));
845      return FALSE;
846    }
847  if (!iface || !NODE_IS_IFACE (iface))
848    {
849      g_warning ("cannot add invalid (non-interface) type `%s' to type `%s'",
850                 type_descriptive_name_I (iface_type),
851                 NODE_NAME (node));
852      return FALSE;
853    }
854  tnode = lookup_type_node_I (NODE_PARENT_TYPE (iface));
855  if (NODE_PARENT_TYPE (tnode) && !type_lookup_iface_entry_L (node, tnode))
856    {
857      /* 2001/7/31:timj: erk, i guess this warning is junk as interface derivation is flat */
858      g_warning ("cannot add sub-interface `%s' to type `%s' which does not conform to super-interface `%s'",
859                 NODE_NAME (iface),
860                 NODE_NAME (node),
861                 NODE_NAME (tnode));
862      return FALSE;
863    }
864  /* allow overriding of interface type introduced for parent type */
865  entry = type_lookup_iface_entry_L (node, iface);
866  if (entry && entry->vtable == NULL && !type_iface_peek_holder_L (iface, NODE_TYPE (node)))
867    {
868      /* ok, we do conform to this interface already, but the interface vtable was not
869       * yet intialized, and we just conform to the interface because it got added to
870       * one of our parents. so we allow overriding of holder info here.
871       */
872      return TRUE;
873    }
874  /* check whether one of our children already conforms (or whether the interface
875   * got added to this node already)
876   */
877  tnode = find_conforming_child_type_L (node, iface);  /* tnode is_a node */
878  if (tnode)
879    {
880      g_warning ("cannot add interface type `%s' to type `%s', since type `%s' already conforms to interface",
881                 NODE_NAME (iface),
882                 NODE_NAME (node),
883                 NODE_NAME (tnode));
884      return FALSE;
885    }
886  prerequisites = IFACE_NODE_PREREQUISITES (iface);
887  for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
888    {
889      tnode = lookup_type_node_I (prerequisites[i]);
890      if (!type_node_is_a_L (node, tnode))
891        {
892          g_warning ("cannot add interface type `%s' to type `%s' which does not conform to prerequisite `%s'",
893                     NODE_NAME (iface),
894                     NODE_NAME (node),
895                     NODE_NAME (tnode));
896          return FALSE;
897        }
898    }
899  return TRUE;
900}
901
902static gboolean
903check_interface_info_I (TypeNode             *iface,
904                        GType                 instance_type,
905                        const GInterfaceInfo *info)
906{
907  if ((info->interface_finalize || info->interface_data) && !info->interface_init)
908    {
909      g_warning ("interface type `%s' for type `%s' comes without initializer",
910                 NODE_NAME (iface),
911                 type_descriptive_name_I (instance_type));
912      return FALSE;
913    }
914 
915  return TRUE;
916}
917
918/* --- type info (type node data) --- */
919static void
920type_data_make_W (TypeNode              *node,
921                  const GTypeInfo       *info,
922                  const GTypeValueTable *value_table)
923{
924  TypeData *data;
925  GTypeValueTable *vtable = NULL;
926  guint vtable_size = 0;
927 
928  g_assert (node->data == NULL && info != NULL);
929 
930  if (!value_table)
931    {
932      TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
933     
934      if (pnode)
935        vtable = pnode->data->common.value_table;
936      else
937        {
938          static const GTypeValueTable zero_vtable = { NULL, };
939         
940          value_table = &zero_vtable;
941        }
942    }
943  if (value_table)
944    {
945      /* need to setup vtable_size since we have to allocate it with data in one chunk */
946      vtable_size = sizeof (GTypeValueTable);
947      if (value_table->collect_format)
948        vtable_size += strlen (value_table->collect_format);
949      if (value_table->lcopy_format)
950        vtable_size += strlen (value_table->lcopy_format);
951      vtable_size += 2;
952    }
953   
954  if (node->is_instantiatable) /* carefull, is_instantiatable is also is_classed */
955    {
956      data = g_malloc0 (sizeof (InstanceData) + vtable_size);
957      if (vtable_size)
958        vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData));
959      data->instance.class_size = info->class_size;
960      data->instance.class_init_base = info->base_init;
961      data->instance.class_finalize_base = info->base_finalize;
962      data->instance.class_init = info->class_init;
963      data->instance.class_finalize = info->class_finalize;
964      data->instance.class_data = info->class_data;
965      data->instance.class = NULL;
966      data->instance.init_state = UNINITIALIZED;
967      data->instance.instance_size = info->instance_size;
968      /* We'll set the final value for data->instance.private size
969       * after the parent class has been initialized
970       */
971      data->instance.private_size = 0;
972#ifdef  DISABLE_MEM_POOLS
973      data->instance.n_preallocs = 0;
974#else   /* !DISABLE_MEM_POOLS */
975      data->instance.n_preallocs = MIN (info->n_preallocs, 1024);
976#endif  /* !DISABLE_MEM_POOLS */
977      data->instance.instance_init = info->instance_init;
978      data->instance.mem_chunk = NULL;
979    }
980  else if (node->is_classed) /* only classed */
981    {
982      data = g_malloc0 (sizeof (ClassData) + vtable_size);
983      if (vtable_size)
984        vtable = G_STRUCT_MEMBER_P (data, sizeof (ClassData));
985      data->class.class_size = info->class_size;
986      data->class.class_init_base = info->base_init;
987      data->class.class_finalize_base = info->base_finalize;
988      data->class.class_init = info->class_init;
989      data->class.class_finalize = info->class_finalize;
990      data->class.class_data = info->class_data;
991      data->class.class = NULL;
992      data->class.init_state = UNINITIALIZED;
993    }
994  else if (NODE_IS_IFACE (node))
995    {
996      data = g_malloc0 (sizeof (IFaceData) + vtable_size);
997      if (vtable_size)
998        vtable = G_STRUCT_MEMBER_P (data, sizeof (IFaceData));
999      data->iface.vtable_size = info->class_size;
1000      data->iface.vtable_init_base = info->base_init;
1001      data->iface.vtable_finalize_base = info->base_finalize;
1002      data->iface.dflt_init = info->class_init;
1003      data->iface.dflt_finalize = info->class_finalize;
1004      data->iface.dflt_data = info->class_data;
1005      data->iface.dflt_vtable = NULL;
1006    }
1007  else
1008    {
1009      data = g_malloc0 (sizeof (CommonData) + vtable_size);
1010      if (vtable_size)
1011        vtable = G_STRUCT_MEMBER_P (data, sizeof (CommonData));
1012    }
1013 
1014  node->data = data;
1015  node->data->common.ref_count = 1;
1016 
1017  if (vtable_size)
1018    {
1019      gchar *p;
1020     
1021      /* we allocate the vtable and its strings together with the type data, so
1022       * children can take over their parent's vtable pointer, and we don't
1023       * need to worry freeing it or not when the child data is destroyed
1024       */
1025      *vtable = *value_table;
1026      p = G_STRUCT_MEMBER_P (vtable, sizeof (*vtable));
1027      p[0] = 0;
1028      vtable->collect_format = p;
1029      if (value_table->collect_format)
1030        {
1031          strcat (p, value_table->collect_format);
1032          p += strlen (value_table->collect_format);
1033        }
1034      p++;
1035      p[0] = 0;
1036      vtable->lcopy_format = p;
1037      if (value_table->lcopy_format)
1038        strcat  (p, value_table->lcopy_format);
1039    }
1040  node->data->common.value_table = vtable;
1041  node->mutatable_check_cache = (node->data->common.value_table->value_init != NULL &&
1042                                 !((G_TYPE_FLAG_VALUE_ABSTRACT | G_TYPE_FLAG_ABSTRACT) &
1043                                   GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags))));
1044 
1045  g_assert (node->data->common.value_table != NULL); /* paranoid */
1046}
1047
1048static inline void
1049type_data_ref_Wm (TypeNode *node)
1050{
1051  if (!node->data)
1052    {
1053      TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
1054      GTypeInfo tmp_info;
1055      GTypeValueTable tmp_value_table;
1056     
1057      g_assert (node->plugin != NULL);
1058     
1059      if (pnode)
1060        {
1061          type_data_ref_Wm (pnode);
1062          if (node->data)
1063            INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
1064        }
1065     
1066      memset (&tmp_info, 0, sizeof (tmp_info));
1067      memset (&tmp_value_table, 0, sizeof (tmp_value_table));
1068     
1069      G_WRITE_UNLOCK (&type_rw_lock);
1070      g_type_plugin_use (node->plugin);
1071      g_type_plugin_complete_type_info (node->plugin, NODE_TYPE (node), &tmp_info, &tmp_value_table);
1072      G_WRITE_LOCK (&type_rw_lock);
1073      if (node->data)
1074        INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
1075     
1076      check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (node), NODE_NAME (node), &tmp_info);
1077      type_data_make_W (node, &tmp_info,
1078                        check_value_table_I (NODE_NAME (node),
1079                                             &tmp_value_table) ? &tmp_value_table : NULL);
1080    }
1081  else
1082    {
1083      g_assert (node->data->common.ref_count > 0);
1084     
1085      node->data->common.ref_count += 1;
1086    }
1087}
1088
1089static inline void
1090type_data_unref_Wm (TypeNode *node,
1091                    gboolean  uncached)
1092{
1093  g_assert (node->data && node->data->common.ref_count);
1094 
1095  if (node->data->common.ref_count > 1)
1096    node->data->common.ref_count -= 1;
1097  else
1098    {
1099      if (!node->plugin)
1100        {
1101          g_warning ("static type `%s' unreferenced too often",
1102                     NODE_NAME (node));
1103          return;
1104        }
1105     
1106      type_data_last_unref_Wm (NODE_TYPE (node), uncached);
1107    }
1108}
1109
1110static void
1111type_node_add_iface_entry_W (TypeNode   *node,
1112                             GType       iface_type,
1113                             IFaceEntry *parent_entry)
1114{
1115  IFaceEntry *entries;
1116  guint i;
1117 
1118  g_assert (node->is_instantiatable && CLASSED_NODE_N_IFACES (node) < MAX_N_IFACES);
1119 
1120  entries = CLASSED_NODE_IFACES_ENTRIES (node);
1121  for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
1122    if (entries[i].iface_type == iface_type)
1123      {
1124        /* this can happen in two cases:
1125         * - our parent type already conformed to iface_type and node
1126         *   got it's own holder info. here, our children already have
1127         *   entries and NULL vtables, since this will only work for
1128         *   uninitialized classes.
1129         * - an interface type is added to an ancestor after it was
1130         *   added to a child type.
1131         */
1132        if (!parent_entry)
1133          g_assert (entries[i].vtable == NULL && entries[i].init_state == UNINITIALIZED);
1134        else
1135          {
1136            /* sick, interface is added to ancestor *after* child type;
1137             * nothing todo, the entry and our children were already setup correctly
1138             */
1139          }
1140        return;
1141      }
1142    else if (entries[i].iface_type > iface_type)
1143      break;
1144  CLASSED_NODE_N_IFACES (node) += 1;
1145  CLASSED_NODE_IFACES_ENTRIES (node) = g_renew (IFaceEntry,
1146                                                CLASSED_NODE_IFACES_ENTRIES (node),
1147                                                CLASSED_NODE_N_IFACES (node));
1148  entries = CLASSED_NODE_IFACES_ENTRIES (node);
1149  g_memmove (entries + i + 1, entries + i, sizeof (entries[0]) * (CLASSED_NODE_N_IFACES (node) - i - 1));
1150  entries[i].iface_type = iface_type;
1151  entries[i].vtable = NULL;
1152  entries[i].init_state = UNINITIALIZED;
1153
1154  if (parent_entry)
1155    {
1156      if (node->data && node->data->class.init_state >= BASE_IFACE_INIT)
1157        {
1158          entries[i].init_state = INITIALIZED;
1159          entries[i].vtable = parent_entry->vtable;
1160        }
1161      for (i = 0; i < node->n_children; i++)
1162        type_node_add_iface_entry_W (lookup_type_node_I (node->children[i]), iface_type, &entries[i]);
1163    }
1164}
1165
1166static void
1167type_add_interface_Wm (TypeNode             *node,
1168                       TypeNode             *iface,
1169                       const GInterfaceInfo *info,
1170                       GTypePlugin          *plugin)
1171{
1172  IFaceHolder *iholder = g_new0 (IFaceHolder, 1);
1173  IFaceEntry *entry;
1174  guint i;
1175 
1176  g_assert (node->is_instantiatable && NODE_IS_IFACE (iface) && ((info && !plugin) || (!info && plugin)));
1177 
1178  iholder->next = iface_node_get_holders_L (iface);
1179  iface_node_set_holders_W (iface, iholder);
1180  iholder->instance_type = NODE_TYPE (node);
1181  iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL;
1182  iholder->plugin = plugin;
1183
1184  /* create an iface entry for this type */
1185  type_node_add_iface_entry_W (node, NODE_TYPE (iface), NULL);
1186 
1187  /* if the class is already (partly) initialized, we may need to base
1188   * initalize and/or initialize the new interface.
1189   */
1190  if (node->data)
1191    {
1192      InitState class_state = node->data->class.init_state;
1193     
1194      if (class_state >= BASE_IFACE_INIT)
1195        type_iface_vtable_base_init_Wm (iface, node);
1196     
1197      if (class_state >= IFACE_INIT)
1198        type_iface_vtable_iface_init_Wm (iface, node);
1199    }
1200 
1201  /* create iface entries for children of this type */
1202  entry = type_lookup_iface_entry_L (node, iface);
1203  for (i = 0; i < node->n_children; i++)
1204    type_node_add_iface_entry_W (lookup_type_node_I (node->children[i]), NODE_TYPE (iface), entry);
1205}
1206
1207static void
1208type_iface_add_prerequisite_W (TypeNode *iface,
1209                               TypeNode *prerequisite_node)
1210{
1211  GType prerequisite_type = NODE_TYPE (prerequisite_node);
1212  GType *prerequisites, *dependants;
1213  guint n_dependants, i;
1214 
1215  g_assert (NODE_IS_IFACE (iface) &&
1216            IFACE_NODE_N_PREREQUISITES (iface) < MAX_N_PREREQUISITES &&
1217            (prerequisite_node->is_instantiatable || NODE_IS_IFACE (prerequisite_node)));
1218 
1219  prerequisites = IFACE_NODE_PREREQUISITES (iface);
1220  for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
1221    if (prerequisites[i] == prerequisite_type)
1222      return;                   /* we already have that prerequisiste */
1223    else if (prerequisites[i] > prerequisite_type)
1224      break;
1225  IFACE_NODE_N_PREREQUISITES (iface) += 1;
1226  IFACE_NODE_PREREQUISITES (iface) = g_renew (GType,
1227                                              IFACE_NODE_PREREQUISITES (iface),
1228                                              IFACE_NODE_N_PREREQUISITES (iface));
1229  prerequisites = IFACE_NODE_PREREQUISITES (iface);
1230  g_memmove (prerequisites + i + 1, prerequisites + i,
1231             sizeof (prerequisites[0]) * (IFACE_NODE_N_PREREQUISITES (iface) - i - 1));
1232  prerequisites[i] = prerequisite_type;
1233 
1234  /* we want to get notified when prerequisites get added to prerequisite_node */
1235  if (NODE_IS_IFACE (prerequisite_node))
1236    {
1237      dependants = iface_node_get_dependants_array_L (prerequisite_node);
1238      n_dependants = dependants ? dependants[0] : 0;
1239      n_dependants += 1;
1240      dependants = g_renew (GType, dependants, n_dependants + 1);
1241      dependants[n_dependants] = NODE_TYPE (iface);
1242      dependants[0] = n_dependants;
1243      iface_node_set_dependants_array_W (prerequisite_node, dependants);
1244    }
1245 
1246  /* we need to notify all dependants */
1247  dependants = iface_node_get_dependants_array_L (iface);
1248  n_dependants = dependants ? dependants[0] : 0;
1249  for (i = 1; i <= n_dependants; i++)
1250    type_iface_add_prerequisite_W (lookup_type_node_I (dependants[i]), prerequisite_node);
1251}
1252
1253void
1254g_type_interface_add_prerequisite (GType interface_type,
1255                                   GType prerequisite_type)
1256{
1257  TypeNode *iface, *prerequisite_node;
1258  IFaceHolder *holders;
1259 
1260  g_return_if_fail (G_TYPE_IS_INTERFACE (interface_type));      /* G_TYPE_IS_INTERFACE() is an external call: _U */
1261  g_return_if_fail (!g_type_is_a (interface_type, prerequisite_type));
1262  g_return_if_fail (!g_type_is_a (prerequisite_type, interface_type));
1263 
1264  iface = lookup_type_node_I (interface_type);
1265  prerequisite_node = lookup_type_node_I (prerequisite_type);
1266  if (!iface || !prerequisite_node || !NODE_IS_IFACE (iface))
1267    {
1268      g_warning ("interface type `%s' or prerequisite type `%s' invalid",
1269                 type_descriptive_name_I (interface_type),
1270                 type_descriptive_name_I (prerequisite_type));
1271      return;
1272    }
1273  G_WRITE_LOCK (&type_rw_lock);
1274  holders = iface_node_get_holders_L (iface);
1275  if (holders)
1276    {
1277      G_WRITE_UNLOCK (&type_rw_lock);
1278      g_warning ("unable to add prerequisite `%s' to interface `%s' which is already in use for `%s'",
1279                 type_descriptive_name_I (prerequisite_type),
1280                 type_descriptive_name_I (interface_type),
1281                 type_descriptive_name_I (holders->instance_type));
1282      return;
1283    }
1284  if (prerequisite_node->is_instantiatable)
1285    {
1286      guint i;
1287     
1288      /* can have at most one publically installable instantiatable prerequisite */
1289      for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
1290        {
1291          TypeNode *prnode = lookup_type_node_I (IFACE_NODE_PREREQUISITES (iface)[i]);
1292         
1293          if (prnode->is_instantiatable)
1294            {
1295              G_WRITE_UNLOCK (&type_rw_lock);
1296              g_warning ("adding prerequisite `%s' to interface `%s' conflicts with existing prerequisite `%s'",
1297                         type_descriptive_name_I (prerequisite_type),
1298                         type_descriptive_name_I (interface_type),
1299                         type_descriptive_name_I (NODE_TYPE (prnode)));
1300              return;
1301            }
1302        }
1303     
1304      for (i = 0; i < prerequisite_node->n_supers + 1; i++)
1305        type_iface_add_prerequisite_W (iface, lookup_type_node_I (prerequisite_node->supers[i]));
1306      G_WRITE_UNLOCK (&type_rw_lock);
1307    }
1308  else if (NODE_IS_IFACE (prerequisite_node))
1309    {
1310      GType *prerequisites;
1311      guint i;
1312     
1313      prerequisites = IFACE_NODE_PREREQUISITES (prerequisite_node);
1314      for (i = 0; i < IFACE_NODE_N_PREREQUISITES (prerequisite_node); i++)
1315        type_iface_add_prerequisite_W (iface, lookup_type_node_I (prerequisites[i]));
1316      type_iface_add_prerequisite_W (iface, prerequisite_node);
1317      G_WRITE_UNLOCK (&type_rw_lock);
1318    }
1319  else
1320    {
1321      G_WRITE_UNLOCK (&type_rw_lock);
1322      g_warning ("prerequisite `%s' for interface `%s' is neither instantiatable nor interface",
1323                 type_descriptive_name_I (prerequisite_type),
1324                 type_descriptive_name_I (interface_type));
1325    }
1326}
1327
1328GType* /* free result */
1329g_type_interface_prerequisites (GType  interface_type,
1330                                guint *n_prerequisites)
1331{
1332  TypeNode *iface;
1333 
1334  g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL);
1335
1336  iface = lookup_type_node_I (interface_type);
1337  if (iface)
1338    {
1339      GType *types;
1340      TypeNode *inode = NULL;
1341      guint i, n = 0;
1342     
1343      G_READ_LOCK (&type_rw_lock);
1344      types = g_new0 (GType, IFACE_NODE_N_PREREQUISITES (iface) + 1);
1345      for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
1346        {
1347          GType prerequisite = IFACE_NODE_PREREQUISITES (iface)[i];
1348          TypeNode *node = lookup_type_node_I (prerequisite);
1349          if (node->is_instantiatable &&
1350              (!inode || type_node_is_a_L (node, inode)))
1351            inode = node;
1352          else
1353            types[n++] = NODE_TYPE (node);
1354        }
1355      if (inode)
1356        types[n++] = NODE_TYPE (inode);
1357     
1358      if (n_prerequisites)
1359        *n_prerequisites = n;
1360      G_READ_UNLOCK (&type_rw_lock);
1361     
1362      return types;
1363    }
1364  else
1365    {
1366      if (n_prerequisites)
1367        *n_prerequisites = 0;
1368     
1369      return NULL;
1370    }
1371}
1372
1373
1374static IFaceHolder*
1375type_iface_peek_holder_L (TypeNode *iface,
1376                          GType     instance_type)
1377{
1378  IFaceHolder *iholder;
1379 
1380  g_assert (NODE_IS_IFACE (iface));
1381 
1382  iholder = iface_node_get_holders_L (iface);
1383  while (iholder && iholder->instance_type != instance_type)
1384    iholder = iholder->next;
1385  return iholder;
1386}
1387
1388static IFaceHolder*
1389type_iface_retrieve_holder_info_Wm (TypeNode *iface,
1390                                    GType     instance_type,
1391                                    gboolean  need_info)
1392{
1393  IFaceHolder *iholder = type_iface_peek_holder_L (iface, instance_type);
1394 
1395  if (iholder && !iholder->info && need_info)
1396    {
1397      GInterfaceInfo tmp_info;
1398     
1399      g_assert (iholder->plugin != NULL);
1400     
1401      type_data_ref_Wm (iface);
1402      if (iholder->info)
1403        INVALID_RECURSION ("g_type_plugin_*", iface->plugin, NODE_NAME (iface));
1404     
1405      memset (&tmp_info, 0, sizeof (tmp_info));
1406     
1407      G_WRITE_UNLOCK (&type_rw_lock);
1408      g_type_plugin_use (iholder->plugin);
1409      g_type_plugin_complete_interface_info (iholder->plugin, instance_type, NODE_TYPE (iface), &tmp_info);
1410      G_WRITE_LOCK (&type_rw_lock);
1411      if (iholder->info)
1412        INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface));
1413     
1414      check_interface_info_I (iface, instance_type, &tmp_info);
1415      iholder->info = g_memdup (&tmp_info, sizeof (tmp_info));
1416    }
1417 
1418  return iholder;       /* we don't modify write lock upon returning NULL */
1419}
1420
1421static void
1422type_iface_blow_holder_info_Wm (TypeNode *iface,
1423                                GType     instance_type)
1424{
1425  IFaceHolder *iholder = iface_node_get_holders_L (iface);
1426 
1427  g_assert (NODE_IS_IFACE (iface));
1428 
1429  while (iholder->instance_type != instance_type)
1430    iholder = iholder->next;
1431 
1432  if (iholder->info && iholder->plugin)
1433    {
1434      g_free (iholder->info);
1435      iholder->info = NULL;
1436     
1437      G_WRITE_UNLOCK (&type_rw_lock);
1438      g_type_plugin_unuse (iholder->plugin);
1439      G_WRITE_LOCK (&type_rw_lock);
1440     
1441      type_data_unref_Wm (iface, FALSE);
1442    }
1443}
1444
1445/* Assumes type's class already exists
1446 */
1447static inline size_t
1448type_total_instance_size_I (TypeNode *node)
1449{
1450  gsize total_instance_size;
1451
1452  total_instance_size = node->data->instance.instance_size;
1453  if (node->data->instance.private_size != 0)
1454    total_instance_size = ALIGN_STRUCT (total_instance_size) + node->data->instance.private_size;
1455
1456  return total_instance_size;
1457}
1458
1459/* --- type structure creation/destruction --- */
1460typedef struct {
1461  gpointer instance;
1462  gpointer class;
1463} InstanceRealClass;
1464static gint
1465instance_real_class_cmp (gconstpointer p1,
1466                         gconstpointer p2)
1467{
1468  const InstanceRealClass *irc1 = p1;
1469  const InstanceRealClass *irc2 = p2;
1470  guint8 *i1 = irc1->instance;
1471  guint8 *i2 = irc2->instance;
1472  return G_BSEARCH_ARRAY_CMP (i1, i2);
1473}
1474G_LOCK_DEFINE_STATIC (instance_real_class);
1475static GBSearchArray *instance_real_class_bsa = NULL;
1476static GBSearchConfig instance_real_class_bconfig = {
1477  sizeof (InstanceRealClass),
1478  instance_real_class_cmp,
1479  0,
1480};
1481static inline void
1482instance_real_class_set (gpointer    instance,
1483                         GTypeClass *class)
1484{
1485  InstanceRealClass key;
1486  key.instance = instance;
1487  key.class = class;
1488  G_LOCK (instance_real_class);
1489  if (!instance_real_class_bsa)
1490    instance_real_class_bsa = g_bsearch_array_create (&instance_real_class_bconfig);
1491  instance_real_class_bsa = g_bsearch_array_replace (instance_real_class_bsa, &instance_real_class_bconfig, &key);
1492  G_UNLOCK (instance_real_class);
1493}
1494static inline void
1495instance_real_class_remove (gpointer instance)
1496{
1497  InstanceRealClass key, *node;
1498  guint index;
1499  key.instance = instance;
1500  G_LOCK (instance_real_class);
1501  node = g_bsearch_array_lookup (instance_real_class_bsa, &instance_real_class_bconfig, &key);
1502  index = g_bsearch_array_get_index (instance_real_class_bsa, &instance_real_class_bconfig, node);
1503  instance_real_class_bsa = g_bsearch_array_remove (instance_real_class_bsa, &instance_real_class_bconfig, index);
1504  if (!g_bsearch_array_get_n_nodes (instance_real_class_bsa))
1505    {
1506      g_bsearch_array_free (instance_real_class_bsa, &instance_real_class_bconfig);
1507      instance_real_class_bsa = NULL;
1508    }
1509  G_UNLOCK (instance_real_class);
1510}
1511static inline GTypeClass*
1512instance_real_class_get (gpointer instance)
1513{
1514  InstanceRealClass key, *node;
1515  key.instance = instance;
1516  G_LOCK (instance_real_class);
1517  node = instance_real_class_bsa ? g_bsearch_array_lookup (instance_real_class_bsa, &instance_real_class_bconfig, &key) : NULL;
1518  G_UNLOCK (instance_real_class);
1519  return node ? node->class : NULL;
1520}
1521
1522GTypeInstance*
1523g_type_create_instance (GType type)
1524{
1525  TypeNode *node;
1526  GTypeInstance *instance;
1527  GTypeClass *class;
1528  guint i;
1529  gsize total_instance_size;
1530 
1531  node = lookup_type_node_I (type);
1532  if (!node || !node->is_instantiatable)
1533    {
1534      g_warning ("cannot create new instance of invalid (non-instantiatable) type `%s'",
1535                 type_descriptive_name_I (type));
1536      return NULL;
1537    }
1538  /* G_TYPE_IS_ABSTRACT() is an external call: _U */
1539  if (!node->mutatable_check_cache && G_TYPE_IS_ABSTRACT (type))
1540    {
1541      g_warning ("cannot create instance of abstract (non-instantiatable) type `%s'",
1542                 type_descriptive_name_I (type));
1543      return NULL;
1544    }
1545 
1546  class = g_type_class_ref (type);
1547
1548  total_instance_size = type_total_instance_size_I (node);
1549 
1550  if (node->data->instance.n_preallocs)
1551    {
1552      G_WRITE_LOCK (&type_rw_lock);
1553      if (!node->data->instance.mem_chunk)
1554        {
1555          /* If there isn't private data, the compiler will have already
1556           * added the necessary padding, but in the private data case, we
1557           * have to pad ourselves to ensure proper alignment of all the
1558           * atoms in the slab.
1559           */
1560          gsize atom_size = total_instance_size;
1561          if (node->data->instance.private_size)
1562            atom_size = ALIGN_STRUCT (atom_size);
1563         
1564          node->data->instance.mem_chunk = g_mem_chunk_new (NODE_NAME (node),
1565                                                            atom_size,
1566                                                            (atom_size *
1567                                                             node->data->instance.n_preallocs),
1568                                                            G_ALLOC_AND_FREE);
1569        }
1570     
1571      instance = g_chunk_new0 (GTypeInstance, node->data->instance.mem_chunk);
1572      G_WRITE_UNLOCK (&type_rw_lock);
1573    }
1574  else
1575    instance = g_malloc0 (total_instance_size); /* fine without read lock */
1576
1577  if (node->data->instance.private_size)
1578    instance_real_class_set (instance, class);
1579  for (i = node->n_supers; i > 0; i--)
1580    {
1581      TypeNode *pnode;
1582     
1583      pnode = lookup_type_node_I (node->supers[i]);
1584      if (pnode->data->instance.instance_init)
1585        {
1586          instance->g_class = pnode->data->instance.class;
1587          pnode->data->instance.instance_init (instance, class);
1588        }
1589    }
1590  if (node->data->instance.private_size)
1591    instance_real_class_remove (instance);
1592
1593  instance->g_class = class;
1594  if (node->data->instance.instance_init)
1595    node->data->instance.instance_init (instance, class);
1596 
1597  return instance;
1598}
1599
1600void
1601g_type_free_instance (GTypeInstance *instance)
1602{
1603  TypeNode *node;
1604  GTypeClass *class;
1605 
1606  g_return_if_fail (instance != NULL && instance->g_class != NULL);
1607 
1608  class = instance->g_class;
1609  node = lookup_type_node_I (class->g_type);
1610  if (!node || !node->is_instantiatable || !node->data || node->data->class.class != (gpointer) class)
1611    {
1612      g_warning ("cannot free instance of invalid (non-instantiatable) type `%s'",
1613                 type_descriptive_name_I (class->g_type));
1614      return;
1615    }
1616  /* G_TYPE_IS_ABSTRACT() is an external call: _U */
1617  if (!node->mutatable_check_cache && G_TYPE_IS_ABSTRACT (NODE_TYPE (node)))
1618    {
1619      g_warning ("cannot free instance of abstract (non-instantiatable) type `%s'",
1620                 NODE_NAME (node));
1621      return;
1622    }
1623 
1624  instance->g_class = NULL;
1625#ifdef G_ENABLE_DEBUG 
1626  memset (instance, 0xaa, type_total_instance_size_I (node));   /* debugging hack */
1627#endif 
1628  if (node->data->instance.n_preallocs)
1629    {
1630      G_WRITE_LOCK (&type_rw_lock);
1631      g_chunk_free (instance, node->data->instance.mem_chunk);
1632      G_WRITE_UNLOCK (&type_rw_lock);
1633    }
1634  else
1635    g_free (instance);
1636 
1637  g_type_class_unref (class);
1638}
1639
1640static void
1641type_iface_ensure_dflt_vtable_Wm (TypeNode *iface)
1642{
1643  g_assert (iface->data);
1644
1645  if (!iface->data->iface.dflt_vtable)
1646    {
1647      GTypeInterface *vtable = g_malloc0 (iface->data->iface.vtable_size);
1648      iface->data->iface.dflt_vtable = vtable;
1649      vtable->g_type = NODE_TYPE (iface);
1650      vtable->g_instance_type = 0;
1651      if (iface->data->iface.vtable_init_base ||
1652          iface->data->iface.dflt_init)
1653        {
1654          G_WRITE_UNLOCK (&type_rw_lock);
1655          if (iface->data->iface.vtable_init_base)
1656            iface->data->iface.vtable_init_base (vtable);
1657          if (iface->data->iface.dflt_init)
1658            iface->data->iface.dflt_init (vtable, (gpointer) iface->data->iface.dflt_data);
1659          G_WRITE_LOCK (&type_rw_lock);
1660        }
1661    }
1662}
1663
1664
1665/* This is called to allocate and do the first part of initializing
1666 * the interface vtable; type_iface_vtable_iface_init_Wm() does the remainder.
1667 *
1668 * A FALSE return indicates that we didn't find an init function for
1669 * this type/iface pair, so the vtable from the parent type should
1670 * be used. Note that the write lock is not modified upon a FALSE
1671 * return.
1672 */
1673static gboolean
1674type_iface_vtable_base_init_Wm (TypeNode *iface,
1675                                TypeNode *node)
1676{
1677  IFaceEntry *entry;
1678  IFaceHolder *iholder;
1679  GTypeInterface *vtable = NULL;
1680  TypeNode *pnode;
1681 
1682  /* type_iface_retrieve_holder_info_Wm() doesn't modify write lock for returning NULL */
1683  iholder = type_iface_retrieve_holder_info_Wm (iface, NODE_TYPE (node), TRUE);
1684  if (!iholder)
1685    return FALSE;       /* we don't modify write lock upon FALSE */
1686
1687  type_iface_ensure_dflt_vtable_Wm (iface);
1688
1689  entry = type_lookup_iface_entry_L (node, iface);
1690
1691  g_assert (iface->data && entry && entry->vtable == NULL && iholder && iholder->info);
1692 
1693  entry->init_state = IFACE_INIT;
1694
1695  pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
1696  if (pnode)    /* want to copy over parent iface contents */
1697    {
1698      IFaceEntry *pentry = type_lookup_iface_entry_L (pnode, iface);
1699     
1700      if (pentry)
1701        vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size);
1702    }
1703  if (!vtable)
1704    vtable = g_memdup (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
1705  entry->vtable = vtable;
1706  vtable->g_type = NODE_TYPE (iface);
1707  vtable->g_instance_type = NODE_TYPE (node);
1708 
1709  if (iface->data->iface.vtable_init_base)
1710    {
1711      G_WRITE_UNLOCK (&type_rw_lock);
1712      iface->data->iface.vtable_init_base (vtable);
1713      G_WRITE_LOCK (&type_rw_lock);
1714    }
1715  return TRUE;  /* initialized the vtable */
1716}
1717
1718/* Finishes what type_iface_vtable_base_init_Wm started by
1719 * calling the interface init function.
1720 * this function may only be called for types with their
1721 * own interface holder info, i.e. types for which
1722 * g_type_add_interface*() was called and not children thereof.
1723 */
1724static void
1725type_iface_vtable_iface_init_Wm (TypeNode *iface,
1726                                 TypeNode *node)
1727{
1728  IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
1729  IFaceHolder *iholder = type_iface_peek_holder_L (iface, NODE_TYPE (node));
1730  GTypeInterface *vtable = NULL;
1731  guint i;
1732 
1733  /* iholder->info should have been filled in by type_iface_vtable_base_init_Wm() */
1734  g_assert (iface->data && entry && iholder && iholder->info);
1735  g_assert (entry->init_state == IFACE_INIT); /* assert prior base_init() */
1736 
1737  entry->init_state = INITIALIZED;
1738     
1739  vtable = entry->vtable;
1740
1741  if (iholder->info->interface_init)
1742    {
1743      G_WRITE_UNLOCK (&type_rw_lock);
1744      if (iholder->info->interface_init)
1745        iholder->info->interface_init (vtable, iholder->info->interface_data);
1746      G_WRITE_LOCK (&type_rw_lock);
1747    }
1748 
1749  for (i = 0; i < static_n_iface_check_funcs; i++)
1750    {
1751      GTypeInterfaceCheckFunc check_func = static_iface_check_funcs[i].check_func;
1752      gpointer check_data = static_iface_check_funcs[i].check_data;
1753
1754      G_WRITE_UNLOCK (&type_rw_lock);
1755      check_func (check_data, (gpointer)vtable);
1756      G_WRITE_LOCK (&type_rw_lock);     
1757    }
1758}
1759
1760static gboolean
1761type_iface_vtable_finalize_Wm (TypeNode       *iface,
1762                               TypeNode       *node,
1763                               GTypeInterface *vtable)
1764{
1765  IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
1766  IFaceHolder *iholder;
1767 
1768  /* type_iface_retrieve_holder_info_Wm() doesn't modify write lock for returning NULL */
1769  iholder = type_iface_retrieve_holder_info_Wm (iface, NODE_TYPE (node), FALSE);
1770  if (!iholder)
1771    return FALSE;       /* we don't modify write lock upon FALSE */
1772 
1773  g_assert (entry && entry->vtable == vtable && iholder->info);
1774 
1775  entry->vtable = NULL;
1776  entry->init_state = UNINITIALIZED;
1777  if (iholder->info->interface_finalize || iface->data->iface.vtable_finalize_base)
1778    {
1779      G_WRITE_UNLOCK (&type_rw_lock);
1780      if (iholder->info->interface_finalize)
1781        iholder->info->interface_finalize (vtable, iholder->info->interface_data);
1782      if (iface->data->iface.vtable_finalize_base)
1783        iface->data->iface.vtable_finalize_base (vtable);
1784      G_WRITE_LOCK (&type_rw_lock);
1785    }
1786  vtable->g_type = 0;
1787  vtable->g_instance_type = 0;
1788  g_free (vtable);
1789 
1790  type_iface_blow_holder_info_Wm (iface, NODE_TYPE (node));
1791 
1792  return TRUE;  /* write lock modified */
1793}
1794
1795static void
1796type_class_init_Wm (TypeNode   *node,
1797                    GTypeClass *pclass)
1798{
1799  GSList *slist, *init_slist = NULL;
1800  GTypeClass *class;
1801  IFaceEntry *entry;
1802  TypeNode *bnode, *pnode;
1803  guint i;
1804 
1805  g_assert (node->is_classed && node->data &&
1806            node->data->class.class_size &&
1807            !node->data->class.class &&
1808            node->data->class.init_state == UNINITIALIZED);
1809
1810  class = g_malloc0 (node->data->class.class_size);
1811  node->data->class.class = class;
1812  node->data->class.init_state = BASE_CLASS_INIT;
1813 
1814  if (pclass)
1815    {
1816      TypeNode *pnode = lookup_type_node_I (pclass->g_type);
1817     
1818      memcpy (class, pclass, pnode->data->class.class_size);
1819
1820      if (node->is_instantiatable)
1821        {
1822          /* We need to initialize the private_size here rather than in
1823           * type_data_make_W() since the class init for the parent
1824           * class may have changed pnode->data->instance.private_size.
1825           */
1826          node->data->instance.private_size = pnode->data->instance.private_size;
1827        }
1828    }
1829  class->g_type = NODE_TYPE (node);
1830 
1831  G_WRITE_UNLOCK (&type_rw_lock);
1832 
1833  /* stack all base class initialization functions, so we
1834   * call them in ascending order.
1835   */
1836  for (bnode = node; bnode; bnode = lookup_type_node_I (NODE_PARENT_TYPE (bnode)))
1837    if (bnode->data->class.class_init_base)
1838      init_slist = g_slist_prepend (init_slist, (gpointer) bnode->data->class.class_init_base);
1839  for (slist = init_slist; slist; slist = slist->next)
1840    {
1841      GBaseInitFunc class_init_base = (GBaseInitFunc) slist->data;
1842     
1843      class_init_base (class);
1844    }
1845  g_slist_free (init_slist);
1846 
1847  G_WRITE_LOCK (&type_rw_lock);
1848
1849  node->data->class.init_state = BASE_IFACE_INIT;
1850 
1851  /* Before we initialize the class, base initialize all interfaces, either
1852   * from parent, or through our holder info
1853   */
1854  pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
1855
1856  i = 0;
1857  while (i < CLASSED_NODE_N_IFACES (node))
1858    {
1859      entry = &CLASSED_NODE_IFACES_ENTRIES (node)[i];
1860      while (i < CLASSED_NODE_N_IFACES (node) &&
1861             entry->init_state == IFACE_INIT)
1862        {
1863          entry++;
1864          i++;
1865        }
1866
1867      if (i == CLASSED_NODE_N_IFACES (node))
1868        break;
1869
1870      if (!type_iface_vtable_base_init_Wm (lookup_type_node_I (entry->iface_type), node))
1871        {
1872          guint j;
1873         
1874          /* need to get this interface from parent, type_iface_vtable_base_init_Wm()
1875           * doesn't modify write lock upon FALSE, so entry is still valid;
1876           */
1877          g_assert (pnode != NULL);
1878         
1879          for (j = 0; j < CLASSED_NODE_N_IFACES (pnode); j++)
1880            {
1881              IFaceEntry *pentry = CLASSED_NODE_IFACES_ENTRIES (pnode) + j;
1882             
1883              if (pentry->iface_type == entry->iface_type)
1884                {
1885                  entry->vtable = pentry->vtable;
1886                  entry->init_state = INITIALIZED;
1887                  break;
1888                }
1889            }
1890          g_assert (entry->vtable != NULL);
1891        }
1892
1893      /* If the write lock was released, additional interface entries might
1894       * have been inserted into CLASSED_NODE_IFACES_ENTRIES (node); they'll
1895       * be base-initialized when inserted, so we don't have to worry that
1896       * we might miss them. Uninitialized entries can only be moved higher
1897       * when new ones are inserted.
1898       */
1899      i++;
1900    }
1901 
1902  node->data->class.init_state = CLASS_INIT;
1903 
1904  G_WRITE_UNLOCK (&type_rw_lock);
1905
1906  if (node->data->class.class_init)
1907    node->data->class.class_init (class, (gpointer) node->data->class.class_data);
1908 
1909  G_WRITE_LOCK (&type_rw_lock);
1910 
1911  node->data->class.init_state = IFACE_INIT;
1912 
1913  /* finish initializing the interfaces through our holder info.
1914   * inherited interfaces are already init_state == INITIALIZED, because
1915   * they either got setup in the above base_init loop, or during
1916   * class_init from within type_add_interface_Wm() for this or
1917   * an anchestor type.
1918   */
1919  i = 0;
1920  while (TRUE)
1921    {
1922      entry = &CLASSED_NODE_IFACES_ENTRIES (node)[i];
1923      while (i < CLASSED_NODE_N_IFACES (node) &&
1924             entry->init_state == INITIALIZED)
1925        {
1926          entry++;
1927          i++;
1928        }
1929
1930      if (i == CLASSED_NODE_N_IFACES (node))
1931        break;
1932
1933      type_iface_vtable_iface_init_Wm (lookup_type_node_I (entry->iface_type), node);
1934     
1935      /* As in the loop above, additional initialized entries might be inserted
1936       * if the write lock is released, but that's harmless because the entries
1937       * we need to initialize only move higher in the list.
1938       */
1939      i++;
1940    }
1941 
1942  node->data->class.init_state = INITIALIZED;
1943}
1944
1945static void
1946type_data_finalize_class_ifaces_Wm (TypeNode *node)
1947{
1948  guint i;
1949
1950  g_assert (node->is_instantiatable && node->data && node->data->class.class && node->data->common.ref_count == 0);
1951
1952 reiterate:
1953  for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
1954    {
1955      IFaceEntry *entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
1956      if (entry->vtable)
1957        {
1958          if (type_iface_vtable_finalize_Wm (lookup_type_node_I (entry->iface_type), node, entry->vtable))
1959            {
1960              /* refetch entries, IFACES_ENTRIES might be modified */
1961              goto reiterate;
1962            }
1963          else
1964            {
1965              /* type_iface_vtable_finalize_Wm() doesn't modify write lock upon FALSE,
1966               * iface vtable came from parent
1967               */
1968              entry->vtable = NULL;
1969              entry->init_state = UNINITIALIZED;
1970            }
1971        }
1972    }
1973}
1974
1975static void
1976type_data_finalize_class_U (TypeNode  *node,
1977                            ClassData *cdata)
1978{
1979  GTypeClass *class = cdata->class;
1980  TypeNode *bnode;
1981 
1982  g_assert (cdata->class && cdata->common.ref_count == 0);
1983 
1984  if (cdata->class_finalize)
1985    cdata->class_finalize (class, (gpointer) cdata->class_data);
1986 
1987  /* call all base class destruction functions in descending order
1988   */
1989  if (cdata->class_finalize_base)
1990    cdata->class_finalize_base (class);
1991  for (bnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); bnode; bnode = lookup_type_node_I (NODE_PARENT_TYPE (bnode)))
1992    if (bnode->data->class.class_finalize_base)
1993      bnode->data->class.class_finalize_base (class);
1994 
1995  g_free (cdata->class);
1996}
1997
1998static void
1999type_data_last_unref_Wm (GType    type,
2000                         gboolean uncached)
2001{
2002  TypeNode *node = lookup_type_node_I (type);
2003 
2004  g_return_if_fail (node != NULL && node->plugin != NULL);
2005 
2006  if (!node->data || node->data->common.ref_count == 0)
2007    {
2008      g_warning ("cannot drop last reference to unreferenced type `%s'",
2009                 type_descriptive_name_I (type));
2010      return;
2011    }
2012
2013  /* call class cache hooks */
2014  if (node->is_classed && node->data && node->data->class.class && static_n_class_cache_funcs && !uncached)
2015    {
2016      guint i;
2017     
2018      G_WRITE_UNLOCK (&type_rw_lock);
2019      G_READ_LOCK (&type_rw_lock);
2020      for (i = 0; i < static_n_class_cache_funcs; i++)
2021        {
2022          GTypeClassCacheFunc cache_func = static_class_cache_funcs[i].cache_func;
2023          gpointer cache_data = static_class_cache_funcs[i].cache_data;
2024          gboolean need_break;
2025         
2026          G_READ_UNLOCK (&type_rw_lock);
2027          need_break = cache_func (cache_data, node->data->class.class);
2028          G_READ_LOCK (&type_rw_lock);
2029          if (!node->data || node->data->common.ref_count == 0)
2030            INVALID_RECURSION ("GType class cache function ", cache_func, NODE_NAME (node));
2031          if (need_break)
2032            break;
2033        }
2034      G_READ_UNLOCK (&type_rw_lock);
2035      G_WRITE_LOCK (&type_rw_lock);
2036    }
2037 
2038  if (node->data->common.ref_count > 1) /* may have been re-referenced meanwhile */
2039    node->data->common.ref_count -= 1;
2040  else
2041    {
2042      GType ptype = NODE_PARENT_TYPE (node);
2043      TypeData *tdata;
2044     
2045      node->data->common.ref_count = 0;
2046     
2047      if (node->is_instantiatable && node->data->instance.mem_chunk)
2048        {
2049          g_mem_chunk_destroy (node->data->instance.mem_chunk);
2050          node->data->instance.mem_chunk = NULL;
2051        }
2052     
2053      tdata = node->data;
2054      if (node->is_classed && tdata->class.class)
2055        {
2056          if (CLASSED_NODE_N_IFACES (node))
2057            type_data_finalize_class_ifaces_Wm (node);
2058          node->mutatable_check_cache = FALSE;
2059          node->data = NULL;
2060          G_WRITE_UNLOCK (&type_rw_lock);
2061          type_data_finalize_class_U (node, &tdata->class);
2062          G_WRITE_LOCK (&type_rw_lock);
2063        }
2064      else if (NODE_IS_IFACE (node) && tdata->iface.dflt_vtable)
2065        {
2066          node->mutatable_check_cache = FALSE;
2067          node->data = NULL;
2068          if (tdata->iface.dflt_finalize || tdata->iface.vtable_finalize_base)
2069            {
2070              G_WRITE_UNLOCK (&type_rw_lock);
2071              if (tdata->iface.dflt_finalize)
2072                tdata->iface.dflt_finalize (tdata->iface.dflt_vtable, (gpointer) tdata->iface.dflt_data);
2073              if (tdata->iface.vtable_finalize_base)
2074                tdata->iface.vtable_finalize_base (tdata->iface.dflt_vtable);
2075              G_WRITE_LOCK (&type_rw_lock);
2076            }
2077          g_free (tdata->iface.dflt_vtable);
2078        }
2079      else
2080        {
2081          node->mutatable_check_cache = FALSE;
2082          node->data = NULL;
2083        }
2084
2085      /* freeing tdata->common.value_table and its contents is taken care of
2086       * by allocating it in one chunk with tdata
2087       */
2088      g_free (tdata);
2089     
2090      G_WRITE_UNLOCK (&type_rw_lock);
2091      g_type_plugin_unuse (node->plugin);
2092      G_WRITE_LOCK (&type_rw_lock);
2093      if (ptype)
2094        type_data_unref_Wm (lookup_type_node_I (ptype), FALSE);
2095    }
2096}
2097
2098void
2099g_type_add_class_cache_func (gpointer            cache_data,
2100                             GTypeClassCacheFunc cache_func)
2101{
2102  guint i;
2103 
2104  g_return_if_fail (cache_func != NULL);
2105 
2106  G_WRITE_LOCK (&type_rw_lock);
2107  i = static_n_class_cache_funcs++;
2108  static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs);
2109  static_class_cache_funcs[i].cache_data = cache_data;
2110  static_class_cache_funcs[i].cache_func = cache_func;
2111  G_WRITE_UNLOCK (&type_rw_lock);
2112}
2113
2114void
2115g_type_remove_class_cache_func (gpointer            cache_data,
2116                                GTypeClassCacheFunc cache_func)
2117{
2118  gboolean found_it = FALSE;
2119  guint i;
2120 
2121  g_return_if_fail (cache_func != NULL);
2122 
2123  G_WRITE_LOCK (&type_rw_lock);
2124  for (i = 0; i < static_n_class_cache_funcs; i++)
2125    if (static_class_cache_funcs[i].cache_data == cache_data &&
2126        static_class_cache_funcs[i].cache_func == cache_func)
2127      {
2128        static_n_class_cache_funcs--;
2129        g_memmove (static_class_cache_funcs + i,
2130                   static_class_cache_funcs + i + 1,
2131                   sizeof (static_class_cache_funcs[0]) * (static_n_class_cache_funcs - i));
2132        static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs);
2133        found_it = TRUE;
2134        break;
2135      }
2136  G_WRITE_UNLOCK (&type_rw_lock);
2137 
2138  if (!found_it)
2139    g_warning (G_STRLOC ": cannot remove unregistered class cache func %p with data %p",
2140               cache_func, cache_data);
2141}
2142
2143
2144void
2145g_type_add_interface_check (gpointer                check_data,
2146                            GTypeInterfaceCheckFunc check_func)
2147{
2148  guint i;
2149 
2150  g_return_if_fail (check_func != NULL);
2151 
2152  G_WRITE_LOCK (&type_rw_lock);
2153  i = static_n_iface_check_funcs++;
2154  static_iface_check_funcs = g_renew (IFaceCheckFunc, static_iface_check_funcs, static_n_iface_check_funcs);
2155  static_iface_check_funcs[i].check_data = check_data;
2156  static_iface_check_funcs[i].check_func = check_func;
2157  G_WRITE_UNLOCK (&type_rw_lock);
2158}
2159
2160void
2161g_type_remove_interface_check (gpointer                check_data,
2162                               GTypeInterfaceCheckFunc check_func)
2163{
2164  gboolean found_it = FALSE;
2165  guint i;
2166 
2167  g_return_if_fail (check_func != NULL);
2168 
2169  G_WRITE_LOCK (&type_rw_lock);
2170  for (i = 0; i < static_n_iface_check_funcs; i++)
2171    if (static_iface_check_funcs[i].check_data == check_data &&
2172        static_iface_check_funcs[i].check_func == check_func)
2173      {
2174        static_n_iface_check_funcs--;
2175        g_memmove (static_iface_check_funcs + i,
2176                   static_iface_check_funcs + i + 1,
2177                   sizeof (static_iface_check_funcs[0]) * (static_n_iface_check_funcs - i));
2178        static_iface_check_funcs = g_renew (IFaceCheckFunc, static_iface_check_funcs, static_n_iface_check_funcs);
2179        found_it = TRUE;
2180        break;
2181      }
2182  G_WRITE_UNLOCK (&type_rw_lock);
2183 
2184  if (!found_it)
2185    g_warning (G_STRLOC ": cannot remove unregistered class check func %p with data %p",
2186               check_func, check_data);
2187}
2188
2189/* --- type registration --- */
2190GType
2191g_type_register_fundamental (GType                       type_id,
2192                             const gchar                *type_name,
2193                             const GTypeInfo            *info,
2194                             const GTypeFundamentalInfo *finfo,
2195                             GTypeFlags                  flags)
2196{
2197  GTypeFundamentalInfo *node_finfo;
2198  TypeNode *node;
2199 
2200  g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, 0);
2201  g_return_val_if_fail (type_id > 0, 0);
2202  g_return_val_if_fail (type_name != NULL, 0);
2203  g_return_val_if_fail (info != NULL, 0);
2204  g_return_val_if_fail (finfo != NULL, 0);
2205 
2206  if (!check_type_name_I (type_name))
2207    return 0;
2208  if ((type_id & TYPE_ID_MASK) ||
2209      type_id > G_TYPE_FUNDAMENTAL_MAX)
2210    {
2211      g_warning ("attempt to register fundamental type `%s' with invalid type id (%lu)",
2212                 type_name,
2213                 type_id);
2214      return 0;
2215    }
2216  if ((finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
2217      !(finfo->type_flags & G_TYPE_FLAG_CLASSED))
2218    {
2219      g_warning ("cannot register instantiatable fundamental type `%s' as non-classed",
2220                 type_name);
2221      return 0;
2222    }
2223  if (lookup_type_node_I (type_id))
2224    {
2225      g_warning ("cannot register existing fundamental type `%s' (as `%s')",
2226                 type_descriptive_name_I (type_id),
2227                 type_name);
2228      return 0;
2229    }
2230 
2231  G_WRITE_LOCK (&type_rw_lock);
2232  node = type_node_fundamental_new_W (type_id, type_name, finfo->type_flags);
2233  node_finfo = type_node_fundamental_info_I (node);
2234  type_add_flags_W (node, flags);
2235 
2236  if (check_type_info_I (NULL, NODE_FUNDAMENTAL_TYPE (node), type_name, info))
2237    type_data_make_W (node, info,
2238                      check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
2239  G_WRITE_UNLOCK (&type_rw_lock);
2240 
2241  return NODE_TYPE (node);
2242}
2243
2244GType
2245g_type_register_static (GType            parent_type,
2246                        const gchar     *type_name,
2247                        const GTypeInfo *info,
2248                        GTypeFlags       flags)
2249{
2250  TypeNode *pnode, *node;
2251  GType type = 0;
2252 
2253  g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, 0);
2254  g_return_val_if_fail (parent_type > 0, 0);
2255  g_return_val_if_fail (type_name != NULL, 0);
2256  g_return_val_if_fail (info != NULL, 0);
2257 
2258  if (!check_type_name_I (type_name) ||
2259      !check_derivation_I (parent_type, type_name))
2260    return 0;
2261  if (info->class_finalize)
2262    {
2263      g_warning ("class finalizer specified for static type `%s'",
2264                 type_name);
2265      return 0;
2266    }
2267 
2268  pnode = lookup_type_node_I (parent_type);
2269  G_WRITE_LOCK (&type_rw_lock);
2270  type_data_ref_Wm (pnode);
2271  if (check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (pnode), type_name, info))
2272    {
2273      node = type_node_new_W (pnode, type_name, NULL);
2274      type_add_flags_W (node, flags);
2275      type = NODE_TYPE (node);
2276      type_data_make_W (node, info,
2277                        check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
2278    }
2279  G_WRITE_UNLOCK (&type_rw_lock);
2280 
2281  return type;
2282}
2283
2284GType
2285g_type_register_dynamic (GType        parent_type,
2286                         const gchar *type_name,
2287                         GTypePlugin *plugin,
2288                         GTypeFlags   flags)
2289{
2290  TypeNode *pnode, *node;
2291  GType type;
2292 
2293  g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, 0);
2294  g_return_val_if_fail (parent_type > 0, 0);
2295  g_return_val_if_fail (type_name != NULL, 0);
2296  g_return_val_if_fail (plugin != NULL, 0);
2297 
2298  if (!check_type_name_I (type_name) ||
2299      !check_derivation_I (parent_type, type_name) ||
2300      !check_plugin_U (plugin, TRUE, FALSE, type_name))
2301    return 0;
2302 
2303  G_WRITE_LOCK (&type_rw_lock);
2304  pnode = lookup_type_node_I (parent_type);
2305  node = type_node_new_W (pnode, type_name, plugin);
2306  type_add_flags_W (node, flags);
2307  type = NODE_TYPE (node);
2308  G_WRITE_UNLOCK (&type_rw_lock);
2309 
2310  return type;
2311}
2312
2313void
2314g_type_add_interface_static (GType                 instance_type,
2315                             GType                 interface_type,
2316                             const GInterfaceInfo *info)
2317{
2318  /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */
2319  g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
2320  g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
2321 
2322  G_WRITE_LOCK (&type_rw_lock);
2323  if (check_add_interface_L (instance_type, interface_type))
2324    {
2325      TypeNode *node = lookup_type_node_I (instance_type);
2326      TypeNode *iface = lookup_type_node_I (interface_type);
2327     
2328      if (check_interface_info_I (iface, NODE_TYPE (node), info))
2329        type_add_interface_Wm (node, iface, info, NULL);
2330    }
2331  G_WRITE_UNLOCK (&type_rw_lock);
2332}
2333
2334void
2335g_type_add_interface_dynamic (GType        instance_type,
2336                              GType        interface_type,
2337                              GTypePlugin *plugin)
2338{
2339  TypeNode *node;
2340 
2341  /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */
2342  g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
2343  g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
2344 
2345  node = lookup_type_node_I (instance_type);
2346  if (!check_plugin_U (plugin, FALSE, TRUE, NODE_NAME (node)))
2347    return;
2348 
2349  G_WRITE_LOCK (&type_rw_lock);
2350  if (check_add_interface_L (instance_type, interface_type))
2351    {
2352      TypeNode *iface = lookup_type_node_I (interface_type);
2353     
2354      type_add_interface_Wm (node, iface, NULL, plugin);
2355    }
2356  G_WRITE_UNLOCK (&type_rw_lock);
2357}
2358
2359
2360/* --- public API functions --- */
2361gpointer
2362g_type_class_ref (GType type)
2363{
2364  TypeNode *node;
2365 
2366  /* optimize for common code path
2367   */
2368  G_WRITE_LOCK (&type_rw_lock);
2369  node = lookup_type_node_I (type);
2370  if (node && node->is_classed && node->data &&
2371      node->data->class.class && node->data->common.ref_count > 0)
2372    {
2373      type_data_ref_Wm (node);
2374      G_WRITE_UNLOCK (&type_rw_lock);
2375     
2376      return node->data->class.class;
2377    }
2378 
2379  if (!node || !node->is_classed ||
2380      (node->data && node->data->common.ref_count < 1))
2381    {
2382      G_WRITE_UNLOCK (&type_rw_lock);
2383      g_warning ("cannot retrieve class for invalid (unclassed) type `%s'",
2384                 type_descriptive_name_I (type));
2385      return NULL;
2386    }
2387 
2388  type_data_ref_Wm (node);
2389 
2390  if (!node->data->class.class)
2391    {
2392      GType ptype = NODE_PARENT_TYPE (node);
2393      GTypeClass *pclass = NULL;
2394     
2395      if (ptype)
2396        {
2397          G_WRITE_UNLOCK (&type_rw_lock);
2398          pclass = g_type_class_ref (ptype);
2399          if (node->data->class.class)
2400            INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
2401          G_WRITE_LOCK (&type_rw_lock);
2402        }
2403     
2404      type_class_init_Wm (node, pclass);
2405    }
2406  G_WRITE_UNLOCK (&type_rw_lock);
2407 
2408  return node->data->class.class;
2409}
2410
2411void
2412g_type_class_unref (gpointer g_class)
2413{
2414  TypeNode *node;
2415  GTypeClass *class = g_class;
2416 
2417  g_return_if_fail (g_class != NULL);
2418 
2419  node = lookup_type_node_I (class->g_type);
2420  G_WRITE_LOCK (&type_rw_lock);
2421  if (node && node->is_classed && node->data &&
2422      node->data->class.class == class && node->data->common.ref_count > 0)
2423    type_data_unref_Wm (node, FALSE);
2424  else
2425    g_warning ("cannot unreference class of invalid (unclassed) type `%s'",
2426               type_descriptive_name_I (class->g_type));
2427  G_WRITE_UNLOCK (&type_rw_lock);
2428}
2429
2430void
2431g_type_class_unref_uncached (gpointer g_class)
2432{
2433  TypeNode *node;
2434  GTypeClass *class = g_class;
2435 
2436  g_return_if_fail (g_class != NULL);
2437 
2438  G_WRITE_LOCK (&type_rw_lock);
2439  node = lookup_type_node_I (class->g_type);
2440  if (node && node->is_classed && node->data &&
2441      node->data->class.class == class && node->data->common.ref_count > 0)
2442    type_data_unref_Wm (node, TRUE);
2443  else
2444    g_warning ("cannot unreference class of invalid (unclassed) type `%s'",
2445               type_descriptive_name_I (class->g_type));
2446  G_WRITE_UNLOCK (&type_rw_lock);
2447}
2448
2449gpointer
2450g_type_class_peek (GType type)
2451{
2452  TypeNode *node;
2453  gpointer class;
2454 
2455  node = lookup_type_node_I (type);
2456  G_READ_LOCK (&type_rw_lock);
2457  if (node && node->is_classed && node->data && node->data->class.class) /* common.ref_count _may_ be 0 */
2458    class = node->data->class.class;
2459  else
2460    class = NULL;
2461  G_READ_UNLOCK (&type_rw_lock);
2462 
2463  return class;
2464}
2465
2466gpointer
2467g_type_class_peek_static (GType type)
2468{
2469  TypeNode *node;
2470  gpointer class;
2471 
2472  node = lookup_type_node_I (type);
2473  G_READ_LOCK (&type_rw_lock);
2474  if (node && node->is_classed && node->data &&
2475      /* peek only static types: */ node->plugin == NULL &&
2476      node->data->class.class) /* common.ref_count _may_ be 0 */
2477    class = node->data->class.class;
2478  else
2479    class = NULL;
2480  G_READ_UNLOCK (&type_rw_lock);
2481 
2482  return class;
2483}
2484
2485gpointer
2486g_type_class_peek_parent (gpointer g_class)
2487{
2488  TypeNode *node;
2489  gpointer class = NULL;
2490 
2491  g_return_val_if_fail (g_class != NULL, NULL);
2492 
2493  node = lookup_type_node_I (G_TYPE_FROM_CLASS (g_class));
2494  /* We used to acquire a read lock here. That is not necessary, since
2495   * parent->data->class.class is constant as long as the derived class
2496   * exists.
2497   */
2498  if (node && node->is_classed && node->data && NODE_PARENT_TYPE (node))
2499    {
2500      node = lookup_type_node_I (NODE_PARENT_TYPE (node));
2501      class = node->data->class.class;
2502    }
2503  else if (NODE_PARENT_TYPE (node))
2504    g_warning (G_STRLOC ": invalid class pointer `%p'", g_class);
2505 
2506  return class;
2507}
2508
2509gpointer
2510g_type_interface_peek (gpointer instance_class,
2511                       GType    iface_type)
2512{
2513  TypeNode *node;
2514  TypeNode *iface;
2515  gpointer vtable = NULL;
2516  GTypeClass *class = instance_class;
2517 
2518  g_return_val_if_fail (instance_class != NULL, NULL);
2519 
2520  node = lookup_type_node_I (class->g_type);
2521  iface = lookup_type_node_I (iface_type);
2522  if (node && node->is_instantiatable && iface)
2523    {
2524      IFaceEntry *entry;
2525     
2526      G_READ_LOCK (&type_rw_lock);
2527     
2528      entry = type_lookup_iface_entry_L (node, iface);
2529      if (entry && entry->vtable)       /* entry is relocatable */
2530        vtable = entry->vtable;
2531     
2532      G_READ_UNLOCK (&type_rw_lock);
2533    }
2534  else
2535    g_warning (G_STRLOC ": invalid class pointer `%p'", class);
2536 
2537  return vtable;
2538}
2539
2540gpointer
2541g_type_interface_peek_parent (gpointer g_iface)
2542{
2543  TypeNode *node;
2544  TypeNode *iface;
2545  gpointer vtable = NULL;
2546  GTypeInterface *iface_class = g_iface;
2547 
2548  g_return_val_if_fail (g_iface != NULL, NULL);
2549 
2550  iface = lookup_type_node_I (iface_class->g_type);
2551  node = lookup_type_node_I (iface_class->g_instance_type);
2552  if (node)
2553    node = lookup_type_node_I (NODE_PARENT_TYPE (node));
2554  if (node && node->is_instantiatable && iface)
2555    {
2556      IFaceEntry *entry;
2557     
2558      G_READ_LOCK (&type_rw_lock);
2559     
2560      entry = type_lookup_iface_entry_L (node, iface);
2561      if (entry && entry->vtable)       /* entry is relocatable */
2562        vtable = entry->vtable;
2563     
2564      G_READ_UNLOCK (&type_rw_lock);
2565    }
2566  else if (node)
2567    g_warning (G_STRLOC ": invalid interface pointer `%p'", g_iface);
2568 
2569  return vtable;
2570}
2571
2572gpointer
2573g_type_default_interface_ref (GType g_type)
2574{
2575  TypeNode *node;
2576 
2577  G_WRITE_LOCK (&type_rw_lock);
2578 
2579  node = lookup_type_node_I (g_type);
2580  if (!node || !NODE_IS_IFACE (node) ||
2581      (node->data && node->data->common.ref_count < 1))
2582    {
2583      G_WRITE_UNLOCK (&type_rw_lock);
2584      g_warning ("cannot retrieve default vtable for invalid or non-interface type '%s'",
2585                 type_descriptive_name_I (g_type));
2586      return NULL;
2587    }
2588 
2589  type_data_ref_Wm (node);
2590
2591  type_iface_ensure_dflt_vtable_Wm (node);
2592
2593  G_WRITE_UNLOCK (&type_rw_lock);
2594 
2595  return node->data->iface.dflt_vtable;
2596}
2597
2598gpointer
2599g_type_default_interface_peek (GType g_type)
2600{
2601  TypeNode *node;
2602  gpointer vtable;
2603 
2604  node = lookup_type_node_I (g_type);
2605  G_READ_LOCK (&type_rw_lock);
2606  if (node && NODE_IS_IFACE (node) && node->data && node->data->iface.dflt_vtable)
2607    vtable = node->data->iface.dflt_vtable;
2608  else
2609    vtable = NULL;
2610  G_READ_UNLOCK (&type_rw_lock);
2611 
2612  return vtable;
2613}
2614
2615void
2616g_type_default_interface_unref (gpointer g_iface)
2617{
2618  TypeNode *node;
2619  GTypeInterface *vtable = g_iface;
2620 
2621  g_return_if_fail (g_iface != NULL);
2622 
2623  node = lookup_type_node_I (vtable->g_type);
2624  G_WRITE_LOCK (&type_rw_lock);
2625  if (node && NODE_IS_IFACE (node) &&
2626      node->data->iface.dflt_vtable == g_iface &&
2627      node->data->common.ref_count > 0)
2628    type_data_unref_Wm (node, FALSE);
2629  else
2630    g_warning ("cannot unreference invalid interface default vtable for '%s'",
2631               type_descriptive_name_I (vtable->g_type));
2632  G_WRITE_UNLOCK (&type_rw_lock);
2633}
2634
2635G_CONST_RETURN gchar*
2636g_type_name (GType type)
2637{
2638  TypeNode *node;
2639 
2640  g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, NULL);
2641 
2642  node = lookup_type_node_I (type);
2643 
2644  return node ? NODE_NAME (node) : NULL;
2645}
2646
2647GQuark
2648g_type_qname (GType type)
2649{
2650  TypeNode *node;
2651 
2652  node = lookup_type_node_I (type);
2653 
2654  return node ? node->qname : 0;
2655}
2656
2657GType
2658g_type_from_name (const gchar *name)
2659{
2660  GType type = 0;
2661  GQuark quark;
2662 
2663  g_return_val_if_fail (name != NULL, 0);
2664 
2665  quark = g_quark_try_string (name);
2666  if (quark)
2667    {
2668      G_READ_LOCK (&type_rw_lock);
2669      type = (GType) g_hash_table_lookup (static_type_nodes_ht, GUINT_TO_POINTER (quark));
2670      G_READ_UNLOCK (&type_rw_lock);
2671    }
2672 
2673  return type;
2674}
2675
2676GType
2677g_type_parent (GType type)
2678{
2679  TypeNode *node;
2680 
2681  node = lookup_type_node_I (type);
2682 
2683  return node ? NODE_PARENT_TYPE (node) : 0;
2684}
2685
2686guint
2687g_type_depth (GType type)
2688{
2689  TypeNode *node;
2690 
2691  node = lookup_type_node_I (type);
2692 
2693  return node ? node->n_supers + 1 : 0;
2694}
2695
2696GType
2697g_type_next_base (GType type,
2698                  GType base_type)
2699{
2700  GType atype = 0;
2701  TypeNode *node;
2702 
2703  node = lookup_type_node_I (type);
2704  if (node)
2705    {
2706      TypeNode *base_node = lookup_type_node_I (base_type);
2707     
2708      if (base_node && base_node->n_supers < node->n_supers)
2709        {
2710          guint n = node->n_supers - base_node->n_supers;
2711         
2712          if (node->supers[n] == base_type)
2713            atype = node->supers[n - 1];
2714        }
2715    }
2716 
2717  return atype;
2718}
2719
2720static inline gboolean
2721type_node_check_conformities_UorL (TypeNode *node,
2722                                   TypeNode *iface_node,
2723                                   /*        support_inheritance */
2724                                   gboolean  support_interfaces,
2725                                   gboolean  support_prerequisites,
2726                                   gboolean  have_lock)
2727{
2728  gboolean match;
2729 
2730  if (/* support_inheritance && */
2731      NODE_IS_ANCESTOR (iface_node, node))
2732    return TRUE;
2733 
2734  support_interfaces = support_interfaces && node->is_instantiatable && NODE_IS_IFACE (iface_node);
2735  support_prerequisites = support_prerequisites && NODE_IS_IFACE (node);
2736  match = FALSE;
2737  if (support_interfaces || support_prerequisites)
2738    {
2739      if (!have_lock)
2740        G_READ_LOCK (&type_rw_lock);
2741      if (support_interfaces && type_lookup_iface_entry_L (node, iface_node))
2742        match = TRUE;
2743      else if (support_prerequisites && type_lookup_prerequisite_L (node, NODE_TYPE (iface_node)))
2744        match = TRUE;
2745      if (!have_lock)
2746        G_READ_UNLOCK (&type_rw_lock);
2747    }
2748  return match;
2749}
2750
2751static gboolean
2752type_node_is_a_L (TypeNode *node,
2753                  TypeNode *iface_node)
2754{
2755  return type_node_check_conformities_UorL (node, iface_node, TRUE, TRUE, TRUE);
2756}
2757
2758static inline gboolean
2759type_node_conforms_to_U (TypeNode *node,
2760                         TypeNode *iface_node,
2761                         gboolean  support_interfaces,
2762                         gboolean  support_prerequisites)
2763{
2764  return type_node_check_conformities_UorL (node, iface_node, support_interfaces, support_prerequisites, FALSE);
2765}
2766
2767gboolean
2768g_type_is_a (GType type,
2769             GType iface_type)
2770{
2771  TypeNode *node, *iface_node;
2772  gboolean is_a;
2773 
2774  node = lookup_type_node_I (type);
2775  iface_node = lookup_type_node_I (iface_type);
2776  is_a = node && iface_node && type_node_conforms_to_U (node, iface_node, TRUE, TRUE);
2777 
2778  return is_a;
2779}
2780
2781GType* /* free result */
2782g_type_children (GType  type,
2783                 guint *n_children)
2784{
2785  TypeNode *node;
2786 
2787  node = lookup_type_node_I (type);
2788  if (node)
2789    {
2790      GType *children;
2791     
2792      G_READ_LOCK (&type_rw_lock);      /* ->children is relocatable */
2793      children = g_new (GType, node->n_children + 1);
2794      memcpy (children, node->children, sizeof (GType) * node->n_children);
2795      children[node->n_children] = 0;
2796     
2797      if (n_children)
2798        *n_children = node->n_children;
2799      G_READ_UNLOCK (&type_rw_lock);
2800     
2801      return children;
2802    }
2803  else
2804    {
2805      if (n_children)
2806        *n_children = 0;
2807     
2808      return NULL;
2809    }
2810}
2811
2812GType* /* free result */
2813g_type_interfaces (GType  type,
2814                   guint *n_interfaces)
2815{
2816  TypeNode *node;
2817 
2818  node = lookup_type_node_I (type);
2819  if (node && node->is_instantiatable)
2820    {
2821      GType *ifaces;
2822      guint i;
2823     
2824      G_READ_LOCK (&type_rw_lock);
2825      ifaces = g_new (GType, CLASSED_NODE_N_IFACES (node) + 1);
2826      for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
2827        ifaces[i] = CLASSED_NODE_IFACES_ENTRIES (node)[i].iface_type;
2828      ifaces[i] = 0;
2829     
2830      if (n_interfaces)
2831        *n_interfaces = CLASSED_NODE_N_IFACES (node);
2832      G_READ_UNLOCK (&type_rw_lock);
2833     
2834      return ifaces;
2835    }
2836  else
2837    {
2838      if (n_interfaces)
2839        *n_interfaces = 0;
2840     
2841      return NULL;
2842    }
2843}
2844
2845typedef struct _QData QData;
2846struct _GData
2847{
2848  guint  n_qdatas;
2849  QData *qdatas;
2850};
2851struct _QData
2852{
2853  GQuark   quark;
2854  gpointer data;
2855};
2856
2857static inline gpointer
2858type_get_qdata_L (TypeNode *node,
2859                  GQuark    quark)
2860{
2861  GData *gdata = node->global_gdata;
2862 
2863  if (quark && gdata && gdata->n_qdatas)
2864    {
2865      QData *qdatas = gdata->qdatas - 1;
2866      guint n_qdatas = gdata->n_qdatas;
2867     
2868      do
2869        {
2870          guint i;
2871          QData *check;
2872         
2873          i = (n_qdatas + 1) / 2;
2874          check = qdatas + i;
2875          if (quark == check->quark)
2876            return check->data;
2877          else if (quark > check->quark)
2878            {
2879              n_qdatas -= i;
2880              qdatas = check;
2881            }
2882          else /* if (quark < check->quark) */
2883            n_qdatas = i - 1;
2884        }
2885      while (n_qdatas);
2886    }
2887  return NULL;
2888}
2889
2890gpointer
2891g_type_get_qdata (GType  type,
2892                  GQuark quark)
2893{
2894  TypeNode *node;
2895  gpointer data;
2896 
2897  node = lookup_type_node_I (type);
2898  if (node)
2899    {
2900      G_READ_LOCK (&type_rw_lock);
2901      data = type_get_qdata_L (node, quark);
2902      G_READ_UNLOCK (&type_rw_lock);
2903    }
2904  else
2905    {
2906      g_return_val_if_fail (node != NULL, NULL);
2907      data = NULL;
2908    }
2909  return data;
2910}
2911
2912static inline void
2913type_set_qdata_W (TypeNode *node,
2914                  GQuark    quark,
2915                  gpointer  data)
2916{
2917  GData *gdata;
2918  QData *qdata;
2919  guint i;
2920 
2921  /* setup qdata list if necessary */
2922  if (!node->global_gdata)
2923    node->global_gdata = g_new0 (GData, 1);
2924  gdata = node->global_gdata;
2925 
2926  /* try resetting old data */
2927  qdata = gdata->qdatas;
2928  for (i = 0; i < gdata->n_qdatas; i++)
2929    if (qdata[i].quark == quark)
2930      {
2931        qdata[i].data = data;
2932        return;
2933      }
2934 
2935  /* add new entry */
2936  gdata->n_qdatas++;
2937  gdata->qdatas = g_renew (QData, gdata->qdatas, gdata->n_qdatas);
2938  qdata = gdata->qdatas;
2939  for (i = 0; i < gdata->n_qdatas - 1; i++)
2940    if (qdata[i].quark > quark)
2941      break;
2942  g_memmove (qdata + i + 1, qdata + i, sizeof (qdata[0]) * (gdata->n_qdatas - i - 1));
2943  qdata[i].quark = quark;
2944  qdata[i].data = data;
2945}
2946
2947void
2948g_type_set_qdata (GType    type,
2949                  GQuark   quark,
2950                  gpointer data)
2951{
2952  TypeNode *node;
2953 
2954  g_return_if_fail (quark != 0);
2955 
2956  node = lookup_type_node_I (type);
2957  if (node)
2958    {
2959      G_WRITE_LOCK (&type_rw_lock);
2960      type_set_qdata_W (node, quark, data);
2961      G_WRITE_UNLOCK (&type_rw_lock);
2962    }
2963  else
2964    g_return_if_fail (node != NULL);
2965}
2966
2967static void
2968type_add_flags_W (TypeNode  *node,
2969                  GTypeFlags flags)
2970{
2971  guint dflags;
2972 
2973  g_return_if_fail ((flags & ~TYPE_FLAG_MASK) == 0);
2974  g_return_if_fail (node != NULL);
2975 
2976  if ((flags & TYPE_FLAG_MASK) && node->is_classed && node->data && node->data->class.class)
2977    g_warning ("tagging type `%s' as abstract after class initialization", NODE_NAME (node));
2978  dflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
2979  dflags |= flags;
2980  type_set_qdata_W (node, static_quark_type_flags, GUINT_TO_POINTER (dflags));
2981}
2982
2983void
2984g_type_query (GType       type,
2985              GTypeQuery *query)
2986{
2987  TypeNode *node;
2988 
2989  g_return_if_fail (query != NULL);
2990 
2991  /* if node is not static and classed, we won't allow query */
2992  query->type = 0;
2993  node = lookup_type_node_I (type);
2994  if (node && node->is_classed && !node->plugin)
2995    {
2996      /* type is classed and probably even instantiatable */
2997      G_READ_LOCK (&type_rw_lock);
2998      if (node->data)   /* type is static or referenced */
2999        {
3000          query->type = NODE_TYPE (node);
3001          query->type_name = NODE_NAME (node);
3002          query->class_size = node->data->class.class_size;
3003          query->instance_size = node->is_instantiatable ? node->data->instance.instance_size : 0;
3004        }
3005      G_READ_UNLOCK (&type_rw_lock);
3006    }
3007}
3008
3009
3010/* --- implementation details --- */
3011gboolean
3012g_type_test_flags (GType type,
3013                   guint flags)
3014{
3015  TypeNode *node;
3016  gboolean result = FALSE;
3017 
3018  node = lookup_type_node_I (type);
3019  if (node)
3020    {
3021      guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK;
3022      guint tflags = flags & TYPE_FLAG_MASK;
3023     
3024      if (fflags)
3025        {
3026          GTypeFundamentalInfo *finfo = type_node_fundamental_info_I (node);
3027         
3028          fflags = (finfo->type_flags & fflags) == fflags;
3029        }
3030      else
3031        fflags = TRUE;
3032     
3033      if (tflags)
3034        {
3035          G_READ_LOCK (&type_rw_lock);
3036          tflags = (tflags & GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags))) == tflags;
3037          G_READ_UNLOCK (&type_rw_lock);
3038        }
3039      else
3040        tflags = TRUE;
3041     
3042      result = tflags && fflags;
3043    }
3044 
3045  return result;
3046}
3047
3048GTypePlugin*
3049g_type_get_plugin (GType type)
3050{
3051  TypeNode *node;
3052 
3053  node = lookup_type_node_I (type);
3054 
3055  return node ? node->plugin : NULL;
3056}
3057
3058GTypePlugin*
3059g_type_interface_get_plugin (GType instance_type,
3060                             GType interface_type)
3061{
3062  TypeNode *node;
3063  TypeNode *iface;
3064 
3065  g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL);    /* G_TYPE_IS_INTERFACE() is an external call: _U */
3066 
3067  node = lookup_type_node_I (instance_type); 
3068  iface = lookup_type_node_I (interface_type);
3069  if (node && iface)
3070    {
3071      IFaceHolder *iholder;
3072      GTypePlugin *plugin;
3073     
3074      G_READ_LOCK (&type_rw_lock);
3075     
3076      iholder = iface_node_get_holders_L (iface);
3077      while (iholder && iholder->instance_type != instance_type)
3078        iholder = iholder->next;
3079      plugin = iholder ? iholder->plugin : NULL;
3080     
3081      G_READ_UNLOCK (&type_rw_lock);
3082     
3083      return plugin;
3084    }
3085 
3086  g_return_val_if_fail (node == NULL, NULL);
3087  g_return_val_if_fail (iface == NULL, NULL);
3088 
3089  g_warning (G_STRLOC ": attempt to look up plugin for invalid instance/interface type pair.");
3090 
3091  return NULL;
3092}
3093
3094GType
3095g_type_fundamental_next (void)
3096{
3097  GType type;
3098 
3099  G_READ_LOCK (&type_rw_lock);
3100  type = static_fundamental_next;
3101  G_READ_UNLOCK (&type_rw_lock);
3102  type = G_TYPE_MAKE_FUNDAMENTAL (type);
3103  return type <= G_TYPE_FUNDAMENTAL_MAX ? type : 0;
3104}
3105
3106GType
3107g_type_fundamental (GType type_id)
3108{
3109  TypeNode *node = lookup_type_node_I (type_id);
3110 
3111  return node ? NODE_FUNDAMENTAL_TYPE (node) : 0;
3112}
3113
3114gboolean
3115g_type_check_instance_is_a (GTypeInstance *type_instance,
3116                            GType          iface_type)
3117{
3118  TypeNode *node, *iface;
3119  gboolean check;
3120 
3121  if (!type_instance || !type_instance->g_class)
3122    return FALSE;
3123 
3124  node = lookup_type_node_I (type_instance->g_class->g_type);
3125  iface = lookup_type_node_I (iface_type);
3126  check = node && node->is_instantiatable && iface && type_node_conforms_to_U (node, iface, TRUE, FALSE);
3127 
3128  return check;
3129}
3130
3131gboolean
3132g_type_check_class_is_a (GTypeClass *type_class,
3133                         GType       is_a_type)
3134{
3135  TypeNode *node, *iface;
3136  gboolean check;
3137 
3138  if (!type_class)
3139    return FALSE;
3140 
3141  node = lookup_type_node_I (type_class->g_type);
3142  iface = lookup_type_node_I (is_a_type);
3143  check = node && node->is_classed && iface && type_node_conforms_to_U (node, iface, FALSE, FALSE);
3144 
3145  return check;
3146}
3147
3148GTypeInstance*
3149g_type_check_instance_cast (GTypeInstance *type_instance,
3150                            GType          iface_type)
3151{
3152  if (type_instance)
3153    {
3154      if (type_instance->g_class)
3155        {
3156          TypeNode *node, *iface;
3157          gboolean is_instantiatable, check;
3158         
3159          node = lookup_type_node_I (type_instance->g_class->g_type);
3160          is_instantiatable = node && node->is_instantiatable;
3161          iface = lookup_type_node_I (iface_type);
3162          check = is_instantiatable && iface && type_node_conforms_to_U (node, iface, TRUE, FALSE);
3163          if (check)
3164            return type_instance;
3165         
3166          if (is_instantiatable)
3167            g_warning ("invalid cast from `%s' to `%s'",
3168                       type_descriptive_name_I (type_instance->g_class->g_type),
3169                       type_descriptive_name_I (iface_type));
3170          else
3171            g_warning ("invalid uninstantiatable type `%s' in cast to `%s'",
3172                       type_descriptive_name_I (type_instance->g_class->g_type),
3173                       type_descriptive_name_I (iface_type));
3174        }
3175      else
3176        g_warning ("invalid unclassed pointer in cast to `%s'",
3177                   type_descriptive_name_I (iface_type));
3178    }
3179 
3180  return type_instance;
3181}
3182
3183GTypeClass*
3184g_type_check_class_cast (GTypeClass *type_class,
3185                         GType       is_a_type)
3186{
3187  if (type_class)
3188    {
3189      TypeNode *node, *iface;
3190      gboolean is_classed, check;
3191     
3192      node = lookup_type_node_I (type_class->g_type);
3193      is_classed = node && node->is_classed;
3194      iface = lookup_type_node_I (is_a_type);
3195      check = is_classed && iface && type_node_conforms_to_U (node, iface, FALSE, FALSE);
3196      if (check)
3197        return type_class;
3198     
3199      if (is_classed)
3200        g_warning ("invalid class cast from `%s' to `%s'",
3201                   type_descriptive_name_I (type_class->g_type),
3202                   type_descriptive_name_I (is_a_type));
3203      else
3204        g_warning ("invalid unclassed type `%s' in class cast to `%s'",
3205                   type_descriptive_name_I (type_class->g_type),
3206                   type_descriptive_name_I (is_a_type));
3207    }
3208  else
3209    g_warning ("invalid class cast from (NULL) pointer to `%s'",
3210               type_descriptive_name_I (is_a_type));
3211  return type_class;
3212}
3213
3214gboolean
3215g_type_check_instance (GTypeInstance *type_instance)
3216{
3217  /* this function is just here to make the signal system
3218   * conveniently elaborated on instance checks
3219   */
3220  if (type_instance)
3221    {
3222      if (type_instance->g_class)
3223        {
3224          TypeNode *node = lookup_type_node_I (type_instance->g_class->g_type);
3225         
3226          if (node && node->is_instantiatable)
3227            return TRUE;
3228         
3229          g_warning ("instance of invalid non-instantiatable type `%s'",
3230                     type_descriptive_name_I (type_instance->g_class->g_type));
3231        }
3232      else
3233        g_warning ("instance with invalid (NULL) class pointer");
3234    }
3235  else
3236    g_warning ("invalid (NULL) pointer instance");
3237 
3238  return FALSE;
3239}
3240
3241static inline gboolean
3242type_check_is_value_type_U (GType type)
3243{
3244  GTypeFlags tflags = G_TYPE_FLAG_VALUE_ABSTRACT;
3245  TypeNode *node;
3246 
3247  /* common path speed up */
3248  node = lookup_type_node_I (type);
3249  if (node && node->mutatable_check_cache)
3250    return TRUE;
3251 
3252  G_READ_LOCK (&type_rw_lock);
3253 restart_check:
3254  if (node)
3255    {
3256      if (node->data && node->data->common.ref_count > 0 &&
3257          node->data->common.value_table->value_init)
3258        tflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
3259      else if (NODE_IS_IFACE (node))
3260        {
3261          guint i;
3262         
3263          for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
3264            {
3265              GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
3266              TypeNode *prnode = lookup_type_node_I (prtype);
3267             
3268              if (prnode->is_instantiatable)
3269                {
3270                  type = prtype;
3271                  node = lookup_type_node_I (type);
3272                  goto restart_check;
3273                }
3274            }
3275        }
3276    }
3277  G_READ_UNLOCK (&type_rw_lock);
3278 
3279  return !(tflags & G_TYPE_FLAG_VALUE_ABSTRACT);
3280}
3281
3282gboolean
3283g_type_check_is_value_type (GType type)
3284{
3285  return type_check_is_value_type_U (type);
3286}
3287
3288gboolean
3289g_type_check_value (GValue *value)
3290{
3291  return value && type_check_is_value_type_U (value->g_type);
3292}
3293
3294gboolean
3295g_type_check_value_holds (GValue *value,
3296                          GType   type)
3297{
3298  return value && type_check_is_value_type_U (value->g_type) && g_type_is_a (value->g_type, type);
3299}
3300
3301GTypeValueTable*
3302g_type_value_table_peek (GType type)
3303{
3304  GTypeValueTable *vtable = NULL;
3305  TypeNode *node = lookup_type_node_I (type);
3306  gboolean has_refed_data, has_table;
3307  TypeData *data;
3308
3309  /* speed up common code path, we're not 100% safe here,
3310   * but we should only get called with referenced types anyway
3311   */
3312  data = node ? node->data : NULL;
3313  if (node && node->mutatable_check_cache)
3314    return data->common.value_table;
3315
3316  G_READ_LOCK (&type_rw_lock);
3317 
3318 restart_table_peek:
3319  has_refed_data = node && node->data && node->data->common.ref_count;
3320  has_table = has_refed_data && node->data->common.value_table->value_init;
3321  if (has_refed_data)
3322    {
3323      if (has_table)
3324        vtable = node->data->common.value_table;
3325      else if (NODE_IS_IFACE (node))
3326        {
3327          guint i;
3328         
3329          for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
3330            {
3331              GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
3332              TypeNode *prnode = lookup_type_node_I (prtype);
3333             
3334              if (prnode->is_instantiatable)
3335                {
3336                  type = prtype;
3337                  node = lookup_type_node_I (type);
3338                  goto restart_table_peek;
3339                }
3340            }
3341        }
3342    }
3343 
3344  G_READ_UNLOCK (&type_rw_lock);
3345 
3346  if (vtable)
3347    return vtable;
3348 
3349  if (!node)
3350    g_warning (G_STRLOC ": type id `%lu' is invalid", type);
3351  if (!has_refed_data)
3352    g_warning ("can't peek value table for type `%s' which is not currently referenced",
3353               type_descriptive_name_I (type));
3354 
3355  return NULL;
3356}
3357
3358G_CONST_RETURN gchar*
3359g_type_name_from_instance (GTypeInstance *instance)
3360{
3361  if (!instance)
3362    return "<NULL-instance>";
3363  else
3364    return g_type_name_from_class (instance->g_class);
3365}
3366
3367G_CONST_RETURN gchar*
3368g_type_name_from_class (GTypeClass *g_class)
3369{
3370  if (!g_class)
3371    return "<NULL-class>";
3372  else
3373    return g_type_name (g_class->g_type);
3374}
3375
3376
3377/* --- foreign prototypes --- */
3378extern void     g_value_c_init          (void); /* sync with gvalue.c */
3379extern void     g_value_types_init      (void); /* sync with gvaluetypes.c */
3380extern void     g_enum_types_init       (void); /* sync with genums.c */
3381extern void     g_param_type_init       (void); /* sync with gparam.c */
3382extern void     g_boxed_type_init       (void); /* sync with gboxed.c */
3383extern void     g_object_type_init      (void); /* sync with gobject.c */
3384extern void     g_param_spec_types_init (void); /* sync with gparamspecs.c */
3385extern void     g_value_transforms_init (void); /* sync with gvaluetransform.c */
3386extern void     g_signal_init           (void); /* sync with gsignal.c */
3387
3388
3389/* --- initialization --- */
3390void
3391g_type_init_with_debug_flags (GTypeDebugFlags debug_flags)
3392{
3393  G_LOCK_DEFINE_STATIC (type_init_lock);
3394  const gchar *env_string;
3395  GTypeInfo info;
3396  TypeNode *node;
3397  GType type;
3398 
3399  G_LOCK (type_init_lock);
3400 
3401  G_WRITE_LOCK (&type_rw_lock);
3402 
3403  if (static_quark_type_flags)
3404    {
3405      G_WRITE_UNLOCK (&type_rw_lock);
3406      G_UNLOCK (type_init_lock);
3407      return;
3408    }
3409 
3410  /* setup GObject library wide debugging flags */
3411  _g_type_debug_flags = debug_flags & G_TYPE_DEBUG_MASK;
3412  env_string = g_getenv ("GOBJECT_DEBUG");
3413  if (env_string != NULL)
3414    {
3415      static GDebugKey debug_keys[] = {
3416        { "objects", G_TYPE_DEBUG_OBJECTS },
3417        { "signals", G_TYPE_DEBUG_SIGNALS },
3418      };
3419     
3420      _g_type_debug_flags |= g_parse_debug_string (env_string,
3421                                                   debug_keys,
3422                                                   sizeof (debug_keys) / sizeof (debug_keys[0]));
3423      env_string = NULL;
3424    }
3425 
3426  /* quarks */
3427  static_quark_type_flags = g_quark_from_static_string ("-g-type-private--GTypeFlags");
3428  static_quark_iface_holder = g_quark_from_static_string ("-g-type-private--IFaceHolder");
3429  static_quark_dependants_array = g_quark_from_static_string ("-g-type-private--dependants-array");
3430 
3431  /* type qname hash table */
3432  static_type_nodes_ht = g_hash_table_new (g_direct_hash, g_direct_equal);
3433 
3434  /* invalid type G_TYPE_INVALID (0)
3435   */
3436  static_fundamental_type_nodes[0] = NULL;
3437 
3438  /* void type G_TYPE_NONE
3439   */
3440  node = type_node_fundamental_new_W (G_TYPE_NONE, "void", 0);
3441  type = NODE_TYPE (node);
3442  g_assert (type == G_TYPE_NONE);
3443 
3444  /* interface fundamental type G_TYPE_INTERFACE (!classed)
3445   */
3446  memset (&info, 0, sizeof (info));
3447  node = type_node_fundamental_new_W (G_TYPE_INTERFACE, "GInterface", G_TYPE_FLAG_DERIVABLE);
3448  type = NODE_TYPE (node);
3449  type_data_make_W (node, &info, NULL);
3450  g_assert (type == G_TYPE_INTERFACE);
3451 
3452  G_WRITE_UNLOCK (&type_rw_lock);
3453 
3454  g_value_c_init ();
3455
3456  /* G_TYPE_TYPE_PLUGIN
3457   */
3458  g_type_plugin_get_type ();
3459 
3460  /* G_TYPE_* value types
3461   */
3462  g_value_types_init ();
3463 
3464  /* G_TYPE_ENUM & G_TYPE_FLAGS
3465   */
3466  g_enum_types_init ();
3467 
3468  /* G_TYPE_BOXED
3469   */
3470  g_boxed_type_init ();
3471 
3472  /* G_TYPE_PARAM
3473   */
3474  g_param_type_init ();
3475 
3476  /* G_TYPE_OBJECT
3477   */
3478  g_object_type_init ();
3479 
3480  /* G_TYPE_PARAM_* pspec types
3481   */
3482  g_param_spec_types_init ();
3483 
3484  /* Value Transformations
3485   */
3486  g_value_transforms_init ();
3487 
3488  /* Signal system
3489   */
3490  g_signal_init ();
3491 
3492  G_UNLOCK (type_init_lock);
3493}
3494
3495void
3496g_type_init (void)
3497{
3498  g_type_init_with_debug_flags (0);
3499}
3500
3501void
3502g_type_class_add_private (gpointer g_class,
3503                          gsize    private_size)
3504{
3505  GType instance_type = ((GTypeClass *)g_class)->g_type;
3506  TypeNode *node = lookup_type_node_I (instance_type);
3507  gsize offset;
3508
3509  if (!node || !node->is_instantiatable || !node->data || node->data->class.class != g_class)
3510    {
3511      g_warning ("cannot add private field to invalid (non-instantiatable) type '%s'",
3512                 type_descriptive_name_I (instance_type));
3513      return;
3514    }
3515
3516  if (NODE_PARENT_TYPE (node))
3517    {
3518      TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
3519      if (node->data->instance.private_size != pnode->data->instance.private_size)
3520        {
3521          g_warning ("g_type_add_private() called multiple times for the same type");
3522          return;
3523        }
3524    }
3525 
3526  G_WRITE_LOCK (&type_rw_lock);
3527
3528  offset = ALIGN_STRUCT (node->data->instance.private_size);
3529  node->data->instance.private_size = offset + private_size;
3530 
3531  G_WRITE_UNLOCK (&type_rw_lock);
3532}
3533
3534gpointer
3535g_type_instance_get_private (GTypeInstance *instance,
3536                             GType          private_type)
3537{
3538  TypeNode *instance_node;
3539  TypeNode *private_node;
3540  TypeNode *parent_node;
3541  GTypeClass *class;
3542  gsize offset;
3543
3544  g_return_val_if_fail (instance != NULL && instance->g_class != NULL, NULL);
3545
3546  /* while instances are initialized, their class pointers change,
3547   * so figure the instances real class first
3548   */
3549  class = instance_real_class_get (instance);
3550  if (!class)
3551    class = instance->g_class;
3552
3553  instance_node = lookup_type_node_I (class->g_type);
3554  if (G_UNLIKELY (!instance_node || !instance_node->is_instantiatable))
3555    {
3556      g_warning ("instance of invalid non-instantiatable type `%s'",
3557                 type_descriptive_name_I (instance->g_class->g_type));
3558      return NULL;
3559    }
3560
3561  private_node = lookup_type_node_I (private_type);
3562  if (G_UNLIKELY (!private_node || !NODE_IS_ANCESTOR (private_node, instance_node)))
3563    {
3564      g_warning ("attempt to retrieve private data for invalid type '%s'",
3565                 type_descriptive_name_I (private_type));
3566      return NULL;
3567    }
3568
3569  /* Note that we don't need a read lock, since instance existing
3570   * means that the instance class and all parent classes
3571   * exist, so the node->data, node->data->instance.instance_size,
3572   * and node->data->instance.private_size are not going to be changed.
3573   * for any of the relevant types.
3574   */
3575
3576  offset = ALIGN_STRUCT (instance_node->data->instance.instance_size);
3577
3578  if (NODE_PARENT_TYPE (private_node))
3579    {
3580      parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node));
3581      g_assert (parent_node->data && parent_node->data->common.ref_count);
3582
3583      if (G_UNLIKELY (private_node->data->instance.private_size == parent_node->data->instance.private_size))
3584        {
3585          g_warning ("g_type_get_private() requires a prior call to g_type_add_private()");
3586          return NULL;
3587        }
3588
3589      offset += ALIGN_STRUCT (parent_node->data->instance.private_size);
3590    }
3591
3592  return G_STRUCT_MEMBER_P (instance, offset);
3593}
Note: See TracBrowser for help on using the repository browser.