mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-04 01:58:54 +01:00 
			
		
		
		
	Wed Jul 18 19:42:31 2001 Tim Janik <timj@gtk.org> * gtype.h: if __GNUC__ is defined, inline a test for an exact type match for instances and classes in G_TYPE_CHECK_INSTANCE_TYPE() and G_TYPE_CHECK_CLASS_TYPE() before calling g_type_instance_is_a().
		
			
				
	
	
		
			2890 lines
		
	
	
		
			81 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2890 lines
		
	
	
		
			81 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* GObject - GLib Type, Object, Parameter and Signal Library
 | 
						|
 * Copyright (C) 1998-1999, 2000-2001 Tim Janik and Red Hat, Inc.
 | 
						|
 *
 | 
						|
 * This library is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU Lesser General Public
 | 
						|
 * License as published by the Free Software Foundation; either
 | 
						|
 * version 2 of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This library is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * Lesser General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Lesser General
 | 
						|
 * Public License along with this library; if not, write to the
 | 
						|
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 | 
						|
 * Boston, MA 02111-1307, USA.
 | 
						|
 */
 | 
						|
#include	"gtype.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * MT safe
 | 
						|
 */
 | 
						|
 | 
						|
#include	"gtypeplugin.h"
 | 
						|
#include	"gvaluecollector.h"
 | 
						|
#include	<string.h>
 | 
						|
 | 
						|
 | 
						|
/* NOTE: some functions (some internal variants and exported ones)
 | 
						|
 * invalidate data portions of the TypeNodes. if external functions/callbacks
 | 
						|
 * are called, pointers to memory maintained by TypeNodes have to be looked up
 | 
						|
 * again. this affects most of the struct TypeNode fields, e.g. ->children or
 | 
						|
 * CLASSED_NODE_IFACES_ENTRIES() respectively IFACE_NODE_PREREQUISITES() (but
 | 
						|
 * not ->supers[]), as all those memory portions can get realloc()ed during
 | 
						|
 * callback invocation.
 | 
						|
 *
 | 
						|
 * TODO:
 | 
						|
 * - g_type_from_name() should do an ordered array lookup after fetching the
 | 
						|
 *   the quark, instead of a second hashtable lookup.
 | 
						|
 * - speedup checks for virtual types, steal a bit somewhere
 | 
						|
 *
 | 
						|
 * FIXME:
 | 
						|
 * - force interface initialization for already existing classes
 | 
						|
 *
 | 
						|
 * LOCKING:
 | 
						|
 * lock handling issues when calling static functions are indicated by
 | 
						|
 * uppercase letter postfixes, all static functions have to have
 | 
						|
 * one of the below postfixes:
 | 
						|
 * - _I:	[Indifferent about locking]
 | 
						|
 *   function doesn't care about locks at all
 | 
						|
 * - _U:	[Unlocked invocation]
 | 
						|
 *   no read or write lock has to be held across function invocation
 | 
						|
 *   (locks may be acquired and released during invocation though)
 | 
						|
 * - _L:	[Locked invocation]
 | 
						|
 *   a write lock or more than 0 read locks have to be held across
 | 
						|
 *   function invocation
 | 
						|
 * - _W:	[Write-locked invocation]
 | 
						|
 *   a write lock has to be held across function invokation
 | 
						|
 * - _Wm:	[Write-locked invocation, mutatable]
 | 
						|
 *   like _W, but the write lock might be released and reacquired
 | 
						|
 *   during invocation, watch your pointers
 | 
						|
 */
 | 
						|
 | 
						|
static GStaticRWLock            type_rw_lock = G_STATIC_RW_LOCK_INIT;
 | 
						|
#define G_READ_LOCK(rw_lock)    g_static_rw_lock_reader_lock (rw_lock)
 | 
						|
#define G_READ_UNLOCK(rw_lock)  g_static_rw_lock_reader_unlock (rw_lock)
 | 
						|
#define G_WRITE_LOCK(rw_lock)   g_static_rw_lock_writer_lock (rw_lock)
 | 
						|
#define G_WRITE_UNLOCK(rw_lock) g_static_rw_lock_writer_unlock (rw_lock)
 | 
						|
#define	INVALID_RECURSION(func, arg, type_name) G_STMT_START{ \
 | 
						|
    static const gchar *_action = " invalidly modified type "; \
 | 
						|
    gpointer _arg = (gpointer) (arg); const gchar *_tname = (type_name), *_fname = (func); \
 | 
						|
    if (_arg) \
 | 
						|
      g_error ("%s(%p)%s`%s'", _fname, _arg, _action, _tname); \
 | 
						|
    else \
 | 
						|
      g_error ("%s()%s`%s'", _fname, _action, _tname); \
 | 
						|
}G_STMT_END
 | 
						|
#define	g_return_val_if_uninitialized(condition, init_function, return_value) G_STMT_START{	\
 | 
						|
  if (!(condition))										\
 | 
						|
    {												\
 | 
						|
      g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,						\
 | 
						|
	     "%s: initialization assertion failed, use %s() prior to this function",		\
 | 
						|
	     G_STRLOC, G_STRINGIFY (init_function));						\
 | 
						|
      return (return_value);									\
 | 
						|
    }												\
 | 
						|
}G_STMT_END
 | 
						|
 | 
						|
#ifdef  G_ENABLE_DEBUG
 | 
						|
#define DEBUG_CODE(debug_type, code_block)  G_STMT_START {    \
 | 
						|
    if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) \
 | 
						|
      { code_block; }                                     \
 | 
						|
} G_STMT_END
 | 
						|
#else /* !G_ENABLE_DEBUG */
 | 
						|
#define DEBUG_CODE(debug_type, code_block)  /* code_block */
 | 
						|
#endif  /* G_ENABLE_DEBUG */
 | 
						|
 | 
						|
#define TYPE_FUNDAMENTAL_FLAG_MASK (G_TYPE_FLAG_CLASSED | \
 | 
						|
				    G_TYPE_FLAG_INSTANTIATABLE | \
 | 
						|
				    G_TYPE_FLAG_DERIVABLE | \
 | 
						|
				    G_TYPE_FLAG_DEEP_DERIVABLE)
 | 
						|
#define	TYPE_FLAG_MASK		   (G_TYPE_FLAG_ABSTRACT | G_TYPE_FLAG_VALUE_ABSTRACT)
 | 
						|
#define	SIZEOF_FUNDAMENTAL_INFO	   ((gssize) MAX (MAX (sizeof (GTypeFundamentalInfo), \
 | 
						|
						       sizeof (gpointer)), \
 | 
						|
                                                  sizeof (glong)))
 | 
						|
 | 
						|
 | 
						|
/* --- typedefs --- */
 | 
						|
typedef struct _TypeNode        TypeNode;
 | 
						|
typedef struct _CommonData      CommonData;
 | 
						|
typedef struct _IFaceData       IFaceData;
 | 
						|
typedef struct _ClassData       ClassData;
 | 
						|
typedef struct _InstanceData    InstanceData;
 | 
						|
typedef union  _TypeData        TypeData;
 | 
						|
typedef struct _IFaceEntry      IFaceEntry;
 | 
						|
typedef struct _IFaceHolder	IFaceHolder;
 | 
						|
 | 
						|
 | 
						|
/* --- prototypes --- */
 | 
						|
static inline GTypeFundamentalInfo*	type_node_fundamental_info_L	(TypeNode		*node);
 | 
						|
static	      void			type_add_flags_W		(TypeNode		*node,
 | 
						|
									 GTypeFlags		 flags);
 | 
						|
static	      void			type_data_make_W		(TypeNode		*node,
 | 
						|
									 const GTypeInfo	*info,
 | 
						|
									 const GTypeValueTable	*value_table);
 | 
						|
static inline void			type_data_ref_Wm		(TypeNode		*node);
 | 
						|
static inline void			type_data_unref_Wm		(TypeNode		*node,
 | 
						|
									 gboolean		 uncached);
 | 
						|
static	      void			type_data_last_unref_Wm		(GType			 type,
 | 
						|
									 gboolean		 uncached);
 | 
						|
static inline gpointer			type_get_qdata_L		(TypeNode		*node,
 | 
						|
									 GQuark			 quark);
 | 
						|
static inline void			type_set_qdata_W		(TypeNode		*node,
 | 
						|
									 GQuark			 quark,
 | 
						|
									 gpointer		 data);
 | 
						|
 | 
						|
 | 
						|
/* --- structures --- */
 | 
						|
struct _GValue	/* kludge, keep in sync with gvalue.h */
 | 
						|
{
 | 
						|
  GType g_type;
 | 
						|
};
 | 
						|
struct _TypeNode
 | 
						|
{
 | 
						|
  GTypePlugin *plugin;
 | 
						|
  guint        n_children : 12;
 | 
						|
  guint        n_supers : 8;
 | 
						|
  guint        _prot_n_ifaces_prerequisites : 9;
 | 
						|
  guint        is_classed : 1;
 | 
						|
  guint        is_instantiatable : 1;
 | 
						|
  guint        free_flag : 1;
 | 
						|
  GType       *children;
 | 
						|
  TypeData    *data;
 | 
						|
  GQuark       qname;
 | 
						|
  GData       *global_gdata;
 | 
						|
  union {
 | 
						|
    IFaceEntry  *iface_entries;		/* for !iface types */
 | 
						|
    GType       *prerequisistes;
 | 
						|
  } _prot;
 | 
						|
  GType        supers[1]; /* flexible array */
 | 
						|
};
 | 
						|
#define SIZEOF_BASE_TYPE_NODE()			(G_STRUCT_OFFSET (TypeNode, supers))
 | 
						|
#define MAX_N_SUPERS				(255)
 | 
						|
#define MAX_N_CHILDREN				(4095)
 | 
						|
#define MAX_N_IFACES				(511)
 | 
						|
#define	MAX_N_PREREQUISITES			(MAX_N_IFACES)
 | 
						|
#define NODE_TYPE(node)				(node->supers[0])
 | 
						|
#define NODE_PARENT_TYPE(node)			(node->supers[1])
 | 
						|
#define NODE_NAME(node)				(g_quark_to_string (node->qname))
 | 
						|
#define	NODE_IS_IFACE(node)			(G_TYPE_IS_INTERFACE (NODE_TYPE (node)))
 | 
						|
#define	CLASSED_NODE_N_IFACES(node)		((node)->_prot_n_ifaces_prerequisites)
 | 
						|
#define	CLASSED_NODE_IFACES_ENTRIES(node)	((node)->_prot.iface_entries)
 | 
						|
#define	IFACE_NODE_N_PREREQUISITES(node)	((node)->_prot_n_ifaces_prerequisites)
 | 
						|
#define	IFACE_NODE_PREREQUISITES(node)		((node)->_prot.prerequisistes)
 | 
						|
#define	iface_node_get_holders_L(node)		((IFaceHolder*) type_get_qdata_L ((node), static_quark_iface_holder))
 | 
						|
#define	iface_node_set_holders_W(node, holders)	(type_set_qdata_W ((node), static_quark_iface_holder, (holders)))
 | 
						|
#define	iface_node_get_dependants_array_L(n)	((GType*) type_get_qdata_L ((n), static_quark_dependants_array))
 | 
						|
#define	iface_node_set_dependants_array_W(n,d)	(type_set_qdata_W ((n), static_quark_dependants_array, (d)))
 | 
						|
 | 
						|
struct _IFaceHolder
 | 
						|
{
 | 
						|
  GType           instance_type;
 | 
						|
  GInterfaceInfo *info;
 | 
						|
  GTypePlugin    *plugin;
 | 
						|
  IFaceHolder    *next;
 | 
						|
};
 | 
						|
struct _IFaceEntry
 | 
						|
{
 | 
						|
  GType           iface_type;
 | 
						|
  GTypeInterface *vtable;
 | 
						|
};
 | 
						|
struct _CommonData
 | 
						|
{
 | 
						|
  guint             ref_count;
 | 
						|
  GTypeValueTable  *value_table;
 | 
						|
};
 | 
						|
struct _IFaceData
 | 
						|
{
 | 
						|
  CommonData         common;
 | 
						|
  guint16            vtable_size;
 | 
						|
  GBaseInitFunc      vtable_init_base;
 | 
						|
  GBaseFinalizeFunc  vtable_finalize_base;
 | 
						|
};
 | 
						|
struct _ClassData
 | 
						|
{
 | 
						|
  CommonData         common;
 | 
						|
  guint16            class_size;
 | 
						|
  GBaseInitFunc      class_init_base;
 | 
						|
  GBaseFinalizeFunc  class_finalize_base;
 | 
						|
  GClassInitFunc     class_init;
 | 
						|
  GClassFinalizeFunc class_finalize;
 | 
						|
  gconstpointer      class_data;
 | 
						|
  gpointer           class;
 | 
						|
};
 | 
						|
struct _InstanceData
 | 
						|
{
 | 
						|
  CommonData         common;
 | 
						|
  guint16            class_size;
 | 
						|
  GBaseInitFunc      class_init_base;
 | 
						|
  GBaseFinalizeFunc  class_finalize_base;
 | 
						|
  GClassInitFunc     class_init;
 | 
						|
  GClassFinalizeFunc class_finalize;
 | 
						|
  gconstpointer      class_data;
 | 
						|
  gpointer           class;
 | 
						|
  guint16            instance_size;
 | 
						|
  guint16            n_preallocs;
 | 
						|
  GInstanceInitFunc  instance_init;
 | 
						|
  GMemChunk        *mem_chunk;
 | 
						|
};
 | 
						|
union _TypeData
 | 
						|
{
 | 
						|
  CommonData         common;
 | 
						|
  IFaceData          iface;
 | 
						|
  ClassData          class;
 | 
						|
  InstanceData       instance;
 | 
						|
};
 | 
						|
typedef struct {
 | 
						|
  gpointer            cache_data;
 | 
						|
  GTypeClassCacheFunc cache_func;
 | 
						|
} ClassCacheFunc;
 | 
						|
 | 
						|
 | 
						|
/* --- variables --- */
 | 
						|
static guint           static_n_class_cache_funcs = 0;
 | 
						|
static ClassCacheFunc *static_class_cache_funcs = NULL;
 | 
						|
static GType           static_last_fundamental_id = 0;
 | 
						|
static GQuark          static_quark_type_flags = 0;
 | 
						|
static GQuark          static_quark_iface_holder = 0;
 | 
						|
static GQuark          static_quark_dependants_array = 0;
 | 
						|
GTypeDebugFlags	       _g_type_debug_flags = 0;
 | 
						|
 | 
						|
 | 
						|
/* --- externs --- */
 | 
						|
const char  *g_log_domain_gruntime = "GRuntime";
 | 
						|
 | 
						|
 | 
						|
/* --- type nodes --- */
 | 
						|
static GHashTable       *static_type_nodes_ht = NULL;
 | 
						|
static GType            *static_branch_seqnos = NULL;
 | 
						|
static TypeNode       ***static_type_nodes = NULL;
 | 
						|
 | 
						|
static inline TypeNode*
 | 
						|
lookup_type_node_L (register GType utype)
 | 
						|
{
 | 
						|
  register GType ftype = G_TYPE_FUNDAMENTAL (utype);
 | 
						|
  register GType b_seqno = G_TYPE_BRANCH_SEQNO (utype);
 | 
						|
  
 | 
						|
  if (ftype < static_last_fundamental_id && b_seqno < static_branch_seqnos[ftype])
 | 
						|
    return static_type_nodes[ftype][b_seqno];
 | 
						|
  else
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static TypeNode*
 | 
						|
type_node_any_new_W (TypeNode             *pnode,
 | 
						|
		     GType                 ftype,
 | 
						|
		     const gchar          *name,
 | 
						|
		     GTypePlugin          *plugin,
 | 
						|
		     GTypeFundamentalFlags type_flags)
 | 
						|
{
 | 
						|
  guint branch_last, n_supers;
 | 
						|
  GType type;
 | 
						|
  TypeNode *node;
 | 
						|
  guint i, node_size = 0;
 | 
						|
  
 | 
						|
  n_supers = pnode ? pnode->n_supers + 1 : 0;
 | 
						|
  branch_last = static_branch_seqnos[ftype]++;
 | 
						|
  type = G_TYPE_DERIVE_ID (ftype, branch_last);
 | 
						|
  g_assert ((type & G_TYPE_FLAG_RESERVED_ID_BIT) == 0);
 | 
						|
  if (!branch_last || g_bit_storage (branch_last - 1) < g_bit_storage (static_branch_seqnos[ftype] - 1))
 | 
						|
    static_type_nodes[ftype] = g_renew (TypeNode*, static_type_nodes[ftype], 1 << g_bit_storage (static_branch_seqnos[ftype] - 1));
 | 
						|
  
 | 
						|
  if (!pnode)
 | 
						|
    node_size += SIZEOF_FUNDAMENTAL_INFO;	      /* fundamental type info */
 | 
						|
  node_size += SIZEOF_BASE_TYPE_NODE ();	      /* TypeNode structure */
 | 
						|
  node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + 0 for ->supers[] */
 | 
						|
  node = g_malloc0 (node_size);
 | 
						|
  if (!pnode)					      /* offset fundamental types */
 | 
						|
    node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO);
 | 
						|
  static_type_nodes[ftype][branch_last] = node;
 | 
						|
  
 | 
						|
  node->n_supers = n_supers;
 | 
						|
  if (!pnode)
 | 
						|
    {
 | 
						|
      node->supers[0] = type;
 | 
						|
      node->supers[1] = 0;
 | 
						|
      
 | 
						|
      node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0;
 | 
						|
      node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0;
 | 
						|
      
 | 
						|
      if (NODE_IS_IFACE (node))
 | 
						|
	{
 | 
						|
          IFACE_NODE_N_PREREQUISITES (node) = 0;
 | 
						|
	  IFACE_NODE_PREREQUISITES (node) = NULL;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  CLASSED_NODE_N_IFACES (node) = 0;
 | 
						|
	  CLASSED_NODE_IFACES_ENTRIES (node) = NULL;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      node->supers[0] = type;
 | 
						|
      memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1));
 | 
						|
      
 | 
						|
      node->is_classed = pnode->is_classed;
 | 
						|
      node->is_instantiatable = pnode->is_instantiatable;
 | 
						|
      
 | 
						|
      if (NODE_IS_IFACE (node))
 | 
						|
	{
 | 
						|
	  IFACE_NODE_N_PREREQUISITES (node) = 0;
 | 
						|
	  IFACE_NODE_PREREQUISITES (node) = NULL;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  CLASSED_NODE_N_IFACES (node) = CLASSED_NODE_N_IFACES (pnode);
 | 
						|
	  CLASSED_NODE_IFACES_ENTRIES (node) = g_memdup (CLASSED_NODE_IFACES_ENTRIES (pnode),
 | 
						|
							 sizeof (CLASSED_NODE_IFACES_ENTRIES (pnode)[0]) *
 | 
						|
							 CLASSED_NODE_N_IFACES (node));
 | 
						|
	}
 | 
						|
      
 | 
						|
      i = pnode->n_children++;
 | 
						|
      pnode->children = g_renew (GType, pnode->children, pnode->n_children);
 | 
						|
      pnode->children[i] = type;
 | 
						|
    }
 | 
						|
  
 | 
						|
  node->plugin = plugin;
 | 
						|
  node->n_children = 0;
 | 
						|
  node->children = NULL;
 | 
						|
  node->data = NULL;
 | 
						|
  node->qname = g_quark_from_string (name);
 | 
						|
  node->global_gdata = NULL;
 | 
						|
  
 | 
						|
  g_hash_table_insert (static_type_nodes_ht,
 | 
						|
		       GUINT_TO_POINTER (node->qname),
 | 
						|
		       GUINT_TO_POINTER (type));
 | 
						|
  return node;
 | 
						|
}
 | 
						|
 | 
						|
static inline GTypeFundamentalInfo*
 | 
						|
type_node_fundamental_info_L (TypeNode *node)
 | 
						|
{
 | 
						|
  GType ftype = G_TYPE_FUNDAMENTAL (NODE_TYPE (node));
 | 
						|
  
 | 
						|
  if (ftype != NODE_TYPE (node))
 | 
						|
    node = lookup_type_node_L (ftype);
 | 
						|
  
 | 
						|
  return node ? G_STRUCT_MEMBER_P (node, - SIZEOF_FUNDAMENTAL_INFO) : NULL;
 | 
						|
}
 | 
						|
 | 
						|
static TypeNode*
 | 
						|
type_node_fundamental_new_W (GType                 ftype,
 | 
						|
			     const gchar          *name,
 | 
						|
			     GTypeFundamentalFlags type_flags)
 | 
						|
{
 | 
						|
  GTypeFundamentalInfo *finfo;
 | 
						|
  TypeNode *node;
 | 
						|
  guint i, flast;
 | 
						|
  
 | 
						|
  flast = static_last_fundamental_id;
 | 
						|
  
 | 
						|
  g_assert (ftype == G_TYPE_FUNDAMENTAL (ftype));
 | 
						|
  
 | 
						|
  type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK;
 | 
						|
  
 | 
						|
  static_last_fundamental_id = MAX (static_last_fundamental_id, ftype + 1);
 | 
						|
  if (static_last_fundamental_id > flast)
 | 
						|
    {
 | 
						|
      static_type_nodes = g_renew (TypeNode**, static_type_nodes, static_last_fundamental_id);
 | 
						|
      static_branch_seqnos = g_renew (GType, static_branch_seqnos, static_last_fundamental_id);
 | 
						|
      for (i = flast; i < static_last_fundamental_id; i++)
 | 
						|
	{
 | 
						|
	  static_type_nodes[i] = NULL;
 | 
						|
	  static_branch_seqnos[i] = 0;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  g_assert (static_branch_seqnos[ftype] == 0);
 | 
						|
  
 | 
						|
  node = type_node_any_new_W (NULL, ftype, name, NULL, type_flags);
 | 
						|
  
 | 
						|
  finfo = type_node_fundamental_info_L (node);
 | 
						|
  finfo->type_flags = type_flags;
 | 
						|
  
 | 
						|
  return node;
 | 
						|
}
 | 
						|
 | 
						|
static TypeNode*
 | 
						|
type_node_new_W (TypeNode    *pnode,
 | 
						|
		 const gchar *name,
 | 
						|
		 GTypePlugin *plugin)
 | 
						|
     
 | 
						|
{
 | 
						|
  g_assert (pnode);
 | 
						|
  g_assert (pnode->n_supers < MAX_N_SUPERS);
 | 
						|
  g_assert (pnode->n_children < MAX_N_CHILDREN);
 | 
						|
  
 | 
						|
  return type_node_any_new_W (pnode, G_TYPE_FUNDAMENTAL (NODE_TYPE (pnode)), name, plugin, 0);
 | 
						|
}
 | 
						|
 | 
						|
static inline IFaceEntry*
 | 
						|
type_lookup_iface_entry_L (TypeNode *node,
 | 
						|
			   TypeNode *iface_node)
 | 
						|
{
 | 
						|
  if (NODE_IS_IFACE (iface_node) && CLASSED_NODE_N_IFACES (node))
 | 
						|
    {
 | 
						|
      IFaceEntry *ifaces = CLASSED_NODE_IFACES_ENTRIES (node) - 1;
 | 
						|
      guint n_ifaces = CLASSED_NODE_N_IFACES (node);
 | 
						|
      GType iface_type = NODE_TYPE (iface_node);
 | 
						|
      
 | 
						|
      do
 | 
						|
	{
 | 
						|
	  guint i;
 | 
						|
	  IFaceEntry *check;
 | 
						|
	  
 | 
						|
	  i = (n_ifaces + 1) >> 1;
 | 
						|
	  check = ifaces + i;
 | 
						|
	  if (iface_type == check->iface_type)
 | 
						|
	    return check;
 | 
						|
	  else if (iface_type > check->iface_type)
 | 
						|
	    {
 | 
						|
	      n_ifaces -= i;
 | 
						|
	      ifaces = check;
 | 
						|
	    }
 | 
						|
	  else /* if (iface_type < check->iface_type) */
 | 
						|
	    n_ifaces = i - 1;
 | 
						|
	}
 | 
						|
      while (n_ifaces);
 | 
						|
    }
 | 
						|
  
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static inline gboolean
 | 
						|
type_lookup_prerequisite_L (TypeNode *iface,
 | 
						|
			    GType     prerequisite_type)
 | 
						|
{
 | 
						|
  if (NODE_IS_IFACE (iface) && IFACE_NODE_N_PREREQUISITES (iface))
 | 
						|
    {
 | 
						|
      GType *prerequisites = IFACE_NODE_PREREQUISITES (iface) - 1;
 | 
						|
      guint n_prerequisites = IFACE_NODE_N_PREREQUISITES (iface);
 | 
						|
 | 
						|
      do
 | 
						|
	{
 | 
						|
	  guint i;
 | 
						|
	  GType *check;
 | 
						|
	  
 | 
						|
	  i = (n_prerequisites + 1) >> 1;
 | 
						|
	  check = prerequisites + i;
 | 
						|
	  if (prerequisite_type == *check)
 | 
						|
	    return TRUE;
 | 
						|
	  else if (prerequisite_type > *check)
 | 
						|
	    {
 | 
						|
	      n_prerequisites -= i;
 | 
						|
	      prerequisites = check;
 | 
						|
	    }
 | 
						|
	  else /* if (prerequisite_type < *check) */
 | 
						|
	    n_prerequisites = i - 1;
 | 
						|
	}
 | 
						|
      while (n_prerequisites);
 | 
						|
    }
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static inline gchar*
 | 
						|
type_descriptive_name_L (GType type)
 | 
						|
{
 | 
						|
  if (type)
 | 
						|
    {
 | 
						|
      TypeNode *node = lookup_type_node_L (type);
 | 
						|
      
 | 
						|
      return node ? NODE_NAME (node) : "<unknown>";
 | 
						|
    }
 | 
						|
  else
 | 
						|
    return "<invalid>";
 | 
						|
}
 | 
						|
 | 
						|
static inline gchar*
 | 
						|
type_descriptive_name_U (GType type)
 | 
						|
{
 | 
						|
  const gchar *name;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  name = type_descriptive_name_L (type);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return (gchar *)name;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* --- type consistency checks --- */
 | 
						|
static gboolean
 | 
						|
check_plugin_U (GTypePlugin *plugin,
 | 
						|
		gboolean     need_complete_type_info,
 | 
						|
		gboolean     need_complete_interface_info,
 | 
						|
		const gchar *type_name)
 | 
						|
{
 | 
						|
  /* G_IS_TYPE_PLUGIN() and G_TYPE_PLUGIN_GET_CLASS() are external calls: _U 
 | 
						|
   */
 | 
						|
  if (!plugin)
 | 
						|
    {
 | 
						|
      g_warning ("plugin handle for type `%s' is NULL",
 | 
						|
		 type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  if (!G_IS_TYPE_PLUGIN (plugin))
 | 
						|
    {
 | 
						|
      g_warning ("plugin pointer (%p) for type `%s' is invalid",
 | 
						|
		 plugin, type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  if (need_complete_type_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_type_info)
 | 
						|
    {
 | 
						|
      g_warning ("plugin for type `%s' has no complete_type_info() implementation",
 | 
						|
		 type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  if (need_complete_interface_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_interface_info)
 | 
						|
    {
 | 
						|
      g_warning ("plugin for type `%s' has no complete_interface_info() implementation",
 | 
						|
		 type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
check_type_name_U (const gchar *type_name)
 | 
						|
{
 | 
						|
  static const gchar *extra_chars = "-_+";
 | 
						|
  const gchar *p = type_name;
 | 
						|
  gboolean name_valid;
 | 
						|
  
 | 
						|
  if (!type_name[0] || !type_name[1] || !type_name[2])
 | 
						|
    {
 | 
						|
      g_warning ("type name `%s' is too short", type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  /* check the first letter */
 | 
						|
  name_valid = (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || p[0] == '_';
 | 
						|
  for (p = type_name + 1; *p; p++)
 | 
						|
    name_valid &= ((p[0] >= 'A' && p[0] <= 'Z') ||
 | 
						|
		   (p[0] >= 'a' && p[0] <= 'z') ||
 | 
						|
		   (p[0] >= '0' && p[0] <= '9') ||
 | 
						|
		   strchr (extra_chars, p[0]));
 | 
						|
  if (!name_valid)
 | 
						|
    {
 | 
						|
      g_warning ("type name `%s' contains invalid characters", type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  if (g_type_from_name (type_name))
 | 
						|
    {
 | 
						|
      g_warning ("cannot register existing type `%s'", type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
check_derivation_U (GType        parent_type,
 | 
						|
		    const gchar *type_name)
 | 
						|
{
 | 
						|
  TypeNode *pnode;
 | 
						|
  GTypeFundamentalInfo* finfo;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  pnode = lookup_type_node_L (parent_type);
 | 
						|
  if (!pnode)
 | 
						|
    {
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      g_warning ("cannot derive type `%s' from invalid parent type `%s'",
 | 
						|
		 type_name,
 | 
						|
		 type_descriptive_name_U (parent_type));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  finfo = type_node_fundamental_info_L (pnode);
 | 
						|
  /* ensure flat derivability */
 | 
						|
  if (!(finfo->type_flags & G_TYPE_FLAG_DERIVABLE))
 | 
						|
    {
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      g_warning ("cannot derive `%s' from non-derivable parent type `%s'",
 | 
						|
		 type_name,
 | 
						|
		 NODE_NAME (pnode));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  /* ensure deep derivability */
 | 
						|
  if (parent_type != G_TYPE_FUNDAMENTAL (parent_type) &&
 | 
						|
      !(finfo->type_flags & G_TYPE_FLAG_DEEP_DERIVABLE))
 | 
						|
    {
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      g_warning ("cannot derive `%s' from non-fundamental parent type `%s'",
 | 
						|
		 type_name,
 | 
						|
		 NODE_NAME (pnode));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
check_collect_format_I (const gchar *collect_format)
 | 
						|
{
 | 
						|
  const gchar *p = collect_format;
 | 
						|
  gchar valid_format[] = { G_VALUE_COLLECT_INT, G_VALUE_COLLECT_LONG,
 | 
						|
			   G_VALUE_COLLECT_DOUBLE, G_VALUE_COLLECT_POINTER,
 | 
						|
			   0 };
 | 
						|
 | 
						|
  while (*p)
 | 
						|
    if (!strchr (valid_format, *p++))
 | 
						|
      return FALSE;
 | 
						|
  return p - collect_format <= G_VALUE_COLLECT_FORMAT_MAX_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
check_value_table_I (const gchar           *type_name,
 | 
						|
		     const GTypeValueTable *value_table)
 | 
						|
{
 | 
						|
  if (!value_table)
 | 
						|
    return FALSE;
 | 
						|
  else if (value_table->value_init == NULL)
 | 
						|
    {
 | 
						|
      if (value_table->value_free || value_table->value_copy ||
 | 
						|
	  value_table->value_peek_pointer ||
 | 
						|
	  value_table->collect_format || value_table->collect_value ||
 | 
						|
	  value_table->lcopy_format || value_table->lcopy_value)
 | 
						|
	g_warning ("cannot handle uninitializable values of type `%s'",
 | 
						|
		   type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  else /* value_table->value_init != NULL */
 | 
						|
    {
 | 
						|
      if (!value_table->value_free)
 | 
						|
	{
 | 
						|
	  /* +++ optional +++
 | 
						|
	   * g_warning ("missing `value_free()' for type `%s'", type_name);
 | 
						|
	   * return FALSE;
 | 
						|
	   */
 | 
						|
	}
 | 
						|
      if (!value_table->value_copy)
 | 
						|
	{
 | 
						|
	  g_warning ("missing `value_copy()' for type `%s'", type_name);
 | 
						|
	  return FALSE;
 | 
						|
	}
 | 
						|
      if ((value_table->collect_format || value_table->collect_value) &&
 | 
						|
	  (!value_table->collect_format || !value_table->collect_value))
 | 
						|
	{
 | 
						|
	  g_warning ("one of `collect_format' and `collect_value()' is unspecified for type `%s'",
 | 
						|
		     type_name);
 | 
						|
	  return FALSE;
 | 
						|
	}
 | 
						|
      if (value_table->collect_format && !check_collect_format_I (value_table->collect_format))
 | 
						|
	{
 | 
						|
	  g_warning ("the `%s' specification for type `%s' is too long or invalid",
 | 
						|
		     "collect_format",
 | 
						|
		     type_name);
 | 
						|
	  return FALSE;
 | 
						|
	}
 | 
						|
      if ((value_table->lcopy_format || value_table->lcopy_value) &&
 | 
						|
	  (!value_table->lcopy_format || !value_table->lcopy_value))
 | 
						|
	{
 | 
						|
	  g_warning ("one of `lcopy_format' and `lcopy_value()' is unspecified for type `%s'",
 | 
						|
		     type_name);
 | 
						|
	  return FALSE;
 | 
						|
	}
 | 
						|
      if (value_table->lcopy_format && !check_collect_format_I (value_table->lcopy_format))
 | 
						|
	{
 | 
						|
	  g_warning ("the `%s' specification for type `%s' is too long or invalid",
 | 
						|
		     "lcopy_format",
 | 
						|
		     type_name);
 | 
						|
	  return FALSE;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
check_type_info_L (TypeNode        *pnode,
 | 
						|
		   GType            ftype,
 | 
						|
		   const gchar     *type_name,
 | 
						|
		   const GTypeInfo *info)
 | 
						|
{
 | 
						|
  GTypeFundamentalInfo *finfo = type_node_fundamental_info_L (lookup_type_node_L (ftype));
 | 
						|
  gboolean is_interface = G_TYPE_IS_INTERFACE (ftype);
 | 
						|
  
 | 
						|
  /* check instance members */
 | 
						|
  if (!(finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
 | 
						|
      (info->instance_size || info->n_preallocs || info->instance_init))
 | 
						|
    {
 | 
						|
      if (pnode)
 | 
						|
	g_warning ("cannot instantiate `%s', derived from non-instantiatable parent type `%s'",
 | 
						|
		   type_name,
 | 
						|
		   NODE_NAME (pnode));
 | 
						|
      else
 | 
						|
	g_warning ("cannot instantiate `%s' as non-instantiatable fundamental",
 | 
						|
		   type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  /* check class & interface members */
 | 
						|
  if (!(finfo->type_flags & G_TYPE_FLAG_CLASSED) &&
 | 
						|
      (info->class_init || info->class_finalize || info->class_data ||
 | 
						|
       (!is_interface && (info->class_size || info->base_init || info->base_finalize))))
 | 
						|
    {
 | 
						|
      if (pnode)
 | 
						|
	g_warning ("cannot create class for `%s', derived from non-classed parent type `%s'",
 | 
						|
		   type_name,
 | 
						|
                   NODE_NAME (pnode));
 | 
						|
      else
 | 
						|
	g_warning ("cannot create class for `%s' as non-classed fundamental",
 | 
						|
		   type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  /* check interface size */
 | 
						|
  if (is_interface && info->class_size < sizeof (GTypeInterface))
 | 
						|
    {
 | 
						|
      g_warning ("specified interface size for type `%s' is smaller than `GTypeInterface' size",
 | 
						|
		 type_name);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  /* check class size */
 | 
						|
  if (finfo->type_flags & G_TYPE_FLAG_CLASSED)
 | 
						|
    {
 | 
						|
      if (info->class_size < sizeof (GTypeClass))
 | 
						|
	{
 | 
						|
	  g_warning ("specified class size for type `%s' is smaller than `GTypeClass' size",
 | 
						|
		     type_name);
 | 
						|
	  return FALSE;
 | 
						|
	}
 | 
						|
      if (pnode && info->class_size < pnode->data->class.class_size)
 | 
						|
	{
 | 
						|
	  g_warning ("specified class size for type `%s' is smaller "
 | 
						|
		     "than the parent type's `%s' class size",
 | 
						|
		     type_name,
 | 
						|
		     NODE_NAME (pnode));
 | 
						|
	  return FALSE;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  /* check instance size */
 | 
						|
  if (finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE)
 | 
						|
    {
 | 
						|
      if (info->instance_size < sizeof (GTypeInstance))
 | 
						|
	{
 | 
						|
	  g_warning ("specified instance size for type `%s' is smaller than `GTypeInstance' size",
 | 
						|
		     type_name);
 | 
						|
	  return FALSE;
 | 
						|
	}
 | 
						|
      if (pnode && info->instance_size < pnode->data->instance.instance_size)
 | 
						|
	{
 | 
						|
	  g_warning ("specified instance size for type `%s' is smaller "
 | 
						|
		     "than the parent type's `%s' instance size",
 | 
						|
		     type_name,
 | 
						|
		     NODE_NAME (pnode));
 | 
						|
	  return FALSE;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static TypeNode*
 | 
						|
find_conforming_type_L (TypeNode *pnode,
 | 
						|
			TypeNode *iface)
 | 
						|
{
 | 
						|
  TypeNode *node = NULL;
 | 
						|
  guint i;
 | 
						|
  
 | 
						|
  if (type_lookup_iface_entry_L (pnode, iface))
 | 
						|
    return pnode;
 | 
						|
  
 | 
						|
  for (i = 0; i < pnode->n_children && !node; i++)
 | 
						|
    node = find_conforming_type_L (lookup_type_node_L (pnode->children[i]), iface);
 | 
						|
  
 | 
						|
  return node;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
check_add_interface_L (GType instance_type,
 | 
						|
		       GType iface_type)
 | 
						|
{
 | 
						|
  TypeNode *node = lookup_type_node_L (instance_type);
 | 
						|
  TypeNode *iface = lookup_type_node_L (iface_type);
 | 
						|
  TypeNode *tnode;
 | 
						|
  
 | 
						|
  if (!node || !node->is_instantiatable)
 | 
						|
    {
 | 
						|
      g_warning ("cannot add interfaces to invalid (non-instantiatable) type `%s'",
 | 
						|
		 type_descriptive_name_L (instance_type));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  if (!iface || !NODE_IS_IFACE (iface))
 | 
						|
    {
 | 
						|
      g_warning ("cannot add invalid (non-interface) type `%s' to type `%s'",
 | 
						|
		 type_descriptive_name_L (iface_type),
 | 
						|
		 NODE_NAME (node));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  tnode = lookup_type_node_L (NODE_PARENT_TYPE (iface));
 | 
						|
  if (NODE_PARENT_TYPE (tnode) && !type_lookup_iface_entry_L (node, tnode))
 | 
						|
    {
 | 
						|
      /* 2001/7/31:timj: erk, i guess this warning is junk as interface derivation is flat */
 | 
						|
      g_warning ("cannot add sub-interface `%s' to type `%s' which does not conform to super-interface `%s'",
 | 
						|
		 NODE_NAME (iface),
 | 
						|
		 NODE_NAME (node),
 | 
						|
		 NODE_NAME (tnode));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  tnode = find_conforming_type_L (node, iface);  // FIXME: iface overriding
 | 
						|
  if (tnode)
 | 
						|
    {
 | 
						|
      g_warning ("cannot add interface type `%s' to type `%s', since type `%s' already conforms to interface",
 | 
						|
		 NODE_NAME (iface),
 | 
						|
		 NODE_NAME (node),
 | 
						|
		 NODE_NAME (tnode));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
check_interface_info_L (TypeNode             *iface,
 | 
						|
			GType                 instance_type,
 | 
						|
			const GInterfaceInfo *info)
 | 
						|
{
 | 
						|
  if ((info->interface_finalize || info->interface_data) && !info->interface_init)
 | 
						|
    {
 | 
						|
      g_warning ("interface type `%s' for type `%s' comes without initializer",
 | 
						|
		 NODE_NAME (iface),
 | 
						|
		 type_descriptive_name_L (instance_type));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/* --- type info (type node data) --- */
 | 
						|
static void
 | 
						|
type_data_make_W (TypeNode              *node,
 | 
						|
		  const GTypeInfo       *info,
 | 
						|
		  const GTypeValueTable *value_table)
 | 
						|
{
 | 
						|
  TypeData *data;
 | 
						|
  GTypeValueTable *vtable = NULL;
 | 
						|
  guint vtable_size = 0;
 | 
						|
  
 | 
						|
  g_assert (node->data == NULL && info != NULL);
 | 
						|
  
 | 
						|
  if (!value_table)
 | 
						|
    {
 | 
						|
      TypeNode *pnode = lookup_type_node_L (NODE_PARENT_TYPE (node));
 | 
						|
      
 | 
						|
      if (pnode)
 | 
						|
	vtable = pnode->data->common.value_table;
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  static const GTypeValueTable zero_vtable = { NULL, };
 | 
						|
	  
 | 
						|
	  value_table = &zero_vtable;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  if (value_table)
 | 
						|
    {
 | 
						|
      /* need to setup vtable_size since we have to allocate it with data in one chunk */
 | 
						|
      vtable_size = sizeof (GTypeValueTable);
 | 
						|
      if (value_table->collect_format)
 | 
						|
	vtable_size += strlen (value_table->collect_format);
 | 
						|
      if (value_table->lcopy_format)
 | 
						|
	vtable_size += strlen (value_table->lcopy_format);
 | 
						|
      vtable_size += 2;
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (node->is_instantiatable) /* carefull, is_instantiatable is also is_classed */
 | 
						|
    {
 | 
						|
      data = g_malloc0 (sizeof (InstanceData) + vtable_size);
 | 
						|
      if (vtable_size)
 | 
						|
	vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData));
 | 
						|
      data->instance.class_size = info->class_size;
 | 
						|
      data->instance.class_init_base = info->base_init;
 | 
						|
      data->instance.class_finalize_base = info->base_finalize;
 | 
						|
      data->instance.class_init = info->class_init;
 | 
						|
      data->instance.class_finalize = info->class_finalize;
 | 
						|
      data->instance.class_data = info->class_data;
 | 
						|
      data->instance.class = NULL;
 | 
						|
      data->instance.instance_size = info->instance_size;
 | 
						|
#ifdef	DISABLE_MEM_POOLS
 | 
						|
      data->instance.n_preallocs = 0;
 | 
						|
#else	/* !DISABLE_MEM_POOLS */
 | 
						|
      data->instance.n_preallocs = MIN (info->n_preallocs, 1024);
 | 
						|
#endif	/* !DISABLE_MEM_POOLS */
 | 
						|
      data->instance.instance_init = info->instance_init;
 | 
						|
      data->instance.mem_chunk = NULL;
 | 
						|
    }
 | 
						|
  else if (node->is_classed) /* only classed */
 | 
						|
    {
 | 
						|
      data = g_malloc0 (sizeof (ClassData) + vtable_size);
 | 
						|
      if (vtable_size)
 | 
						|
	vtable = G_STRUCT_MEMBER_P (data, sizeof (ClassData));
 | 
						|
      data->class.class_size = info->class_size;
 | 
						|
      data->class.class_init_base = info->base_init;
 | 
						|
      data->class.class_finalize_base = info->base_finalize;
 | 
						|
      data->class.class_init = info->class_init;
 | 
						|
      data->class.class_finalize = info->class_finalize;
 | 
						|
      data->class.class_data = info->class_data;
 | 
						|
      data->class.class = NULL;
 | 
						|
    }
 | 
						|
  else if (NODE_IS_IFACE (node))
 | 
						|
    {
 | 
						|
      data = g_malloc0 (sizeof (IFaceData) + vtable_size);
 | 
						|
      if (vtable_size)
 | 
						|
	vtable = G_STRUCT_MEMBER_P (data, sizeof (IFaceData));
 | 
						|
      data->iface.vtable_size = info->class_size;
 | 
						|
      data->iface.vtable_init_base = info->base_init;
 | 
						|
      data->iface.vtable_finalize_base = info->base_finalize;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      data = g_malloc0 (sizeof (CommonData) + vtable_size);
 | 
						|
      if (vtable_size)
 | 
						|
	vtable = G_STRUCT_MEMBER_P (data, sizeof (CommonData));
 | 
						|
    }
 | 
						|
  
 | 
						|
  node->data = data;
 | 
						|
  node->data->common.ref_count = 1;
 | 
						|
  
 | 
						|
  if (vtable_size)
 | 
						|
    {
 | 
						|
      gchar *p;
 | 
						|
 | 
						|
      /* we allocate the vtable and its strings together with the type data, so
 | 
						|
       * children can take over their parent's vtable pointer, and we don't
 | 
						|
       * need to worry freeing it or not when the child data is destroyed
 | 
						|
       */
 | 
						|
      *vtable = *value_table;
 | 
						|
      p = G_STRUCT_MEMBER_P (vtable, sizeof (*vtable));
 | 
						|
      p[0] = 0;
 | 
						|
      vtable->collect_format = p;
 | 
						|
      if (value_table->collect_format)
 | 
						|
	{
 | 
						|
	  strcat (p, value_table->collect_format);
 | 
						|
	  p += strlen (value_table->collect_format);
 | 
						|
	}
 | 
						|
      p++;
 | 
						|
      p[0] = 0;
 | 
						|
      vtable->lcopy_format = p;
 | 
						|
      if (value_table->lcopy_format)
 | 
						|
	strcat  (p, value_table->lcopy_format);
 | 
						|
    }
 | 
						|
  node->data->common.value_table = vtable;
 | 
						|
  
 | 
						|
  g_assert (node->data->common.value_table != NULL); /* paranoid */
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
type_data_ref_Wm (TypeNode *node)
 | 
						|
{
 | 
						|
  if (!node->data)
 | 
						|
    {
 | 
						|
      TypeNode *pnode = lookup_type_node_L (NODE_PARENT_TYPE (node));
 | 
						|
      GTypeInfo tmp_info;
 | 
						|
      GTypeValueTable tmp_value_table;
 | 
						|
      
 | 
						|
      g_assert (node->plugin != NULL);
 | 
						|
      
 | 
						|
      if (pnode)
 | 
						|
	{
 | 
						|
	  type_data_ref_Wm (pnode);
 | 
						|
	  if (node->data)
 | 
						|
	    INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
 | 
						|
	}
 | 
						|
      
 | 
						|
      memset (&tmp_info, 0, sizeof (tmp_info));
 | 
						|
      memset (&tmp_value_table, 0, sizeof (tmp_value_table));
 | 
						|
      
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      g_type_plugin_use (node->plugin);
 | 
						|
      g_type_plugin_complete_type_info (node->plugin, NODE_TYPE (node), &tmp_info, &tmp_value_table);
 | 
						|
      G_WRITE_LOCK (&type_rw_lock);
 | 
						|
      if (node->data)
 | 
						|
	INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
 | 
						|
      
 | 
						|
      check_type_info_L (pnode, G_TYPE_FUNDAMENTAL (NODE_TYPE (node)), NODE_NAME (node), &tmp_info);
 | 
						|
      type_data_make_W (node, &tmp_info,
 | 
						|
			check_value_table_I (NODE_NAME (node),
 | 
						|
					     &tmp_value_table) ? &tmp_value_table : NULL);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      g_assert (node->data->common.ref_count > 0);
 | 
						|
      
 | 
						|
      node->data->common.ref_count += 1;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
type_data_unref_Wm (TypeNode *node,
 | 
						|
		    gboolean  uncached)
 | 
						|
{
 | 
						|
  g_assert (node->data && node->data->common.ref_count);
 | 
						|
  
 | 
						|
  if (node->data->common.ref_count > 1)
 | 
						|
    node->data->common.ref_count -= 1;
 | 
						|
  else
 | 
						|
    {
 | 
						|
      if (!node->plugin)
 | 
						|
	{
 | 
						|
	  g_warning ("static type `%s' unreferenced too often",
 | 
						|
		     NODE_NAME (node));
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
      
 | 
						|
      type_data_last_unref_Wm (NODE_TYPE (node), uncached);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_node_add_iface_entry_W (TypeNode *node,
 | 
						|
			     GType     iface_type)
 | 
						|
{
 | 
						|
  IFaceEntry *entries;
 | 
						|
  guint i;
 | 
						|
  
 | 
						|
  g_assert (node->is_instantiatable && CLASSED_NODE_N_IFACES (node) < MAX_N_IFACES);
 | 
						|
  
 | 
						|
  entries = CLASSED_NODE_IFACES_ENTRIES (node);
 | 
						|
  for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
 | 
						|
    if (entries[i].iface_type == iface_type)
 | 
						|
      {
 | 
						|
	g_warning ("failed to add interface, type `%s' already conforms to interface type `%s'",
 | 
						|
		   type_descriptive_name_L (NODE_TYPE (node)),
 | 
						|
		   type_descriptive_name_L (iface_type));
 | 
						|
	return;
 | 
						|
      }
 | 
						|
    else if (entries[i].iface_type > iface_type)
 | 
						|
      break;
 | 
						|
  CLASSED_NODE_N_IFACES (node) += 1;
 | 
						|
  CLASSED_NODE_IFACES_ENTRIES (node) = g_renew (IFaceEntry,
 | 
						|
						CLASSED_NODE_IFACES_ENTRIES (node),
 | 
						|
						CLASSED_NODE_N_IFACES (node));
 | 
						|
  entries = CLASSED_NODE_IFACES_ENTRIES (node);
 | 
						|
  g_memmove (entries + i + 1, entries + i, sizeof (entries[0]) * (CLASSED_NODE_N_IFACES (node) - i - 1));
 | 
						|
  entries[i].iface_type = iface_type;
 | 
						|
  entries[i].vtable = NULL;
 | 
						|
  
 | 
						|
  for (i = 0; i < node->n_children; i++)
 | 
						|
    type_node_add_iface_entry_W (lookup_type_node_L (node->children[i]), iface_type);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_add_interface_W (TypeNode             *node,
 | 
						|
		      TypeNode             *iface,
 | 
						|
		      const GInterfaceInfo *info,
 | 
						|
		      GTypePlugin          *plugin)
 | 
						|
{
 | 
						|
  IFaceHolder *iholder = g_new0 (IFaceHolder, 1);
 | 
						|
  
 | 
						|
  /* we must not call any functions of GInterfaceInfo from within here, since
 | 
						|
   * we got most probably called from _within_ a type registration function
 | 
						|
   */
 | 
						|
  g_assert (node->is_instantiatable && NODE_IS_IFACE (iface) && ((info && !plugin) || (!info && plugin)));
 | 
						|
  
 | 
						|
  iholder->next = iface_node_get_holders_L (iface);
 | 
						|
  iface_node_set_holders_W (iface, iholder);
 | 
						|
  iholder->instance_type = NODE_TYPE (node);
 | 
						|
  iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL;
 | 
						|
  iholder->plugin = plugin;
 | 
						|
  
 | 
						|
  type_node_add_iface_entry_W (node, NODE_TYPE (iface));
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_iface_add_prerequisite_W (TypeNode *iface,
 | 
						|
			       TypeNode *prerequisite_node)
 | 
						|
{
 | 
						|
  GType prerequisite_type = NODE_TYPE (prerequisite_node);
 | 
						|
  GType *prerequisites, *dependants;
 | 
						|
  guint n_dependants, i;
 | 
						|
 | 
						|
  g_assert (NODE_IS_IFACE (iface) &&
 | 
						|
	    IFACE_NODE_N_PREREQUISITES (iface) < MAX_N_PREREQUISITES &&
 | 
						|
	    (prerequisite_node->is_instantiatable || NODE_IS_IFACE (prerequisite_node)));
 | 
						|
 | 
						|
  prerequisites = IFACE_NODE_PREREQUISITES (iface);
 | 
						|
  for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
 | 
						|
    if (prerequisites[i] == prerequisite_type)
 | 
						|
      return;			/* we already have that prerequisiste */
 | 
						|
    else if (prerequisites[i] > prerequisite_type)
 | 
						|
      break;
 | 
						|
  IFACE_NODE_N_PREREQUISITES (iface) += 1;
 | 
						|
  IFACE_NODE_PREREQUISITES (iface) = g_renew (GType,
 | 
						|
					      IFACE_NODE_PREREQUISITES (iface),
 | 
						|
					      IFACE_NODE_N_PREREQUISITES (iface));
 | 
						|
  prerequisites = IFACE_NODE_PREREQUISITES (iface);
 | 
						|
  g_memmove (prerequisites + i + 1, prerequisites + i,
 | 
						|
	     sizeof (prerequisites[0]) * (IFACE_NODE_N_PREREQUISITES (iface) - i - 1));
 | 
						|
  prerequisites[i] = prerequisite_type;
 | 
						|
 | 
						|
  /* we want to get notified when prerequisites get added to prerequisite_node */
 | 
						|
  if (NODE_IS_IFACE (prerequisite_node))
 | 
						|
    {
 | 
						|
      dependants = iface_node_get_dependants_array_L (prerequisite_node);
 | 
						|
      n_dependants = dependants ? dependants[0] : 0;
 | 
						|
      n_dependants += 1;
 | 
						|
      dependants = g_renew (GType, dependants, n_dependants + 1);
 | 
						|
      dependants[n_dependants] = NODE_TYPE (iface);
 | 
						|
      dependants[0] = n_dependants;
 | 
						|
      iface_node_set_dependants_array_W (prerequisite_node, dependants);
 | 
						|
    }
 | 
						|
 | 
						|
  /* we need to notify all dependants */
 | 
						|
  dependants = iface_node_get_dependants_array_L (iface);
 | 
						|
  n_dependants = dependants ? dependants[0] : 0;
 | 
						|
  for (i = 1; i <= n_dependants; i++)
 | 
						|
    type_iface_add_prerequisite_W (lookup_type_node_L (dependants[i]), prerequisite_node);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_interface_add_prerequisite (GType interface_type,
 | 
						|
				   GType prerequisite_type)
 | 
						|
{
 | 
						|
  TypeNode *iface, *prerequisite_node;
 | 
						|
  IFaceHolder *holders;
 | 
						|
 | 
						|
  g_return_if_fail (G_TYPE_IS_INTERFACE (interface_type));
 | 
						|
  g_return_if_fail (!g_type_is_a (interface_type, prerequisite_type));
 | 
						|
  g_return_if_fail (!g_type_is_a (prerequisite_type, interface_type));
 | 
						|
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  iface = lookup_type_node_L (interface_type);
 | 
						|
  prerequisite_node = lookup_type_node_L (prerequisite_type);
 | 
						|
  if (!iface || !prerequisite_node || !NODE_IS_IFACE (iface))
 | 
						|
    {
 | 
						|
      g_warning ("interface type `%s' or prerequisite type `%s' invalid",
 | 
						|
		 type_descriptive_name_L (interface_type),
 | 
						|
		 type_descriptive_name_L (prerequisite_type));
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  holders = iface_node_get_holders_L (iface);
 | 
						|
  if (holders)
 | 
						|
    {
 | 
						|
      g_warning ("unable to add prerequisite `%s' to interface `%s' which is already in use for `%s'",
 | 
						|
		 type_descriptive_name_L (prerequisite_type),
 | 
						|
		 type_descriptive_name_L (interface_type),
 | 
						|
		 type_descriptive_name_L (holders->instance_type));
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  if (prerequisite_node->is_instantiatable)
 | 
						|
    {
 | 
						|
      guint i;
 | 
						|
 | 
						|
      /* can have at most one publically installable instantiatable prerequisite */
 | 
						|
      for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
 | 
						|
	{
 | 
						|
	  TypeNode *prnode = lookup_type_node_L (IFACE_NODE_PREREQUISITES (iface)[i]);
 | 
						|
 | 
						|
	  if (prnode->is_instantiatable)
 | 
						|
	    {
 | 
						|
	      g_warning ("adding prerequisite `%s' to interface `%s' conflicts with existing prerequisite `%s'",
 | 
						|
			 type_descriptive_name_L (prerequisite_type),
 | 
						|
			 type_descriptive_name_L (interface_type),
 | 
						|
			 type_descriptive_name_L (NODE_TYPE (prnode)));
 | 
						|
	      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
	      return;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
      for (i = 0; i < prerequisite_node->n_supers + 1; i++)
 | 
						|
	type_iface_add_prerequisite_W (iface, lookup_type_node_L (prerequisite_node->supers[i]));
 | 
						|
    }
 | 
						|
  else if (NODE_IS_IFACE (prerequisite_node))
 | 
						|
    {
 | 
						|
      GType *dependants;
 | 
						|
      guint n_dependants, i;
 | 
						|
 | 
						|
      dependants = iface_node_get_dependants_array_L (prerequisite_node);
 | 
						|
      n_dependants = dependants ? dependants[0] : 0;
 | 
						|
      for (i = 1; i <= n_dependants; i++)
 | 
						|
	type_iface_add_prerequisite_W (iface, lookup_type_node_L (dependants[i]));
 | 
						|
      type_iface_add_prerequisite_W (iface, prerequisite_node);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    g_warning ("prerequisite `%s' for interface `%s' is neither instantiatable nor interface",
 | 
						|
	       type_descriptive_name_L (prerequisite_type),
 | 
						|
	       type_descriptive_name_L (interface_type));
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
}
 | 
						|
 | 
						|
static IFaceHolder*
 | 
						|
type_iface_retrive_holder_info_Wm (TypeNode *iface,
 | 
						|
				   GType     instance_type)
 | 
						|
{
 | 
						|
  IFaceHolder *iholder = iface_node_get_holders_L (iface);
 | 
						|
  
 | 
						|
  g_assert (NODE_IS_IFACE (iface));
 | 
						|
  
 | 
						|
  while (iholder->instance_type != instance_type)
 | 
						|
    iholder = iholder->next;
 | 
						|
  
 | 
						|
  if (!iholder->info)
 | 
						|
    {
 | 
						|
      GInterfaceInfo tmp_info;
 | 
						|
      
 | 
						|
      g_assert (iholder->plugin != NULL);
 | 
						|
      
 | 
						|
      type_data_ref_Wm (iface);
 | 
						|
      if (iholder->info)
 | 
						|
	INVALID_RECURSION ("g_type_plugin_*", iface->plugin, NODE_NAME (iface));
 | 
						|
      
 | 
						|
      memset (&tmp_info, 0, sizeof (tmp_info));
 | 
						|
      
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      g_type_plugin_use (iholder->plugin);
 | 
						|
      g_type_plugin_complete_interface_info (iholder->plugin, instance_type, NODE_TYPE (iface), &tmp_info);
 | 
						|
      G_WRITE_LOCK (&type_rw_lock);
 | 
						|
      if (iholder->info)
 | 
						|
        INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface));
 | 
						|
      
 | 
						|
      check_interface_info_L (iface, instance_type, &tmp_info);
 | 
						|
      iholder->info = g_memdup (&tmp_info, sizeof (tmp_info));
 | 
						|
    }
 | 
						|
  
 | 
						|
  return iholder;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_iface_blow_holder_info_Wm (TypeNode *iface,
 | 
						|
				GType     instance_type)
 | 
						|
{
 | 
						|
  IFaceHolder *iholder = iface_node_get_holders_L (iface);
 | 
						|
  
 | 
						|
  g_assert (NODE_IS_IFACE (iface));
 | 
						|
  
 | 
						|
  while (iholder->instance_type != instance_type)
 | 
						|
    iholder = iholder->next;
 | 
						|
  
 | 
						|
  if (iholder->info && iholder->plugin)
 | 
						|
    {
 | 
						|
      g_free (iholder->info);
 | 
						|
      iholder->info = NULL;
 | 
						|
      
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      g_type_plugin_unuse (iholder->plugin);
 | 
						|
      G_WRITE_LOCK (&type_rw_lock);
 | 
						|
      
 | 
						|
      type_data_unref_Wm (iface, FALSE);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* --- type structure creation/destruction --- */
 | 
						|
GTypeInstance*
 | 
						|
g_type_create_instance (GType type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  GTypeInstance *instance;
 | 
						|
  GTypeClass *class;
 | 
						|
  guint i;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  if (!node || !node->is_instantiatable)
 | 
						|
    {
 | 
						|
      g_warning ("cannot create new instance of invalid (non-instantiatable) type `%s'",
 | 
						|
		 type_descriptive_name_U (type));
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  /* G_TYPE_IS_ABSTRACT() is an external call: _U */
 | 
						|
  if (G_TYPE_IS_ABSTRACT (type))
 | 
						|
    {
 | 
						|
      g_warning ("cannot create instance of abstract (non-instantiatable) type `%s'",
 | 
						|
		 type_descriptive_name_U (type));
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  
 | 
						|
  class = g_type_class_ref (type);
 | 
						|
  
 | 
						|
  if (node->data->instance.n_preallocs)
 | 
						|
    {
 | 
						|
      G_WRITE_LOCK (&type_rw_lock);
 | 
						|
      if (!node->data->instance.mem_chunk)
 | 
						|
	node->data->instance.mem_chunk = g_mem_chunk_new (NODE_NAME (node),
 | 
						|
							  node->data->instance.instance_size,
 | 
						|
							  (node->data->instance.instance_size *
 | 
						|
							   node->data->instance.n_preallocs),
 | 
						|
							  G_ALLOC_AND_FREE);
 | 
						|
      instance = g_chunk_new0 (GTypeInstance, node->data->instance.mem_chunk);
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    instance = g_malloc0 (node->data->instance.instance_size);	/* fine without read lock */
 | 
						|
  for (i = node->n_supers; i > 0; i--)
 | 
						|
    {
 | 
						|
      TypeNode *pnode;
 | 
						|
      
 | 
						|
      G_READ_LOCK (&type_rw_lock);
 | 
						|
      pnode = lookup_type_node_L (node->supers[i]);
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      
 | 
						|
      if (pnode->data->instance.instance_init)
 | 
						|
	{
 | 
						|
	  instance->g_class = pnode->data->instance.class;
 | 
						|
	  pnode->data->instance.instance_init (instance, class);
 | 
						|
	}
 | 
						|
    }
 | 
						|
  instance->g_class = class;
 | 
						|
  
 | 
						|
  if (node->data->instance.instance_init)
 | 
						|
    node->data->instance.instance_init (instance, class);
 | 
						|
  
 | 
						|
  return instance;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_free_instance (GTypeInstance *instance)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  GTypeClass *class;
 | 
						|
  
 | 
						|
  g_return_if_fail (instance != NULL && instance->g_class != NULL);
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  class = instance->g_class;
 | 
						|
  node = lookup_type_node_L (class->g_type);
 | 
						|
  if (!node || !node->is_instantiatable || !node->data || node->data->class.class != (gpointer) class)
 | 
						|
    {
 | 
						|
      g_warning ("cannot free instance of invalid (non-instantiatable) type `%s'",
 | 
						|
		 type_descriptive_name_L (class->g_type));
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  /* G_TYPE_IS_ABSTRACT() is an external call: _U */
 | 
						|
  if (G_TYPE_IS_ABSTRACT (NODE_TYPE (node)))
 | 
						|
    {
 | 
						|
      g_warning ("cannot free instance of abstract (non-instantiatable) type `%s'",
 | 
						|
		 NODE_NAME (node));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  
 | 
						|
  instance->g_class = NULL;
 | 
						|
  memset (instance, 0xaa, node->data->instance.instance_size);	/* FIXME: debugging hack */
 | 
						|
  if (node->data->instance.n_preallocs)
 | 
						|
    {
 | 
						|
      G_WRITE_LOCK (&type_rw_lock);
 | 
						|
      g_chunk_free (instance, node->data->instance.mem_chunk);
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    g_free (instance);
 | 
						|
  
 | 
						|
  g_type_class_unref (class);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_propagate_iface_vtable_W (TypeNode       *pnode,
 | 
						|
			       TypeNode       *iface,
 | 
						|
			       GTypeInterface *vtable)
 | 
						|
{
 | 
						|
  IFaceEntry *entry = type_lookup_iface_entry_L (pnode, iface);
 | 
						|
  guint i;
 | 
						|
  
 | 
						|
  entry->vtable = vtable;
 | 
						|
  for (i = 0; i < pnode->n_children; i++)
 | 
						|
    {
 | 
						|
      TypeNode *node = lookup_type_node_L (pnode->children[i]);
 | 
						|
      
 | 
						|
      type_propagate_iface_vtable_W (node, iface, vtable);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_iface_vtable_init_Wm (TypeNode *iface,
 | 
						|
			   TypeNode *node)
 | 
						|
{
 | 
						|
#ifndef G_DISABLE_ASSERT
 | 
						|
  IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
 | 
						|
#endif
 | 
						|
  IFaceHolder *iholder = type_iface_retrive_holder_info_Wm (iface, NODE_TYPE (node));
 | 
						|
  GTypeInterface *vtable;
 | 
						|
  
 | 
						|
  g_assert (iface->data && entry && entry->vtable == NULL && iholder && iholder->info);
 | 
						|
  
 | 
						|
  vtable = g_malloc0 (iface->data->iface.vtable_size);
 | 
						|
  type_propagate_iface_vtable_W (node, iface, vtable);
 | 
						|
  vtable->g_type = NODE_TYPE (iface);
 | 
						|
  vtable->g_instance_type = NODE_TYPE (node);
 | 
						|
  
 | 
						|
  if (iface->data->iface.vtable_init_base || iholder->info->interface_init)
 | 
						|
    {
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      if (iface->data->iface.vtable_init_base)
 | 
						|
	iface->data->iface.vtable_init_base (vtable);
 | 
						|
      if (iholder->info->interface_init)
 | 
						|
	iholder->info->interface_init (vtable, iholder->info->interface_data);
 | 
						|
      G_WRITE_LOCK (&type_rw_lock);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_iface_vtable_finalize_Wm (TypeNode       *iface,
 | 
						|
			       TypeNode       *node,
 | 
						|
			       GTypeInterface *vtable)
 | 
						|
{
 | 
						|
#ifndef G_DISABLE_ASSERT
 | 
						|
  IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
 | 
						|
#endif
 | 
						|
  IFaceHolder *iholder = iface_node_get_holders_L (iface);
 | 
						|
  
 | 
						|
  g_assert (entry && entry->vtable == vtable);
 | 
						|
  
 | 
						|
  while (iholder->instance_type != NODE_TYPE (node))
 | 
						|
    iholder = iholder->next;
 | 
						|
  g_assert (iholder && iholder->info);
 | 
						|
  
 | 
						|
  type_propagate_iface_vtable_W (node, iface, NULL);
 | 
						|
  if (iholder->info->interface_finalize || iface->data->iface.vtable_finalize_base)
 | 
						|
    {
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      if (iholder->info->interface_finalize)
 | 
						|
	iholder->info->interface_finalize (vtable, iholder->info->interface_data);
 | 
						|
      if (iface->data->iface.vtable_finalize_base)
 | 
						|
	iface->data->iface.vtable_finalize_base (vtable);
 | 
						|
      G_WRITE_LOCK (&type_rw_lock);
 | 
						|
    }
 | 
						|
  vtable->g_type = 0;
 | 
						|
  vtable->g_instance_type = 0;
 | 
						|
  g_free (vtable);
 | 
						|
  
 | 
						|
  type_iface_blow_holder_info_Wm (iface, NODE_TYPE (node));
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_class_init_Wm (TypeNode   *node,
 | 
						|
		    GTypeClass *pclass)
 | 
						|
{
 | 
						|
  GSList *slist, *init_slist = NULL;
 | 
						|
  GTypeClass *class;
 | 
						|
  IFaceEntry *entry;
 | 
						|
  TypeNode *bnode;
 | 
						|
  guint i;
 | 
						|
  
 | 
						|
  g_assert (node->is_classed && node->data &&
 | 
						|
	    node->data->class.class_size &&
 | 
						|
	    !node->data->class.class);
 | 
						|
  
 | 
						|
  class = g_malloc0 (node->data->class.class_size);
 | 
						|
  node->data->class.class = class;
 | 
						|
  
 | 
						|
  if (pclass)
 | 
						|
    {
 | 
						|
      TypeNode *pnode = lookup_type_node_L (pclass->g_type);
 | 
						|
      
 | 
						|
      memcpy (class, pclass, pnode->data->class.class_size);
 | 
						|
    }
 | 
						|
  class->g_type = NODE_TYPE (node);
 | 
						|
  
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  /* stack all base class initialization functions, so we
 | 
						|
   * call them in ascending order.
 | 
						|
   */
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  for (bnode = node; bnode; bnode = lookup_type_node_L (NODE_PARENT_TYPE (bnode)))
 | 
						|
    if (bnode->data->class.class_init_base)
 | 
						|
      init_slist = g_slist_prepend (init_slist, (gpointer) bnode->data->class.class_init_base);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  for (slist = init_slist; slist; slist = slist->next)
 | 
						|
    {
 | 
						|
      GBaseInitFunc class_init_base = (GBaseInitFunc) slist->data;
 | 
						|
      
 | 
						|
      class_init_base (class);
 | 
						|
    }
 | 
						|
  g_slist_free (init_slist);
 | 
						|
  
 | 
						|
  if (node->data->class.class_init)
 | 
						|
    node->data->class.class_init (class, (gpointer) node->data->class.class_data);
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  /* ok, we got the class done, now initialize all interfaces */
 | 
						|
  for (entry = NULL, i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
 | 
						|
    if (!CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable)
 | 
						|
      entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
 | 
						|
  while (entry)
 | 
						|
    {
 | 
						|
      type_iface_vtable_init_Wm (lookup_type_node_L (entry->iface_type), node);
 | 
						|
      
 | 
						|
      for (entry = NULL, i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
 | 
						|
	if (!CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable)
 | 
						|
	  entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_data_finalize_class_ifaces_Wm (TypeNode *node)
 | 
						|
{
 | 
						|
  IFaceEntry *entry;
 | 
						|
  guint i;
 | 
						|
  
 | 
						|
  g_assert (node->is_instantiatable && node->data && node->data->class.class && node->data->common.ref_count == 0);
 | 
						|
  
 | 
						|
  g_message ("finalizing interfaces for %sClass `%s'",
 | 
						|
	     type_descriptive_name_L (G_TYPE_FUNDAMENTAL (NODE_TYPE (node))),
 | 
						|
	     type_descriptive_name_L (NODE_TYPE (node)));
 | 
						|
  
 | 
						|
  for (entry = NULL, i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
 | 
						|
    if (CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable &&
 | 
						|
	CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable->g_instance_type == NODE_TYPE (node))
 | 
						|
      entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
 | 
						|
  while (entry)
 | 
						|
    {
 | 
						|
      type_iface_vtable_finalize_Wm (lookup_type_node_L (entry->iface_type), node, entry->vtable);
 | 
						|
      
 | 
						|
      for (entry = NULL, i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
 | 
						|
	if (CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable &&
 | 
						|
	    CLASSED_NODE_IFACES_ENTRIES (node)[i].vtable->g_instance_type == NODE_TYPE (node))
 | 
						|
	  entry = CLASSED_NODE_IFACES_ENTRIES (node) + i;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_data_finalize_class_U (TypeNode  *node,
 | 
						|
			    ClassData *cdata)
 | 
						|
{
 | 
						|
  GTypeClass *class = cdata->class;
 | 
						|
  TypeNode *bnode;
 | 
						|
  
 | 
						|
  g_assert (cdata->class && cdata->common.ref_count == 0);
 | 
						|
  
 | 
						|
  if (cdata->class_finalize)
 | 
						|
    cdata->class_finalize (class, (gpointer) cdata->class_data);
 | 
						|
  
 | 
						|
  /* call all base class destruction functions in descending order
 | 
						|
   */
 | 
						|
  if (cdata->class_finalize_base)
 | 
						|
    cdata->class_finalize_base (class);
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  for (bnode = lookup_type_node_L (NODE_PARENT_TYPE (node)); bnode; bnode = lookup_type_node_L (NODE_PARENT_TYPE (bnode)))
 | 
						|
    if (bnode->data->class.class_finalize_base)
 | 
						|
      {
 | 
						|
	G_READ_UNLOCK (&type_rw_lock);
 | 
						|
	bnode->data->class.class_finalize_base (class);
 | 
						|
	G_READ_LOCK (&type_rw_lock);
 | 
						|
      }
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  class->g_type = 0;
 | 
						|
  g_free (cdata->class);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_data_last_unref_Wm (GType    type,
 | 
						|
			 gboolean uncached)
 | 
						|
{
 | 
						|
  TypeNode *node = lookup_type_node_L (type);
 | 
						|
  
 | 
						|
  g_return_if_fail (node != NULL && node->plugin != NULL);
 | 
						|
  
 | 
						|
  if (!node->data || node->data->common.ref_count == 0)
 | 
						|
    {
 | 
						|
      g_warning ("cannot drop last reference to unreferenced type `%s'",
 | 
						|
		 type_descriptive_name_U (type));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (node->is_classed && node->data && node->data->class.class && static_n_class_cache_funcs)
 | 
						|
    {
 | 
						|
      guint i;
 | 
						|
      
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      G_READ_LOCK (&type_rw_lock);
 | 
						|
      for (i = 0; i < static_n_class_cache_funcs; i++)
 | 
						|
	{
 | 
						|
	  GTypeClassCacheFunc cache_func = static_class_cache_funcs[i].cache_func;
 | 
						|
	  gpointer cache_data = static_class_cache_funcs[i].cache_data;
 | 
						|
	  gboolean need_break;
 | 
						|
	  
 | 
						|
	  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
	  need_break = cache_func (cache_data, node->data->class.class);
 | 
						|
	  G_READ_LOCK (&type_rw_lock);
 | 
						|
	  if (!node->data || node->data->common.ref_count == 0)
 | 
						|
	    INVALID_RECURSION ("GType class cache function ", cache_func, NODE_NAME (node));
 | 
						|
	  if (need_break)
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      G_WRITE_LOCK (&type_rw_lock);
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (node->data->common.ref_count > 1)	/* may have been re-referenced meanwhile */
 | 
						|
    node->data->common.ref_count -= 1;
 | 
						|
  else
 | 
						|
    {
 | 
						|
      GType ptype = NODE_PARENT_TYPE (node);
 | 
						|
      TypeData *tdata;
 | 
						|
      
 | 
						|
      node->data->common.ref_count = 0;
 | 
						|
      
 | 
						|
      if (node->is_instantiatable && node->data->instance.mem_chunk)
 | 
						|
	{
 | 
						|
	  g_mem_chunk_destroy (node->data->instance.mem_chunk);
 | 
						|
	  node->data->instance.mem_chunk = NULL;
 | 
						|
	}
 | 
						|
      
 | 
						|
      tdata = node->data;
 | 
						|
      if (node->is_classed && tdata->class.class)
 | 
						|
	{
 | 
						|
	  if (CLASSED_NODE_N_IFACES (node))
 | 
						|
	    type_data_finalize_class_ifaces_Wm (node);
 | 
						|
	  node->data = NULL;
 | 
						|
	  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
	  type_data_finalize_class_U (node, &tdata->class);
 | 
						|
	  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
	}
 | 
						|
      else
 | 
						|
	node->data = NULL;
 | 
						|
 | 
						|
      /* freeing tdata->common.value_table and its contents is taking care of
 | 
						|
       * by allocating it in one chunk with tdata
 | 
						|
       */
 | 
						|
      g_free (tdata);
 | 
						|
      
 | 
						|
      if (ptype)
 | 
						|
	type_data_unref_Wm (lookup_type_node_L (ptype), FALSE);
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      g_type_plugin_unuse (node->plugin);
 | 
						|
      G_WRITE_LOCK (&type_rw_lock);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_add_class_cache_func (gpointer            cache_data,
 | 
						|
			     GTypeClassCacheFunc cache_func)
 | 
						|
{
 | 
						|
  guint i;
 | 
						|
  
 | 
						|
  g_return_if_fail (cache_func != NULL);
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  i = static_n_class_cache_funcs++;
 | 
						|
  static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs);
 | 
						|
  static_class_cache_funcs[i].cache_data = cache_data;
 | 
						|
  static_class_cache_funcs[i].cache_func = cache_func;
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_remove_class_cache_func (gpointer            cache_data,
 | 
						|
				GTypeClassCacheFunc cache_func)
 | 
						|
{
 | 
						|
  gboolean found_it = FALSE;
 | 
						|
  guint i;
 | 
						|
  
 | 
						|
  g_return_if_fail (cache_func != NULL);
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  for (i = 0; i < static_n_class_cache_funcs; i++)
 | 
						|
    if (static_class_cache_funcs[i].cache_data == cache_data &&
 | 
						|
	static_class_cache_funcs[i].cache_func == cache_func)
 | 
						|
      {
 | 
						|
	static_n_class_cache_funcs--;
 | 
						|
	g_memmove (static_class_cache_funcs + i,
 | 
						|
		   static_class_cache_funcs + i + 1,
 | 
						|
		   sizeof (static_class_cache_funcs[0]) * (static_n_class_cache_funcs - i));
 | 
						|
	static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs);
 | 
						|
	found_it = TRUE;
 | 
						|
	break;
 | 
						|
      }
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  if (!found_it)
 | 
						|
    g_warning (G_STRLOC ": cannot remove unregistered class cache func %p with data %p",
 | 
						|
	       cache_func, cache_data);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* --- type registration --- */
 | 
						|
GType
 | 
						|
g_type_register_fundamental (GType                       type_id,
 | 
						|
			     const gchar                *type_name,
 | 
						|
			     const GTypeInfo            *info,
 | 
						|
			     const GTypeFundamentalInfo *finfo,
 | 
						|
			     GTypeFlags			 flags)
 | 
						|
{
 | 
						|
  GTypeFundamentalInfo *node_finfo;
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  g_return_val_if_uninitialized (static_last_fundamental_id, g_type_init, 0);
 | 
						|
  g_return_val_if_fail (type_id > 0, 0);
 | 
						|
  g_return_val_if_fail (type_name != NULL, 0);
 | 
						|
  g_return_val_if_fail (info != NULL, 0);
 | 
						|
  g_return_val_if_fail (finfo != NULL, 0);
 | 
						|
  
 | 
						|
  if (!check_type_name_U (type_name))
 | 
						|
    return 0;
 | 
						|
  if (G_TYPE_FUNDAMENTAL (type_id) != type_id)
 | 
						|
    {
 | 
						|
      g_warning ("cannot register fundamental type `%s' with non-fundamental id (%u)",
 | 
						|
		 type_name,
 | 
						|
		 type_id);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  if ((finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) &&
 | 
						|
      !(finfo->type_flags & G_TYPE_FLAG_CLASSED))
 | 
						|
    {
 | 
						|
      g_warning ("cannot register instantiatable fundamental type `%s' as non-classed",
 | 
						|
		 type_name);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  if (lookup_type_node_L (type_id))
 | 
						|
    {
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      g_warning ("cannot register existing fundamental type `%s' (as `%s')",
 | 
						|
		 type_descriptive_name_U (type_id),
 | 
						|
		 type_name);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  
 | 
						|
  node = type_node_fundamental_new_W (type_id, type_name, finfo->type_flags);
 | 
						|
  node_finfo = type_node_fundamental_info_L (node);
 | 
						|
  type_add_flags_W (node, flags);
 | 
						|
  
 | 
						|
  if (check_type_info_L (NULL, G_TYPE_FUNDAMENTAL (NODE_TYPE (node)), type_name, info))
 | 
						|
    type_data_make_W (node, info,
 | 
						|
		      check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return NODE_TYPE (node);
 | 
						|
}
 | 
						|
 | 
						|
GType
 | 
						|
g_type_register_static (GType            parent_type,
 | 
						|
			const gchar     *type_name,
 | 
						|
			const GTypeInfo *info,
 | 
						|
			GTypeFlags	 flags)
 | 
						|
{
 | 
						|
  TypeNode *pnode, *node;
 | 
						|
  GType type = 0;
 | 
						|
  
 | 
						|
  g_return_val_if_uninitialized (static_last_fundamental_id, g_type_init, 0);
 | 
						|
  g_return_val_if_fail (parent_type > 0, 0);
 | 
						|
  g_return_val_if_fail (type_name != NULL, 0);
 | 
						|
  g_return_val_if_fail (info != NULL, 0);
 | 
						|
  
 | 
						|
  if (!check_type_name_U (type_name) ||
 | 
						|
      !check_derivation_U (parent_type, type_name))
 | 
						|
    return 0;
 | 
						|
  if (info->class_finalize)
 | 
						|
    {
 | 
						|
      g_warning ("class finalizer specified for static type `%s'",
 | 
						|
		 type_name);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  pnode = lookup_type_node_L (parent_type);
 | 
						|
  type_data_ref_Wm (pnode);
 | 
						|
  if (check_type_info_L (pnode, G_TYPE_FUNDAMENTAL (parent_type), type_name, info))
 | 
						|
    {
 | 
						|
      node = type_node_new_W (pnode, type_name, NULL);
 | 
						|
      type_add_flags_W (node, flags);
 | 
						|
      type = NODE_TYPE (node);
 | 
						|
      type_data_make_W (node, info,
 | 
						|
			check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
 | 
						|
    }
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
GType
 | 
						|
g_type_register_dynamic (GType        parent_type,
 | 
						|
			 const gchar *type_name,
 | 
						|
			 GTypePlugin *plugin,
 | 
						|
			 GTypeFlags   flags)
 | 
						|
{
 | 
						|
  TypeNode *pnode, *node;
 | 
						|
  GType type;
 | 
						|
  
 | 
						|
  g_return_val_if_uninitialized (static_last_fundamental_id, g_type_init, 0);
 | 
						|
  g_return_val_if_fail (parent_type > 0, 0);
 | 
						|
  g_return_val_if_fail (type_name != NULL, 0);
 | 
						|
  g_return_val_if_fail (plugin != NULL, 0);
 | 
						|
  
 | 
						|
  if (!check_type_name_U (type_name) ||
 | 
						|
      !check_derivation_U (parent_type, type_name) ||
 | 
						|
      !check_plugin_U (plugin, TRUE, FALSE, type_name))
 | 
						|
    return 0;
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  pnode = lookup_type_node_L (parent_type);
 | 
						|
  node = type_node_new_W (pnode, type_name, plugin);
 | 
						|
  type_add_flags_W (node, flags);
 | 
						|
  type = NODE_TYPE (node);
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_add_interface_static (GType                 instance_type,
 | 
						|
			     GType                 interface_type,
 | 
						|
			     const GInterfaceInfo *info)
 | 
						|
{
 | 
						|
  /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */
 | 
						|
  g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
 | 
						|
  g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  if (check_add_interface_L (instance_type, interface_type))
 | 
						|
    {
 | 
						|
      TypeNode *node = lookup_type_node_L (instance_type);
 | 
						|
      TypeNode *iface = lookup_type_node_L (interface_type);
 | 
						|
      
 | 
						|
      if (check_interface_info_L (iface, NODE_TYPE (node), info))
 | 
						|
	type_add_interface_W (node, iface, info, NULL);
 | 
						|
    }
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_add_interface_dynamic (GType        instance_type,
 | 
						|
			      GType        interface_type,
 | 
						|
			      GTypePlugin *plugin)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */
 | 
						|
  g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type));
 | 
						|
  g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE);
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (instance_type);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  if (!check_plugin_U (plugin, FALSE, TRUE, NODE_NAME (node)))
 | 
						|
    return;
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  if (check_add_interface_L (instance_type, interface_type))
 | 
						|
    {
 | 
						|
      TypeNode *iface = lookup_type_node_L (interface_type);
 | 
						|
      
 | 
						|
      type_add_interface_W (node, iface, NULL, plugin);
 | 
						|
    }
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* --- public API functions --- */
 | 
						|
gpointer
 | 
						|
g_type_class_ref (GType type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  /* optimize for common code path
 | 
						|
   */
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node && node->is_classed && node->data &&
 | 
						|
      node->data->class.class && node->data->common.ref_count > 0)
 | 
						|
    {
 | 
						|
      type_data_ref_Wm (node);
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      
 | 
						|
      return node->data->class.class;
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (!node || !node->is_classed ||
 | 
						|
      (node->data && node->data->common.ref_count < 1))
 | 
						|
    {
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      g_warning ("cannot retrive class for invalid (unclassed) type `%s'",
 | 
						|
		 type_descriptive_name_U (type));
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  
 | 
						|
  type_data_ref_Wm (node);
 | 
						|
  
 | 
						|
  if (!node->data->class.class)
 | 
						|
    {
 | 
						|
      GType ptype = NODE_PARENT_TYPE (node);
 | 
						|
      GTypeClass *pclass = NULL;
 | 
						|
      
 | 
						|
      if (ptype)
 | 
						|
	{
 | 
						|
	  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
	  pclass = g_type_class_ref (ptype);
 | 
						|
	  if (node->data->class.class)
 | 
						|
            INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
 | 
						|
	  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
	}
 | 
						|
      
 | 
						|
      type_class_init_Wm (node, pclass);
 | 
						|
    }
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return node->data->class.class;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_class_unref (gpointer g_class)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  GTypeClass *class = g_class;
 | 
						|
  
 | 
						|
  g_return_if_fail (g_class != NULL);
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (class->g_type);
 | 
						|
  if (node && node->is_classed && node->data &&
 | 
						|
      node->data->class.class == class && node->data->common.ref_count > 0)
 | 
						|
    type_data_unref_Wm (node, FALSE);
 | 
						|
  else
 | 
						|
    g_warning ("cannot unreference class of invalid (unclassed) type `%s'",
 | 
						|
	       type_descriptive_name_L (class->g_type));
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_class_unref_uncached (gpointer g_class)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  GTypeClass *class = g_class;
 | 
						|
  
 | 
						|
  g_return_if_fail (g_class != NULL);
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (class->g_type);
 | 
						|
  if (node && node->is_classed && node->data &&
 | 
						|
      node->data->class.class == class && node->data->common.ref_count > 0)
 | 
						|
    type_data_unref_Wm (node, TRUE);
 | 
						|
  else
 | 
						|
    g_warning ("cannot unreference class of invalid (unclassed) type `%s'",
 | 
						|
	       type_descriptive_name_L (class->g_type));
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
}
 | 
						|
 | 
						|
gpointer
 | 
						|
g_type_class_peek (GType type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  gpointer class;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node && node->is_classed && node->data && node->data->class.class) /* common.ref_count _may_ be 0 */
 | 
						|
    class = node->data->class.class;
 | 
						|
  else
 | 
						|
    class = NULL;
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return class;
 | 
						|
}
 | 
						|
 | 
						|
gpointer
 | 
						|
g_type_class_peek_parent (gpointer g_class)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  gpointer class;
 | 
						|
  
 | 
						|
  g_return_val_if_fail (g_class != NULL, NULL);
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (G_TYPE_FROM_CLASS (g_class));
 | 
						|
  if (node && node->is_classed && node->data && NODE_PARENT_TYPE (node))
 | 
						|
    {
 | 
						|
      node = lookup_type_node_L (NODE_PARENT_TYPE (node));
 | 
						|
      class = node->data->class.class;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    class = NULL;
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return class;
 | 
						|
}
 | 
						|
 | 
						|
gpointer
 | 
						|
g_type_interface_peek (gpointer instance_class,
 | 
						|
		       GType    iface_type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  TypeNode *iface;
 | 
						|
  gpointer vtable = NULL;
 | 
						|
  GTypeClass *class = instance_class;
 | 
						|
  
 | 
						|
  g_return_val_if_fail (instance_class != NULL, NULL);
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (class->g_type);
 | 
						|
  iface = lookup_type_node_L (iface_type);
 | 
						|
  if (node && node->is_instantiatable && iface)
 | 
						|
    {
 | 
						|
      IFaceEntry *entry = type_lookup_iface_entry_L (node, iface);
 | 
						|
      
 | 
						|
      if (entry && entry->vtable)
 | 
						|
	vtable = entry->vtable;
 | 
						|
    }
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return vtable;
 | 
						|
}
 | 
						|
 | 
						|
G_CONST_RETURN gchar*
 | 
						|
g_type_name (GType type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  g_return_val_if_uninitialized (static_last_fundamental_id, g_type_init, NULL);
 | 
						|
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return node ? NODE_NAME (node) : NULL;
 | 
						|
}
 | 
						|
 | 
						|
GQuark
 | 
						|
g_type_qname (GType type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return node ? node->qname : 0;
 | 
						|
}
 | 
						|
 | 
						|
GType
 | 
						|
g_type_from_name (const gchar *name)
 | 
						|
{
 | 
						|
  GType type = 0;
 | 
						|
  GQuark quark;
 | 
						|
  
 | 
						|
  g_return_val_if_fail (name != NULL, 0);
 | 
						|
  
 | 
						|
  quark = g_quark_try_string (name);
 | 
						|
  if (quark)
 | 
						|
    {
 | 
						|
      G_READ_LOCK (&type_rw_lock);
 | 
						|
      type = GPOINTER_TO_UINT (g_hash_table_lookup (static_type_nodes_ht, GUINT_TO_POINTER (quark)));
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
    }
 | 
						|
  
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
GType
 | 
						|
g_type_parent (GType type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return node ? NODE_PARENT_TYPE (node) : 0;
 | 
						|
}
 | 
						|
 | 
						|
guint
 | 
						|
g_type_depth (GType type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return node ? node->n_supers + 1 : 0;
 | 
						|
}
 | 
						|
 | 
						|
GType
 | 
						|
g_type_next_base (GType type,
 | 
						|
		  GType base_type)
 | 
						|
{
 | 
						|
  GType atype = 0;
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node)
 | 
						|
    {
 | 
						|
      TypeNode *base_node = lookup_type_node_L (base_type);
 | 
						|
      
 | 
						|
      if (base_node && base_node->n_supers < node->n_supers)
 | 
						|
	{
 | 
						|
	  guint n = node->n_supers - base_node->n_supers;
 | 
						|
	  
 | 
						|
	  if (node->supers[n] == base_type)
 | 
						|
	    atype = node->supers[n - 1];
 | 
						|
	}
 | 
						|
    }
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return atype;
 | 
						|
}
 | 
						|
 | 
						|
static inline gboolean
 | 
						|
type_node_is_a_L (TypeNode *node,
 | 
						|
		  TypeNode *iface_node,
 | 
						|
		  /*        support_inheritance */
 | 
						|
		  gboolean  support_interfaces,
 | 
						|
		  gboolean  support_prerequisites)
 | 
						|
{
 | 
						|
  if (support_interfaces &&
 | 
						|
      node->is_instantiatable && NODE_IS_IFACE (iface_node) &&
 | 
						|
      type_lookup_iface_entry_L (node, iface_node) != NULL)
 | 
						|
    return TRUE;
 | 
						|
  else if (/* support_inheritance && */
 | 
						|
	   iface_node->n_supers <= node->n_supers &&
 | 
						|
	   node->supers[node->n_supers - iface_node->n_supers] == NODE_TYPE (iface_node))
 | 
						|
    return TRUE;
 | 
						|
  else if (support_prerequisites &&
 | 
						|
	   NODE_IS_IFACE (node) &&
 | 
						|
	   type_lookup_prerequisite_L (node, NODE_TYPE (iface_node)))
 | 
						|
    return TRUE;
 | 
						|
  else
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
gboolean
 | 
						|
g_type_is_a (GType type,
 | 
						|
	     GType iface_type)
 | 
						|
{
 | 
						|
  TypeNode *node, *iface_node;
 | 
						|
  gboolean is_a;
 | 
						|
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  iface_node = lookup_type_node_L (iface_type);
 | 
						|
  is_a = node && iface_node && type_node_is_a_L (node, iface_node, TRUE, TRUE);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
 | 
						|
  return is_a;
 | 
						|
}
 | 
						|
 | 
						|
guint
 | 
						|
g_type_fundamental_branch_last (GType type)
 | 
						|
{
 | 
						|
  GType ftype = G_TYPE_FUNDAMENTAL (type);
 | 
						|
  guint last_type;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  last_type = ftype < static_last_fundamental_id ? static_branch_seqnos[ftype] : 0;
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return last_type;
 | 
						|
}
 | 
						|
 | 
						|
GType* /* free result */
 | 
						|
g_type_children (GType  type,
 | 
						|
		 guint *n_children)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node)
 | 
						|
    {
 | 
						|
      GType *children = g_new (GType, node->n_children + 1);
 | 
						|
      
 | 
						|
      memcpy (children, node->children, sizeof (GType) * node->n_children);
 | 
						|
      children[node->n_children] = 0;
 | 
						|
      
 | 
						|
      if (n_children)
 | 
						|
	*n_children = node->n_children;
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      
 | 
						|
      return children;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      if (n_children)
 | 
						|
	*n_children = 0;
 | 
						|
      
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
GType* /* free result */
 | 
						|
g_type_interfaces (GType  type,
 | 
						|
		   guint *n_interfaces)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node && node->is_instantiatable)
 | 
						|
    {
 | 
						|
      GType *ifaces = g_new (GType, CLASSED_NODE_N_IFACES (node) + 1);
 | 
						|
      guint i;
 | 
						|
      
 | 
						|
      for (i = 0; i < CLASSED_NODE_N_IFACES (node); i++)
 | 
						|
	ifaces[i] = CLASSED_NODE_IFACES_ENTRIES (node)[i].iface_type;
 | 
						|
      ifaces[i] = 0;
 | 
						|
      
 | 
						|
      if (n_interfaces)
 | 
						|
	*n_interfaces = CLASSED_NODE_N_IFACES (node);
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      
 | 
						|
      return ifaces;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      if (n_interfaces)
 | 
						|
	*n_interfaces = 0;
 | 
						|
      
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
typedef struct _QData QData;
 | 
						|
struct _GData
 | 
						|
{
 | 
						|
  guint  n_qdatas;
 | 
						|
  QData *qdatas;
 | 
						|
};
 | 
						|
struct _QData
 | 
						|
{
 | 
						|
  GQuark   quark;
 | 
						|
  gpointer data;
 | 
						|
};
 | 
						|
 | 
						|
static inline gpointer
 | 
						|
type_get_qdata_L (TypeNode *node,
 | 
						|
		  GQuark    quark)
 | 
						|
{
 | 
						|
  GData *gdata = node->global_gdata;
 | 
						|
  
 | 
						|
  if (quark && gdata && gdata->n_qdatas)
 | 
						|
    {
 | 
						|
      QData *qdatas = gdata->qdatas - 1;
 | 
						|
      guint n_qdatas = gdata->n_qdatas;
 | 
						|
      
 | 
						|
      do
 | 
						|
	{
 | 
						|
	  guint i;
 | 
						|
	  QData *check;
 | 
						|
	  
 | 
						|
	  i = (n_qdatas + 1) / 2;
 | 
						|
	  check = qdatas + i;
 | 
						|
	  if (quark == check->quark)
 | 
						|
	    return check->data;
 | 
						|
	  else if (quark > check->quark)
 | 
						|
	    {
 | 
						|
	      n_qdatas -= i;
 | 
						|
	      qdatas = check;
 | 
						|
	    }
 | 
						|
	  else /* if (quark < check->quark) */
 | 
						|
	    n_qdatas = i - 1;
 | 
						|
	}
 | 
						|
      while (n_qdatas);
 | 
						|
    }
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
gpointer
 | 
						|
g_type_get_qdata (GType  type,
 | 
						|
		  GQuark quark)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  gpointer data;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node)
 | 
						|
    {
 | 
						|
      data = type_get_qdata_L (node, quark);
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      g_return_val_if_fail (node != NULL, NULL);
 | 
						|
      data = NULL;
 | 
						|
    }
 | 
						|
  return data;
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
type_set_qdata_W (TypeNode *node,
 | 
						|
		  GQuark    quark,
 | 
						|
		  gpointer  data)
 | 
						|
{
 | 
						|
  GData *gdata;
 | 
						|
  QData *qdata;
 | 
						|
  guint i;
 | 
						|
  
 | 
						|
  /* setup qdata list if necessary */
 | 
						|
  if (!node->global_gdata)
 | 
						|
    node->global_gdata = g_new0 (GData, 1);
 | 
						|
  gdata = node->global_gdata;
 | 
						|
  
 | 
						|
  /* try resetting old data */
 | 
						|
  qdata = gdata->qdatas;
 | 
						|
  for (i = 0; i < gdata->n_qdatas; i++)
 | 
						|
    if (qdata[i].quark == quark)
 | 
						|
      {
 | 
						|
	qdata[i].data = data;
 | 
						|
	return;
 | 
						|
      }
 | 
						|
  
 | 
						|
  /* add new entry */
 | 
						|
  gdata->n_qdatas++;
 | 
						|
  gdata->qdatas = g_renew (QData, gdata->qdatas, gdata->n_qdatas);
 | 
						|
  qdata = gdata->qdatas;
 | 
						|
  for (i = 0; i < gdata->n_qdatas - 1; i++)
 | 
						|
    if (qdata[i].quark > quark)
 | 
						|
      break;
 | 
						|
  g_memmove (qdata + i + 1, qdata + i, sizeof (qdata[0]) * (gdata->n_qdatas - i - 1));
 | 
						|
  qdata[i].quark = quark;
 | 
						|
  qdata[i].data = data;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_set_qdata (GType    type,
 | 
						|
		  GQuark   quark,
 | 
						|
		  gpointer data)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  g_return_if_fail (quark != 0);
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node)
 | 
						|
    {
 | 
						|
      type_set_qdata_W (node, quark, data);
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      g_return_if_fail (node != NULL);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
type_add_flags_W (TypeNode  *node,
 | 
						|
		  GTypeFlags flags)
 | 
						|
{
 | 
						|
  guint dflags;
 | 
						|
  
 | 
						|
  g_return_if_fail ((flags & ~TYPE_FLAG_MASK) == 0);
 | 
						|
  g_return_if_fail (node != NULL);
 | 
						|
  
 | 
						|
  if ((flags & TYPE_FLAG_MASK) && node->is_classed && node->data && node->data->class.class)
 | 
						|
    g_warning ("tagging type `%s' as abstract after class initialization", NODE_NAME (node));
 | 
						|
  dflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
 | 
						|
  dflags |= flags;
 | 
						|
  type_set_qdata_W (node, static_quark_type_flags, GUINT_TO_POINTER (dflags));
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
g_type_query (GType       type,
 | 
						|
	      GTypeQuery *query)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
 | 
						|
  g_return_if_fail (query != NULL);
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node && node->is_classed && !node->plugin && node->data)
 | 
						|
    {
 | 
						|
      /* type is classed and static, probably even instantiatable */
 | 
						|
 | 
						|
      query->type = NODE_TYPE (node);
 | 
						|
      query->type_name = NODE_NAME (node);
 | 
						|
      query->class_size = node->data->class.class_size;
 | 
						|
      query->instance_size = node->is_instantiatable ? node->data->instance.instance_size : 0;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      /* node is not static and classed, won't allow query */
 | 
						|
      query->type = 0;
 | 
						|
    }
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* --- implementation details --- */
 | 
						|
gboolean
 | 
						|
g_type_check_flags (GType type,
 | 
						|
		    guint flags)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  gboolean result = FALSE;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node)
 | 
						|
    {
 | 
						|
      guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK;
 | 
						|
      guint tflags = flags & TYPE_FLAG_MASK;
 | 
						|
      
 | 
						|
      if (fflags)
 | 
						|
	{
 | 
						|
	  GTypeFundamentalInfo *finfo = type_node_fundamental_info_L (node);
 | 
						|
	  
 | 
						|
	  fflags = (finfo->type_flags & fflags) == fflags;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	fflags = TRUE;
 | 
						|
      
 | 
						|
      if (tflags)
 | 
						|
	tflags = (tflags & GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags))) == tflags;
 | 
						|
      else
 | 
						|
	tflags = TRUE;
 | 
						|
      
 | 
						|
      result = tflags && fflags;
 | 
						|
    }
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
GTypePlugin*
 | 
						|
g_type_get_plugin (GType type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return node ? node->plugin : NULL;
 | 
						|
}
 | 
						|
 | 
						|
GTypePlugin*
 | 
						|
g_type_interface_get_plugin (GType instance_type,
 | 
						|
			     GType interface_type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  TypeNode *iface;
 | 
						|
  
 | 
						|
  g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL);
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (instance_type);  
 | 
						|
  iface = lookup_type_node_L (interface_type);
 | 
						|
  if (node && iface)
 | 
						|
    {
 | 
						|
      IFaceHolder *iholder = iface_node_get_holders_L (iface);
 | 
						|
      
 | 
						|
      while (iholder && iholder->instance_type != instance_type)
 | 
						|
	iholder = iholder->next;
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      
 | 
						|
      if (iholder)
 | 
						|
	return iholder->plugin;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  g_return_val_if_fail (node == NULL, NULL);
 | 
						|
  g_return_val_if_fail (iface == NULL, NULL);
 | 
						|
  
 | 
						|
  g_warning (G_STRLOC ": attempt to look up plugin for invalid instance/interface type pair.");
 | 
						|
  
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
GType
 | 
						|
g_type_fundamental_last (void)
 | 
						|
{
 | 
						|
  GType type;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  type = static_last_fundamental_id;
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
gboolean
 | 
						|
g_type_instance_is_a (GTypeInstance *type_instance,
 | 
						|
		      GType          iface_type)
 | 
						|
{
 | 
						|
  TypeNode *node, *iface;
 | 
						|
  gboolean check;
 | 
						|
 | 
						|
  if (!type_instance || !type_instance->g_class)
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type_instance->g_class->g_type);
 | 
						|
  iface = lookup_type_node_L (iface_type);
 | 
						|
  check = node && node->is_instantiatable && iface && type_node_is_a_L (node, iface, TRUE, FALSE);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
 | 
						|
  return check;
 | 
						|
}
 | 
						|
 | 
						|
gboolean
 | 
						|
g_type_class_is_a (GTypeClass *type_class,
 | 
						|
		   GType       is_a_type)
 | 
						|
{
 | 
						|
  TypeNode *node, *iface;
 | 
						|
  gboolean check;
 | 
						|
 | 
						|
  if (!type_class)
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
  node = lookup_type_node_L (type_class->g_type);
 | 
						|
  iface = lookup_type_node_L (is_a_type);
 | 
						|
  check = node && node->is_classed && iface && type_node_is_a_L (node, iface, FALSE, FALSE);
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
 | 
						|
  return check;
 | 
						|
}
 | 
						|
 | 
						|
GTypeInstance*
 | 
						|
g_type_check_instance_cast (GTypeInstance *type_instance,
 | 
						|
			    GType          iface_type)
 | 
						|
{
 | 
						|
  if (type_instance)
 | 
						|
    {
 | 
						|
      if (type_instance->g_class)
 | 
						|
	{
 | 
						|
	  TypeNode *node, *iface;
 | 
						|
	  gboolean is_instantiatable, check;
 | 
						|
 | 
						|
	  G_READ_LOCK (&type_rw_lock);
 | 
						|
	  node = lookup_type_node_L (type_instance->g_class->g_type);
 | 
						|
	  is_instantiatable = node && node->is_instantiatable;
 | 
						|
	  iface = lookup_type_node_L (iface_type);
 | 
						|
	  check = is_instantiatable && iface && type_node_is_a_L (node, iface, TRUE, FALSE);
 | 
						|
	  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
	  if (check)
 | 
						|
	    return type_instance;
 | 
						|
 | 
						|
	  if (is_instantiatable)
 | 
						|
	    g_warning ("invalid cast from `%s' to `%s'",
 | 
						|
		       type_descriptive_name_U (type_instance->g_class->g_type),
 | 
						|
		       type_descriptive_name_U (iface_type));
 | 
						|
	  else
 | 
						|
	    g_warning ("invalid uninstantiatable type `%s' in cast to `%s'",
 | 
						|
		       type_descriptive_name_U (type_instance->g_class->g_type),
 | 
						|
		       type_descriptive_name_U (iface_type));
 | 
						|
	}
 | 
						|
      else
 | 
						|
	g_warning ("invalid unclassed pointer in cast to `%s'",
 | 
						|
		   type_descriptive_name_U (iface_type));
 | 
						|
    }
 | 
						|
  else
 | 
						|
    g_warning ("invalid cast from (NULL) pointer to `%s'",
 | 
						|
	       type_descriptive_name_U (iface_type));
 | 
						|
  
 | 
						|
  return type_instance;
 | 
						|
}
 | 
						|
 | 
						|
GTypeClass*
 | 
						|
g_type_check_class_cast (GTypeClass *type_class,
 | 
						|
			 GType       is_a_type)
 | 
						|
{
 | 
						|
  if (type_class)
 | 
						|
    {
 | 
						|
      TypeNode *node, *iface;
 | 
						|
      gboolean is_classed, check;
 | 
						|
      
 | 
						|
      G_READ_LOCK (&type_rw_lock);
 | 
						|
      node = lookup_type_node_L (type_class->g_type);
 | 
						|
      is_classed = node && node->is_classed;
 | 
						|
      iface = lookup_type_node_L (is_a_type);
 | 
						|
      check = is_classed && iface && type_node_is_a_L (node, iface, FALSE, FALSE);
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      if (check)
 | 
						|
	return type_class;
 | 
						|
 | 
						|
      if (is_classed)
 | 
						|
	g_warning ("invalid class cast from `%s' to `%s'",
 | 
						|
		   type_descriptive_name_U (type_class->g_type),
 | 
						|
		   type_descriptive_name_U (is_a_type));
 | 
						|
      else
 | 
						|
	g_warning ("invalid unclassed type `%s' in class cast to `%s'",
 | 
						|
		   type_descriptive_name_U (type_class->g_type),
 | 
						|
		   type_descriptive_name_U (is_a_type));
 | 
						|
    }
 | 
						|
  else
 | 
						|
    g_warning ("invalid class cast from (NULL) pointer to `%s'",
 | 
						|
	       type_descriptive_name_U (is_a_type));
 | 
						|
  return type_class;
 | 
						|
}
 | 
						|
 | 
						|
gboolean
 | 
						|
g_type_check_instance (GTypeInstance *type_instance)
 | 
						|
{
 | 
						|
  /* this function is just here to make the signal system
 | 
						|
   * conveniently elaborated on instance checks
 | 
						|
   */
 | 
						|
  if (type_instance)
 | 
						|
    {
 | 
						|
      if (type_instance->g_class)
 | 
						|
	{
 | 
						|
	  TypeNode *node;
 | 
						|
	  gboolean is_instantiatable;
 | 
						|
	  
 | 
						|
	  G_READ_LOCK (&type_rw_lock);
 | 
						|
	  node = lookup_type_node_L (type_instance->g_class->g_type);
 | 
						|
	  is_instantiatable = node && node->is_instantiatable;
 | 
						|
	  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
	  if (is_instantiatable)
 | 
						|
	    return TRUE;
 | 
						|
 | 
						|
	  g_warning ("instance of invalid non-instantiatable type `%s'",
 | 
						|
		     type_descriptive_name_U (type_instance->g_class->g_type));
 | 
						|
	}
 | 
						|
      else
 | 
						|
	g_warning ("instance with invalid (NULL) class pointer");
 | 
						|
    }
 | 
						|
  else
 | 
						|
    g_warning ("invalid (NULL) pointer instance");
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static inline gboolean
 | 
						|
type_check_is_value_type_U (GType type)
 | 
						|
{
 | 
						|
  GTypeFlags tflags = G_TYPE_FLAG_VALUE_ABSTRACT;
 | 
						|
  TypeNode *node;
 | 
						|
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
 restart_check:
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (node)
 | 
						|
    {
 | 
						|
      if (node->data && node->data->common.ref_count > 0 &&
 | 
						|
	  node->data->common.value_table->value_init)
 | 
						|
	tflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
 | 
						|
      else if (NODE_IS_IFACE (node))
 | 
						|
	{
 | 
						|
	  guint i;
 | 
						|
 | 
						|
	  for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
 | 
						|
	    {
 | 
						|
	      GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
 | 
						|
	      TypeNode *prnode = lookup_type_node_L (prtype);
 | 
						|
 | 
						|
	      if (prnode->is_instantiatable)
 | 
						|
		{
 | 
						|
		  type = prtype;
 | 
						|
		  goto restart_check;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
 | 
						|
  return !(tflags & G_TYPE_FLAG_VALUE_ABSTRACT);
 | 
						|
}
 | 
						|
 | 
						|
gboolean
 | 
						|
g_type_check_is_value_type (GType type)
 | 
						|
{
 | 
						|
  return type_check_is_value_type_U (type);
 | 
						|
}
 | 
						|
 | 
						|
gboolean
 | 
						|
g_type_check_value (GValue *value)
 | 
						|
{
 | 
						|
  return value && type_check_is_value_type_U (value->g_type);
 | 
						|
}
 | 
						|
 | 
						|
gboolean
 | 
						|
g_type_check_value_holds (GValue *value,
 | 
						|
			  GType   type)
 | 
						|
{
 | 
						|
  return value && type_check_is_value_type_U (value->g_type) && g_type_is_a (value->g_type, type);
 | 
						|
}
 | 
						|
 | 
						|
GTypeValueTable*
 | 
						|
g_type_value_table_peek (GType type)
 | 
						|
{
 | 
						|
  TypeNode *node;
 | 
						|
  GTypeValueTable *vtable;
 | 
						|
  
 | 
						|
  G_READ_LOCK (&type_rw_lock);
 | 
						|
 restart_table_peek:
 | 
						|
  node = lookup_type_node_L (type);
 | 
						|
  if (!node)
 | 
						|
    {
 | 
						|
      g_warning (G_STRLOC ": type id `%u' is invalid", type);
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  if (!node->data || node->data->common.ref_count < 1)
 | 
						|
    {
 | 
						|
      g_warning ("can't peek value table for type `%s' which is not currently referenced",
 | 
						|
		 type_descriptive_name_L (type));
 | 
						|
      G_READ_UNLOCK (&type_rw_lock);
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  if (node->data->common.value_table->value_init)
 | 
						|
    vtable = node->data->common.value_table;
 | 
						|
  else if (NODE_IS_IFACE (node))
 | 
						|
    {
 | 
						|
      guint i;
 | 
						|
 | 
						|
      for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
 | 
						|
	{
 | 
						|
	  GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
 | 
						|
	  TypeNode *prnode = lookup_type_node_L (prtype);
 | 
						|
 | 
						|
	  if (prnode->is_instantiatable)
 | 
						|
	    {
 | 
						|
	      type = prtype;
 | 
						|
	      goto restart_table_peek;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      vtable = NULL;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    vtable = NULL;
 | 
						|
  G_READ_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  return vtable;
 | 
						|
}
 | 
						|
 | 
						|
G_CONST_RETURN gchar*
 | 
						|
g_type_name_from_instance (GTypeInstance *instance)
 | 
						|
{
 | 
						|
  if (!instance)
 | 
						|
    return "<NULL-instance>";
 | 
						|
  else
 | 
						|
    return g_type_name_from_class (instance->g_class);
 | 
						|
}
 | 
						|
 | 
						|
G_CONST_RETURN gchar*
 | 
						|
g_type_name_from_class (GTypeClass *g_class)
 | 
						|
{
 | 
						|
  if (!g_class)
 | 
						|
    return "<NULL-class>";
 | 
						|
  else
 | 
						|
    return g_type_name (g_class->g_type);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* --- foreign prototypes --- */
 | 
						|
extern void	g_value_types_init	(void); /* sync with gvaluetypes.c */
 | 
						|
extern void	g_enum_types_init	(void);	/* sync with genums.c */
 | 
						|
extern void     g_param_type_init       (void);	/* sync with gparam.c */
 | 
						|
extern void     g_boxed_type_init       (void);	/* sync with gboxed.c */
 | 
						|
extern void     g_object_type_init      (void);	/* sync with gobject.c */
 | 
						|
extern void	g_param_spec_types_init	(void);	/* sync with gparamspecs.c */
 | 
						|
extern void	g_value_transforms_init	(void); /* sync with gvaluetransform.c */
 | 
						|
extern void	g_signal_init		(void);	/* sync with gsignal.c */
 | 
						|
 | 
						|
 | 
						|
/* --- initialization --- */
 | 
						|
void
 | 
						|
g_type_init_with_debug_flags (GTypeDebugFlags debug_flags)
 | 
						|
{
 | 
						|
  G_LOCK_DEFINE_STATIC (type_init_lock);
 | 
						|
  static TypeNode *type0_node = NULL;
 | 
						|
  const gchar *env_string;
 | 
						|
  GTypeInfo info;
 | 
						|
  TypeNode *node;
 | 
						|
  GType type;
 | 
						|
  
 | 
						|
  G_LOCK (type_init_lock);
 | 
						|
  
 | 
						|
  G_WRITE_LOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  if (static_last_fundamental_id)
 | 
						|
    {
 | 
						|
      G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
      G_UNLOCK (type_init_lock);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  /* setup GRuntime wide debugging flags */
 | 
						|
  _g_type_debug_flags = debug_flags & G_TYPE_DEBUG_MASK;
 | 
						|
  env_string = g_getenv ("GRUNTIME_DEBUG");
 | 
						|
  if (env_string != NULL)
 | 
						|
    {
 | 
						|
      static GDebugKey debug_keys[] = {
 | 
						|
	{ "objects", G_TYPE_DEBUG_OBJECTS },
 | 
						|
	{ "signals", G_TYPE_DEBUG_SIGNALS },
 | 
						|
      };
 | 
						|
 | 
						|
      _g_type_debug_flags |= g_parse_debug_string (env_string,
 | 
						|
						   debug_keys,
 | 
						|
						   sizeof (debug_keys) / sizeof (debug_keys[0]));
 | 
						|
      env_string = NULL;
 | 
						|
    }
 | 
						|
  
 | 
						|
  /* quarks */
 | 
						|
  static_quark_type_flags = g_quark_from_static_string ("-g-type-private--GTypeFlags");
 | 
						|
  static_quark_iface_holder = g_quark_from_static_string ("-g-type-private--IFaceHolder");
 | 
						|
  static_quark_dependants_array = g_quark_from_static_string ("-g-type-private--dependants-array");
 | 
						|
  
 | 
						|
  /* type qname hash table */
 | 
						|
  static_type_nodes_ht = g_hash_table_new (g_direct_hash, g_direct_equal);
 | 
						|
  
 | 
						|
  /* invalid type G_TYPE_INVALID (0)
 | 
						|
   */
 | 
						|
  static_last_fundamental_id = 1;
 | 
						|
  static_type_nodes = g_renew (TypeNode**, static_type_nodes, static_last_fundamental_id);
 | 
						|
  static_type_nodes[0] = &type0_node;
 | 
						|
  static_branch_seqnos = g_renew (GType, static_branch_seqnos, static_last_fundamental_id);
 | 
						|
  static_branch_seqnos[0] = 1;
 | 
						|
  
 | 
						|
  /* void type G_TYPE_NONE
 | 
						|
   */
 | 
						|
  node = type_node_fundamental_new_W (G_TYPE_NONE, "void", 0);
 | 
						|
  type = NODE_TYPE (node);
 | 
						|
  g_assert (type == G_TYPE_NONE);
 | 
						|
  
 | 
						|
  /* interface fundamental type G_TYPE_INTERFACE (!classed)
 | 
						|
   */
 | 
						|
  memset (&info, 0, sizeof (info));
 | 
						|
  node = type_node_fundamental_new_W (G_TYPE_INTERFACE, "GInterface", G_TYPE_FLAG_DERIVABLE);
 | 
						|
  type = NODE_TYPE (node);
 | 
						|
  type_data_make_W (node, &info, NULL);
 | 
						|
  g_assert (type == G_TYPE_INTERFACE);
 | 
						|
  
 | 
						|
  G_WRITE_UNLOCK (&type_rw_lock);
 | 
						|
  
 | 
						|
  /* G_TYPE_TYPE_PLUGIN
 | 
						|
   */
 | 
						|
  g_type_plugin_get_type ();
 | 
						|
  
 | 
						|
  /* G_TYPE_* value types
 | 
						|
   */
 | 
						|
  g_value_types_init ();
 | 
						|
  
 | 
						|
  /* G_TYPE_ENUM & G_TYPE_FLAGS
 | 
						|
   */
 | 
						|
  g_enum_types_init ();
 | 
						|
  
 | 
						|
  /* G_TYPE_BOXED
 | 
						|
   */
 | 
						|
  g_boxed_type_init ();
 | 
						|
  
 | 
						|
  /* G_TYPE_PARAM
 | 
						|
   */
 | 
						|
  g_param_type_init ();
 | 
						|
  
 | 
						|
  /* G_TYPE_OBJECT
 | 
						|
   */
 | 
						|
  g_object_type_init ();
 | 
						|
  
 | 
						|
  /* G_TYPE_PARAM_* pspec types
 | 
						|
   */
 | 
						|
  g_param_spec_types_init ();
 | 
						|
  
 | 
						|
  /* Value Transformations
 | 
						|
   */
 | 
						|
  g_value_transforms_init ();
 | 
						|
 | 
						|
  /* Signal system
 | 
						|
   */
 | 
						|
  g_signal_init ();
 | 
						|
  
 | 
						|
  G_UNLOCK (type_init_lock);
 | 
						|
}
 | 
						|
 | 
						|
void 
 | 
						|
g_type_init (void)
 | 
						|
{
 | 
						|
  g_type_init_with_debug_flags (0);
 | 
						|
}
 |