📄 gtype.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 "glibconfig.h"#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. * * 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;#ifdef LOCK_DEBUG#define G_READ_LOCK(rw_lock) do { g_printerr (G_STRLOC ": readL++\n"); g_static_rw_lock_reader_lock (rw_lock); } while (0)#define G_READ_UNLOCK(rw_lock) do { g_printerr (G_STRLOC ": readL--\n"); g_static_rw_lock_reader_unlock (rw_lock); } while (0)#define G_WRITE_LOCK(rw_lock) do { g_printerr (G_STRLOC ": writeL++\n"); g_static_rw_lock_writer_lock (rw_lock); } while (0)#define G_WRITE_UNLOCK(rw_lock) do { g_printerr (G_STRLOC ": writeL--\n"); g_static_rw_lock_writer_unlock (rw_lock); } while (0)#else#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)#endif#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_I (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);static IFaceHolder* type_iface_peek_holder_L (TypeNode *iface, GType instance_type);static gboolean type_node_is_a_L (TypeNode *node, TypeNode *iface_node);/* --- structures --- */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 mutatable_check_cache : 1; /* combines some common path checks */ GType *children; TypeData * volatile 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_FUNDAMENTAL_TYPE(node) (node->supers[node->n_supers])#define NODE_NAME(node) (g_quark_to_string (node->qname))#define NODE_IS_IFACE(node) (NODE_FUNDAMENTAL_TYPE (node) == G_TYPE_INTERFACE)#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)))#define TYPE_ID_MASK ((GType) ((1 << G_TYPE_FUNDAMENTAL_SHIFT) - 1))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 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;/* --- type nodes --- */static GHashTable *static_type_nodes_ht = NULL;static TypeNode *static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { 0, };static GType static_fundamental_next = G_TYPE_RESERVED_USER_FIRST;static inline TypeNode*lookup_type_node_I (register GType utype){ if (utype > G_TYPE_FUNDAMENTAL_MAX) return (TypeNode*) (utype & ~TYPE_ID_MASK); else return static_fundamental_type_nodes[utype >> G_TYPE_FUNDAMENTAL_SHIFT];}static TypeNode*type_node_any_new_W (TypeNode *pnode, GType ftype, const gchar *name, GTypePlugin *plugin, GTypeFundamentalFlags type_flags){ guint n_supers; GType type; TypeNode *node; guint i, node_size = 0; n_supers = pnode ? pnode->n_supers + 1 : 0; 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_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node; type = ftype; } else type = (GType) node; g_assert ((type & TYPE_ID_MASK) == 0); 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 { guint j; 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)); for (j = 0; j < CLASSED_NODE_N_IFACES (node); j++) CLASSED_NODE_IFACES_ENTRIES (node)[j].vtable = NULL; } 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), (gpointer) type); return node;}static inline GTypeFundamentalInfo*type_node_fundamental_info_I (TypeNode *node){ GType ftype = NODE_FUNDAMENTAL_TYPE (node); if (ftype != NODE_TYPE (node)) node = lookup_type_node_I (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; g_assert ((ftype & TYPE_ID_MASK) == 0); g_assert (ftype <= G_TYPE_FUNDAMENTAL_MAX); if (ftype >> G_TYPE_FUNDAMENTAL_SHIFT == static_fundamental_next) static_fundamental_next++; type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK; node = type_node_any_new_W (NULL, ftype, name, NULL, type_flags); finfo = type_node_fundamental_info_I (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, NODE_FUNDAMENTAL_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -