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



Sorry about the last message ... here's what I
meant to attach.

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	27 Feb 2003 23:21:43 -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	27 Feb 2003 23:21:43 -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 *private = MY_OBJECT_GET_PRIVATE (my_object);
+
+  return private->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 
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	27 Feb 2003 23:21:43 -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	27 Feb 2003 23:21:43 -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)
     {
@@ -3024,4 +3049,67 @@ 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          instance_type)
+{
+  TypeNode *node = lookup_type_node_I (instance_type);
+  TypeNode *parent_node;
+  gsize offset;
+
+  if (G_UNLIKELY (!node || !node->is_instantiatable))
+    {
+      g_warning ("cannot retrieve private instant for non-instantiatable type '%s'",
+		 type_descriptive_name_I (instance_type));
+      return NULL;
+    }
+
+  /* Note that we don't need a read lock, since instance existing
+   * means that the instance class exists, and thus,
+   * node->data and node->data->instance.private_size are
+   * not going to be changed.
+   */
+  
+  parent_node = lookup_type_node_I (NODE_PARENT_TYPE (node));
+
+  g_assert (parent_node->data && parent_node->data->common.ref_count);
+
+  offset = ALIGN_STRUCT (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	27 Feb 2003 23:21:43 -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	27 Feb 2003 23:21:43 -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,21 @@ 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)
+{
+  DerivedObjectPrivate *priv;
+
+  priv = DERIVED_OBJECT_GET_PRIVATE (dobject);
 
+  g_assert (priv);
+  g_assert ((gchar *)priv >= (gchar *)TEST_OBJECT_GET_PRIVATE (dobject) + sizeof (TestObjectPrivate));
+}
 
 /* --- main --- */
 int


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]