From 41383b303c0bb54da68bbf5500b5e2d9e552ab69 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 17 Mar 2010 15:11:00 +0100 Subject: [PATCH] Bug 612502 - Add support for class private data This adds the two new functions g_type_add_class_private() and g_type_class_get_private() and a convenience macro for the getter G_TYPE_CLASS_GET_PRIVATE(). --- gobject/gtype.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- gobject/gtype.h | 21 ++++++++++ 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/gobject/gtype.c b/gobject/gtype.c index 767506f..a1e4c85 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -323,6 +323,7 @@ struct _ClassData { CommonData common; guint16 class_size; + guint16 class_private_size; int volatile init_state; /* atomic - g_type_class_ref reads it unlocked */ GBaseInitFunc class_init_base; GBaseFinalizeFunc class_finalize_base; @@ -336,6 +337,7 @@ struct _InstanceData { CommonData common; guint16 class_size; + guint16 class_private_size; int volatile init_state; /* atomic - g_type_class_ref reads it unlocked */ GBaseInitFunc class_init_base; GBaseFinalizeFunc class_finalize_base; @@ -1081,6 +1083,8 @@ type_data_make_W (TypeNode *node, if (node->is_instantiatable) /* carefull, is_instantiatable is also is_classed */ { + TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); + data = g_malloc0 (sizeof (InstanceData) + vtable_size); if (vtable_size) vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData)); @@ -1097,6 +1101,9 @@ type_data_make_W (TypeNode *node, * after the parent class has been initialized */ data->instance.private_size = 0; + data->instance.class_private_size = 0; + if (pnode) + data->instance.class_private_size = pnode->data->instance.class_private_size; #ifdef DISABLE_MEM_POOLS data->instance.n_preallocs = 0; #else /* !DISABLE_MEM_POOLS */ @@ -1106,6 +1113,8 @@ type_data_make_W (TypeNode *node, } else if (node->is_classed) /* only classed */ { + TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); + data = g_malloc0 (sizeof (ClassData) + vtable_size); if (vtable_size) vtable = G_STRUCT_MEMBER_P (data, sizeof (ClassData)); @@ -1116,6 +1125,9 @@ type_data_make_W (TypeNode *node, data->class.class_finalize = info->class_finalize; data->class.class_data = info->class_data; data->class.class = NULL; + data->class.class_private_size = 0; + if (pnode) + data->class.class_private_size = pnode->data->class.class_private_size; data->class.init_state = UNINITIALIZED; } else if (NODE_IS_IFACE (node)) @@ -2084,12 +2096,17 @@ type_class_init_Wm (TypeNode *node, TypeNode *bnode, *pnode; guint i; + /* Accessing data->class will work for instantiable types + * too because ClassData is a subset of InstanceData + */ g_assert (node->is_classed && node->data && node->data->class.class_size && !node->data->class.class && node->data->class.init_state == UNINITIALIZED); - - class = g_malloc0 (node->data->class.class_size); + if (node->data->class.class_private_size) + class = g_malloc0 (ALIGN_STRUCT (node->data->class.class_size) + node->data->class.class_private_size); + else + class = g_malloc0 (node->data->class.class_size); node->data->class.class = class; g_atomic_int_set (&node->data->class.init_state, BASE_CLASS_INIT); @@ -2098,6 +2115,7 @@ type_class_init_Wm (TypeNode *node, TypeNode *pnode = lookup_type_node_I (pclass->g_type); memcpy (class, pclass, pnode->data->class.class_size); + memcpy (G_STRUCT_MEMBER_P (class, ALIGN_STRUCT (node->data->class.class_size)), G_STRUCT_MEMBER_P (pclass, ALIGN_STRUCT (pnode->data->class.class_size)), pnode->data->class.class_private_size); if (node->is_instantiatable) { @@ -4485,5 +4503,101 @@ g_type_instance_get_private (GTypeInstance *instance, return G_STRUCT_MEMBER_P (instance, offset); } +/** + * g_type_add_class_private: + * @class_type: GType of an classed type. + * @private_size: size of private structure. + * + * Registers a private class structure for a classed type; + * when the class is allocated, the private structures for + * the class and all of its parent types are allocated + * sequentially in the same memory block as the public + * structures. This function should be called in the + * type's get_type() function after the type is registered. + * The private structure can be retrieved using the + * G_TYPE_CLASS_GET_PRIVATE() macro. + * + * Since: 2.24 + */ +void +g_type_add_class_private (GType class_type, + gsize private_size) +{ + TypeNode *node = lookup_type_node_I (class_type); + gsize offset; + + g_return_if_fail (private_size > 0); + + if (!node || !node->is_classed || !node->data) + { + g_warning ("cannot add class private field to invalid type '%s'", + type_descriptive_name_I (class_type)); + return; + } + + if (NODE_PARENT_TYPE (node)) + { + TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); + if (node->data->class.class_private_size != pnode->data->class.class_private_size) + { + g_warning ("g_type_add_class_private() called multiple times for the same type"); + return; + } + } + + G_WRITE_LOCK (&type_rw_lock); + + offset = ALIGN_STRUCT (node->data->class.class_private_size); + node->data->class.class_private_size = offset + private_size; + + G_WRITE_UNLOCK (&type_rw_lock); +} + +gpointer +g_type_class_get_private (GTypeClass *klass, + GType private_type) +{ + TypeNode *class_node; + TypeNode *private_node; + TypeNode *parent_node; + gsize offset; + + g_return_val_if_fail (klass != NULL, NULL); + + class_node = lookup_type_node_I (klass->g_type); + if (G_UNLIKELY (!class_node || !class_node->is_classed)) + { + g_warning ("class of invalid type `%s'", + type_descriptive_name_I (klass->g_type)); + return NULL; + } + + private_node = lookup_type_node_I (private_type); + if (G_UNLIKELY (!private_node || !NODE_IS_ANCESTOR (private_node, class_node))) + { + g_warning ("attempt to retrieve private data for invalid type '%s'", + type_descriptive_name_I (private_type)); + return NULL; + } + + offset = ALIGN_STRUCT (class_node->data->class.class_size); + + if (NODE_PARENT_TYPE (private_node)) + { + parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node)); + g_assert (parent_node->data && NODE_REFCOUNT (parent_node) > 0); + + if (G_UNLIKELY (private_node->data->class.class_private_size == parent_node->data->class.class_private_size)) + { + g_warning ("g_type_instance_get_class_private() requires a prior call to g_type_class_add_class_private()"); + return NULL; + } + + offset += ALIGN_STRUCT (parent_node->data->class.class_private_size); + } + + return G_STRUCT_MEMBER_P (klass, offset); +} + #define __G_TYPE_C__ #include "gobjectaliasdef.c" diff --git a/gobject/gtype.h b/gobject/gtype.h index 3c7f6e5..33a4a8b 100644 --- a/gobject/gtype.h +++ b/gobject/gtype.h @@ -606,6 +606,22 @@ struct _GTypeQuery */ #define G_TYPE_INSTANCE_GET_PRIVATE(instance, g_type, c_type) ((c_type*) g_type_instance_get_private ((GTypeInstance*) (instance), (g_type))) +/** + * G_TYPE_CLASS_GET_PRIVATE: + * @klass: the class of a type deriving from @private_type. + * @g_type: the type identifying which private data to retrieve. + * @c_type: The C type for the private structure. + * + * Gets the private class structure for a particular type. + * The private structure must have been registered in the + * get_type() function with g_type_add_class_private(). + * + * This macro should only be used in type implementations. + * + * Since: 2.24 + * Returns: a pointer to the private data structure. + */ +#define G_TYPE_CLASS_GET_PRIVATE(klass, g_type, c_type) ((c_type*) g_type_class_get_private ((GTypeClass*) (klass), (g_type))) /** * GTypeDebugFlags: @@ -1218,6 +1234,11 @@ void g_type_class_add_private (gpointer g_class, gpointer g_type_instance_get_private (GTypeInstance *instance, GType private_type); +void g_type_add_class_private (GType class_type, + gsize private_size); +gpointer g_type_class_get_private (GTypeClass *klass, + GType private_type); + /* --- GType boilerplate --- */ /** -- 2.7.4