Re: Another version of instance-private-data [really!]
- From: Owen Taylor <otaylor redhat com>
- To: Tim Janik <timj gtk org>
- Cc: Gtk+ Developers <gtk-devel-list gnome org>
- Subject: Re: Another version of instance-private-data [really!]
- Date: 05 Mar 2003 11:40:12 -0500
On Tue, 2003-03-04 at 23:04, Tim Janik wrote:
> > +/* 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)
> > +
>
> there's alignment logic in the definition of
> SIZEOF_FUNDAMENTAL_INFO already implemented, it should be
> seperated and reused (and is well tested on a number of
> systems already, including ia64).
I don't see anything immediately usable. The SIZEOF_FUNDAMENTAL_INFO
stuff is relying on that the maximally aligned thing in
GType is either a gpointer or a glong.
An example of where we need larger alignment than
SIZEOF_FUNDAMENTAL_INFO is a 32-bit platform where doubles are 64-bit
and need to be naturally aligned (aligned on 64-bit boundaries)
We could reuse the stronger ALIGN_STRUCT macro for the fundamental-info
code, but that's going to waste space on a lot of platforms.
> > @@ -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 */
>
> i fail to see how this could compile, since you added total_instance_size
> to g_type_create_instance() only.
Good catch - accidental substitution leakage and I wasn't compiling
with --enable-debug. Though actually, we do want total_instance_size()
here's so I've split it out into a little inline function.
> > +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)
>
> there's no need to cast g_class into a (gpointer) which it is already.
Fixed.
> > +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;
> > + }
>
> we better check whether private_node is a parent node of instance,
> rather than just checking whether it's instantiatable (which is
> a pretty arbitrary check for an assumed parent type), that is:
>
> if (G_UNLIKELY (!private_node ||
> private_node->n_supers > instance_node->n_supers ||
> instance_node->supers[instance_node->n_supers -
> private_node->n_supers] !=
> NODE_TYPE (private_node)))
>
Strikes me as a bit expensive, but I've gone ahead and done it...
I've added a NODE_IS_ANCESTOR() macro that I've used here
and in type_node_check_conformaties_UorL() to avoid duplicating the
logic.
[...]
> > + parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node));
> > +
> > + g_assert (parent_node->data && parent_node->data->common.ref_count);
>
> bad assertion, parent_node might be NULL if you request private data
> from a fundamental type instance.
> > +
> > + offset = ALIGN_STRUCT (instance_node->data->instance.instance_size) + parent_node->data->instance.private_size;
>
> so better do:
>
> offset = ALIGN_STRUCT (instance_node->data->instance.instance_size);
> if (parent_node)
> offset += ALIGN_STRUCT (parent_node->data->instance.private_size);
> (using ALIGN_STRUCT() in this place to correspond to the ALIGN_STRUCT()
> you used in g_type_class_add_private())
OK, I've done something like that. Although we've made sure that
lookup_type_node_I (G_TYPE_NONE) => NULL, it feels a little dirty
to me, so I've done 'if (NODE_PARENT_TYPE (private_node))' instead.
> > +
> > + return (gpointer)((gchar *)instance + ALIGN_STRUCT (offset));
>
> glib has a macro for this, so the code should read:
>
> return G_STRUCT_MEMBER_P (instance, offset);
> (ALIGN_STRUCT() not needed with the above if (parent_node) branch)
OK, changed.
New patch attached. I've also fixed some bugs in the preallocs > 0 case;
there is a subtlety there ... if instance size is, say 8 and private
size 1, then it's fine to malloc 9 bytes if we are malloc'ing a single
instance, but if we have an array of structures, then we need to malloc
ALIGN_STRUCT(9) bytes for each or the later elements in the array won't
be properly aligned.
Regards,
Owen
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 5 Mar 2003 16:32:10 -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 5 Mar 2003 16:32:10 -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: docs/reference/gobject/tmpl/param_value_types.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/gobject/tmpl/param_value_types.sgml,v
retrieving revision 1.9
diff -u -p -r1.9 param_value_types.sgml
--- docs/reference/gobject/tmpl/param_value_types.sgml 7 Feb 2003 22:08:53 -0000 1.9
+++ docs/reference/gobject/tmpl/param_value_types.sgml 5 Mar 2003 16:32:10 -0000
@@ -840,7 +840,7 @@ See g_param_spec_internal() for details
@maximum: maximum value for the property specified
@default_value: default value for the property specified
@flags: flags for the property specified
- Returns: a newly created parameter specification
+ Returns: a newly created parameter specification
<!-- ##### FUNCTION g_value_set_double ##### -->
@@ -1557,6 +1557,6 @@ See g_param_spec_internal() for details
@element_spec: a #GParamSpec describing the elements contained in
arrays of this property, may be %NULL
@flags: flags for the property specified
- Returns: a newly created parameter specification
+ Returns: a newly created parameter specification
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 5 Mar 2003 16:32:10 -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 5 Mar 2003 16:32:10 -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;
@@ -182,6 +194,10 @@ struct _TypeNode
#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))
+#define NODE_IS_ANCESTOR(ancestor, node) \
+ ((ancestor)->n_supers <= (node)->n_supers && \
+ (node)->supers[(node)->n_supers - (ancestor)->n_supers] == NODE_TYPE (ancestor))
+
struct _IFaceHolder
{
@@ -229,6 +245,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 +926,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 */
@@ -1338,6 +1362,19 @@ type_iface_blow_holder_info_Wm (TypeNode
}
}
+/* Assumes type's class already exists
+ */
+static inline size_t
+type_total_instance_size_I (TypeNode *node)
+{
+ gsize total_instance_size;
+
+ 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;
+
+ return total_instance_size;
+}
/* --- type structure creation/destruction --- */
GTypeInstance*
@@ -1347,6 +1384,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,21 +1402,35 @@ g_type_create_instance (GType type)
}
class = g_type_class_ref (type);
+
+ total_instance_size = type_total_instance_size_I (node);
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);
+ {
+ /* If there isn't private data, the compiler will have already
+ * added the necessary padding, but in the private data case, we
+ * have to pad ourselves to ensure proper alignment of all the
+ * atoms in the slab.
+ */
+ gsize atom_size = total_instance_size;
+ if (node->data->instance.private_size)
+ atom_size = ALIGN_STRUCT (atom_size);
+
+ node->data->instance.mem_chunk = g_mem_chunk_new (NODE_NAME (node),
+ atom_size,
+ (atom_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 +1476,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, type_total_instance_size_I (node)); /* debugging hack */
#endif
if (node->data->instance.n_preallocs)
{
@@ -2255,8 +2307,7 @@ type_node_check_conformities_UorL (TypeN
gboolean match;
if (/* support_inheritance && */
- iface_node->n_supers <= node->n_supers &&
- node->supers[node->n_supers - iface_node->n_supers] == NODE_TYPE (iface_node))
+ NODE_IS_ANCESTOR (iface_node, node))
return TRUE;
support_interfaces = support_interfaces && node->is_instantiatable && NODE_IS_IFACE (iface_node);
@@ -3024,4 +3075,84 @@ 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 != 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 || !NODE_IS_ANCESTOR (private_node, instance_node)))
+ {
+ g_warning ("attempt to retrieve private data for invalid 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.
+ */
+
+ offset = ALIGN_STRUCT (instance_node->data->instance.instance_size);
+
+ if (NODE_PARENT_TYPE (private_node))
+ {
+ 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 (parent_node->data->instance.private_size);
+ }
+
+ return G_STRUCT_MEMBER_P (instance, 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 5 Mar 2003 16:32:10 -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 5 Mar 2003 16:32:10 -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]