Read the source code!
看再多的文档,最后都要回归到code上面来。
/* Basic Type Macros */ #define G_TYPE_FUNDAMENTAL(type) (g_type_fundamental (type)) #define G_TYPE_FUNDAMENTAL_MAX (255 << G_TYPE_FUNDAMENTAL_SHIFT) //1020 #define G_TYPE_INVALID G_TYPE_MAKE_FUNDAMENTAL (0) //0 #define G_TYPE_NONE G_TYPE_MAKE_FUNDAMENTAL (1) //4 #define G_TYPE_INTERFACE G_TYPE_MAKE_FUNDAMENTAL (2) //8 #define G_TYPE_CHAR G_TYPE_MAKE_FUNDAMENTAL (3) //12 #define G_TYPE_UCHAR G_TYPE_MAKE_FUNDAMENTAL (4) //16 #define G_TYPE_BOOLEAN G_TYPE_MAKE_FUNDAMENTAL (5) //20 #define G_TYPE_INT G_TYPE_MAKE_FUNDAMENTAL (6) //24 #define G_TYPE_UINT G_TYPE_MAKE_FUNDAMENTAL (7) #define G_TYPE_LONG G_TYPE_MAKE_FUNDAMENTAL (8) #define G_TYPE_ULONG G_TYPE_MAKE_FUNDAMENTAL (9) #define G_TYPE_INT64 G_TYPE_MAKE_FUNDAMENTAL (10) #define G_TYPE_UINT64 G_TYPE_MAKE_FUNDAMENTAL (11) #define G_TYPE_ENUM G_TYPE_MAKE_FUNDAMENTAL (12) #define G_TYPE_FLAGS G_TYPE_MAKE_FUNDAMENTAL (13) #define G_TYPE_FLOAT G_TYPE_MAKE_FUNDAMENTAL (14) #define G_TYPE_DOUBLE G_TYPE_MAKE_FUNDAMENTAL (15) #define G_TYPE_STRING G_TYPE_MAKE_FUNDAMENTAL (16) #define G_TYPE_POINTER G_TYPE_MAKE_FUNDAMENTAL (17) #define G_TYPE_BOXED G_TYPE_MAKE_FUNDAMENTAL (18) #define G_TYPE_PARAM G_TYPE_MAKE_FUNDAMENTAL (19) #define G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20) #define G_TYPE_VARIANT G_TYPE_MAKE_FUNDAMENTAL (21) //84
#define G_TYPE_FUNDAMENTAL_SHIFT (2)
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; }
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]; } 这种左移,右移的移位操作,本身效率是高,但是为什么要这样做? |
模板文件,这些宏,在后面用户自定义GObject时非常有用,
要理解他们,用好他们;
/* --- structures --- */ struct _TypeNode { guint volatile ref_count; GTypePlugin *plugin; guint n_children; /* writable with lock */ //子辈的个数 guint n_supers : 8; //父辈的个数 guint n_prerequisites : 9; guint is_classed : 1; guint is_instantiatable : 1; guint mutatable_check_cache : 1; /* combines some common path checks */ GType *children; /* writable with lock */ //指针数组,用来保持孩子的信息:pnode->children[i] = type; pnode->children = g_renew (GType, pnode->children, pnode->n_children); TypeData * volatile data; GQuark qname; GData *global_gdata; union { GAtomicArray iface_entries; /* for !iface types */ GAtomicArray offsets; } _prot; GType *prerequisites; GType supers[1]; /* flexible array */ //直接用memory copy进行增长 }; #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]) //最顶层的父亲,就是基本类型 /* --- type nodes --- */ static GHashTable *static_type_nodes_ht = NULL; static TypeNode *static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { NULL, }; //全局的指针数组,用来保存基本类型,256个 static GType static_fundamental_next = G_TYPE_RESERVED_USER_FIRST; ?为什么需要一个hash table和一个全局的指针数组来保存Node节点呢? 数组查找快?
下面这个函数,同时操作上面的hash table和全局数组static_fundamental_type_nodes[]
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; //如果有父类,则父类加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); //如果没有父节点,则直接保存在基础类型static_fundamental_type_nodes数组中 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 _g_atomic_array_init (CLASSED_NODE_IFACES_ENTRIES (node)); } else { //如果有父节点 node->supers[0] = type; //第一个节点就是自己 //node->supers+1,指针后移动 //把父节点的所有数据,都复制一份给当前节点,作为当前节点的父类信息 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; IFaceEntries *entries; entries = _g_atomic_array_copy (CLASSED_NODE_IFACES_ENTRIES (pnode), IFACE_ENTRIES_HEADER_SIZE, 0); if (entries) { for (j = 0; j < IFACE_ENTRIES_N_ENTRIES (entries); j++) { entries->entry[j].vtable = NULL; entries->entry[j].init_state = UNINITIALIZED; } _g_atomic_array_update (CLASSED_NODE_IFACES_ENTRIES (node), entries); } } //再和父类建立好关系 i = pnode->n_children++; pnode->children = g_renew (GType, pnode->children, pnode->n_children); pnode->children[i] = type; } TRACE(GOBJECT_TYPE_NEW(name, node->supers[1], 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; //同时压入hash table中 g_hash_table_insert (static_type_nodes_ht, GUINT_TO_POINTER (node->qname), (gpointer) type); return node; }
上面提到的那个静态全局数组:TypeNode * static_fundamental_type_nodes[256];
TypeNode * |
TypeNode * |
TypeNode * |
…… |
TypeNode * |
保存的基础节点,即:没有父类的节点类型:同时,这些type也是可以做父亲的类型
| `Void | `GInterface | `GTypePlugin | `gchar | `guchar | `gboolean | `gint | `guint | `glong | `gulong | `gint64 | `guint64 | `GEnum | `GFlags | `gfloat | `gdouble | `gchararray | `gpointer | `GType | `GBoxed | `GValueArray | `GParam | `GParamVariant | `GObject | `GVariant
下面是个内联函数,可以取代宏,有编译器直接展开,效率高;
同时,也可以检查参数的有效性;
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]; }
数组的直接访问,效率是非常高的。
另外一个Hash Table: GHashTable *static_type_nodes_ht = NULL;
只有一个函数进行了调用:
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 = (GType) g_hash_table_lookup (static_type_nodes_ht, GUINT_TO_POINTER (quark)); G_READ_UNLOCK (&type_rw_lock); } return type; }
根据“名字”来查询,Hash Table的效率要高;