Re: Another version of instance-private-data [really!]



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;
+};
+
+&num;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]