#include <string.h>
#include "gtype.h"
+#include "gtype-private.h"
#include "gtypeplugin.h"
#include "gvaluecollector.h"
#include "gbsearcharray.h"
-#include "gobjectalias.h"
#include "gatomicarray.h"
+#include "gobject_trace.h"
/**
else \
g_error ("%s()%s`%s'", _fname, _action, _tname); \
}G_STMT_END
-#define g_return_val_if_uninitialized(condition, init_function, return_value) G_STMT_START{ \
- if (!(condition)) \
- { \
- g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
- "%s: initialization assertion failed, use %s() prior to this function", \
- G_STRLOC, G_STRINGIFY (init_function)); \
- return (return_value); \
- } \
+#define g_return_val_if_type_system_uninitialized(return_value) G_STMT_START{ \
+ if (G_UNLIKELY (!static_quark_type_flags)) \
+ { \
+ g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
+ "%s: You forgot to call g_type_init()", \
+ G_STRLOC); \
+ return (return_value); \
+ } \
}G_STMT_END
#ifdef G_ENABLE_DEBUG
/* --- typedefs --- */
typedef struct _TypeNode TypeNode;
typedef struct _CommonData CommonData;
+typedef struct _BoxedData BoxedData;
typedef struct _IFaceData IFaceData;
typedef struct _ClassData ClassData;
typedef struct _InstanceData InstanceData;
GTypePlugin *plugin;
guint n_children; /* writable with lock */
guint n_supers : 8;
- guint _prot_n_prerequisites : 9;
+ guint n_prerequisites : 9;
guint is_classed : 1;
guint is_instantiatable : 1;
guint mutatable_check_cache : 1; /* combines some common path checks */
GData *global_gdata;
union {
GAtomicArray iface_entries; /* for !iface types */
- GType *prerequisistes;
+ GAtomicArray offsets;
} _prot;
+ GType *prerequisites;
GType supers[1]; /* flexible array */
};
#define NODE_FUNDAMENTAL_TYPE(node) (node->supers[node->n_supers])
#define NODE_NAME(node) (g_quark_to_string (node->qname))
#define NODE_REFCOUNT(node) ((guint) g_atomic_int_get ((int *) &(node)->ref_count))
+#define NODE_IS_BOXED(node) (NODE_FUNDAMENTAL_TYPE (node) == G_TYPE_BOXED)
#define NODE_IS_IFACE(node) (NODE_FUNDAMENTAL_TYPE (node) == G_TYPE_INTERFACE)
#define CLASSED_NODE_IFACES_ENTRIES(node) (&(node)->_prot.iface_entries)
#define CLASSED_NODE_IFACES_ENTRIES_LOCKED(node)(G_ATOMIC_ARRAY_GET_LOCKED(CLASSED_NODE_IFACES_ENTRIES((node)), IFaceEntries))
-#define IFACE_NODE_N_PREREQUISITES(node) ((node)->_prot_n_prerequisites)
-#define IFACE_NODE_PREREQUISITES(node) ((node)->_prot.prerequisistes)
+#define IFACE_NODE_N_PREREQUISITES(node) ((node)->n_prerequisites)
+#define IFACE_NODE_PREREQUISITES(node) ((node)->prerequisites)
#define iface_node_get_holders_L(node) ((IFaceHolder*) type_get_qdata_L ((node), static_quark_iface_holder))
#define iface_node_set_holders_W(node, holders) (type_set_qdata_W ((node), static_quark_iface_holder, (holders)))
#define iface_node_get_dependants_array_L(n) ((GType*) type_get_qdata_L ((n), static_quark_dependants_array))
GTypeValueTable *value_table;
};
+struct _BoxedData
+{
+ CommonData data;
+ GBoxedCopyFunc copy_func;
+ GBoxedFreeFunc free_func;
+};
+
struct _IFaceData
{
CommonData common;
GClassFinalizeFunc dflt_finalize;
gconstpointer dflt_data;
gpointer dflt_vtable;
- GAtomicArray offsets;
};
struct _ClassData
{
CommonData common;
guint16 class_size;
+ guint16 class_private_size;
int volatile init_state; /* atomic - g_type_class_ref reads it unlocked */
GBaseInitFunc class_init_base;
GBaseFinalizeFunc class_finalize_base;
{
CommonData common;
guint16 class_size;
+ guint16 class_private_size;
int volatile init_state; /* atomic - g_type_class_ref reads it unlocked */
GBaseInitFunc class_init_base;
GBaseFinalizeFunc class_finalize_base;
union _TypeData
{
CommonData common;
+ BoxedData boxed;
IFaceData iface;
ClassData class;
InstanceData instance;
pnode->children = g_renew (GType, pnode->children, pnode->n_children);
pnode->children[i] = type;
}
-
+
+ TRACE(GOBJECT_TYPE_NEW(name, node->supers[1], type));
+
node->plugin = plugin;
node->n_children = 0;
node->children = NULL;
return NULL;
G_ATOMIC_ARRAY_DO_TRANSACTION
- (&iface_node->data->iface.offsets, guint8,
+ (&iface_node->_prot.offsets, guint8,
entry = NULL;
offsets = transaction_data;
if (node->is_instantiatable) /* carefull, is_instantiatable is also is_classed */
{
+ TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
+
data = g_malloc0 (sizeof (InstanceData) + vtable_size);
if (vtable_size)
vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData));
* after the parent class has been initialized
*/
data->instance.private_size = 0;
+ data->instance.class_private_size = 0;
+ if (pnode)
+ data->instance.class_private_size = pnode->data->instance.class_private_size;
#ifdef DISABLE_MEM_POOLS
data->instance.n_preallocs = 0;
#else /* !DISABLE_MEM_POOLS */
}
else if (node->is_classed) /* only classed */
{
+ TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
+
data = g_malloc0 (sizeof (ClassData) + vtable_size);
if (vtable_size)
vtable = G_STRUCT_MEMBER_P (data, sizeof (ClassData));
data->class.class_finalize = info->class_finalize;
data->class.class_data = info->class_data;
data->class.class = NULL;
+ data->class.class_private_size = 0;
+ if (pnode)
+ data->class.class_private_size = pnode->data->class.class_private_size;
data->class.init_state = UNINITIALIZED;
}
else if (NODE_IS_IFACE (node))
data->iface.dflt_data = info->class_data;
data->iface.dflt_vtable = NULL;
}
+ else if (NODE_IS_BOXED (node))
+ {
+ data = g_malloc0 (sizeof (BoxedData) + vtable_size);
+ if (vtable_size)
+ vtable = G_STRUCT_MEMBER_P (data, sizeof (BoxedData));
+ }
else
{
data = g_malloc0 (sizeof (CommonData) + vtable_size);
{
guint8 *offsets;
- offsets = G_ATOMIC_ARRAY_GET_LOCKED (&iface_node->data->iface.offsets, guint8);
+ offsets = G_ATOMIC_ARRAY_GET_LOCKED (&iface_node->_prot.offsets, guint8);
if (offsets == NULL)
return TRUE;
int new_size, old_size;
int i;
- old_offsets = G_ATOMIC_ARRAY_GET_LOCKED (&iface_node->data->iface.offsets, guint8);
+ old_offsets = G_ATOMIC_ARRAY_GET_LOCKED (&iface_node->_prot.offsets, guint8);
if (old_offsets == NULL)
old_size = 0;
else
}
new_size = MAX (old_size, offset + 1);
- offsets = _g_atomic_array_copy (&iface_node->data->iface.offsets,
+ offsets = _g_atomic_array_copy (&iface_node->_prot.offsets,
0, new_size - old_size);
/* Mark new area as unused */
offsets[offset] = index + 1;
- _g_atomic_array_update (&iface_node->data->iface.offsets, offsets);
+ _g_atomic_array_update (&iface_node->_prot.offsets, offsets);
}
static void
/**
* g_type_interface_prerequisites:
* @interface_type: an interface type
- * @n_prerequisites: location to return the number of prerequisites, or %NULL
+ * @n_prerequisites: (out) (allow-none): location to return the number
+ * of prerequisites, or %NULL
*
* Returns the prerequisites of an interfaces type.
*
* Since: 2.2
*
- * Returns: a newly-allocated zero-terminated array of #GType containing
- * the prerequisites of @interface_type
+ * Returns: (array length=n_prerequisites) (transfer full): a
+ * newly-allocated zero-terminated array of #GType containing
+ * the prerequisites of @interface_type
*/
GType*
g_type_interface_prerequisites (GType interface_type,
{
GType prerequisite = IFACE_NODE_PREREQUISITES (iface)[i];
TypeNode *node = lookup_type_node_I (prerequisite);
- if (node->is_instantiatable &&
- (!inode || type_node_is_a_L (node, inode)))
- inode = node;
+ if (node->is_instantiatable)
+ {
+ if (!inode || type_node_is_a_L (node, inode))
+ inode = node;
+ }
else
types[n++] = NODE_TYPE (node);
}
}
/**
- * g_type_create_instance:
+ * g_type_create_instance: (skip)
* @type: An instantiatable type to create an instance for.
*
* Creates and initializes an instance of @type if @type is valid and
instance->g_class = class;
if (node->data->instance.instance_init)
node->data->instance.instance_init (instance, class);
-
+
+ TRACE(GOBJECT_OBJECT_NEW(instance, type));
+
return instance;
}
TypeNode *bnode, *pnode;
guint i;
+ /* Accessing data->class will work for instantiable types
+ * too because ClassData is a subset of InstanceData
+ */
g_assert (node->is_classed && node->data &&
node->data->class.class_size &&
!node->data->class.class &&
node->data->class.init_state == UNINITIALIZED);
-
- class = g_malloc0 (node->data->class.class_size);
+ if (node->data->class.class_private_size)
+ class = g_malloc0 (ALIGN_STRUCT (node->data->class.class_size) + node->data->class.class_private_size);
+ else
+ class = g_malloc0 (node->data->class.class_size);
node->data->class.class = class;
g_atomic_int_set (&node->data->class.init_state, BASE_CLASS_INIT);
TypeNode *pnode = lookup_type_node_I (pclass->g_type);
memcpy (class, pclass, pnode->data->class.class_size);
+ memcpy (G_STRUCT_MEMBER_P (class, ALIGN_STRUCT (node->data->class.class_size)), G_STRUCT_MEMBER_P (pclass, ALIGN_STRUCT (pnode->data->class.class_size)), pnode->data->class.class_private_size);
if (node->is_instantiatable)
{
}
/**
- * g_type_add_class_cache_func:
+ * g_type_add_class_cache_func: (skip)
* @cache_data: data to be passed to @cache_func
* @cache_func: a #GTypeClassCacheFunc
*
}
/**
- * g_type_remove_class_cache_func:
+ * g_type_remove_class_cache_func: (skip)
* @cache_data: data that was given when adding @cache_func
* @cache_func: a #GTypeClassCacheFunc
*
/**
- * g_type_add_interface_check:
+ * g_type_add_interface_check: (skip)
* @check_data: data to pass to @check_func
* @check_func: function to be called after each interface
* is initialized.
}
/**
- * g_type_remove_interface_check:
+ * g_type_remove_interface_check: (skip)
* @check_data: callback data passed to g_type_add_interface_check()
* @check_func: callback function passed to g_type_add_interface_check()
*
{
TypeNode *node;
- g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, 0);
+ g_return_val_if_type_system_uninitialized (0);
g_return_val_if_fail (type_id > 0, 0);
g_return_val_if_fail (type_name != NULL, 0);
g_return_val_if_fail (info != NULL, 0);
}
/**
- * g_type_register_static_simple:
+ * g_type_register_static_simple: (skip)
* @parent_type: Type from which this type will be derived.
* @type_name: 0-terminated string used as the name of the new type.
* @class_size: Size of the class structure (see #GTypeInfo)
TypeNode *pnode, *node;
GType type = 0;
- g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, 0);
+ g_return_val_if_type_system_uninitialized (0);
g_return_val_if_fail (parent_type > 0, 0);
g_return_val_if_fail (type_name != NULL, 0);
g_return_val_if_fail (info != NULL, 0);
TypeNode *pnode, *node;
GType type;
- g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, 0);
+ g_return_val_if_type_system_uninitialized (0);
g_return_val_if_fail (parent_type > 0, 0);
g_return_val_if_fail (type_name != NULL, 0);
g_return_val_if_fail (plugin != NULL, 0);
* @type. This function will demand-create the class if it doesn't
* exist already.
*
- * Returns: The #GTypeClass structure for the given type ID.
+ * Returns: (type GObject.TypeClass) (transfer none): The #GTypeClass
+ * structure for the given type ID.
*/
gpointer
g_type_class_ref (GType type)
/**
* g_type_class_unref:
- * @g_class: The #GTypeClass structure to unreference.
+ * @g_class: (type GObject.TypeClass): The #GTypeClass structure to
+ * unreference.
*
* Decrements the reference count of the class structure being passed in.
* Once the last reference count of a class has been released, classes
}
/**
- * g_type_class_unref_uncached:
- * @g_class: The #GTypeClass structure to unreference.
+ * g_type_class_unref_uncached: (skip)
+ * @g_class: (type GObject.TypeClass): The #GTypeClass structure to
+ * unreference.
*
* A variant of g_type_class_unref() for use in #GTypeClassCacheFunc
* implementations. It unreferences a class without consulting the chain
* may return %NULL if the class of the type passed in does not currently
* exist (hasn't been referenced before).
*
- * Returns: The #GTypeClass structure for the given type ID or %NULL
- * if the class does not currently exist.
+ * Returns: (type GObject.TypeClass) (transfer none): The #GTypeClass
+ * structure for the given type ID or %NULL if the class does not
+ * currently exist.
*/
gpointer
g_type_class_peek (GType type)
gpointer class;
node = lookup_type_node_I (type);
- G_READ_LOCK (&type_rw_lock);
- if (node && node->is_classed && node->data &&
+ if (node && node->is_classed && NODE_REFCOUNT (node) &&
g_atomic_int_get (&node->data->class.init_state) == INITIALIZED)
/* ref_count _may_ be 0 */
class = node->data->class.class;
else
class = NULL;
- G_READ_UNLOCK (&type_rw_lock);
return class;
}
* static types.
*
* Since: 2.4
- * Returns: The #GTypeClass structure for the given type ID or %NULL
- * if the class does not currently exist or is dynamically loaded.
+ * Returns: (type GObject.TypeClass) (transfer none): The #GTypeClass
+ * structure for the given type ID or %NULL if the class does not
+ * currently exist or is dynamically loaded.
*/
gpointer
g_type_class_peek_static (GType type)
gpointer class;
node = lookup_type_node_I (type);
- G_READ_LOCK (&type_rw_lock);
- if (node && node->is_classed && node->data &&
+ if (node && node->is_classed && NODE_REFCOUNT (node) &&
/* peek only static types: */ node->plugin == NULL &&
g_atomic_int_get (&node->data->class.init_state) == INITIALIZED)
/* ref_count _may_ be 0 */
class = node->data->class.class;
else
class = NULL;
- G_READ_UNLOCK (&type_rw_lock);
return class;
}
/**
* g_type_class_peek_parent:
- * @g_class: The #GTypeClass structure to retrieve the parent class for.
+ * @g_class: (type GObject.TypeClass): The #GTypeClass structure to
+ * retrieve the parent class for.
*
* This is a convenience function often needed in class initializers.
* It returns the class structure of the immediate parent type of the
* g_type_class_peek (g_type_parent (G_TYPE_FROM_CLASS (g_class)));
* </programlisting>
*
- * Returns: The parent class of @g_class.
+ * Returns: (type GObject.TypeClass) (transfer none): The parent class
+ * of @g_class.
*/
gpointer
g_type_class_peek_parent (gpointer g_class)
/**
* g_type_interface_peek:
- * @instance_class: A #GTypeClass structure.
+ * @instance_class: (type GObject.TypeClass): A #GTypeClass structure.
* @iface_type: An interface ID which this class conforms to.
*
* Returns the #GTypeInterface structure of an interface to which the
* passed in class conforms.
*
- * Returns: The GTypeInterface structure of iface_type if implemented
- * by @instance_class, %NULL otherwise
+ * Returns: (type GObject.TypeInterface) (transfer none): The GTypeInterface
+ * structure of iface_type if implemented by @instance_class, %NULL
+ * otherwise
*/
gpointer
g_type_interface_peek (gpointer instance_class,
/**
* g_type_interface_peek_parent:
- * @g_iface: A #GTypeInterface structure.
+ * @g_iface: (type GObject.TypeInterface): A #GTypeInterface structure.
*
* Returns the corresponding #GTypeInterface structure of the parent type
* of the instance type to which @g_iface belongs. This is useful when
* deriving the implementation of an interface from the parent type and
* then possibly overriding some methods.
*
- * Returns: The corresponding #GTypeInterface structure of the parent
- * type of the instance type to which @g_iface belongs, or
- * %NULL if the parent type doesn't conform to the interface.
+ * Returns: (transfer none) (type GObject.TypeInterface): The
+ * corresponding #GTypeInterface structure of the parent type of the
+ * instance type to which @g_iface belongs, or %NULL if the parent
+ * type doesn't conform to the interface.
*/
gpointer
g_type_interface_peek_parent (gpointer g_iface)
*
* Since: 2.4
*
- * Returns: the default vtable for the interface; call
- * g_type_default_interface_unref() when you are done using
- * the interface.
+ * Returns: (type GObject.TypeInterface) (transfer none): the default
+ * vtable for the interface; call g_type_default_interface_unref()
+ * when you are done using the interface.
*/
gpointer
g_type_default_interface_ref (GType g_type)
*
* Since: 2.4
*
- * Returns: the default vtable for the interface, or %NULL
- * if the type is not currently in use.
+ * Returns: (type GObject.TypeInterface) (transfer none): the default
+ * vtable for the interface, or %NULL if the type is not currently in
+ * use.
*/
gpointer
g_type_default_interface_peek (GType g_type)
gpointer vtable;
node = lookup_type_node_I (g_type);
- G_READ_LOCK (&type_rw_lock);
- if (node && NODE_IS_IFACE (node) && node->data && node->data->iface.dflt_vtable)
+ if (node && NODE_IS_IFACE (node) && NODE_REFCOUNT (node))
vtable = node->data->iface.dflt_vtable;
else
vtable = NULL;
- G_READ_UNLOCK (&type_rw_lock);
return vtable;
}
/**
* g_type_default_interface_unref:
- * @g_iface: the default vtable structure for a interface, as
- * returned by g_type_default_interface_ref()
+ * @g_iface: (type GObject.TypeInterface): the default vtable
+ * structure for a interface, as returned by
+ * g_type_default_interface_ref()
*
* Decrements the reference count for the type corresponding to the
* interface default vtable @g_iface. If the type is dynamic, then
{
TypeNode *node;
- g_return_val_if_uninitialized (static_quark_type_flags, g_type_init, NULL);
+ g_return_val_if_type_system_uninitialized (NULL);
node = lookup_type_node_I (type);
/**
* g_type_children:
* @type: The parent type.
- * @n_children: Optional #guint pointer to contain the number of child types.
+ * @n_children: (out) (allow-none): Optional #guint pointer to contain
+ * the number of child types.
*
* Return a newly allocated and 0-terminated array of type IDs, listing the
* child types of @type. The return value has to be g_free()ed after use.
*
- * Returns: Newly allocated and 0-terminated array of child types.
+ * Returns: (array length=n_children) (transfer full): Newly allocated
+ * and 0-terminated array of child types.
*/
GType*
g_type_children (GType type,
/**
* g_type_interfaces:
* @type: The type to list interface types for.
- * @n_interfaces: Optional #guint pointer to contain the number of
- * interface types.
+ * @n_interfaces: (out) (allow-none): Optional #guint pointer to
+ * contain the number of interface types.
*
* Return a newly allocated and 0-terminated array of type IDs, listing the
* interface types that @type conforms to. The return value has to be
* g_free()ed after use.
*
- * Returns: Newly allocated and 0-terminated array of interface types.
+ * Returns: (array length=n_interfaces) (transfer full): Newly
+ * allocated and 0-terminated array of interface types.
*/
GType*
g_type_interfaces (GType type,
* Obtains data which has previously been attached to @type
* with g_type_set_qdata().
*
- * Returns: the data, or %NULL if no data was found
+ * Returns: (transfer none): the data, or %NULL if no data was found
*/
gpointer
g_type_get_qdata (GType type,
/**
* g_type_query:
* @type: the #GType value of a static, classed type.
- * @query: A user provided structure that is filled in with constant values
- * upon success.
+ * @query: (out caller-allocates): A user provided structure that is
+ * filled in with constant values upon success.
*
* Queries the type system for information about a specific type.
* This function will fill in a user-provided structure to hold
* Returns the #GTypePlugin structure for @type or
* %NULL if @type does not have a #GTypePlugin structure.
*
- * Returns: The corresponding plugin if @type is a dynamic type,
- * %NULL otherwise.
+ * Returns: (transfer none): The corresponding plugin if @type is a
+ * dynamic type, %NULL otherwise.
*/
GTypePlugin*
g_type_get_plugin (GType type)
* @interface_type has not been added to @instance_type or does not
* have a #GTypePlugin structure. See g_type_add_interface_dynamic().
*
- * Returns: the #GTypePlugin for the dynamic interface @interface_type
- * of @instance_type.
+ * Returns: (transfer none): the #GTypePlugin for the dynamic
+ * interface @interface_type of @instance_type.
*/
GTypePlugin*
g_type_interface_get_plugin (GType instance_type,
}
/**
- * g_type_value_table_peek:
+ * g_type_value_table_peek: (skip)
* @type: A #GType value.
*
* Returns the location of the #GTypeValueTable associated with @type.
GTypeValueTable *vtable = NULL;
TypeNode *node = lookup_type_node_I (type);
gboolean has_refed_data, has_table;
- TypeData *data;
- /* speed up common code path, we're not 100% safe here,
- * but we should only get called with referenced types anyway
- */
- data = node ? node->data : NULL;
- if (node && node->mutatable_check_cache)
- return data->common.value_table;
+ if (node && NODE_REFCOUNT (node) && node->mutatable_check_cache)
+ return node->data->common.value_table;
G_READ_LOCK (&type_rw_lock);
}
+/* --- private api for gboxed.c --- */
+gpointer
+_g_type_boxed_copy (GType type, gpointer value)
+{
+ TypeNode *node = lookup_type_node_I (type);
+
+ return node->data->boxed.copy_func (value);
+}
+
+void
+_g_type_boxed_free (GType type, gpointer value)
+{
+ TypeNode *node = lookup_type_node_I (type);
+
+ node->data->boxed.free_func (value);
+}
+
+void
+_g_type_boxed_init (GType type,
+ GBoxedCopyFunc copy_func,
+ GBoxedFreeFunc free_func)
+{
+ TypeNode *node = lookup_type_node_I (type);
+
+ node->data->boxed.copy_func = copy_func;
+ node->data->boxed.free_func = free_func;
+}
+
/* --- initialization --- */
/**
* g_type_init_with_debug_flags:
GTypeInfo info;
TypeNode *node;
volatile GType votype;
-
+
+#ifdef G_THREADS_ENABLED
+ if (!g_thread_get_initialized())
+ g_thread_init (NULL);
+#endif
+
G_LOCK (type_init_lock);
G_WRITE_LOCK (&type_rw_lock);
* to initialize the type system and assorted other code portions
* (such as the various fundamental type implementations or the signal
* system).
+ *
+ * Since version 2.24 this also initializes the thread system
*/
void
g_type_init (void)
* @g_class: class structure for an instantiatable type
* @private_size: size of private structure.
*
- * Registers a private structure for an instantiatable type;
- * when an object is allocated, the private structures for
+ * Registers a private structure for an instantiatable type.
+ *
+ * When an object is allocated, the private structures for
* the type 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.
+ * structures.
+ *
+ * Note that the accumulated size of the private structures of
+ * a type and all its parent types cannot excced 64kB.
+ *
+ * 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.
+ * type's class_init() function.
*
* |[
+ * typedef struct _MyObject MyObject;
* typedef struct _MyObjectPrivate MyObjectPrivate;
*
+ * struct _MyObject {
+ * GObject parent;
+ *
+ * MyObjectPrivate *priv;
+ * };
+ *
* 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 void
+ * my_object_init (MyObject *my_object)
+ * {
+ * my_object->priv = G_TYPE_INSTANCE_GET_PRIVATE (my_object,
+ * MY_TYPE_OBJECT,
+ * MyObjectPrivate);
+ * }
+ *
* static int
* my_object_get_some_field (MyObject *my_object)
* {
- * MyObjectPrivate *priv = MY_OBJECT_GET_PRIVATE (my_object);
+ * MyObjectPrivate *priv = my_object->priv;
*
* return priv->some_field;
* }
gsize offset;
g_return_if_fail (private_size > 0);
+ g_return_if_fail (private_size <= 0xffff);
if (!node || !node->is_instantiatable || !node->data || node->data->class.class != g_class)
{
G_WRITE_LOCK (&type_rw_lock);
offset = ALIGN_STRUCT (node->data->instance.private_size);
+
+ g_assert (offset + private_size <= 0xffff);
+
node->data->instance.private_size = offset + private_size;
G_WRITE_UNLOCK (&type_rw_lock);
return G_STRUCT_MEMBER_P (instance, offset);
}
-#define __G_TYPE_C__
-#include "gobjectaliasdef.c"
+/**
+ * g_type_add_class_private:
+ * @class_type: GType of an classed type.
+ * @private_size: size of private structure.
+ *
+ * Registers a private class structure for a classed type;
+ * when the class is allocated, the private structures for
+ * the class 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 get_type() function after the type is registered.
+ * The private structure can be retrieved using the
+ * G_TYPE_CLASS_GET_PRIVATE() macro.
+ *
+ * Since: 2.24
+ */
+void
+g_type_add_class_private (GType class_type,
+ gsize private_size)
+{
+ TypeNode *node = lookup_type_node_I (class_type);
+ gsize offset;
+
+ g_return_if_fail (private_size > 0);
+
+ if (!node || !node->is_classed || !node->data)
+ {
+ g_warning ("cannot add class private field to invalid type '%s'",
+ type_descriptive_name_I (class_type));
+ return;
+ }
+
+ if (NODE_PARENT_TYPE (node))
+ {
+ TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
+ if (node->data->class.class_private_size != pnode->data->class.class_private_size)
+ {
+ g_warning ("g_type_add_class_private() called multiple times for the same type");
+ return;
+ }
+ }
+
+ G_WRITE_LOCK (&type_rw_lock);
+
+ offset = ALIGN_STRUCT (node->data->class.class_private_size);
+ node->data->class.class_private_size = offset + private_size;
+
+ G_WRITE_UNLOCK (&type_rw_lock);
+}
+
+gpointer
+g_type_class_get_private (GTypeClass *klass,
+ GType private_type)
+{
+ TypeNode *class_node;
+ TypeNode *private_node;
+ TypeNode *parent_node;
+ gsize offset;
+
+ g_return_val_if_fail (klass != NULL, NULL);
+
+ class_node = lookup_type_node_I (klass->g_type);
+ if (G_UNLIKELY (!class_node || !class_node->is_classed))
+ {
+ g_warning ("class of invalid type `%s'",
+ type_descriptive_name_I (klass->g_type));
+ return NULL;
+ }
+
+ private_node = lookup_type_node_I (private_type);
+ if (G_UNLIKELY (!private_node || !NODE_IS_ANCESTOR (private_node, class_node)))
+ {
+ g_warning ("attempt to retrieve private data for invalid type '%s'",
+ type_descriptive_name_I (private_type));
+ return NULL;
+ }
+
+ offset = ALIGN_STRUCT (class_node->data->class.class_size);
+
+ if (NODE_PARENT_TYPE (private_node))
+ {
+ parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node));
+ g_assert (parent_node->data && NODE_REFCOUNT (parent_node) > 0);
+
+ if (G_UNLIKELY (private_node->data->class.class_private_size == parent_node->data->class.class_private_size))
+ {
+ g_warning ("g_type_instance_get_class_private() requires a prior call to g_type_class_add_class_private()");
+ return NULL;
+ }
+
+ offset += ALIGN_STRUCT (parent_node->data->class.class_private_size);
+ }
+
+ return G_STRUCT_MEMBER_P (klass, offset);
+}