Re: Instance private data



>	I've attached a patch that implements g_type_get_private_offset(). The
> only worry I can see about this is that it might encourage people to
> start poking in the private structures - but I don't think we've had any
> cases of people doing that with the 'priv' pointers ....

I think it's a reasonable addition ... one thing though is that you
are relying on only one private structure being added for each type
(that is, that the private data offset can be found from the private
data offset of the parent), something that my patch didn't require.

I've added a check that g_type_add_private() is called no more than
once to the patch.

> 	Oh, the patch adds some tests of this to testgobject was well, which
> may be useful even if you don't want get_private_offset().

Cool, thanks.

> >  d) As long as people are required to call g_type_add_private() in their
> >     class_init(), it should work fine for dynamically loaded
> >     types. My patch doesn't try to catch calling g_type_add_private()
> >     at the wrong time, but I really don't imagine that people will
> >     try to call it elsewhere.
> 
> 	Hmm ... my initial foolish instinct was to do it in get_type() - so
> maybe a check might be worthwhile ...

Yeah, probably partially caused by the name 'g_type_add_private' being
similar to g_type_add_interface(). Don't know a better name though.

I've added a check for g_type_add_private() being called prior to
class_init() time as well.

Tim - if I move the docs to the template files, is this OK to commit?

Regards,
                                            Owen


Index: gobject.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gobject.c,v
retrieving revision 1.57
diff -u -p -r1.57 gobject.c
--- gobject.c	7 Feb 2003 22:04:24 -0000	1.57
+++ gobject.c	13 Feb 2003 21:19:33 -0000
@@ -192,11 +192,15 @@ static void
 g_object_base_class_init (GObjectClass *class)
 {
   GObjectClass *pclass = g_type_class_peek_parent (class);
+  GTypeQuery query;
 
   /* reset instance specific fields and methods that don't get inherited */
   class->construct_properties = pclass ? g_slist_copy (pclass->construct_properties) : NULL;
   class->get_property = NULL;
   class->set_property = NULL;
+
+  g_type_query (G_TYPE_FROM_CLASS (class), &query);
+  class->private_base = query.instance_size;
 }
 
 static void
Index: gobject.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gobject.h,v
retrieving revision 1.26
diff -u -p -r1.26 gobject.h
--- gobject.h	21 Mar 2002 00:34:04 -0000	1.26
+++ gobject.h	13 Feb 2003 21:19:33 -0000
@@ -44,6 +44,10 @@ G_BEGIN_DECLS
 #define G_OBJECT_CLASS_NAME(class)  (g_type_name (G_OBJECT_CLASS_TYPE (class)))
 #define G_VALUE_HOLDS_OBJECT(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_OBJECT))
 
+#define G_OBJECT_GET_PRIVATE(private_type, object, offset)	\
+ ((private_type *)(((guchar *) (object)) +			\
+	           G_OBJECT_GET_CLASS (object)->private_base +	\
+	           (offset)))
 
 /* --- typedefs & structures --- */
 typedef struct _GObject                  GObject;
@@ -98,8 +102,11 @@ struct  _GObjectClass
   /* signals */
   void	     (*notify)			(GObject	*object,
 					 GParamSpec	*pspec);
+
+  gsize      private_base;
+  
   /* padding */
-  gpointer	pdummy[8];
+  gpointer	pdummy[7];
 };
 struct _GObjectConstructParam
 {
Index: gtype.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.c,v
retrieving revision 1.59
diff -u -p -r1.59 gtype.c
--- gtype.c	7 Feb 2003 22:04:24 -0000	1.59
+++ gtype.c	13 Feb 2003 21:19:34 -0000
@@ -229,6 +229,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 +910,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 */
@@ -1371,14 +1379,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 *
+							  ((node->data->instance.instance_size + node->data->instance.private_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 (node->data->instance.instance_size + node->data->instance.private_size);	/* fine without read lock */
   for (i = node->n_supers; i > 0; i--)
     {
       TypeNode *pnode;
@@ -1424,7 +1432,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, node->data->instance.instance_size + node->data->instance.private_size);	/* debugging hack */
 #endif  
   if (node->data->instance.n_preallocs)
     {
@@ -1527,7 +1535,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 +3032,125 @@ void 
 g_type_init (void)
 {
   g_type_init_with_debug_flags (0);
+}
+
+/* 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)
+
+/**
+ * g_type_add_private:
+ * @instance_type: an instantiatable type
+ * @private_size: size of private structure.
+ * 
+ * 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 return value can be
+ * used subsequently to retrieve the private structure.
+ * 
+ * Return value: the offset to add to the object location,
+ *   along with the size of the public instance, to get
+ *   the private structure. See the G_OBJECT_GET_PRIVATE()
+ *   macro for the normal way that this offset is used.
+ **/
+gsize
+g_type_add_private (GType instance_type,
+		    gsize private_size)
+{
+  TypeNode *node = lookup_type_node_I (instance_type);
+  gsize result;
+
+  if (!node || !node->is_instantiatable)
+    {
+      g_warning ("cannot add private field to non-instantiatable type '%s'",
+		 type_descriptive_name_I (instance_type));
+      return 0;
+    }
+
+  if (!node->data->instance.class)
+    {
+      g_warning ("g_type_add_private() must be called from within class_init");
+      return 0;
+    }
+
+  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 0;
+	}
+    }
+  
+  G_WRITE_LOCK (&type_rw_lock);
+
+  if (node->data && node->data->common.ref_count > 0)
+    {
+      result = ALIGN_STRUCT (node->data->instance.private_size);
+      
+      node->data->instance.private_size = result + private_size;
+    }
+  else
+    {
+      g_warning ("g_type_add_private() called on unreferenced type '%s'\n"
+		 "should be called in class_init() function.",
+		 type_descriptive_name_I (instance_type));
+      result = 0;
+    }
+  
+  G_WRITE_UNLOCK (&type_rw_lock);
+
+  return result;
+}
+
+/**
+ * g_type_get_private_offset:
+ * @instance_type: an instantiatable type
+ * 
+ * Retrieves the offset of the type's private structure
+ * from the end of an instance of that type's structure.
+ * This is the same as the return value from
+ * g_type_add_private().
+ * 
+ * Return value: the offset to add to the object location,
+ *   along with the size of the public instance, to get
+ *   the private structure. See the G_OBJECT_GET_PRIVATE()
+ *   macro for the normal way that this offset is used.
+ **/
+gsize
+g_type_get_private_offset (GType instance_type)
+{
+  TypeNode *node = lookup_type_node_I (instance_type);
+  gsize result;
+
+  if (!node || !node->is_instantiatable)
+    {
+      g_warning ("cannot retrieve private offset for non-instantiatable type '%s'",
+		 type_descriptive_name_I (instance_type));
+      return 0;
+    }
+
+  node = lookup_type_node_I (NODE_PARENT_TYPE (node));
+
+  g_assert (node->data && node->data->common.ref_count);
+
+  G_READ_LOCK (&type_rw_lock);
+
+  result = node->data->instance.private_size;
+
+  G_READ_UNLOCK (&type_rw_lock);
+    
+  return ALIGN_STRUCT (result);
 }
Index: gtype.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.h,v
retrieving revision 1.47
diff -u -p -r1.47 gtype.h
--- gtype.h	3 Dec 2002 23:54:54 -0000	1.47
+++ gtype.h	13 Feb 2003 21:19:34 -0000
@@ -297,6 +297,9 @@ void  g_type_interface_add_prerequisite 
 					 GType			     prerequisite_type);
 GType *g_type_interface_prerequisites   (GType                       interface_type,
 					 guint                       *n_prerequisites);
+gsize g_type_add_private                (GType                       instance_type,
+					 gsize                       private_size);
+gsize g_type_get_private_offset         (GType                       instance_type);
 
 
 /* --- protected (for fundamental type implementations) --- */
Index: testgobject.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/testgobject.c,v
retrieving revision 1.6
diff -u -p -r1.6 testgobject.c
--- testgobject.c	12 Oct 2002 20:04:58 -0000	1.6
+++ testgobject.c	13 Feb 2003 21:19:34 -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_OBJECT_GET_PRIVATE (TestObjectPrivate, (o), test_object_private_offset))
+typedef struct _TestObject        TestObject;
+typedef struct _TestObjectClass   TestObjectClass;
+typedef struct _TestObjectPrivate TestObjectPrivate;
 struct _TestObject
 {
   GObject parent_instance;
@@ -140,6 +142,12 @@ struct _TestObjectClass
 			 TestIface  *iface_object,
 			 gpointer    tdata);
 };
+struct _TestObjectPrivate
+{
+  int     dummy1;
+  gdouble dummy2;
+};
+static gsize test_object_private_offset = 0;
 static void	test_object_class_init	(TestObjectClass	*class);
 static void	test_object_init	(TestObject		*tobject);
 static gboolean	test_signal_accumulator	(GSignalInvocationHint	*ihint,
@@ -190,10 +198,17 @@ 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);
+
+  test_object_private_offset = g_type_add_private (G_OBJECT_CLASS_TYPE (class), sizeof (TestObjectPrivate));
 }
 static void
 test_object_init (TestObject *tobject)
 {
+  TestObjectPrivate *priv;
+
+  priv = TEST_OBJECT_GET_PRIVATE (tobject);
+
+  g_assert (g_type_get_private_offset (G_OBJECT_TYPE (tobject)) == test_object_private_offset);
 }
 static gboolean
 test_signal_accumulator (GSignalInvocationHint *ihint,
@@ -274,8 +289,17 @@ 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_OBJECT_GET_PRIVATE (DerivedObjectPrivate, (o), derived_object_private_offset))
+typedef struct _TestObject           DerivedObject;
+typedef struct _TestObjectClass      DerivedObjectClass;
+typedef struct _DerivedObjectPrivate DerivedObjectPrivate;
+struct _DerivedObjectPrivate
+{
+  char dummy;
+};
+static gsize derived_object_private_offset = 0;
+static void derived_object_class_init (DerivedObjectClass *class);
+static void derived_object_init       (DerivedObject      *dobject);
 GType
 derived_object_get_type (void)
 {
@@ -288,12 +312,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 +327,20 @@ derived_object_get_type (void)
 
   return derived_object_type;
 }
+static void
+derived_object_class_init (DerivedObjectClass *class)
+{
+  derived_object_private_offset = g_type_add_private (G_OBJECT_CLASS_TYPE (class), sizeof (DerivedObjectPrivate));
+}
+static void
+derived_object_init (DerivedObject *dobject)
+{
+  DerivedObjectPrivate *priv;
+
+  priv = DERIVED_OBJECT_GET_PRIVATE (dobject);
 
+  g_assert (g_type_get_private_offset (G_OBJECT_TYPE (dobject)) == derived_object_private_offset);
+}
 
 /* --- main --- */
 int


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