Re: Another version of instance-private-data [really!]
- From: Owen Taylor <otaylor redhat com>
- To: timj gtk org
- Cc: gtk-devel-list gnome org
- Subject: Re: Another version of instance-private-data [really!]
- Date: 03 Mar 2003 13:03:17 -0500
Tim pointed out that in this patch, I was confusing
the instance type with the type for which the private
data was registered.
The attached patch fixes and tests getting the
private data for an ancestor type of the instance
type.
Index: docs/reference/gobject/gobject-sections.txt
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/gobject/gobject-sections.txt,v
retrieving revision 1.23
diff -u -p -r1.23 gobject-sections.txt
--- docs/reference/gobject/gobject-sections.txt 9 Dec 2002 19:06:42 -0000 1.23
+++ docs/reference/gobject/gobject-sections.txt 3 Mar 2003 18:00:04 -0000
@@ -30,6 +30,7 @@ G_TYPE_FROM_CLASS
G_TYPE_FROM_INTERFACE
G_TYPE_INSTANCE_GET_CLASS
G_TYPE_INSTANCE_GET_INTERFACE
+G_TYPE_INSTANCE_GET_PRIVATE
G_TYPE_CHECK_INSTANCE
G_TYPE_CHECK_INSTANCE_CAST
G_TYPE_CHECK_INSTANCE_TYPE
@@ -52,6 +53,7 @@ g_type_class_ref
g_type_class_peek
g_type_class_unref
g_type_class_peek_parent
+g_type_class_add_private
g_type_interface_peek
g_type_interface_peek_parent
g_type_children
@@ -97,6 +99,7 @@ g_type_check_class_is_a
g_type_check_is_value_type
g_type_check_value
g_type_check_value_holds
+g_type_instance_get_private
g_type_test_flags
g_type_name_from_instance
g_type_name_from_class
Index: docs/reference/gobject/tmpl/gtype.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/gobject/tmpl/gtype.sgml,v
retrieving revision 1.22
diff -u -p -r1.22 gtype.sgml
--- docs/reference/gobject/tmpl/gtype.sgml 7 Feb 2003 22:08:53 -0000 1.22
+++ docs/reference/gobject/tmpl/gtype.sgml 3 Mar 2003 18:00:04 -0000
@@ -462,6 +462,17 @@ Returns the interface structure for inte
@c_type: The corresponding C type of @g_type.
+<!-- ##### MACRO G_TYPE_INSTANCE_GET_PRIVATE ##### -->
+<para>
+Gets the private structure for a particular type.
+The private structure must have added from the class_init
+function with g_type_class_add_private().
+</para>
+
+ instance: the instance 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.
+
<!-- ##### MACRO G_TYPE_CHECK_INSTANCE ##### -->
<para>
@@ -693,6 +704,48 @@ g_type_class_peek (g_type_parent (G_TYPE
@Returns: The parent class of @g_class.
+<!-- ##### FUNCTION g_type_class_add_private ##### -->
+<para>
+Registers a private structure for a instantiatable type;
+when an object is allocated, the private structures for
+the type and 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 class_init() function. The private structure can
+be retrieved using the G_TYPE_INSTANCE_GET_PRIVATE() macro.
+The following example shows attaching a private structure
+<structname>MyObjectPrivate</structname> to an object
+<structname>MyObject</structname> defined in the standard GObject
+fashion.
+</para>
+<programlisting>
+typedef struct _MyObjectPrivate MyObjectPrivate;
+
+struct _MyObjectPrivate {
+ int some_field;
+};
+
+#define MY_OBJECT_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), MY_TYPE_OBJECT, MyObjectPrivate))
+
+static void
+my_object_class_init (MyObjectClass *klass)
+{
+ g_type_class_add_private (klass, sizeof (MyObjectPrivate));
+}
+
+static int
+my_object_get_some_field (MyObject *my_object)
+{
+ MyObjectPrivate *priv = MY_OBJECT_GET_PRIVATE (my_object);
+
+ return priv->some_field;
+}
+</programlisting>
+
+ g_class: class structure for an instantiatable type
+ private_size: size of private structure.
+
<!-- ##### FUNCTION g_type_interface_peek ##### -->
<para>
Returns the #GTypeInterface structure of an interface to which the passed in
@@ -751,7 +804,6 @@ Returns the prerequisites of an interfac
@n_prerequisites: location to return the number of prerequisites, or %NULL
@Returns: a newly-allocated zero-terminated array of #GType containing
the prerequisites of @interface_type
-<!-- # Unused Parameters # -->
@Since: 2.2
Index: gobject/ChangeLog
===================================================================
RCS file: /cvs/gnome/glib/gobject/ChangeLog,v
retrieving revision 1.241
diff -u -p -r1.241 ChangeLog
--- gobject/ChangeLog 17 Feb 2003 20:17:17 -0000 1.241
+++ gobject/ChangeLog 3 Mar 2003 18:00:04 -0000
@@ -1,3 +1,9 @@
+Thu Feb 27 17:33:19 2003 Owen Taylor <otaylor redhat com>
+
+ * gtype.[ch]: Add support for instance-private data. (#101959)
+ g_type_class_add_private(), g_type_instance_get_private(),
+ G_TYPE_INSTANCE_GET_PRIVATE().
+
Mon Feb 17 20:59:47 2003 Tim Janik <timj gtk org>
* gvalue.c (g_value_register_transform_func): don't assert the types
Index: gobject/gtype.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.c,v
retrieving revision 1.59
diff -u -p -r1.59 gtype.c
--- gobject/gtype.c 7 Feb 2003 22:04:24 -0000 1.59
+++ gobject/gtype.c 3 Mar 2003 18:00:05 -0000
@@ -107,6 +107,18 @@ static GStaticRWLock type_rw_
sizeof (gpointer)), \
sizeof (glong)))
+/* The 2*sizeof(size_t) alignment here is borrowed from
+ * GNU libc, so it should be good most everywhere.
+ * It is more conservative than is needed on some 64-bit
+ * platforms, but ia64 does require a 16-byte alignment.
+ * The SIMD extensions for x86 and ppc32 would want a
+ * larger alignment than this, but we don't need to
+ * do better than malloc.
+ */
+#define STRUCT_ALIGNMENT (2 * sizeof (gsize))
+#define ALIGN_STRUCT(offset) \
+ ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT)
+
/* --- typedefs --- */
typedef struct _TypeNode TypeNode;
@@ -229,6 +241,7 @@ struct _InstanceData
gconstpointer class_data;
gpointer class;
guint16 instance_size;
+ guint16 private_size;
guint16 n_preallocs;
GInstanceInitFunc instance_init;
GMemChunk *mem_chunk;
@@ -909,6 +922,13 @@ type_data_make_W (TypeNode
data->instance.class_data = info->class_data;
data->instance.class = NULL;
data->instance.instance_size = info->instance_size;
+ if (NODE_PARENT_TYPE (node))
+ {
+ TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
+ data->instance.private_size = pnode->data->instance.private_size;
+ }
+ else
+ data->instance.private_size = 0;
#ifdef DISABLE_MEM_POOLS
data->instance.n_preallocs = 0;
#else /* !DISABLE_MEM_POOLS */
@@ -1347,6 +1367,7 @@ g_type_create_instance (GType type)
GTypeInstance *instance;
GTypeClass *class;
guint i;
+ gsize total_instance_size;
node = lookup_type_node_I (type);
if (!node || !node->is_instantiatable)
@@ -1364,6 +1385,10 @@ g_type_create_instance (GType type)
}
class = g_type_class_ref (type);
+
+ total_instance_size = node->data->instance.instance_size;
+ if (node->data->instance.private_size != 0)
+ total_instance_size = ALIGN_STRUCT (total_instance_size) + node->data->instance.private_size;
if (node->data->instance.n_preallocs)
{
@@ -1371,14 +1396,14 @@ g_type_create_instance (GType type)
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 *
+ (total_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 */
+ instance = g_malloc0 (total_instance_size); /* fine without read lock */
for (i = node->n_supers; i > 0; i--)
{
TypeNode *pnode;
@@ -1424,7 +1449,7 @@ g_type_free_instance (GTypeInstance *ins
instance->g_class = NULL;
#ifdef G_ENABLE_DEBUG
- memset (instance, 0xaa, node->data->instance.instance_size); /* debugging hack */
+ memset (instance, 0xaa, total_instance_size); /* debugging hack */
#endif
if (node->data->instance.n_preallocs)
{
@@ -1527,7 +1552,7 @@ type_class_init_Wm (TypeNode *node,
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;
@@ -3024,4 +3049,80 @@ void
g_type_init (void)
{
g_type_init_with_debug_flags (0);
+}
+
+void
+g_type_class_add_private (gpointer g_class,
+ gsize private_size)
+{
+ GType instance_type = ((GTypeClass *)g_class)->g_type;
+ TypeNode *node = lookup_type_node_I (instance_type);
+ gsize offset;
+
+ if (!node || !node->is_instantiatable || !node->data || node->data->class.class != (gpointer) g_class)
+ {
+ g_warning ("cannot add private field to invalid (non-instantiatable) type '%s'",
+ type_descriptive_name_I (instance_type));
+ return;
+ }
+
+ if (NODE_PARENT_TYPE (node))
+ {
+ TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
+ if (node->data->instance.private_size != pnode->data->instance.private_size)
+ {
+ g_warning ("g_type_add_private() called multiple times for the same type");
+ return;
+ }
+ }
+
+ G_WRITE_LOCK (&type_rw_lock);
+
+ offset = ALIGN_STRUCT (node->data->instance.private_size);
+ node->data->instance.private_size = offset + private_size;
+
+ G_WRITE_UNLOCK (&type_rw_lock);
+}
+
+gpointer
+g_type_instance_get_private (GTypeInstance *instance,
+ GType private_type)
+{
+ TypeNode *instance_node;
+ TypeNode *private_node;
+ TypeNode *parent_node;
+ gsize offset;
+
+ g_return_val_if_fail (instance != NULL && instance->g_class != NULL, NULL);
+
+ instance_node = lookup_type_node_I (instance->g_class->g_type);
+ if (G_UNLIKELY (!instance_node || !instance_node->is_instantiatable))
+ {
+ g_warning ("instance of invalid non-instantiatable type `%s'",
+ type_descriptive_name_I (instance->g_class->g_type));
+ return NULL;
+ }
+
+ private_node = lookup_type_node_I (private_type);
+ if (G_UNLIKELY (!private_node || !private_node->is_instantiatable))
+ {
+ g_warning ("cannot retrieve private instant for non-instantiatable type '%s'",
+ type_descriptive_name_I (private_type));
+ return NULL;
+ }
+
+ /* Note that we don't need a read lock, since instance existing
+ * means that the instance class and all parent classes
+ * exist, so the node->data, node->data->instance.instance_size,
+ * and node->data->instance.private_size are not going to be changed.
+ * for any of the relevant types.
+ */
+
+ parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node));
+
+ g_assert (parent_node->data && parent_node->data->common.ref_count);
+
+ offset = ALIGN_STRUCT (instance_node->data->instance.instance_size) + parent_node->data->instance.private_size;
+
+ return (gpointer)((gchar *)instance + ALIGN_STRUCT (offset));
}
Index: gobject/gtype.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.h,v
retrieving revision 1.47
diff -u -p -r1.47 gtype.h
--- gobject/gtype.h 3 Dec 2002 23:54:54 -0000 1.47
+++ gobject/gtype.h 3 Mar 2003 18:00:05 -0000
@@ -150,6 +150,8 @@ struct _GTypeQuery
#define G_TYPE_FROM_CLASS(g_class) (((GTypeClass*) (g_class))->g_type)
#define G_TYPE_FROM_INTERFACE(g_iface) (((GTypeInterface*) (g_iface))->g_type)
+#define G_TYPE_INSTANCE_GET_PRIVATE(instance, g_type, c_type) ((c_type*) g_type_instance_get_private ((GTypeInstance*) (instance), (g_type)))
+
/* debug flags for g_type_init_with_debug_flags() */
typedef enum /*< skip >*/
@@ -298,6 +300,10 @@ void g_type_interface_add_prerequisite
GType *g_type_interface_prerequisites (GType interface_type,
guint *n_prerequisites);
+void g_type_class_add_private (gpointer g_class,
+ gsize private_size);
+gpointer g_type_instance_get_private (GTypeInstance *instance,
+ GType private_type);
/* --- protected (for fundamental type implementations) --- */
GTypePlugin* g_type_get_plugin (GType type);
Index: gobject/testgobject.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/testgobject.c,v
retrieving revision 1.6
diff -u -p -r1.6 testgobject.c
--- gobject/testgobject.c 12 Oct 2002 20:04:58 -0000 1.6
+++ gobject/testgobject.c 3 Mar 2003 18:00:05 -0000
@@ -126,8 +126,10 @@ iface_print_string (TestIface *tiobj,
#define TEST_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TEST_TYPE_OBJECT))
#define TEST_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_OBJECT))
#define TEST_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_OBJECT, TestObjectClass))
-typedef struct _TestObject TestObject;
-typedef struct _TestObjectClass TestObjectClass;
+#define TEST_OBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TEST_TYPE_OBJECT, TestObjectPrivate))
+typedef struct _TestObject TestObject;
+typedef struct _TestObjectClass TestObjectClass;
+typedef struct _TestObjectPrivate TestObjectPrivate;
struct _TestObject
{
GObject parent_instance;
@@ -140,6 +142,11 @@ struct _TestObjectClass
TestIface *iface_object,
gpointer tdata);
};
+struct _TestObjectPrivate
+{
+ int dummy1;
+ gdouble dummy2;
+};
static void test_object_class_init (TestObjectClass *class);
static void test_object_init (TestObject *tobject);
static gboolean test_signal_accumulator (GSignalInvocationHint *ihint,
@@ -190,10 +197,18 @@ test_object_class_init (TestObjectClass
test_signal_accumulator, NULL,
g_cclosure_marshal_STRING__OBJECT_POINTER,
G_TYPE_STRING, 2, TEST_TYPE_IFACE, G_TYPE_POINTER);
+
+ g_type_class_add_private (class, sizeof (TestObjectPrivate));
}
static void
test_object_init (TestObject *tobject)
{
+ TestObjectPrivate *priv;
+
+ priv = TEST_OBJECT_GET_PRIVATE (tobject);
+
+ g_assert (priv);
+ g_assert ((gchar *)priv >= (gchar *)tobject + sizeof (TestObject));
}
static gboolean
test_signal_accumulator (GSignalInvocationHint *ihint,
@@ -274,8 +289,16 @@ derived_object_test_iface_init (gpointer
#define DERIVED_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), DERIVED_TYPE_OBJECT))
#define DERIVED_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DERIVED_TYPE_OBJECT))
#define DERIVED_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DERIVED_TYPE_OBJECT, DerivedObjectClass))
-typedef struct _TestObject DerivedObject;
-typedef struct _TestObjectClass DerivedObjectClass;
+#define DERIVED_OBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DERIVED_TYPE_OBJECT, DerivedObjectPrivate))
+typedef struct _TestObject DerivedObject;
+typedef struct _TestObjectClass DerivedObjectClass;
+typedef struct _DerivedObjectPrivate DerivedObjectPrivate;
+struct _DerivedObjectPrivate
+{
+ char dummy;
+};
+static void derived_object_class_init (DerivedObjectClass *class);
+static void derived_object_init (DerivedObject *dobject);
GType
derived_object_get_type (void)
{
@@ -288,12 +311,12 @@ derived_object_get_type (void)
sizeof (DerivedObjectClass),
NULL, /* base_init */
NULL, /* base_finalize */
- NULL, /* class_init */
+ (GClassInitFunc) derived_object_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (DerivedObject),
5, /* n_preallocs */
- NULL, /* instance_init */
+ (GInstanceInitFunc) derived_object_init,
};
GInterfaceInfo iface_info = { derived_object_test_iface_init, NULL, GUINT_TO_POINTER (87) };
@@ -303,7 +326,28 @@ derived_object_get_type (void)
return derived_object_type;
}
+static void
+derived_object_class_init (DerivedObjectClass *class)
+{
+ g_type_class_add_private (class, sizeof (DerivedObjectPrivate));
+}
+static void
+derived_object_init (DerivedObject *dobject)
+{
+ TestObjectPrivate *test_priv;
+ DerivedObjectPrivate *derived_priv;
+
+ derived_priv = DERIVED_OBJECT_GET_PRIVATE (dobject);
+ g_assert (derived_priv);
+ g_assert ((gchar *)derived_priv >= (gchar *)TEST_OBJECT_GET_PRIVATE (dobject) + sizeof (TestObjectPrivate));
+
+ test_priv = TEST_OBJECT_GET_PRIVATE (dobject);
+
+ g_assert (test_priv);
+ g_assert ((gchar *)test_priv >= (gchar *)dobject + sizeof (TestObject));
+
+}
/* --- main --- */
int
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]