1 | /* GObject - GLib Type, Object, Parameter and Signal Library |
2 | * Copyright (C) 1998-1999, 2000-2001 Tim Janik and Red Hat, Inc. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General |
15 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * MT safe |
20 | */ |
21 | |
22 | #include "config.h" |
23 | |
24 | #include "../glib/gvalgrind.h" |
25 | #include <string.h> |
26 | |
27 | #include "gtype.h" |
28 | #include "gtype-private.h" |
29 | #include "gtypeplugin.h" |
30 | #include "gvaluecollector.h" |
31 | #include "gatomicarray.h" |
32 | #include "gobject_trace.h" |
33 | |
34 | #include "glib-private.h" |
35 | #include "gconstructor.h" |
36 | |
37 | #ifdef G_OS_WIN32 |
38 | #include <windows.h> |
39 | #endif |
40 | |
41 | #ifdef G_ENABLE_DEBUG |
42 | #define IF_DEBUG(debug_type) if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) |
43 | #endif |
44 | |
45 | /** |
46 | * SECTION:gtype |
47 | * @short_description: The GLib Runtime type identification and |
48 | * management system |
49 | * @title:Type Information |
50 | * |
51 | * The GType API is the foundation of the GObject system. It provides the |
52 | * facilities for registering and managing all fundamental data types, |
53 | * user-defined object and interface types. |
54 | * |
55 | * For type creation and registration purposes, all types fall into one of |
56 | * two categories: static or dynamic. Static types are never loaded or |
57 | * unloaded at run-time as dynamic types may be. Static types are created |
58 | * with g_type_register_static() that gets type specific information passed |
59 | * in via a #GTypeInfo structure. |
60 | * |
61 | * Dynamic types are created with g_type_register_dynamic() which takes a |
62 | * #GTypePlugin structure instead. The remaining type information (the |
63 | * #GTypeInfo structure) is retrieved during runtime through #GTypePlugin |
64 | * and the g_type_plugin_*() API. |
65 | * |
66 | * These registration functions are usually called only once from a |
67 | * function whose only purpose is to return the type identifier for a |
68 | * specific class. Once the type (or class or interface) is registered, |
69 | * it may be instantiated, inherited, or implemented depending on exactly |
70 | * what sort of type it is. |
71 | * |
72 | * There is also a third registration function for registering fundamental |
73 | * types called g_type_register_fundamental() which requires both a #GTypeInfo |
74 | * structure and a #GTypeFundamentalInfo structure but it is seldom used |
75 | * since most fundamental types are predefined rather than user-defined. |
76 | * |
77 | * Type instance and class structs are limited to a total of 64 KiB, |
78 | * including all parent types. Similarly, type instances' private data |
79 | * (as created by G_ADD_PRIVATE()) are limited to a total of |
80 | * 64 KiB. If a type instance needs a large static buffer, allocate it |
81 | * separately (typically by using #GArray or #GPtrArray) and put a pointer |
82 | * to the buffer in the structure. |
83 | * |
84 | * As mentioned in the [GType conventions][gtype-conventions], type names must |
85 | * be at least three characters long. There is no upper length limit. The first |
86 | * character must be a letter (a–z or A–Z) or an underscore (‘_’). Subsequent |
87 | * characters can be letters, numbers or any of ‘-_+’. |
88 | */ |
89 | |
90 | |
91 | /* NOTE: some functions (some internal variants and exported ones) |
92 | * invalidate data portions of the TypeNodes. if external functions/callbacks |
93 | * are called, pointers to memory maintained by TypeNodes have to be looked up |
94 | * again. this affects most of the struct TypeNode fields, e.g. ->children or |
95 | * CLASSED_NODE_IFACES_ENTRIES() respectively IFACE_NODE_PREREQUISITES() (but |
96 | * not ->supers[]), as all those memory portions can get realloc()ed during |
97 | * callback invocation. |
98 | * |
99 | * LOCKING: |
100 | * lock handling issues when calling static functions are indicated by |
101 | * uppercase letter postfixes, all static functions have to have |
102 | * one of the below postfixes: |
103 | * - _I: [Indifferent about locking] |
104 | * function doesn't care about locks at all |
105 | * - _U: [Unlocked invocation] |
106 | * no read or write lock has to be held across function invocation |
107 | * (locks may be acquired and released during invocation though) |
108 | * - _L: [Locked invocation] |
109 | * a write lock or more than 0 read locks have to be held across |
110 | * function invocation |
111 | * - _W: [Write-locked invocation] |
112 | * a write lock has to be held across function invocation |
113 | * - _Wm: [Write-locked invocation, mutatable] |
114 | * like _W, but the write lock might be released and reacquired |
115 | * during invocation, watch your pointers |
116 | * - _WmREC: [Write-locked invocation, mutatable, recursive] |
117 | * like _Wm, but also acquires recursive mutex class_init_rec_mutex |
118 | */ |
119 | |
120 | #ifdef LOCK_DEBUG |
121 | #define G_READ_LOCK(rw_lock) do { g_printerr (G_STRLOC ": readL++\n"); g_rw_lock_reader_lock (rw_lock); } while (0) |
122 | #define G_READ_UNLOCK(rw_lock) do { g_printerr (G_STRLOC ": readL--\n"); g_rw_lock_reader_unlock (rw_lock); } while (0) |
123 | #define G_WRITE_LOCK(rw_lock) do { g_printerr (G_STRLOC ": writeL++\n"); g_rw_lock_writer_lock (rw_lock); } while (0) |
124 | #define G_WRITE_UNLOCK(rw_lock) do { g_printerr (G_STRLOC ": writeL--\n"); g_rw_lock_writer_unlock (rw_lock); } while (0) |
125 | #else |
126 | #define G_READ_LOCK(rw_lock) g_rw_lock_reader_lock (rw_lock) |
127 | #define G_READ_UNLOCK(rw_lock) g_rw_lock_reader_unlock (rw_lock) |
128 | #define G_WRITE_LOCK(rw_lock) g_rw_lock_writer_lock (rw_lock) |
129 | #define G_WRITE_UNLOCK(rw_lock) g_rw_lock_writer_unlock (rw_lock) |
130 | #endif |
131 | #define INVALID_RECURSION(func, arg, type_name) G_STMT_START{ \ |
132 | static const gchar _action[] = " invalidly modified type "; \ |
133 | gpointer _arg = (gpointer) (arg); const gchar *_tname = (type_name), *_fname = (func); \ |
134 | if (_arg) \ |
135 | g_error ("%s(%p)%s'%s'", _fname, _arg, _action, _tname); \ |
136 | else \ |
137 | g_error ("%s()%s'%s'", _fname, _action, _tname); \ |
138 | }G_STMT_END |
139 | #define g_assert_type_system_initialized() \ |
140 | g_assert (static_quark_type_flags) |
141 | |
142 | #define TYPE_FUNDAMENTAL_FLAG_MASK (G_TYPE_FLAG_CLASSED | \ |
143 | G_TYPE_FLAG_INSTANTIATABLE | \ |
144 | G_TYPE_FLAG_DERIVABLE | \ |
145 | G_TYPE_FLAG_DEEP_DERIVABLE) |
146 | #define TYPE_FLAG_MASK (G_TYPE_FLAG_ABSTRACT | G_TYPE_FLAG_VALUE_ABSTRACT) |
147 | #define SIZEOF_FUNDAMENTAL_INFO ((gssize) MAX (MAX (sizeof (GTypeFundamentalInfo), \ |
148 | sizeof (gpointer)), \ |
149 | sizeof (glong))) |
150 | |
151 | /* The 2*sizeof(size_t) alignment here is borrowed from |
152 | * GNU libc, so it should be good most everywhere. |
153 | * It is more conservative than is needed on some 64-bit |
154 | * platforms, but ia64 does require a 16-byte alignment. |
155 | * The SIMD extensions for x86 and ppc32 would want a |
156 | * larger alignment than this, but we don't need to |
157 | * do better than malloc. |
158 | */ |
159 | #define STRUCT_ALIGNMENT (2 * sizeof (gsize)) |
160 | #define ALIGN_STRUCT(offset) \ |
161 | ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT) |
162 | |
163 | |
164 | /* --- typedefs --- */ |
165 | typedef struct _TypeNode TypeNode; |
166 | typedef struct _CommonData CommonData; |
167 | typedef struct _BoxedData BoxedData; |
168 | typedef struct _IFaceData IFaceData; |
169 | typedef struct _ClassData ClassData; |
170 | typedef struct _InstanceData InstanceData; |
171 | typedef union _TypeData TypeData; |
172 | typedef struct _IFaceEntries IFaceEntries; |
173 | typedef struct _IFaceEntry IFaceEntry; |
174 | typedef struct _IFaceHolder IFaceHolder; |
175 | |
176 | |
177 | /* --- prototypes --- */ |
178 | static inline GTypeFundamentalInfo* type_node_fundamental_info_I (TypeNode *node); |
179 | static void type_add_flags_W (TypeNode *node, |
180 | GTypeFlags flags); |
181 | static void type_data_make_W (TypeNode *node, |
182 | const GTypeInfo *info, |
183 | const GTypeValueTable *value_table); |
184 | static inline void type_data_ref_Wm (TypeNode *node); |
185 | static inline void type_data_unref_U (TypeNode *node, |
186 | gboolean uncached); |
187 | static void type_data_last_unref_Wm (TypeNode * node, |
188 | gboolean uncached); |
189 | static inline gpointer type_get_qdata_L (TypeNode *node, |
190 | GQuark quark); |
191 | static inline void type_set_qdata_W (TypeNode *node, |
192 | GQuark quark, |
193 | gpointer data); |
194 | static IFaceHolder* type_iface_peek_holder_L (TypeNode *iface, |
195 | GType instance_type); |
196 | static gboolean type_iface_vtable_base_init_Wm (TypeNode *iface, |
197 | TypeNode *node); |
198 | static void type_iface_vtable_iface_init_Wm (TypeNode *iface, |
199 | TypeNode *node); |
200 | static gboolean type_node_is_a_L (TypeNode *node, |
201 | TypeNode *iface_node); |
202 | |
203 | |
204 | /* --- enumeration --- */ |
205 | |
206 | /* The InitState enumeration is used to track the progress of initializing |
207 | * both classes and interface vtables. Keeping the state of initialization |
208 | * is necessary to handle new interfaces being added while we are initializing |
209 | * the class or other interfaces. |
210 | */ |
211 | typedef enum |
212 | { |
213 | UNINITIALIZED, |
214 | BASE_CLASS_INIT, |
215 | BASE_IFACE_INIT, |
216 | CLASS_INIT, |
217 | IFACE_INIT, |
218 | INITIALIZED |
219 | } InitState; |
220 | |
221 | /* --- structures --- */ |
222 | struct _TypeNode |
223 | { |
224 | guint ref_count; /* (atomic) */ |
225 | #ifdef G_ENABLE_DEBUG |
226 | guint instance_count; /* (atomic) */ |
227 | #endif |
228 | GTypePlugin *plugin; |
229 | guint n_children; /* writable with lock */ |
230 | guint n_supers : 8; |
231 | guint n_prerequisites : 9; |
232 | guint is_classed : 1; |
233 | guint is_instantiatable : 1; |
234 | guint mutatable_check_cache : 1; /* combines some common path checks */ |
235 | GType *children; /* writable with lock */ |
236 | TypeData *data; |
237 | GQuark qname; |
238 | GData *global_gdata; |
239 | union { |
240 | GAtomicArray iface_entries; /* for !iface types */ |
241 | GAtomicArray offsets; |
242 | } _prot; |
243 | GType *prerequisites; |
244 | GType supers[1]; /* flexible array */ |
245 | }; |
246 | |
247 | #define SIZEOF_BASE_TYPE_NODE() (G_STRUCT_OFFSET (TypeNode, supers)) |
248 | #define MAX_N_SUPERS (255) |
249 | #define MAX_N_CHILDREN (G_MAXUINT) |
250 | #define MAX_N_INTERFACES (255) /* Limited by offsets being 8 bits */ |
251 | #define MAX_N_PREREQUISITES (511) |
252 | #define NODE_TYPE(node) (node->supers[0]) |
253 | #define NODE_PARENT_TYPE(node) (node->supers[1]) |
254 | #define NODE_FUNDAMENTAL_TYPE(node) (node->supers[node->n_supers]) |
255 | #define NODE_NAME(node) (g_quark_to_string (node->qname)) |
256 | #define NODE_REFCOUNT(node) ((guint) g_atomic_int_get ((int *) &(node)->ref_count)) |
257 | #define NODE_IS_BOXED(node) (NODE_FUNDAMENTAL_TYPE (node) == G_TYPE_BOXED) |
258 | #define NODE_IS_IFACE(node) (NODE_FUNDAMENTAL_TYPE (node) == G_TYPE_INTERFACE) |
259 | #define CLASSED_NODE_IFACES_ENTRIES(node) (&(node)->_prot.iface_entries) |
260 | #define CLASSED_NODE_IFACES_ENTRIES_LOCKED(node)(G_ATOMIC_ARRAY_GET_LOCKED(CLASSED_NODE_IFACES_ENTRIES((node)), IFaceEntries)) |
261 | #define IFACE_NODE_N_PREREQUISITES(node) ((node)->n_prerequisites) |
262 | #define IFACE_NODE_PREREQUISITES(node) ((node)->prerequisites) |
263 | #define iface_node_get_holders_L(node) ((IFaceHolder*) type_get_qdata_L ((node), static_quark_iface_holder)) |
264 | #define iface_node_set_holders_W(node, holders) (type_set_qdata_W ((node), static_quark_iface_holder, (holders))) |
265 | #define iface_node_get_dependants_array_L(n) ((GType*) type_get_qdata_L ((n), static_quark_dependants_array)) |
266 | #define iface_node_set_dependants_array_W(n,d) (type_set_qdata_W ((n), static_quark_dependants_array, (d))) |
267 | #define TYPE_ID_MASK ((GType) ((1 << G_TYPE_FUNDAMENTAL_SHIFT) - 1)) |
268 | |
269 | #define NODE_IS_ANCESTOR(ancestor, node) \ |
270 | ((ancestor)->n_supers <= (node)->n_supers && \ |
271 | (node)->supers[(node)->n_supers - (ancestor)->n_supers] == NODE_TYPE (ancestor)) |
272 | |
273 | struct _IFaceHolder |
274 | { |
275 | GType instance_type; |
276 | GInterfaceInfo *info; |
277 | GTypePlugin *plugin; |
278 | IFaceHolder *next; |
279 | }; |
280 | |
281 | struct _IFaceEntry |
282 | { |
283 | GType iface_type; |
284 | GTypeInterface *vtable; |
285 | InitState init_state; |
286 | }; |
287 | |
288 | struct _IFaceEntries { |
289 | gsize offset_index; |
290 | IFaceEntry entry[1]; |
291 | }; |
292 | |
293 | #define (sizeof(IFaceEntries) - sizeof(IFaceEntry)) |
294 | #define IFACE_ENTRIES_N_ENTRIES(_entries) ( (G_ATOMIC_ARRAY_DATA_SIZE((_entries)) - IFACE_ENTRIES_HEADER_SIZE) / sizeof(IFaceEntry) ) |
295 | |
296 | struct _CommonData |
297 | { |
298 | GTypeValueTable *value_table; |
299 | }; |
300 | |
301 | struct _BoxedData |
302 | { |
303 | CommonData data; |
304 | GBoxedCopyFunc copy_func; |
305 | GBoxedFreeFunc free_func; |
306 | }; |
307 | |
308 | struct _IFaceData |
309 | { |
310 | CommonData common; |
311 | guint16 vtable_size; |
312 | GBaseInitFunc vtable_init_base; |
313 | GBaseFinalizeFunc vtable_finalize_base; |
314 | GClassInitFunc dflt_init; |
315 | GClassFinalizeFunc dflt_finalize; |
316 | gconstpointer dflt_data; |
317 | gpointer dflt_vtable; |
318 | }; |
319 | |
320 | struct _ClassData |
321 | { |
322 | CommonData common; |
323 | guint16 class_size; |
324 | guint16 class_private_size; |
325 | int init_state; /* (atomic) - g_type_class_ref reads it unlocked */ |
326 | GBaseInitFunc class_init_base; |
327 | GBaseFinalizeFunc class_finalize_base; |
328 | GClassInitFunc class_init; |
329 | GClassFinalizeFunc class_finalize; |
330 | gconstpointer class_data; |
331 | gpointer class; |
332 | }; |
333 | |
334 | struct _InstanceData |
335 | { |
336 | CommonData common; |
337 | guint16 class_size; |
338 | guint16 class_private_size; |
339 | int init_state; /* (atomic) - g_type_class_ref reads it unlocked */ |
340 | GBaseInitFunc class_init_base; |
341 | GBaseFinalizeFunc class_finalize_base; |
342 | GClassInitFunc class_init; |
343 | GClassFinalizeFunc class_finalize; |
344 | gconstpointer class_data; |
345 | gpointer class; |
346 | guint16 instance_size; |
347 | guint16 private_size; |
348 | guint16 n_preallocs; |
349 | GInstanceInitFunc instance_init; |
350 | }; |
351 | |
352 | union _TypeData |
353 | { |
354 | CommonData common; |
355 | BoxedData boxed; |
356 | IFaceData iface; |
357 | ClassData class; |
358 | InstanceData instance; |
359 | }; |
360 | |
361 | typedef struct { |
362 | gpointer cache_data; |
363 | GTypeClassCacheFunc cache_func; |
364 | } ClassCacheFunc; |
365 | |
366 | typedef struct { |
367 | gpointer check_data; |
368 | GTypeInterfaceCheckFunc check_func; |
369 | } IFaceCheckFunc; |
370 | |
371 | |
372 | /* --- variables --- */ |
373 | static GRWLock type_rw_lock; |
374 | static GRecMutex class_init_rec_mutex; |
375 | static guint static_n_class_cache_funcs = 0; |
376 | static ClassCacheFunc *static_class_cache_funcs = NULL; |
377 | static guint static_n_iface_check_funcs = 0; |
378 | static IFaceCheckFunc *static_iface_check_funcs = NULL; |
379 | static GQuark static_quark_type_flags = 0; |
380 | static GQuark static_quark_iface_holder = 0; |
381 | static GQuark static_quark_dependants_array = 0; |
382 | static guint type_registration_serial = 0; |
383 | |
384 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
385 | GTypeDebugFlags _g_type_debug_flags = 0; |
386 | G_GNUC_END_IGNORE_DEPRECATIONS |
387 | |
388 | /* --- type nodes --- */ |
389 | static GHashTable *static_type_nodes_ht = NULL; |
390 | static TypeNode *static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { NULL, }; |
391 | static GType static_fundamental_next = G_TYPE_RESERVED_USER_FIRST; |
392 | |
393 | static inline TypeNode* |
394 | lookup_type_node_I (GType utype) |
395 | { |
396 | if (utype > G_TYPE_FUNDAMENTAL_MAX) |
397 | return (TypeNode*) (utype & ~TYPE_ID_MASK); |
398 | else |
399 | return static_fundamental_type_nodes[utype >> G_TYPE_FUNDAMENTAL_SHIFT]; |
400 | } |
401 | |
402 | /** |
403 | * g_type_get_type_registration_serial: |
404 | * |
405 | * Returns an opaque serial number that represents the state of the set |
406 | * of registered types. Any time a type is registered this serial changes, |
407 | * which means you can cache information based on type lookups (such as |
408 | * g_type_from_name()) and know if the cache is still valid at a later |
409 | * time by comparing the current serial with the one at the type lookup. |
410 | * |
411 | * Since: 2.36 |
412 | * |
413 | * Returns: An unsigned int, representing the state of type registrations |
414 | */ |
415 | guint |
416 | g_type_get_type_registration_serial (void) |
417 | { |
418 | return (guint)g_atomic_int_get ((gint *)&type_registration_serial); |
419 | } |
420 | |
421 | static TypeNode* |
422 | type_node_any_new_W (TypeNode *pnode, |
423 | GType ftype, |
424 | const gchar *name, |
425 | GTypePlugin *plugin, |
426 | GTypeFundamentalFlags type_flags) |
427 | { |
428 | guint n_supers; |
429 | GType type; |
430 | TypeNode *node; |
431 | guint i, node_size = 0; |
432 | |
433 | n_supers = pnode ? pnode->n_supers + 1 : 0; |
434 | |
435 | if (!pnode) |
436 | node_size += SIZEOF_FUNDAMENTAL_INFO; /* fundamental type info */ |
437 | node_size += SIZEOF_BASE_TYPE_NODE (); /* TypeNode structure */ |
438 | node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + (0) for ->supers[] */ |
439 | node = g_malloc0 (n_bytes: node_size); |
440 | if (!pnode) /* offset fundamental types */ |
441 | { |
442 | node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO); |
443 | static_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node; |
444 | type = ftype; |
445 | |
446 | #if ENABLE_VALGRIND |
447 | VALGRIND_MALLOCLIKE_BLOCK (node, node_size - SIZEOF_FUNDAMENTAL_INFO, FALSE, TRUE); |
448 | #endif |
449 | } |
450 | else |
451 | type = (GType) node; |
452 | |
453 | g_assert ((type & TYPE_ID_MASK) == 0); |
454 | |
455 | node->n_supers = n_supers; |
456 | if (!pnode) |
457 | { |
458 | node->supers[0] = type; |
459 | node->supers[1] = 0; |
460 | |
461 | node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0; |
462 | node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0; |
463 | |
464 | if (NODE_IS_IFACE (node)) |
465 | { |
466 | IFACE_NODE_N_PREREQUISITES (node) = 0; |
467 | IFACE_NODE_PREREQUISITES (node) = NULL; |
468 | } |
469 | else |
470 | _g_atomic_array_init (CLASSED_NODE_IFACES_ENTRIES (node)); |
471 | } |
472 | else |
473 | { |
474 | node->supers[0] = type; |
475 | memcpy (dest: node->supers + 1, src: pnode->supers, n: sizeof (GType) * (1 + pnode->n_supers + 1)); |
476 | |
477 | node->is_classed = pnode->is_classed; |
478 | node->is_instantiatable = pnode->is_instantiatable; |
479 | |
480 | if (NODE_IS_IFACE (node)) |
481 | { |
482 | IFACE_NODE_N_PREREQUISITES (node) = 0; |
483 | IFACE_NODE_PREREQUISITES (node) = NULL; |
484 | } |
485 | else |
486 | { |
487 | guint j; |
488 | IFaceEntries *entries; |
489 | |
490 | entries = _g_atomic_array_copy (CLASSED_NODE_IFACES_ENTRIES (pnode), |
491 | IFACE_ENTRIES_HEADER_SIZE, |
492 | additional_element_size: 0); |
493 | if (entries) |
494 | { |
495 | for (j = 0; j < IFACE_ENTRIES_N_ENTRIES (entries); j++) |
496 | { |
497 | entries->entry[j].vtable = NULL; |
498 | entries->entry[j].init_state = UNINITIALIZED; |
499 | } |
500 | _g_atomic_array_update (CLASSED_NODE_IFACES_ENTRIES (node), |
501 | new_data: entries); |
502 | } |
503 | } |
504 | |
505 | i = pnode->n_children++; |
506 | pnode->children = g_renew (GType, pnode->children, pnode->n_children); |
507 | pnode->children[i] = type; |
508 | } |
509 | |
510 | TRACE(GOBJECT_TYPE_NEW(name, node->supers[1], type)); |
511 | |
512 | node->plugin = plugin; |
513 | node->n_children = 0; |
514 | node->children = NULL; |
515 | node->data = NULL; |
516 | node->qname = g_quark_from_string (string: name); |
517 | node->global_gdata = NULL; |
518 | g_hash_table_insert (hash_table: static_type_nodes_ht, |
519 | key: (gpointer) g_quark_to_string (quark: node->qname), |
520 | value: (gpointer) type); |
521 | |
522 | g_atomic_int_inc ((gint *)&type_registration_serial); |
523 | |
524 | return node; |
525 | } |
526 | |
527 | static inline GTypeFundamentalInfo* |
528 | type_node_fundamental_info_I (TypeNode *node) |
529 | { |
530 | GType ftype = NODE_FUNDAMENTAL_TYPE (node); |
531 | |
532 | if (ftype != NODE_TYPE (node)) |
533 | node = lookup_type_node_I (utype: ftype); |
534 | |
535 | return node ? G_STRUCT_MEMBER_P (node, -SIZEOF_FUNDAMENTAL_INFO) : NULL; |
536 | } |
537 | |
538 | static TypeNode* |
539 | type_node_fundamental_new_W (GType ftype, |
540 | const gchar *name, |
541 | GTypeFundamentalFlags type_flags) |
542 | { |
543 | GTypeFundamentalInfo *finfo; |
544 | TypeNode *node; |
545 | |
546 | g_assert ((ftype & TYPE_ID_MASK) == 0); |
547 | g_assert (ftype <= G_TYPE_FUNDAMENTAL_MAX); |
548 | |
549 | if (ftype >> G_TYPE_FUNDAMENTAL_SHIFT == static_fundamental_next) |
550 | static_fundamental_next++; |
551 | |
552 | type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK; |
553 | |
554 | node = type_node_any_new_W (NULL, ftype, name, NULL, type_flags); |
555 | |
556 | finfo = type_node_fundamental_info_I (node); |
557 | finfo->type_flags = type_flags; |
558 | |
559 | return node; |
560 | } |
561 | |
562 | static TypeNode* |
563 | type_node_new_W (TypeNode *pnode, |
564 | const gchar *name, |
565 | GTypePlugin *plugin) |
566 | |
567 | { |
568 | g_assert (pnode); |
569 | g_assert (pnode->n_supers < MAX_N_SUPERS); |
570 | g_assert (pnode->n_children < MAX_N_CHILDREN); |
571 | |
572 | return type_node_any_new_W (pnode, NODE_FUNDAMENTAL_TYPE (pnode), name, plugin, type_flags: 0); |
573 | } |
574 | |
575 | static inline IFaceEntry* |
576 | lookup_iface_entry_I (IFaceEntries *entries, |
577 | TypeNode *iface_node) |
578 | { |
579 | guint8 *offsets; |
580 | gsize offset_index; |
581 | IFaceEntry *check; |
582 | gsize index; |
583 | IFaceEntry *entry; |
584 | |
585 | if (entries == NULL) |
586 | return NULL; |
587 | |
588 | G_ATOMIC_ARRAY_DO_TRANSACTION |
589 | (&iface_node->_prot.offsets, guint8, |
590 | |
591 | entry = NULL; |
592 | offsets = transaction_data; |
593 | offset_index = entries->offset_index; |
594 | if (offsets != NULL && |
595 | offset_index < G_ATOMIC_ARRAY_DATA_SIZE(offsets)) |
596 | { |
597 | index = offsets[offset_index]; |
598 | if (index > 0) |
599 | { |
600 | /* zero means unset, subtract one to get real index */ |
601 | index -= 1; |
602 | |
603 | if (index < IFACE_ENTRIES_N_ENTRIES (entries)) |
604 | { |
605 | check = (IFaceEntry *)&entries->entry[index]; |
606 | if (check->iface_type == NODE_TYPE (iface_node)) |
607 | entry = check; |
608 | } |
609 | } |
610 | } |
611 | ); |
612 | |
613 | return entry; |
614 | } |
615 | |
616 | static inline IFaceEntry* |
617 | type_lookup_iface_entry_L (TypeNode *node, |
618 | TypeNode *iface_node) |
619 | { |
620 | if (!NODE_IS_IFACE (iface_node)) |
621 | return NULL; |
622 | |
623 | return lookup_iface_entry_I (CLASSED_NODE_IFACES_ENTRIES_LOCKED (node), |
624 | iface_node); |
625 | } |
626 | |
627 | |
628 | static inline gboolean |
629 | type_lookup_iface_vtable_I (TypeNode *node, |
630 | TypeNode *iface_node, |
631 | gpointer *vtable_ptr) |
632 | { |
633 | IFaceEntry *entry; |
634 | gboolean res; |
635 | |
636 | if (!NODE_IS_IFACE (iface_node)) |
637 | { |
638 | if (vtable_ptr) |
639 | *vtable_ptr = NULL; |
640 | return FALSE; |
641 | } |
642 | |
643 | G_ATOMIC_ARRAY_DO_TRANSACTION |
644 | (CLASSED_NODE_IFACES_ENTRIES (node), IFaceEntries, |
645 | |
646 | entry = lookup_iface_entry_I (transaction_data, iface_node); |
647 | res = entry != NULL; |
648 | if (vtable_ptr) |
649 | { |
650 | if (entry) |
651 | *vtable_ptr = entry->vtable; |
652 | else |
653 | *vtable_ptr = NULL; |
654 | } |
655 | ); |
656 | |
657 | return res; |
658 | } |
659 | |
660 | static inline gboolean |
661 | type_lookup_prerequisite_L (TypeNode *iface, |
662 | GType prerequisite_type) |
663 | { |
664 | if (NODE_IS_IFACE (iface) && IFACE_NODE_N_PREREQUISITES (iface)) |
665 | { |
666 | GType *prerequisites = IFACE_NODE_PREREQUISITES (iface) - 1; |
667 | guint n_prerequisites = IFACE_NODE_N_PREREQUISITES (iface); |
668 | |
669 | do |
670 | { |
671 | guint i; |
672 | GType *check; |
673 | |
674 | i = (n_prerequisites + 1) >> 1; |
675 | check = prerequisites + i; |
676 | if (prerequisite_type == *check) |
677 | return TRUE; |
678 | else if (prerequisite_type > *check) |
679 | { |
680 | n_prerequisites -= i; |
681 | prerequisites = check; |
682 | } |
683 | else /* if (prerequisite_type < *check) */ |
684 | n_prerequisites = i - 1; |
685 | } |
686 | while (n_prerequisites); |
687 | } |
688 | return FALSE; |
689 | } |
690 | |
691 | static const gchar* |
692 | type_descriptive_name_I (GType type) |
693 | { |
694 | if (type) |
695 | { |
696 | TypeNode *node = lookup_type_node_I (utype: type); |
697 | |
698 | return node ? NODE_NAME (node) : "<unknown>" ; |
699 | } |
700 | else |
701 | return "<invalid>" ; |
702 | } |
703 | |
704 | |
705 | /* --- type consistency checks --- */ |
706 | static gboolean |
707 | check_plugin_U (GTypePlugin *plugin, |
708 | gboolean need_complete_type_info, |
709 | gboolean need_complete_interface_info, |
710 | const gchar *type_name) |
711 | { |
712 | /* G_IS_TYPE_PLUGIN() and G_TYPE_PLUGIN_GET_CLASS() are external calls: _U |
713 | */ |
714 | if (!plugin) |
715 | { |
716 | g_warning ("plugin handle for type '%s' is NULL" , |
717 | type_name); |
718 | return FALSE; |
719 | } |
720 | if (!G_IS_TYPE_PLUGIN (plugin)) |
721 | { |
722 | g_warning ("plugin pointer (%p) for type '%s' is invalid" , |
723 | plugin, type_name); |
724 | return FALSE; |
725 | } |
726 | if (need_complete_type_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_type_info) |
727 | { |
728 | g_warning ("plugin for type '%s' has no complete_type_info() implementation" , |
729 | type_name); |
730 | return FALSE; |
731 | } |
732 | if (need_complete_interface_info && !G_TYPE_PLUGIN_GET_CLASS (plugin)->complete_interface_info) |
733 | { |
734 | g_warning ("plugin for type '%s' has no complete_interface_info() implementation" , |
735 | type_name); |
736 | return FALSE; |
737 | } |
738 | return TRUE; |
739 | } |
740 | |
741 | static gboolean |
742 | check_type_name_I (const gchar *type_name) |
743 | { |
744 | static const gchar [] = "-_+" ; |
745 | const gchar *p = type_name; |
746 | gboolean name_valid; |
747 | |
748 | if (!type_name[0] || !type_name[1] || !type_name[2]) |
749 | { |
750 | g_warning ("type name '%s' is too short" , type_name); |
751 | return FALSE; |
752 | } |
753 | /* check the first letter */ |
754 | name_valid = (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || p[0] == '_'; |
755 | for (p = type_name + 1; *p; p++) |
756 | name_valid &= ((p[0] >= 'A' && p[0] <= 'Z') || |
757 | (p[0] >= 'a' && p[0] <= 'z') || |
758 | (p[0] >= '0' && p[0] <= '9') || |
759 | strchr (s: extra_chars, c: p[0])); |
760 | if (!name_valid) |
761 | { |
762 | g_warning ("type name '%s' contains invalid characters" , type_name); |
763 | return FALSE; |
764 | } |
765 | if (g_type_from_name (name: type_name)) |
766 | { |
767 | g_warning ("cannot register existing type '%s'" , type_name); |
768 | return FALSE; |
769 | } |
770 | |
771 | return TRUE; |
772 | } |
773 | |
774 | static gboolean |
775 | check_derivation_I (GType parent_type, |
776 | const gchar *type_name) |
777 | { |
778 | TypeNode *pnode; |
779 | GTypeFundamentalInfo* finfo; |
780 | |
781 | pnode = lookup_type_node_I (utype: parent_type); |
782 | if (!pnode) |
783 | { |
784 | g_warning ("cannot derive type '%s' from invalid parent type '%s'" , |
785 | type_name, |
786 | type_descriptive_name_I (parent_type)); |
787 | return FALSE; |
788 | } |
789 | finfo = type_node_fundamental_info_I (node: pnode); |
790 | /* ensure flat derivability */ |
791 | if (!(finfo->type_flags & G_TYPE_FLAG_DERIVABLE)) |
792 | { |
793 | g_warning ("cannot derive '%s' from non-derivable parent type '%s'" , |
794 | type_name, |
795 | NODE_NAME (pnode)); |
796 | return FALSE; |
797 | } |
798 | /* ensure deep derivability */ |
799 | if (parent_type != NODE_FUNDAMENTAL_TYPE (pnode) && |
800 | !(finfo->type_flags & G_TYPE_FLAG_DEEP_DERIVABLE)) |
801 | { |
802 | g_warning ("cannot derive '%s' from non-fundamental parent type '%s'" , |
803 | type_name, |
804 | NODE_NAME (pnode)); |
805 | return FALSE; |
806 | } |
807 | |
808 | return TRUE; |
809 | } |
810 | |
811 | static gboolean |
812 | check_collect_format_I (const gchar *collect_format) |
813 | { |
814 | const gchar *p = collect_format; |
815 | gchar valid_format[] = { G_VALUE_COLLECT_INT, G_VALUE_COLLECT_LONG, |
816 | G_VALUE_COLLECT_INT64, G_VALUE_COLLECT_DOUBLE, |
817 | G_VALUE_COLLECT_POINTER, 0 }; |
818 | |
819 | while (*p) |
820 | if (!strchr (s: valid_format, c: *p++)) |
821 | return FALSE; |
822 | return p - collect_format <= G_VALUE_COLLECT_FORMAT_MAX_LENGTH; |
823 | } |
824 | |
825 | static gboolean |
826 | check_value_table_I (const gchar *type_name, |
827 | const GTypeValueTable *value_table) |
828 | { |
829 | if (!value_table) |
830 | return FALSE; |
831 | else if (value_table->value_init == NULL) |
832 | { |
833 | if (value_table->value_free || value_table->value_copy || |
834 | value_table->value_peek_pointer || |
835 | value_table->collect_format || value_table->collect_value || |
836 | value_table->lcopy_format || value_table->lcopy_value) |
837 | g_warning ("cannot handle uninitializable values of type '%s'" , |
838 | type_name); |
839 | return FALSE; |
840 | } |
841 | else /* value_table->value_init != NULL */ |
842 | { |
843 | if (!value_table->value_free) |
844 | { |
845 | /* +++ optional +++ |
846 | * g_warning ("missing 'value_free()' for type '%s'", type_name); |
847 | * return FALSE; |
848 | */ |
849 | } |
850 | if (!value_table->value_copy) |
851 | { |
852 | g_warning ("missing 'value_copy()' for type '%s'" , type_name); |
853 | return FALSE; |
854 | } |
855 | if ((value_table->collect_format || value_table->collect_value) && |
856 | (!value_table->collect_format || !value_table->collect_value)) |
857 | { |
858 | g_warning ("one of 'collect_format' and 'collect_value()' is unspecified for type '%s'" , |
859 | type_name); |
860 | return FALSE; |
861 | } |
862 | if (value_table->collect_format && !check_collect_format_I (collect_format: value_table->collect_format)) |
863 | { |
864 | g_warning ("the '%s' specification for type '%s' is too long or invalid" , |
865 | "collect_format" , |
866 | type_name); |
867 | return FALSE; |
868 | } |
869 | if ((value_table->lcopy_format || value_table->lcopy_value) && |
870 | (!value_table->lcopy_format || !value_table->lcopy_value)) |
871 | { |
872 | g_warning ("one of 'lcopy_format' and 'lcopy_value()' is unspecified for type '%s'" , |
873 | type_name); |
874 | return FALSE; |
875 | } |
876 | if (value_table->lcopy_format && !check_collect_format_I (collect_format: value_table->lcopy_format)) |
877 | { |
878 | g_warning ("the '%s' specification for type '%s' is too long or invalid" , |
879 | "lcopy_format" , |
880 | type_name); |
881 | return FALSE; |
882 | } |
883 | } |
884 | return TRUE; |
885 | } |
886 | |
887 | static gboolean |
888 | check_type_info_I (TypeNode *pnode, |
889 | GType ftype, |
890 | const gchar *type_name, |
891 | const GTypeInfo *info) |
892 | { |
893 | GTypeFundamentalInfo *finfo = type_node_fundamental_info_I (node: lookup_type_node_I (utype: ftype)); |
894 | gboolean is_interface = ftype == G_TYPE_INTERFACE; |
895 | |
896 | g_assert (ftype <= G_TYPE_FUNDAMENTAL_MAX && !(ftype & TYPE_ID_MASK)); |
897 | |
898 | /* check instance members */ |
899 | if (!(finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) && |
900 | (info->instance_size || info->n_preallocs || info->instance_init)) |
901 | { |
902 | if (pnode) |
903 | g_warning ("cannot instantiate '%s', derived from non-instantiatable parent type '%s'" , |
904 | type_name, |
905 | NODE_NAME (pnode)); |
906 | else |
907 | g_warning ("cannot instantiate '%s' as non-instantiatable fundamental" , |
908 | type_name); |
909 | return FALSE; |
910 | } |
911 | /* check class & interface members */ |
912 | if (!((finfo->type_flags & G_TYPE_FLAG_CLASSED) || is_interface) && |
913 | (info->class_init || info->class_finalize || info->class_data || |
914 | info->class_size || info->base_init || info->base_finalize)) |
915 | { |
916 | if (pnode) |
917 | g_warning ("cannot create class for '%s', derived from non-classed parent type '%s'" , |
918 | type_name, |
919 | NODE_NAME (pnode)); |
920 | else |
921 | g_warning ("cannot create class for '%s' as non-classed fundamental" , |
922 | type_name); |
923 | return FALSE; |
924 | } |
925 | /* check interface size */ |
926 | if (is_interface && info->class_size < sizeof (GTypeInterface)) |
927 | { |
928 | g_warning ("specified interface size for type '%s' is smaller than 'GTypeInterface' size" , |
929 | type_name); |
930 | return FALSE; |
931 | } |
932 | /* check class size */ |
933 | if (finfo->type_flags & G_TYPE_FLAG_CLASSED) |
934 | { |
935 | if (info->class_size < sizeof (GTypeClass)) |
936 | { |
937 | g_warning ("specified class size for type '%s' is smaller than 'GTypeClass' size" , |
938 | type_name); |
939 | return FALSE; |
940 | } |
941 | if (pnode && info->class_size < pnode->data->class.class_size) |
942 | { |
943 | g_warning ("specified class size for type '%s' is smaller " |
944 | "than the parent type's '%s' class size" , |
945 | type_name, |
946 | NODE_NAME (pnode)); |
947 | return FALSE; |
948 | } |
949 | } |
950 | /* check instance size */ |
951 | if (finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) |
952 | { |
953 | if (info->instance_size < sizeof (GTypeInstance)) |
954 | { |
955 | g_warning ("specified instance size for type '%s' is smaller than 'GTypeInstance' size" , |
956 | type_name); |
957 | return FALSE; |
958 | } |
959 | if (pnode && info->instance_size < pnode->data->instance.instance_size) |
960 | { |
961 | g_warning ("specified instance size for type '%s' is smaller " |
962 | "than the parent type's '%s' instance size" , |
963 | type_name, |
964 | NODE_NAME (pnode)); |
965 | return FALSE; |
966 | } |
967 | } |
968 | |
969 | return TRUE; |
970 | } |
971 | |
972 | static TypeNode* |
973 | find_conforming_child_type_L (TypeNode *pnode, |
974 | TypeNode *iface) |
975 | { |
976 | TypeNode *node = NULL; |
977 | guint i; |
978 | |
979 | if (type_lookup_iface_entry_L (node: pnode, iface_node: iface)) |
980 | return pnode; |
981 | |
982 | for (i = 0; i < pnode->n_children && !node; i++) |
983 | node = find_conforming_child_type_L (pnode: lookup_type_node_I (utype: pnode->children[i]), iface); |
984 | |
985 | return node; |
986 | } |
987 | |
988 | static gboolean |
989 | check_add_interface_L (GType instance_type, |
990 | GType iface_type) |
991 | { |
992 | TypeNode *node = lookup_type_node_I (utype: instance_type); |
993 | TypeNode *iface = lookup_type_node_I (utype: iface_type); |
994 | IFaceEntry *entry; |
995 | TypeNode *tnode; |
996 | GType *prerequisites; |
997 | guint i; |
998 | |
999 | |
1000 | if (!node || !node->is_instantiatable) |
1001 | { |
1002 | g_warning ("cannot add interfaces to invalid (non-instantiatable) type '%s'" , |
1003 | type_descriptive_name_I (instance_type)); |
1004 | return FALSE; |
1005 | } |
1006 | if (!iface || !NODE_IS_IFACE (iface)) |
1007 | { |
1008 | g_warning ("cannot add invalid (non-interface) type '%s' to type '%s'" , |
1009 | type_descriptive_name_I (iface_type), |
1010 | NODE_NAME (node)); |
1011 | return FALSE; |
1012 | } |
1013 | if (node->data && node->data->class.class) |
1014 | { |
1015 | g_warning ("attempting to add an interface (%s) to class (%s) after class_init" , |
1016 | NODE_NAME (iface), NODE_NAME (node)); |
1017 | return FALSE; |
1018 | } |
1019 | tnode = lookup_type_node_I (NODE_PARENT_TYPE (iface)); |
1020 | if (NODE_PARENT_TYPE (tnode) && !type_lookup_iface_entry_L (node, iface_node: tnode)) |
1021 | { |
1022 | /* 2001/7/31:timj: erk, i guess this warning is junk as interface derivation is flat */ |
1023 | g_warning ("cannot add sub-interface '%s' to type '%s' which does not conform to super-interface '%s'" , |
1024 | NODE_NAME (iface), |
1025 | NODE_NAME (node), |
1026 | NODE_NAME (tnode)); |
1027 | return FALSE; |
1028 | } |
1029 | /* allow overriding of interface type introduced for parent type */ |
1030 | entry = type_lookup_iface_entry_L (node, iface_node: iface); |
1031 | if (entry && entry->vtable == NULL && !type_iface_peek_holder_L (iface, NODE_TYPE (node))) |
1032 | { |
1033 | /* ok, we do conform to this interface already, but the interface vtable was not |
1034 | * yet initialized, and we just conform to the interface because it got added to |
1035 | * one of our parents. so we allow overriding of holder info here. |
1036 | */ |
1037 | return TRUE; |
1038 | } |
1039 | /* check whether one of our children already conforms (or whether the interface |
1040 | * got added to this node already) |
1041 | */ |
1042 | tnode = find_conforming_child_type_L (pnode: node, iface); /* tnode is_a node */ |
1043 | if (tnode) |
1044 | { |
1045 | g_warning ("cannot add interface type '%s' to type '%s', since type '%s' already conforms to interface" , |
1046 | NODE_NAME (iface), |
1047 | NODE_NAME (node), |
1048 | NODE_NAME (tnode)); |
1049 | return FALSE; |
1050 | } |
1051 | prerequisites = IFACE_NODE_PREREQUISITES (iface); |
1052 | for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++) |
1053 | { |
1054 | tnode = lookup_type_node_I (utype: prerequisites[i]); |
1055 | if (!type_node_is_a_L (node, iface_node: tnode)) |
1056 | { |
1057 | g_warning ("cannot add interface type '%s' to type '%s' which does not conform to prerequisite '%s'" , |
1058 | NODE_NAME (iface), |
1059 | NODE_NAME (node), |
1060 | NODE_NAME (tnode)); |
1061 | return FALSE; |
1062 | } |
1063 | } |
1064 | return TRUE; |
1065 | } |
1066 | |
1067 | static gboolean |
1068 | check_interface_info_I (TypeNode *iface, |
1069 | GType instance_type, |
1070 | const GInterfaceInfo *info) |
1071 | { |
1072 | if ((info->interface_finalize || info->interface_data) && !info->interface_init) |
1073 | { |
1074 | g_warning ("interface type '%s' for type '%s' comes without initializer" , |
1075 | NODE_NAME (iface), |
1076 | type_descriptive_name_I (instance_type)); |
1077 | return FALSE; |
1078 | } |
1079 | |
1080 | return TRUE; |
1081 | } |
1082 | |
1083 | /* --- type info (type node data) --- */ |
1084 | static void |
1085 | type_data_make_W (TypeNode *node, |
1086 | const GTypeInfo *info, |
1087 | const GTypeValueTable *value_table) |
1088 | { |
1089 | TypeData *data; |
1090 | GTypeValueTable *vtable = NULL; |
1091 | guint vtable_size = 0; |
1092 | |
1093 | g_assert (node->data == NULL && info != NULL); |
1094 | |
1095 | if (!value_table) |
1096 | { |
1097 | TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
1098 | |
1099 | if (pnode) |
1100 | vtable = pnode->data->common.value_table; |
1101 | else |
1102 | { |
1103 | static const GTypeValueTable zero_vtable = { NULL, }; |
1104 | |
1105 | value_table = &zero_vtable; |
1106 | } |
1107 | } |
1108 | if (value_table) |
1109 | { |
1110 | /* need to setup vtable_size since we have to allocate it with data in one chunk */ |
1111 | vtable_size = sizeof (GTypeValueTable); |
1112 | if (value_table->collect_format) |
1113 | vtable_size += strlen (s: value_table->collect_format); |
1114 | if (value_table->lcopy_format) |
1115 | vtable_size += strlen (s: value_table->lcopy_format); |
1116 | vtable_size += 2; |
1117 | } |
1118 | |
1119 | if (node->is_instantiatable) /* careful, is_instantiatable is also is_classed */ |
1120 | { |
1121 | TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
1122 | |
1123 | data = g_malloc0 (n_bytes: sizeof (InstanceData) + vtable_size); |
1124 | if (vtable_size) |
1125 | vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData)); |
1126 | data->instance.class_size = info->class_size; |
1127 | data->instance.class_init_base = info->base_init; |
1128 | data->instance.class_finalize_base = info->base_finalize; |
1129 | data->instance.class_init = info->class_init; |
1130 | data->instance.class_finalize = info->class_finalize; |
1131 | data->instance.class_data = info->class_data; |
1132 | data->instance.class = NULL; |
1133 | data->instance.init_state = UNINITIALIZED; |
1134 | data->instance.instance_size = info->instance_size; |
1135 | /* We'll set the final value for data->instance.private size |
1136 | * after the parent class has been initialized |
1137 | */ |
1138 | data->instance.private_size = 0; |
1139 | data->instance.class_private_size = 0; |
1140 | if (pnode) |
1141 | data->instance.class_private_size = pnode->data->instance.class_private_size; |
1142 | data->instance.n_preallocs = MIN (info->n_preallocs, 1024); |
1143 | data->instance.instance_init = info->instance_init; |
1144 | } |
1145 | else if (node->is_classed) /* only classed */ |
1146 | { |
1147 | TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
1148 | |
1149 | data = g_malloc0 (n_bytes: sizeof (ClassData) + vtable_size); |
1150 | if (vtable_size) |
1151 | vtable = G_STRUCT_MEMBER_P (data, sizeof (ClassData)); |
1152 | data->class.class_size = info->class_size; |
1153 | data->class.class_init_base = info->base_init; |
1154 | data->class.class_finalize_base = info->base_finalize; |
1155 | data->class.class_init = info->class_init; |
1156 | data->class.class_finalize = info->class_finalize; |
1157 | data->class.class_data = info->class_data; |
1158 | data->class.class = NULL; |
1159 | data->class.class_private_size = 0; |
1160 | if (pnode) |
1161 | data->class.class_private_size = pnode->data->class.class_private_size; |
1162 | data->class.init_state = UNINITIALIZED; |
1163 | } |
1164 | else if (NODE_IS_IFACE (node)) |
1165 | { |
1166 | data = g_malloc0 (n_bytes: sizeof (IFaceData) + vtable_size); |
1167 | if (vtable_size) |
1168 | vtable = G_STRUCT_MEMBER_P (data, sizeof (IFaceData)); |
1169 | data->iface.vtable_size = info->class_size; |
1170 | data->iface.vtable_init_base = info->base_init; |
1171 | data->iface.vtable_finalize_base = info->base_finalize; |
1172 | data->iface.dflt_init = info->class_init; |
1173 | data->iface.dflt_finalize = info->class_finalize; |
1174 | data->iface.dflt_data = info->class_data; |
1175 | data->iface.dflt_vtable = NULL; |
1176 | } |
1177 | else if (NODE_IS_BOXED (node)) |
1178 | { |
1179 | data = g_malloc0 (n_bytes: sizeof (BoxedData) + vtable_size); |
1180 | if (vtable_size) |
1181 | vtable = G_STRUCT_MEMBER_P (data, sizeof (BoxedData)); |
1182 | } |
1183 | else |
1184 | { |
1185 | data = g_malloc0 (n_bytes: sizeof (CommonData) + vtable_size); |
1186 | if (vtable_size) |
1187 | vtable = G_STRUCT_MEMBER_P (data, sizeof (CommonData)); |
1188 | } |
1189 | |
1190 | node->data = data; |
1191 | |
1192 | if (vtable_size) |
1193 | { |
1194 | gchar *p; |
1195 | |
1196 | /* we allocate the vtable and its strings together with the type data, so |
1197 | * children can take over their parent's vtable pointer, and we don't |
1198 | * need to worry freeing it or not when the child data is destroyed |
1199 | */ |
1200 | *vtable = *value_table; |
1201 | p = G_STRUCT_MEMBER_P (vtable, sizeof (*vtable)); |
1202 | p[0] = 0; |
1203 | vtable->collect_format = p; |
1204 | if (value_table->collect_format) |
1205 | { |
1206 | strcat (dest: p, src: value_table->collect_format); |
1207 | p += strlen (s: value_table->collect_format); |
1208 | } |
1209 | p++; |
1210 | p[0] = 0; |
1211 | vtable->lcopy_format = p; |
1212 | if (value_table->lcopy_format) |
1213 | strcat (dest: p, src: value_table->lcopy_format); |
1214 | } |
1215 | node->data->common.value_table = vtable; |
1216 | node->mutatable_check_cache = (node->data->common.value_table->value_init != NULL && |
1217 | !((G_TYPE_FLAG_VALUE_ABSTRACT | G_TYPE_FLAG_ABSTRACT) & |
1218 | GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags)))); |
1219 | |
1220 | g_assert (node->data->common.value_table != NULL); /* paranoid */ |
1221 | |
1222 | g_atomic_int_set ((int *) &node->ref_count, 1); |
1223 | } |
1224 | |
1225 | static inline void |
1226 | type_data_ref_Wm (TypeNode *node) |
1227 | { |
1228 | if (!node->data) |
1229 | { |
1230 | TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
1231 | GTypeInfo tmp_info; |
1232 | GTypeValueTable tmp_value_table; |
1233 | |
1234 | g_assert (node->plugin != NULL); |
1235 | |
1236 | if (pnode) |
1237 | { |
1238 | type_data_ref_Wm (node: pnode); |
1239 | if (node->data) |
1240 | INVALID_RECURSION ("g_type_plugin_*" , node->plugin, NODE_NAME (node)); |
1241 | } |
1242 | |
1243 | memset (s: &tmp_info, c: 0, n: sizeof (tmp_info)); |
1244 | memset (s: &tmp_value_table, c: 0, n: sizeof (tmp_value_table)); |
1245 | |
1246 | G_WRITE_UNLOCK (&type_rw_lock); |
1247 | g_type_plugin_use (plugin: node->plugin); |
1248 | g_type_plugin_complete_type_info (plugin: node->plugin, NODE_TYPE (node), info: &tmp_info, value_table: &tmp_value_table); |
1249 | G_WRITE_LOCK (&type_rw_lock); |
1250 | if (node->data) |
1251 | INVALID_RECURSION ("g_type_plugin_*" , node->plugin, NODE_NAME (node)); |
1252 | |
1253 | check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (node), NODE_NAME (node), info: &tmp_info); |
1254 | type_data_make_W (node, info: &tmp_info, |
1255 | value_table: check_value_table_I (NODE_NAME (node), |
1256 | value_table: &tmp_value_table) ? &tmp_value_table : NULL); |
1257 | } |
1258 | else |
1259 | { |
1260 | g_assert (NODE_REFCOUNT (node) > 0); |
1261 | |
1262 | g_atomic_int_inc ((int *) &node->ref_count); |
1263 | } |
1264 | } |
1265 | |
1266 | static inline gboolean |
1267 | type_data_ref_U (TypeNode *node) |
1268 | { |
1269 | guint current; |
1270 | |
1271 | do { |
1272 | current = NODE_REFCOUNT (node); |
1273 | |
1274 | if (current < 1) |
1275 | return FALSE; |
1276 | } while (!g_atomic_int_compare_and_exchange ((int *) &node->ref_count, current, current + 1)); |
1277 | |
1278 | return TRUE; |
1279 | } |
1280 | |
1281 | static gboolean |
1282 | iface_node_has_available_offset_L (TypeNode *iface_node, |
1283 | gsize offset, |
1284 | int for_index) |
1285 | { |
1286 | guint8 *offsets; |
1287 | |
1288 | offsets = G_ATOMIC_ARRAY_GET_LOCKED (&iface_node->_prot.offsets, guint8); |
1289 | if (offsets == NULL) |
1290 | return TRUE; |
1291 | |
1292 | if (G_ATOMIC_ARRAY_DATA_SIZE (offsets) <= offset) |
1293 | return TRUE; |
1294 | |
1295 | if (offsets[offset] == 0 || |
1296 | offsets[offset] == for_index+1) |
1297 | return TRUE; |
1298 | |
1299 | return FALSE; |
1300 | } |
1301 | |
1302 | static gsize |
1303 | find_free_iface_offset_L (IFaceEntries *entries) |
1304 | { |
1305 | IFaceEntry *entry; |
1306 | TypeNode *iface_node; |
1307 | gsize offset; |
1308 | int i; |
1309 | int n_entries; |
1310 | |
1311 | n_entries = IFACE_ENTRIES_N_ENTRIES (entries); |
1312 | offset = 0; |
1313 | do |
1314 | { |
1315 | for (i = 0; i < n_entries; i++) |
1316 | { |
1317 | entry = &entries->entry[i]; |
1318 | iface_node = lookup_type_node_I (utype: entry->iface_type); |
1319 | |
1320 | if (!iface_node_has_available_offset_L (iface_node, offset, for_index: i)) |
1321 | { |
1322 | offset++; |
1323 | break; |
1324 | } |
1325 | } |
1326 | } |
1327 | while (i != n_entries); |
1328 | |
1329 | return offset; |
1330 | } |
1331 | |
1332 | static void |
1333 | iface_node_set_offset_L (TypeNode *iface_node, |
1334 | gsize offset, |
1335 | int index) |
1336 | { |
1337 | guint8 *offsets, *old_offsets; |
1338 | gsize new_size, old_size; |
1339 | gsize i; |
1340 | |
1341 | old_offsets = G_ATOMIC_ARRAY_GET_LOCKED (&iface_node->_prot.offsets, guint8); |
1342 | if (old_offsets == NULL) |
1343 | old_size = 0; |
1344 | else |
1345 | { |
1346 | old_size = G_ATOMIC_ARRAY_DATA_SIZE (old_offsets); |
1347 | if (offset < old_size && |
1348 | old_offsets[offset] == index + 1) |
1349 | return; /* Already set to this index, return */ |
1350 | } |
1351 | new_size = MAX (old_size, offset + 1); |
1352 | |
1353 | offsets = _g_atomic_array_copy (array: &iface_node->_prot.offsets, |
1354 | header_size: 0, additional_element_size: new_size - old_size); |
1355 | |
1356 | /* Mark new area as unused */ |
1357 | for (i = old_size; i < new_size; i++) |
1358 | offsets[i] = 0; |
1359 | |
1360 | offsets[offset] = index + 1; |
1361 | |
1362 | _g_atomic_array_update (array: &iface_node->_prot.offsets, new_data: offsets); |
1363 | } |
1364 | |
1365 | static void |
1366 | type_node_add_iface_entry_W (TypeNode *node, |
1367 | GType iface_type, |
1368 | IFaceEntry *parent_entry) |
1369 | { |
1370 | IFaceEntries *entries; |
1371 | IFaceEntry *entry; |
1372 | TypeNode *iface_node; |
1373 | guint i, j; |
1374 | guint num_entries; |
1375 | |
1376 | g_assert (node->is_instantiatable); |
1377 | |
1378 | entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node); |
1379 | if (entries != NULL) |
1380 | { |
1381 | num_entries = IFACE_ENTRIES_N_ENTRIES (entries); |
1382 | |
1383 | g_assert (num_entries < MAX_N_INTERFACES); |
1384 | |
1385 | for (i = 0; i < num_entries; i++) |
1386 | { |
1387 | entry = &entries->entry[i]; |
1388 | if (entry->iface_type == iface_type) |
1389 | { |
1390 | /* this can happen in two cases: |
1391 | * - our parent type already conformed to iface_type and node |
1392 | * got its own holder info. here, our children already have |
1393 | * entries and NULL vtables, since this will only work for |
1394 | * uninitialized classes. |
1395 | * - an interface type is added to an ancestor after it was |
1396 | * added to a child type. |
1397 | */ |
1398 | if (!parent_entry) |
1399 | g_assert (entry->vtable == NULL && entry->init_state == UNINITIALIZED); |
1400 | else |
1401 | { |
1402 | /* sick, interface is added to ancestor *after* child type; |
1403 | * nothing todo, the entry and our children were already setup correctly |
1404 | */ |
1405 | } |
1406 | return; |
1407 | } |
1408 | } |
1409 | } |
1410 | |
1411 | entries = _g_atomic_array_copy (CLASSED_NODE_IFACES_ENTRIES (node), |
1412 | IFACE_ENTRIES_HEADER_SIZE, |
1413 | additional_element_size: sizeof (IFaceEntry)); |
1414 | num_entries = IFACE_ENTRIES_N_ENTRIES (entries); |
1415 | i = num_entries - 1; |
1416 | if (i == 0) |
1417 | entries->offset_index = 0; |
1418 | entries->entry[i].iface_type = iface_type; |
1419 | entries->entry[i].vtable = NULL; |
1420 | entries->entry[i].init_state = UNINITIALIZED; |
1421 | |
1422 | if (parent_entry) |
1423 | { |
1424 | if (node->data && g_atomic_int_get (&node->data->class.init_state) >= BASE_IFACE_INIT) |
1425 | { |
1426 | entries->entry[i].init_state = INITIALIZED; |
1427 | entries->entry[i].vtable = parent_entry->vtable; |
1428 | } |
1429 | } |
1430 | |
1431 | /* Update offsets in iface */ |
1432 | iface_node = lookup_type_node_I (utype: iface_type); |
1433 | |
1434 | if (iface_node_has_available_offset_L (iface_node, |
1435 | offset: entries->offset_index, |
1436 | for_index: i)) |
1437 | { |
1438 | iface_node_set_offset_L (iface_node, |
1439 | offset: entries->offset_index, index: i); |
1440 | } |
1441 | else |
1442 | { |
1443 | entries->offset_index = |
1444 | find_free_iface_offset_L (entries); |
1445 | for (j = 0; j < IFACE_ENTRIES_N_ENTRIES (entries); j++) |
1446 | { |
1447 | entry = &entries->entry[j]; |
1448 | iface_node = |
1449 | lookup_type_node_I (utype: entry->iface_type); |
1450 | iface_node_set_offset_L (iface_node, |
1451 | offset: entries->offset_index, index: j); |
1452 | } |
1453 | } |
1454 | |
1455 | _g_atomic_array_update (CLASSED_NODE_IFACES_ENTRIES (node), new_data: entries); |
1456 | |
1457 | if (parent_entry) |
1458 | { |
1459 | for (i = 0; i < node->n_children; i++) |
1460 | type_node_add_iface_entry_W (node: lookup_type_node_I (utype: node->children[i]), iface_type, parent_entry: &entries->entry[i]); |
1461 | } |
1462 | } |
1463 | |
1464 | static void |
1465 | type_add_interface_Wm (TypeNode *node, |
1466 | TypeNode *iface, |
1467 | const GInterfaceInfo *info, |
1468 | GTypePlugin *plugin) |
1469 | { |
1470 | IFaceHolder *iholder = g_new0 (IFaceHolder, 1); |
1471 | IFaceEntry *entry; |
1472 | guint i; |
1473 | |
1474 | g_assert (node->is_instantiatable && NODE_IS_IFACE (iface) && ((info && !plugin) || (!info && plugin))); |
1475 | |
1476 | iholder->next = iface_node_get_holders_L (iface); |
1477 | iface_node_set_holders_W (iface, iholder); |
1478 | iholder->instance_type = NODE_TYPE (node); |
1479 | iholder->info = info ? g_memdup2 (mem: info, byte_size: sizeof (*info)) : NULL; |
1480 | iholder->plugin = plugin; |
1481 | |
1482 | /* create an iface entry for this type */ |
1483 | type_node_add_iface_entry_W (node, NODE_TYPE (iface), NULL); |
1484 | |
1485 | /* if the class is already (partly) initialized, we may need to base |
1486 | * initialize and/or initialize the new interface. |
1487 | */ |
1488 | if (node->data) |
1489 | { |
1490 | InitState class_state = g_atomic_int_get (&node->data->class.init_state); |
1491 | |
1492 | if (class_state >= BASE_IFACE_INIT) |
1493 | type_iface_vtable_base_init_Wm (iface, node); |
1494 | |
1495 | if (class_state >= IFACE_INIT) |
1496 | type_iface_vtable_iface_init_Wm (iface, node); |
1497 | } |
1498 | |
1499 | /* create iface entries for children of this type */ |
1500 | entry = type_lookup_iface_entry_L (node, iface_node: iface); |
1501 | for (i = 0; i < node->n_children; i++) |
1502 | type_node_add_iface_entry_W (node: lookup_type_node_I (utype: node->children[i]), NODE_TYPE (iface), parent_entry: entry); |
1503 | } |
1504 | |
1505 | static void |
1506 | type_iface_add_prerequisite_W (TypeNode *iface, |
1507 | TypeNode *prerequisite_node) |
1508 | { |
1509 | GType prerequisite_type = NODE_TYPE (prerequisite_node); |
1510 | GType *prerequisites, *dependants; |
1511 | guint n_dependants, i; |
1512 | |
1513 | g_assert (NODE_IS_IFACE (iface) && |
1514 | IFACE_NODE_N_PREREQUISITES (iface) < MAX_N_PREREQUISITES && |
1515 | (prerequisite_node->is_instantiatable || NODE_IS_IFACE (prerequisite_node))); |
1516 | |
1517 | prerequisites = IFACE_NODE_PREREQUISITES (iface); |
1518 | for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++) |
1519 | if (prerequisites[i] == prerequisite_type) |
1520 | return; /* we already have that prerequisiste */ |
1521 | else if (prerequisites[i] > prerequisite_type) |
1522 | break; |
1523 | IFACE_NODE_N_PREREQUISITES (iface) += 1; |
1524 | IFACE_NODE_PREREQUISITES (iface) = g_renew (GType, |
1525 | IFACE_NODE_PREREQUISITES (iface), |
1526 | IFACE_NODE_N_PREREQUISITES (iface)); |
1527 | prerequisites = IFACE_NODE_PREREQUISITES (iface); |
1528 | memmove (dest: prerequisites + i + 1, src: prerequisites + i, |
1529 | n: sizeof (prerequisites[0]) * (IFACE_NODE_N_PREREQUISITES (iface) - i - 1)); |
1530 | prerequisites[i] = prerequisite_type; |
1531 | |
1532 | /* we want to get notified when prerequisites get added to prerequisite_node */ |
1533 | if (NODE_IS_IFACE (prerequisite_node)) |
1534 | { |
1535 | dependants = iface_node_get_dependants_array_L (prerequisite_node); |
1536 | n_dependants = dependants ? dependants[0] : 0; |
1537 | n_dependants += 1; |
1538 | dependants = g_renew (GType, dependants, n_dependants + 1); |
1539 | dependants[n_dependants] = NODE_TYPE (iface); |
1540 | dependants[0] = n_dependants; |
1541 | iface_node_set_dependants_array_W (prerequisite_node, dependants); |
1542 | } |
1543 | |
1544 | /* we need to notify all dependants */ |
1545 | dependants = iface_node_get_dependants_array_L (iface); |
1546 | n_dependants = dependants ? dependants[0] : 0; |
1547 | for (i = 1; i <= n_dependants; i++) |
1548 | type_iface_add_prerequisite_W (iface: lookup_type_node_I (utype: dependants[i]), prerequisite_node); |
1549 | } |
1550 | |
1551 | /** |
1552 | * g_type_interface_add_prerequisite: |
1553 | * @interface_type: #GType value of an interface type |
1554 | * @prerequisite_type: #GType value of an interface or instantiatable type |
1555 | * |
1556 | * Adds @prerequisite_type to the list of prerequisites of @interface_type. |
1557 | * This means that any type implementing @interface_type must also implement |
1558 | * @prerequisite_type. Prerequisites can be thought of as an alternative to |
1559 | * interface derivation (which GType doesn't support). An interface can have |
1560 | * at most one instantiatable prerequisite type. |
1561 | */ |
1562 | void |
1563 | g_type_interface_add_prerequisite (GType interface_type, |
1564 | GType prerequisite_type) |
1565 | { |
1566 | TypeNode *iface, *prerequisite_node; |
1567 | IFaceHolder *holders; |
1568 | |
1569 | g_return_if_fail (G_TYPE_IS_INTERFACE (interface_type)); /* G_TYPE_IS_INTERFACE() is an external call: _U */ |
1570 | g_return_if_fail (!g_type_is_a (interface_type, prerequisite_type)); |
1571 | g_return_if_fail (!g_type_is_a (prerequisite_type, interface_type)); |
1572 | |
1573 | iface = lookup_type_node_I (utype: interface_type); |
1574 | prerequisite_node = lookup_type_node_I (utype: prerequisite_type); |
1575 | if (!iface || !prerequisite_node || !NODE_IS_IFACE (iface)) |
1576 | { |
1577 | g_warning ("interface type '%s' or prerequisite type '%s' invalid" , |
1578 | type_descriptive_name_I (interface_type), |
1579 | type_descriptive_name_I (prerequisite_type)); |
1580 | return; |
1581 | } |
1582 | G_WRITE_LOCK (&type_rw_lock); |
1583 | holders = iface_node_get_holders_L (iface); |
1584 | if (holders) |
1585 | { |
1586 | G_WRITE_UNLOCK (&type_rw_lock); |
1587 | g_warning ("unable to add prerequisite '%s' to interface '%s' which is already in use for '%s'" , |
1588 | type_descriptive_name_I (prerequisite_type), |
1589 | type_descriptive_name_I (interface_type), |
1590 | type_descriptive_name_I (holders->instance_type)); |
1591 | return; |
1592 | } |
1593 | if (prerequisite_node->is_instantiatable) |
1594 | { |
1595 | guint i; |
1596 | |
1597 | /* can have at most one publicly installable instantiatable prerequisite */ |
1598 | for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++) |
1599 | { |
1600 | TypeNode *prnode = lookup_type_node_I (IFACE_NODE_PREREQUISITES (iface)[i]); |
1601 | |
1602 | if (prnode->is_instantiatable) |
1603 | { |
1604 | G_WRITE_UNLOCK (&type_rw_lock); |
1605 | g_warning ("adding prerequisite '%s' to interface '%s' conflicts with existing prerequisite '%s'" , |
1606 | type_descriptive_name_I (prerequisite_type), |
1607 | type_descriptive_name_I (interface_type), |
1608 | type_descriptive_name_I (NODE_TYPE (prnode))); |
1609 | return; |
1610 | } |
1611 | } |
1612 | |
1613 | for (i = 0; i < prerequisite_node->n_supers + 1u; i++) |
1614 | type_iface_add_prerequisite_W (iface, prerequisite_node: lookup_type_node_I (utype: prerequisite_node->supers[i])); |
1615 | G_WRITE_UNLOCK (&type_rw_lock); |
1616 | } |
1617 | else if (NODE_IS_IFACE (prerequisite_node)) |
1618 | { |
1619 | GType *prerequisites; |
1620 | guint i; |
1621 | |
1622 | prerequisites = IFACE_NODE_PREREQUISITES (prerequisite_node); |
1623 | for (i = 0; i < IFACE_NODE_N_PREREQUISITES (prerequisite_node); i++) |
1624 | type_iface_add_prerequisite_W (iface, prerequisite_node: lookup_type_node_I (utype: prerequisites[i])); |
1625 | type_iface_add_prerequisite_W (iface, prerequisite_node); |
1626 | G_WRITE_UNLOCK (&type_rw_lock); |
1627 | } |
1628 | else |
1629 | { |
1630 | G_WRITE_UNLOCK (&type_rw_lock); |
1631 | g_warning ("prerequisite '%s' for interface '%s' is neither instantiatable nor interface" , |
1632 | type_descriptive_name_I (prerequisite_type), |
1633 | type_descriptive_name_I (interface_type)); |
1634 | } |
1635 | } |
1636 | |
1637 | /** |
1638 | * g_type_interface_prerequisites: |
1639 | * @interface_type: an interface type |
1640 | * @n_prerequisites: (out) (optional): location to return the number |
1641 | * of prerequisites, or %NULL |
1642 | * |
1643 | * Returns the prerequisites of an interfaces type. |
1644 | * |
1645 | * Since: 2.2 |
1646 | * |
1647 | * Returns: (array length=n_prerequisites) (transfer full): a |
1648 | * newly-allocated zero-terminated array of #GType containing |
1649 | * the prerequisites of @interface_type |
1650 | */ |
1651 | GType* |
1652 | g_type_interface_prerequisites (GType interface_type, |
1653 | guint *n_prerequisites) |
1654 | { |
1655 | TypeNode *iface; |
1656 | |
1657 | g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL); |
1658 | |
1659 | iface = lookup_type_node_I (utype: interface_type); |
1660 | if (iface) |
1661 | { |
1662 | GType *types; |
1663 | TypeNode *inode = NULL; |
1664 | guint i, n = 0; |
1665 | |
1666 | G_READ_LOCK (&type_rw_lock); |
1667 | types = g_new0 (GType, IFACE_NODE_N_PREREQUISITES (iface) + 1); |
1668 | for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++) |
1669 | { |
1670 | GType prerequisite = IFACE_NODE_PREREQUISITES (iface)[i]; |
1671 | TypeNode *node = lookup_type_node_I (utype: prerequisite); |
1672 | if (node->is_instantiatable) |
1673 | { |
1674 | if (!inode || type_node_is_a_L (node, iface_node: inode)) |
1675 | inode = node; |
1676 | } |
1677 | else |
1678 | types[n++] = NODE_TYPE (node); |
1679 | } |
1680 | if (inode) |
1681 | types[n++] = NODE_TYPE (inode); |
1682 | |
1683 | if (n_prerequisites) |
1684 | *n_prerequisites = n; |
1685 | G_READ_UNLOCK (&type_rw_lock); |
1686 | |
1687 | return types; |
1688 | } |
1689 | else |
1690 | { |
1691 | if (n_prerequisites) |
1692 | *n_prerequisites = 0; |
1693 | |
1694 | return NULL; |
1695 | } |
1696 | } |
1697 | |
1698 | /** |
1699 | * g_type_interface_instantiatable_prerequisite: |
1700 | * @interface_type: an interface type |
1701 | * |
1702 | * Returns the most specific instantiatable prerequisite of an |
1703 | * interface type. If the interface type has no instantiatable |
1704 | * prerequisite, %G_TYPE_INVALID is returned. |
1705 | * |
1706 | * See g_type_interface_add_prerequisite() for more information |
1707 | * about prerequisites. |
1708 | * |
1709 | * Returns: the instantiatable prerequisite type or %G_TYPE_INVALID if none |
1710 | * |
1711 | * Since: 2.68 |
1712 | **/ |
1713 | GType |
1714 | g_type_interface_instantiatable_prerequisite (GType interface_type) |
1715 | { |
1716 | TypeNode *inode = NULL; |
1717 | TypeNode *iface; |
1718 | guint i; |
1719 | |
1720 | g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), G_TYPE_INVALID); |
1721 | |
1722 | iface = lookup_type_node_I (utype: interface_type); |
1723 | if (iface == NULL) |
1724 | return G_TYPE_INVALID; |
1725 | |
1726 | G_READ_LOCK (&type_rw_lock); |
1727 | |
1728 | for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++) |
1729 | { |
1730 | GType prerequisite = IFACE_NODE_PREREQUISITES (iface)[i]; |
1731 | TypeNode *node = lookup_type_node_I (utype: prerequisite); |
1732 | if (node->is_instantiatable) |
1733 | { |
1734 | if (!inode || type_node_is_a_L (node, iface_node: inode)) |
1735 | inode = node; |
1736 | } |
1737 | } |
1738 | |
1739 | G_READ_UNLOCK (&type_rw_lock); |
1740 | |
1741 | if (inode) |
1742 | return NODE_TYPE (inode); |
1743 | else |
1744 | return G_TYPE_INVALID; |
1745 | } |
1746 | |
1747 | static IFaceHolder* |
1748 | type_iface_peek_holder_L (TypeNode *iface, |
1749 | GType instance_type) |
1750 | { |
1751 | IFaceHolder *iholder; |
1752 | |
1753 | g_assert (NODE_IS_IFACE (iface)); |
1754 | |
1755 | iholder = iface_node_get_holders_L (iface); |
1756 | while (iholder && iholder->instance_type != instance_type) |
1757 | iholder = iholder->next; |
1758 | return iholder; |
1759 | } |
1760 | |
1761 | static IFaceHolder* |
1762 | type_iface_retrieve_holder_info_Wm (TypeNode *iface, |
1763 | GType instance_type, |
1764 | gboolean need_info) |
1765 | { |
1766 | IFaceHolder *iholder = type_iface_peek_holder_L (iface, instance_type); |
1767 | |
1768 | if (iholder && !iholder->info && need_info) |
1769 | { |
1770 | GInterfaceInfo tmp_info; |
1771 | |
1772 | g_assert (iholder->plugin != NULL); |
1773 | |
1774 | type_data_ref_Wm (node: iface); |
1775 | if (iholder->info) |
1776 | INVALID_RECURSION ("g_type_plugin_*" , iface->plugin, NODE_NAME (iface)); |
1777 | |
1778 | memset (s: &tmp_info, c: 0, n: sizeof (tmp_info)); |
1779 | |
1780 | G_WRITE_UNLOCK (&type_rw_lock); |
1781 | g_type_plugin_use (plugin: iholder->plugin); |
1782 | g_type_plugin_complete_interface_info (plugin: iholder->plugin, instance_type, NODE_TYPE (iface), info: &tmp_info); |
1783 | G_WRITE_LOCK (&type_rw_lock); |
1784 | if (iholder->info) |
1785 | INVALID_RECURSION ("g_type_plugin_*" , iholder->plugin, NODE_NAME (iface)); |
1786 | |
1787 | check_interface_info_I (iface, instance_type, info: &tmp_info); |
1788 | iholder->info = g_memdup2 (mem: &tmp_info, byte_size: sizeof (tmp_info)); |
1789 | } |
1790 | |
1791 | return iholder; /* we don't modify write lock upon returning NULL */ |
1792 | } |
1793 | |
1794 | static void |
1795 | type_iface_blow_holder_info_Wm (TypeNode *iface, |
1796 | GType instance_type) |
1797 | { |
1798 | IFaceHolder *iholder = iface_node_get_holders_L (iface); |
1799 | |
1800 | g_assert (NODE_IS_IFACE (iface)); |
1801 | |
1802 | while (iholder->instance_type != instance_type) |
1803 | iholder = iholder->next; |
1804 | |
1805 | if (iholder->info && iholder->plugin) |
1806 | { |
1807 | g_free (mem: iholder->info); |
1808 | iholder->info = NULL; |
1809 | |
1810 | G_WRITE_UNLOCK (&type_rw_lock); |
1811 | g_type_plugin_unuse (plugin: iholder->plugin); |
1812 | type_data_unref_U (node: iface, FALSE); |
1813 | G_WRITE_LOCK (&type_rw_lock); |
1814 | } |
1815 | } |
1816 | |
1817 | /** |
1818 | * g_type_create_instance: (skip) |
1819 | * @type: an instantiatable type to create an instance for |
1820 | * |
1821 | * Creates and initializes an instance of @type if @type is valid and |
1822 | * can be instantiated. The type system only performs basic allocation |
1823 | * and structure setups for instances: actual instance creation should |
1824 | * happen through functions supplied by the type's fundamental type |
1825 | * implementation. So use of g_type_create_instance() is reserved for |
1826 | * implementers of fundamental types only. E.g. instances of the |
1827 | * #GObject hierarchy should be created via g_object_new() and never |
1828 | * directly through g_type_create_instance() which doesn't handle things |
1829 | * like singleton objects or object construction. |
1830 | * |
1831 | * The extended members of the returned instance are guaranteed to be filled |
1832 | * with zeros. |
1833 | * |
1834 | * Note: Do not use this function, unless you're implementing a |
1835 | * fundamental type. Also language bindings should not use this |
1836 | * function, but g_object_new() instead. |
1837 | * |
1838 | * Returns: an allocated and initialized instance, subject to further |
1839 | * treatment by the fundamental type implementation |
1840 | */ |
1841 | GTypeInstance* |
1842 | g_type_create_instance (GType type) |
1843 | { |
1844 | TypeNode *node; |
1845 | GTypeInstance *instance; |
1846 | GTypeClass *class; |
1847 | gchar *allocated; |
1848 | gint private_size; |
1849 | gint ivar_size; |
1850 | guint i; |
1851 | |
1852 | node = lookup_type_node_I (utype: type); |
1853 | if (!node || !node->is_instantiatable) |
1854 | { |
1855 | g_error ("cannot create new instance of invalid (non-instantiatable) type '%s'" , |
1856 | type_descriptive_name_I (type)); |
1857 | } |
1858 | /* G_TYPE_IS_ABSTRACT() is an external call: _U */ |
1859 | if (!node->mutatable_check_cache && G_TYPE_IS_ABSTRACT (type)) |
1860 | { |
1861 | g_error ("cannot create instance of abstract (non-instantiatable) type '%s'" , |
1862 | type_descriptive_name_I (type)); |
1863 | } |
1864 | |
1865 | class = g_type_class_ref (type); |
1866 | |
1867 | /* We allocate the 'private' areas before the normal instance data, in |
1868 | * reverse order. This allows the private area of a particular class |
1869 | * to always be at a constant relative address to the instance data. |
1870 | * If we stored the private data after the instance data this would |
1871 | * not be the case (since a subclass that added more instance |
1872 | * variables would push the private data further along). |
1873 | * |
1874 | * This presents problems for valgrindability, of course, so we do a |
1875 | * workaround for that case. We identify the start of the object to |
1876 | * valgrind as an allocated block (so that pointers to objects show up |
1877 | * as 'reachable' instead of 'possibly lost'). We then add an extra |
1878 | * pointer at the end of the object, after all instance data, back to |
1879 | * the start of the private area so that it is also recorded as |
1880 | * reachable. We also add extra private space at the start because |
1881 | * valgrind doesn't seem to like us claiming to have allocated an |
1882 | * address that it saw allocated by malloc(). |
1883 | */ |
1884 | private_size = node->data->instance.private_size; |
1885 | ivar_size = node->data->instance.instance_size; |
1886 | |
1887 | #ifdef ENABLE_VALGRIND |
1888 | if (private_size && RUNNING_ON_VALGRIND) |
1889 | { |
1890 | private_size += ALIGN_STRUCT (1); |
1891 | |
1892 | /* Allocate one extra pointer size... */ |
1893 | allocated = g_slice_alloc0 (block_size: private_size + ivar_size + sizeof (gpointer)); |
1894 | /* ... and point it back to the start of the private data. */ |
1895 | *(gpointer *) (allocated + private_size + ivar_size) = allocated + ALIGN_STRUCT (1); |
1896 | |
1897 | /* Tell valgrind that it should treat the object itself as such */ |
1898 | VALGRIND_MALLOCLIKE_BLOCK (allocated + private_size, ivar_size + sizeof (gpointer), 0, TRUE); |
1899 | VALGRIND_MALLOCLIKE_BLOCK (allocated + ALIGN_STRUCT (1), private_size - ALIGN_STRUCT (1), 0, TRUE); |
1900 | } |
1901 | else |
1902 | #endif |
1903 | allocated = g_slice_alloc0 (block_size: private_size + ivar_size); |
1904 | |
1905 | instance = (GTypeInstance *) (allocated + private_size); |
1906 | |
1907 | for (i = node->n_supers; i > 0; i--) |
1908 | { |
1909 | TypeNode *pnode; |
1910 | |
1911 | pnode = lookup_type_node_I (utype: node->supers[i]); |
1912 | if (pnode->data->instance.instance_init) |
1913 | { |
1914 | instance->g_class = pnode->data->instance.class; |
1915 | pnode->data->instance.instance_init (instance, class); |
1916 | } |
1917 | } |
1918 | |
1919 | instance->g_class = class; |
1920 | if (node->data->instance.instance_init) |
1921 | node->data->instance.instance_init (instance, class); |
1922 | |
1923 | #ifdef G_ENABLE_DEBUG |
1924 | IF_DEBUG (INSTANCE_COUNT) |
1925 | { |
1926 | g_atomic_int_inc ((int *) &node->instance_count); |
1927 | } |
1928 | #endif |
1929 | |
1930 | TRACE(GOBJECT_OBJECT_NEW(instance, type)); |
1931 | |
1932 | return instance; |
1933 | } |
1934 | |
1935 | /** |
1936 | * g_type_free_instance: |
1937 | * @instance: an instance of a type |
1938 | * |
1939 | * Frees an instance of a type, returning it to the instance pool for |
1940 | * the type, if there is one. |
1941 | * |
1942 | * Like g_type_create_instance(), this function is reserved for |
1943 | * implementors of fundamental types. |
1944 | */ |
1945 | void |
1946 | g_type_free_instance (GTypeInstance *instance) |
1947 | { |
1948 | TypeNode *node; |
1949 | GTypeClass *class; |
1950 | gchar *allocated; |
1951 | gint private_size; |
1952 | gint ivar_size; |
1953 | |
1954 | g_return_if_fail (instance != NULL && instance->g_class != NULL); |
1955 | |
1956 | class = instance->g_class; |
1957 | node = lookup_type_node_I (utype: class->g_type); |
1958 | if (!node || !node->is_instantiatable || !node->data || node->data->class.class != (gpointer) class) |
1959 | { |
1960 | g_warning ("cannot free instance of invalid (non-instantiatable) type '%s'" , |
1961 | type_descriptive_name_I (class->g_type)); |
1962 | return; |
1963 | } |
1964 | /* G_TYPE_IS_ABSTRACT() is an external call: _U */ |
1965 | if (!node->mutatable_check_cache && G_TYPE_IS_ABSTRACT (NODE_TYPE (node))) |
1966 | { |
1967 | g_warning ("cannot free instance of abstract (non-instantiatable) type '%s'" , |
1968 | NODE_NAME (node)); |
1969 | return; |
1970 | } |
1971 | |
1972 | instance->g_class = NULL; |
1973 | private_size = node->data->instance.private_size; |
1974 | ivar_size = node->data->instance.instance_size; |
1975 | allocated = ((gchar *) instance) - private_size; |
1976 | |
1977 | #ifdef G_ENABLE_DEBUG |
1978 | memset (s: allocated, c: 0xaa, n: ivar_size + private_size); |
1979 | #endif |
1980 | |
1981 | #ifdef ENABLE_VALGRIND |
1982 | /* See comment in g_type_create_instance() about what's going on here. |
1983 | * We're basically unwinding what we put into motion there. |
1984 | */ |
1985 | if (private_size && RUNNING_ON_VALGRIND) |
1986 | { |
1987 | private_size += ALIGN_STRUCT (1); |
1988 | allocated -= ALIGN_STRUCT (1); |
1989 | |
1990 | /* Clear out the extra pointer... */ |
1991 | *(gpointer *) (allocated + private_size + ivar_size) = NULL; |
1992 | /* ... and ensure we include it in the size we free. */ |
1993 | g_slice_free1 (block_size: private_size + ivar_size + sizeof (gpointer), mem_block: allocated); |
1994 | |
1995 | VALGRIND_FREELIKE_BLOCK (allocated + ALIGN_STRUCT (1), 0); |
1996 | VALGRIND_FREELIKE_BLOCK (instance, 0); |
1997 | } |
1998 | else |
1999 | #endif |
2000 | g_slice_free1 (block_size: private_size + ivar_size, mem_block: allocated); |
2001 | |
2002 | #ifdef G_ENABLE_DEBUG |
2003 | IF_DEBUG (INSTANCE_COUNT) |
2004 | { |
2005 | g_atomic_int_add ((int *) &node->instance_count, -1); |
2006 | } |
2007 | #endif |
2008 | |
2009 | g_type_class_unref (g_class: class); |
2010 | } |
2011 | |
2012 | static void |
2013 | type_iface_ensure_dflt_vtable_Wm (TypeNode *iface) |
2014 | { |
2015 | g_assert (iface->data); |
2016 | |
2017 | if (!iface->data->iface.dflt_vtable) |
2018 | { |
2019 | GTypeInterface *vtable = g_malloc0 (n_bytes: iface->data->iface.vtable_size); |
2020 | iface->data->iface.dflt_vtable = vtable; |
2021 | vtable->g_type = NODE_TYPE (iface); |
2022 | vtable->g_instance_type = 0; |
2023 | if (iface->data->iface.vtable_init_base || |
2024 | iface->data->iface.dflt_init) |
2025 | { |
2026 | G_WRITE_UNLOCK (&type_rw_lock); |
2027 | if (iface->data->iface.vtable_init_base) |
2028 | iface->data->iface.vtable_init_base (vtable); |
2029 | if (iface->data->iface.dflt_init) |
2030 | iface->data->iface.dflt_init (vtable, (gpointer) iface->data->iface.dflt_data); |
2031 | G_WRITE_LOCK (&type_rw_lock); |
2032 | } |
2033 | } |
2034 | } |
2035 | |
2036 | |
2037 | /* This is called to allocate and do the first part of initializing |
2038 | * the interface vtable; type_iface_vtable_iface_init_Wm() does the remainder. |
2039 | * |
2040 | * A FALSE return indicates that we didn't find an init function for |
2041 | * this type/iface pair, so the vtable from the parent type should |
2042 | * be used. Note that the write lock is not modified upon a FALSE |
2043 | * return. |
2044 | */ |
2045 | static gboolean |
2046 | type_iface_vtable_base_init_Wm (TypeNode *iface, |
2047 | TypeNode *node) |
2048 | { |
2049 | IFaceEntry *entry; |
2050 | IFaceHolder *iholder; |
2051 | GTypeInterface *vtable = NULL; |
2052 | TypeNode *pnode; |
2053 | |
2054 | /* type_iface_retrieve_holder_info_Wm() doesn't modify write lock for returning NULL */ |
2055 | iholder = type_iface_retrieve_holder_info_Wm (iface, NODE_TYPE (node), TRUE); |
2056 | if (!iholder) |
2057 | return FALSE; /* we don't modify write lock upon FALSE */ |
2058 | |
2059 | type_iface_ensure_dflt_vtable_Wm (iface); |
2060 | |
2061 | entry = type_lookup_iface_entry_L (node, iface_node: iface); |
2062 | |
2063 | g_assert (iface->data && entry && entry->vtable == NULL && iholder && iholder->info); |
2064 | |
2065 | entry->init_state = IFACE_INIT; |
2066 | |
2067 | pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
2068 | if (pnode) /* want to copy over parent iface contents */ |
2069 | { |
2070 | IFaceEntry *pentry = type_lookup_iface_entry_L (node: pnode, iface_node: iface); |
2071 | |
2072 | if (pentry) |
2073 | vtable = g_memdup2 (mem: pentry->vtable, byte_size: iface->data->iface.vtable_size); |
2074 | } |
2075 | if (!vtable) |
2076 | vtable = g_memdup2 (mem: iface->data->iface.dflt_vtable, byte_size: iface->data->iface.vtable_size); |
2077 | entry->vtable = vtable; |
2078 | vtable->g_type = NODE_TYPE (iface); |
2079 | vtable->g_instance_type = NODE_TYPE (node); |
2080 | |
2081 | if (iface->data->iface.vtable_init_base) |
2082 | { |
2083 | G_WRITE_UNLOCK (&type_rw_lock); |
2084 | iface->data->iface.vtable_init_base (vtable); |
2085 | G_WRITE_LOCK (&type_rw_lock); |
2086 | } |
2087 | return TRUE; /* initialized the vtable */ |
2088 | } |
2089 | |
2090 | /* Finishes what type_iface_vtable_base_init_Wm started by |
2091 | * calling the interface init function. |
2092 | * this function may only be called for types with their |
2093 | * own interface holder info, i.e. types for which |
2094 | * g_type_add_interface*() was called and not children thereof. |
2095 | */ |
2096 | static void |
2097 | type_iface_vtable_iface_init_Wm (TypeNode *iface, |
2098 | TypeNode *node) |
2099 | { |
2100 | IFaceEntry *entry = type_lookup_iface_entry_L (node, iface_node: iface); |
2101 | IFaceHolder *iholder = type_iface_peek_holder_L (iface, NODE_TYPE (node)); |
2102 | GTypeInterface *vtable = NULL; |
2103 | guint i; |
2104 | |
2105 | /* iholder->info should have been filled in by type_iface_vtable_base_init_Wm() */ |
2106 | g_assert (iface->data && entry && iholder && iholder->info); |
2107 | g_assert (entry->init_state == IFACE_INIT); /* assert prior base_init() */ |
2108 | |
2109 | entry->init_state = INITIALIZED; |
2110 | |
2111 | vtable = entry->vtable; |
2112 | |
2113 | if (iholder->info->interface_init) |
2114 | { |
2115 | G_WRITE_UNLOCK (&type_rw_lock); |
2116 | if (iholder->info->interface_init) |
2117 | iholder->info->interface_init (vtable, iholder->info->interface_data); |
2118 | G_WRITE_LOCK (&type_rw_lock); |
2119 | } |
2120 | |
2121 | for (i = 0; i < static_n_iface_check_funcs; i++) |
2122 | { |
2123 | GTypeInterfaceCheckFunc check_func = static_iface_check_funcs[i].check_func; |
2124 | gpointer check_data = static_iface_check_funcs[i].check_data; |
2125 | |
2126 | G_WRITE_UNLOCK (&type_rw_lock); |
2127 | check_func (check_data, (gpointer)vtable); |
2128 | G_WRITE_LOCK (&type_rw_lock); |
2129 | } |
2130 | } |
2131 | |
2132 | static gboolean |
2133 | type_iface_vtable_finalize_Wm (TypeNode *iface, |
2134 | TypeNode *node, |
2135 | GTypeInterface *vtable) |
2136 | { |
2137 | IFaceEntry *entry = type_lookup_iface_entry_L (node, iface_node: iface); |
2138 | IFaceHolder *iholder; |
2139 | |
2140 | /* type_iface_retrieve_holder_info_Wm() doesn't modify write lock for returning NULL */ |
2141 | iholder = type_iface_retrieve_holder_info_Wm (iface, NODE_TYPE (node), FALSE); |
2142 | if (!iholder) |
2143 | return FALSE; /* we don't modify write lock upon FALSE */ |
2144 | |
2145 | g_assert (entry && entry->vtable == vtable && iholder->info); |
2146 | |
2147 | entry->vtable = NULL; |
2148 | entry->init_state = UNINITIALIZED; |
2149 | if (iholder->info->interface_finalize || iface->data->iface.vtable_finalize_base) |
2150 | { |
2151 | G_WRITE_UNLOCK (&type_rw_lock); |
2152 | if (iholder->info->interface_finalize) |
2153 | iholder->info->interface_finalize (vtable, iholder->info->interface_data); |
2154 | if (iface->data->iface.vtable_finalize_base) |
2155 | iface->data->iface.vtable_finalize_base (vtable); |
2156 | G_WRITE_LOCK (&type_rw_lock); |
2157 | } |
2158 | vtable->g_type = 0; |
2159 | vtable->g_instance_type = 0; |
2160 | g_free (mem: vtable); |
2161 | |
2162 | type_iface_blow_holder_info_Wm (iface, NODE_TYPE (node)); |
2163 | |
2164 | return TRUE; /* write lock modified */ |
2165 | } |
2166 | |
2167 | static void |
2168 | type_class_init_Wm (TypeNode *node, |
2169 | GTypeClass *pclass) |
2170 | { |
2171 | GSList *slist, *init_slist = NULL; |
2172 | GTypeClass *class; |
2173 | IFaceEntries *entries; |
2174 | IFaceEntry *entry; |
2175 | TypeNode *bnode, *pnode; |
2176 | guint i; |
2177 | |
2178 | /* Accessing data->class will work for instantiatable types |
2179 | * too because ClassData is a subset of InstanceData |
2180 | */ |
2181 | g_assert (node->is_classed && node->data && |
2182 | node->data->class.class_size && |
2183 | !node->data->class.class && |
2184 | g_atomic_int_get (&node->data->class.init_state) == UNINITIALIZED); |
2185 | if (node->data->class.class_private_size) |
2186 | class = g_malloc0 (ALIGN_STRUCT (node->data->class.class_size) + node->data->class.class_private_size); |
2187 | else |
2188 | class = g_malloc0 (n_bytes: node->data->class.class_size); |
2189 | node->data->class.class = class; |
2190 | g_atomic_int_set (&node->data->class.init_state, BASE_CLASS_INIT); |
2191 | |
2192 | if (pclass) |
2193 | { |
2194 | TypeNode *pnode = lookup_type_node_I (utype: pclass->g_type); |
2195 | |
2196 | memcpy (dest: class, src: pclass, n: pnode->data->class.class_size); |
2197 | 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)), n: pnode->data->class.class_private_size); |
2198 | |
2199 | if (node->is_instantiatable) |
2200 | { |
2201 | /* We need to initialize the private_size here rather than in |
2202 | * type_data_make_W() since the class init for the parent |
2203 | * class may have changed pnode->data->instance.private_size. |
2204 | */ |
2205 | node->data->instance.private_size = pnode->data->instance.private_size; |
2206 | } |
2207 | } |
2208 | class->g_type = NODE_TYPE (node); |
2209 | |
2210 | G_WRITE_UNLOCK (&type_rw_lock); |
2211 | |
2212 | /* stack all base class initialization functions, so we |
2213 | * call them in ascending order. |
2214 | */ |
2215 | for (bnode = node; bnode; bnode = lookup_type_node_I (NODE_PARENT_TYPE (bnode))) |
2216 | if (bnode->data->class.class_init_base) |
2217 | init_slist = g_slist_prepend (list: init_slist, data: (gpointer) bnode->data->class.class_init_base); |
2218 | for (slist = init_slist; slist; slist = slist->next) |
2219 | { |
2220 | GBaseInitFunc class_init_base = (GBaseInitFunc) slist->data; |
2221 | |
2222 | class_init_base (class); |
2223 | } |
2224 | g_slist_free (list: init_slist); |
2225 | |
2226 | G_WRITE_LOCK (&type_rw_lock); |
2227 | |
2228 | g_atomic_int_set (&node->data->class.init_state, BASE_IFACE_INIT); |
2229 | |
2230 | /* Before we initialize the class, base initialize all interfaces, either |
2231 | * from parent, or through our holder info |
2232 | */ |
2233 | pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
2234 | |
2235 | i = 0; |
2236 | while ((entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node)) != NULL && |
2237 | i < IFACE_ENTRIES_N_ENTRIES (entries)) |
2238 | { |
2239 | entry = &entries->entry[i]; |
2240 | while (i < IFACE_ENTRIES_N_ENTRIES (entries) && |
2241 | entry->init_state == IFACE_INIT) |
2242 | { |
2243 | entry++; |
2244 | i++; |
2245 | } |
2246 | |
2247 | if (i == IFACE_ENTRIES_N_ENTRIES (entries)) |
2248 | break; |
2249 | |
2250 | if (!type_iface_vtable_base_init_Wm (iface: lookup_type_node_I (utype: entry->iface_type), node)) |
2251 | { |
2252 | guint j; |
2253 | IFaceEntries *pentries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (pnode); |
2254 | |
2255 | /* need to get this interface from parent, type_iface_vtable_base_init_Wm() |
2256 | * doesn't modify write lock upon FALSE, so entry is still valid; |
2257 | */ |
2258 | g_assert (pnode != NULL); |
2259 | |
2260 | if (pentries) |
2261 | for (j = 0; j < IFACE_ENTRIES_N_ENTRIES (pentries); j++) |
2262 | { |
2263 | IFaceEntry *pentry = &pentries->entry[j]; |
2264 | |
2265 | if (pentry->iface_type == entry->iface_type) |
2266 | { |
2267 | entry->vtable = pentry->vtable; |
2268 | entry->init_state = INITIALIZED; |
2269 | break; |
2270 | } |
2271 | } |
2272 | g_assert (entry->vtable != NULL); |
2273 | } |
2274 | |
2275 | /* If the write lock was released, additional interface entries might |
2276 | * have been inserted into CLASSED_NODE_IFACES_ENTRIES (node); they'll |
2277 | * be base-initialized when inserted, so we don't have to worry that |
2278 | * we might miss them. Uninitialized entries can only be moved higher |
2279 | * when new ones are inserted. |
2280 | */ |
2281 | i++; |
2282 | } |
2283 | |
2284 | g_atomic_int_set (&node->data->class.init_state, CLASS_INIT); |
2285 | |
2286 | G_WRITE_UNLOCK (&type_rw_lock); |
2287 | |
2288 | if (node->data->class.class_init) |
2289 | node->data->class.class_init (class, (gpointer) node->data->class.class_data); |
2290 | |
2291 | G_WRITE_LOCK (&type_rw_lock); |
2292 | |
2293 | g_atomic_int_set (&node->data->class.init_state, IFACE_INIT); |
2294 | |
2295 | /* finish initializing the interfaces through our holder info. |
2296 | * inherited interfaces are already init_state == INITIALIZED, because |
2297 | * they either got setup in the above base_init loop, or during |
2298 | * class_init from within type_add_interface_Wm() for this or |
2299 | * an ancestor type. |
2300 | */ |
2301 | i = 0; |
2302 | while ((entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node)) != NULL) |
2303 | { |
2304 | entry = &entries->entry[i]; |
2305 | while (i < IFACE_ENTRIES_N_ENTRIES (entries) && |
2306 | entry->init_state == INITIALIZED) |
2307 | { |
2308 | entry++; |
2309 | i++; |
2310 | } |
2311 | |
2312 | if (i == IFACE_ENTRIES_N_ENTRIES (entries)) |
2313 | break; |
2314 | |
2315 | type_iface_vtable_iface_init_Wm (iface: lookup_type_node_I (utype: entry->iface_type), node); |
2316 | |
2317 | /* As in the loop above, additional initialized entries might be inserted |
2318 | * if the write lock is released, but that's harmless because the entries |
2319 | * we need to initialize only move higher in the list. |
2320 | */ |
2321 | i++; |
2322 | } |
2323 | |
2324 | g_atomic_int_set (&node->data->class.init_state, INITIALIZED); |
2325 | } |
2326 | |
2327 | static void |
2328 | type_data_finalize_class_ifaces_Wm (TypeNode *node) |
2329 | { |
2330 | guint i; |
2331 | IFaceEntries *entries; |
2332 | |
2333 | g_assert (node->is_instantiatable && node->data && node->data->class.class && NODE_REFCOUNT (node) == 0); |
2334 | |
2335 | reiterate: |
2336 | entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node); |
2337 | for (i = 0; entries != NULL && i < IFACE_ENTRIES_N_ENTRIES (entries); i++) |
2338 | { |
2339 | IFaceEntry *entry = &entries->entry[i]; |
2340 | if (entry->vtable) |
2341 | { |
2342 | if (type_iface_vtable_finalize_Wm (iface: lookup_type_node_I (utype: entry->iface_type), node, vtable: entry->vtable)) |
2343 | { |
2344 | /* refetch entries, IFACES_ENTRIES might be modified */ |
2345 | goto reiterate; |
2346 | } |
2347 | else |
2348 | { |
2349 | /* type_iface_vtable_finalize_Wm() doesn't modify write lock upon FALSE, |
2350 | * iface vtable came from parent |
2351 | */ |
2352 | entry->vtable = NULL; |
2353 | entry->init_state = UNINITIALIZED; |
2354 | } |
2355 | } |
2356 | } |
2357 | } |
2358 | |
2359 | static void |
2360 | type_data_finalize_class_U (TypeNode *node, |
2361 | ClassData *cdata) |
2362 | { |
2363 | GTypeClass *class = cdata->class; |
2364 | TypeNode *bnode; |
2365 | |
2366 | g_assert (cdata->class && NODE_REFCOUNT (node) == 0); |
2367 | |
2368 | if (cdata->class_finalize) |
2369 | cdata->class_finalize (class, (gpointer) cdata->class_data); |
2370 | |
2371 | /* call all base class destruction functions in descending order |
2372 | */ |
2373 | if (cdata->class_finalize_base) |
2374 | cdata->class_finalize_base (class); |
2375 | for (bnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); bnode; bnode = lookup_type_node_I (NODE_PARENT_TYPE (bnode))) |
2376 | if (bnode->data->class.class_finalize_base) |
2377 | bnode->data->class.class_finalize_base (class); |
2378 | |
2379 | g_free (mem: cdata->class); |
2380 | } |
2381 | |
2382 | static void |
2383 | type_data_last_unref_Wm (TypeNode *node, |
2384 | gboolean uncached) |
2385 | { |
2386 | g_return_if_fail (node != NULL && node->plugin != NULL); |
2387 | |
2388 | if (!node->data || NODE_REFCOUNT (node) == 0) |
2389 | { |
2390 | g_warning ("cannot drop last reference to unreferenced type '%s'" , |
2391 | NODE_NAME (node)); |
2392 | return; |
2393 | } |
2394 | |
2395 | /* call class cache hooks */ |
2396 | if (node->is_classed && node->data && node->data->class.class && static_n_class_cache_funcs && !uncached) |
2397 | { |
2398 | guint i; |
2399 | |
2400 | G_WRITE_UNLOCK (&type_rw_lock); |
2401 | G_READ_LOCK (&type_rw_lock); |
2402 | for (i = 0; i < static_n_class_cache_funcs; i++) |
2403 | { |
2404 | GTypeClassCacheFunc cache_func = static_class_cache_funcs[i].cache_func; |
2405 | gpointer cache_data = static_class_cache_funcs[i].cache_data; |
2406 | gboolean need_break; |
2407 | |
2408 | G_READ_UNLOCK (&type_rw_lock); |
2409 | need_break = cache_func (cache_data, node->data->class.class); |
2410 | G_READ_LOCK (&type_rw_lock); |
2411 | if (!node->data || NODE_REFCOUNT (node) == 0) |
2412 | INVALID_RECURSION ("GType class cache function " , cache_func, NODE_NAME (node)); |
2413 | if (need_break) |
2414 | break; |
2415 | } |
2416 | G_READ_UNLOCK (&type_rw_lock); |
2417 | G_WRITE_LOCK (&type_rw_lock); |
2418 | } |
2419 | |
2420 | /* may have been re-referenced meanwhile */ |
2421 | if (g_atomic_int_dec_and_test ((int *) &node->ref_count)) |
2422 | { |
2423 | GType ptype = NODE_PARENT_TYPE (node); |
2424 | TypeData *tdata; |
2425 | |
2426 | if (node->is_instantiatable) |
2427 | { |
2428 | /* destroy node->data->instance.mem_chunk */ |
2429 | } |
2430 | |
2431 | tdata = node->data; |
2432 | if (node->is_classed && tdata->class.class) |
2433 | { |
2434 | if (CLASSED_NODE_IFACES_ENTRIES_LOCKED (node) != NULL) |
2435 | type_data_finalize_class_ifaces_Wm (node); |
2436 | node->mutatable_check_cache = FALSE; |
2437 | node->data = NULL; |
2438 | G_WRITE_UNLOCK (&type_rw_lock); |
2439 | type_data_finalize_class_U (node, cdata: &tdata->class); |
2440 | G_WRITE_LOCK (&type_rw_lock); |
2441 | } |
2442 | else if (NODE_IS_IFACE (node) && tdata->iface.dflt_vtable) |
2443 | { |
2444 | node->mutatable_check_cache = FALSE; |
2445 | node->data = NULL; |
2446 | if (tdata->iface.dflt_finalize || tdata->iface.vtable_finalize_base) |
2447 | { |
2448 | G_WRITE_UNLOCK (&type_rw_lock); |
2449 | if (tdata->iface.dflt_finalize) |
2450 | tdata->iface.dflt_finalize (tdata->iface.dflt_vtable, (gpointer) tdata->iface.dflt_data); |
2451 | if (tdata->iface.vtable_finalize_base) |
2452 | tdata->iface.vtable_finalize_base (tdata->iface.dflt_vtable); |
2453 | G_WRITE_LOCK (&type_rw_lock); |
2454 | } |
2455 | g_free (mem: tdata->iface.dflt_vtable); |
2456 | } |
2457 | else |
2458 | { |
2459 | node->mutatable_check_cache = FALSE; |
2460 | node->data = NULL; |
2461 | } |
2462 | |
2463 | /* freeing tdata->common.value_table and its contents is taken care of |
2464 | * by allocating it in one chunk with tdata |
2465 | */ |
2466 | g_free (mem: tdata); |
2467 | |
2468 | G_WRITE_UNLOCK (&type_rw_lock); |
2469 | g_type_plugin_unuse (plugin: node->plugin); |
2470 | if (ptype) |
2471 | type_data_unref_U (node: lookup_type_node_I (utype: ptype), FALSE); |
2472 | G_WRITE_LOCK (&type_rw_lock); |
2473 | } |
2474 | } |
2475 | |
2476 | static inline void |
2477 | type_data_unref_U (TypeNode *node, |
2478 | gboolean uncached) |
2479 | { |
2480 | guint current; |
2481 | |
2482 | do { |
2483 | current = NODE_REFCOUNT (node); |
2484 | |
2485 | if (current <= 1) |
2486 | { |
2487 | if (!node->plugin) |
2488 | { |
2489 | g_warning ("static type '%s' unreferenced too often" , |
2490 | NODE_NAME (node)); |
2491 | return; |
2492 | } |
2493 | else |
2494 | { |
2495 | /* This is the last reference of a type from a plugin. We are |
2496 | * experimentally disabling support for unloading type |
2497 | * plugins, so don't allow the last ref to drop. |
2498 | */ |
2499 | return; |
2500 | } |
2501 | |
2502 | g_assert (current > 0); |
2503 | |
2504 | g_rec_mutex_lock (rec_mutex: &class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */ |
2505 | G_WRITE_LOCK (&type_rw_lock); |
2506 | type_data_last_unref_Wm (node, uncached); |
2507 | G_WRITE_UNLOCK (&type_rw_lock); |
2508 | g_rec_mutex_unlock (rec_mutex: &class_init_rec_mutex); |
2509 | return; |
2510 | } |
2511 | } while (!g_atomic_int_compare_and_exchange ((int *) &node->ref_count, current, current - 1)); |
2512 | } |
2513 | |
2514 | /** |
2515 | * g_type_add_class_cache_func: (skip) |
2516 | * @cache_data: data to be passed to @cache_func |
2517 | * @cache_func: a #GTypeClassCacheFunc |
2518 | * |
2519 | * Adds a #GTypeClassCacheFunc to be called before the reference count of a |
2520 | * class goes from one to zero. This can be used to prevent premature class |
2521 | * destruction. All installed #GTypeClassCacheFunc functions will be chained |
2522 | * until one of them returns %TRUE. The functions have to check the class id |
2523 | * passed in to figure whether they actually want to cache the class of this |
2524 | * type, since all classes are routed through the same #GTypeClassCacheFunc |
2525 | * chain. |
2526 | */ |
2527 | void |
2528 | g_type_add_class_cache_func (gpointer cache_data, |
2529 | GTypeClassCacheFunc cache_func) |
2530 | { |
2531 | guint i; |
2532 | |
2533 | g_return_if_fail (cache_func != NULL); |
2534 | |
2535 | G_WRITE_LOCK (&type_rw_lock); |
2536 | i = static_n_class_cache_funcs++; |
2537 | static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs); |
2538 | static_class_cache_funcs[i].cache_data = cache_data; |
2539 | static_class_cache_funcs[i].cache_func = cache_func; |
2540 | G_WRITE_UNLOCK (&type_rw_lock); |
2541 | } |
2542 | |
2543 | /** |
2544 | * g_type_remove_class_cache_func: (skip) |
2545 | * @cache_data: data that was given when adding @cache_func |
2546 | * @cache_func: a #GTypeClassCacheFunc |
2547 | * |
2548 | * Removes a previously installed #GTypeClassCacheFunc. The cache |
2549 | * maintained by @cache_func has to be empty when calling |
2550 | * g_type_remove_class_cache_func() to avoid leaks. |
2551 | */ |
2552 | void |
2553 | g_type_remove_class_cache_func (gpointer cache_data, |
2554 | GTypeClassCacheFunc cache_func) |
2555 | { |
2556 | gboolean found_it = FALSE; |
2557 | guint i; |
2558 | |
2559 | g_return_if_fail (cache_func != NULL); |
2560 | |
2561 | G_WRITE_LOCK (&type_rw_lock); |
2562 | for (i = 0; i < static_n_class_cache_funcs; i++) |
2563 | if (static_class_cache_funcs[i].cache_data == cache_data && |
2564 | static_class_cache_funcs[i].cache_func == cache_func) |
2565 | { |
2566 | static_n_class_cache_funcs--; |
2567 | memmove (dest: static_class_cache_funcs + i, |
2568 | src: static_class_cache_funcs + i + 1, |
2569 | n: sizeof (static_class_cache_funcs[0]) * (static_n_class_cache_funcs - i)); |
2570 | static_class_cache_funcs = g_renew (ClassCacheFunc, static_class_cache_funcs, static_n_class_cache_funcs); |
2571 | found_it = TRUE; |
2572 | break; |
2573 | } |
2574 | G_WRITE_UNLOCK (&type_rw_lock); |
2575 | |
2576 | if (!found_it) |
2577 | g_warning (G_STRLOC ": cannot remove unregistered class cache func %p with data %p" , |
2578 | cache_func, cache_data); |
2579 | } |
2580 | |
2581 | |
2582 | /** |
2583 | * g_type_add_interface_check: (skip) |
2584 | * @check_data: data to pass to @check_func |
2585 | * @check_func: function to be called after each interface |
2586 | * is initialized |
2587 | * |
2588 | * Adds a function to be called after an interface vtable is |
2589 | * initialized for any class (i.e. after the @interface_init |
2590 | * member of #GInterfaceInfo has been called). |
2591 | * |
2592 | * This function is useful when you want to check an invariant |
2593 | * that depends on the interfaces of a class. For instance, the |
2594 | * implementation of #GObject uses this facility to check that an |
2595 | * object implements all of the properties that are defined on its |
2596 | * interfaces. |
2597 | * |
2598 | * Since: 2.4 |
2599 | */ |
2600 | void |
2601 | g_type_add_interface_check (gpointer check_data, |
2602 | GTypeInterfaceCheckFunc check_func) |
2603 | { |
2604 | guint i; |
2605 | |
2606 | g_return_if_fail (check_func != NULL); |
2607 | |
2608 | G_WRITE_LOCK (&type_rw_lock); |
2609 | i = static_n_iface_check_funcs++; |
2610 | static_iface_check_funcs = g_renew (IFaceCheckFunc, static_iface_check_funcs, static_n_iface_check_funcs); |
2611 | static_iface_check_funcs[i].check_data = check_data; |
2612 | static_iface_check_funcs[i].check_func = check_func; |
2613 | G_WRITE_UNLOCK (&type_rw_lock); |
2614 | } |
2615 | |
2616 | /** |
2617 | * g_type_remove_interface_check: (skip) |
2618 | * @check_data: callback data passed to g_type_add_interface_check() |
2619 | * @check_func: callback function passed to g_type_add_interface_check() |
2620 | * |
2621 | * Removes an interface check function added with |
2622 | * g_type_add_interface_check(). |
2623 | * |
2624 | * Since: 2.4 |
2625 | */ |
2626 | void |
2627 | g_type_remove_interface_check (gpointer check_data, |
2628 | GTypeInterfaceCheckFunc check_func) |
2629 | { |
2630 | gboolean found_it = FALSE; |
2631 | guint i; |
2632 | |
2633 | g_return_if_fail (check_func != NULL); |
2634 | |
2635 | G_WRITE_LOCK (&type_rw_lock); |
2636 | for (i = 0; i < static_n_iface_check_funcs; i++) |
2637 | if (static_iface_check_funcs[i].check_data == check_data && |
2638 | static_iface_check_funcs[i].check_func == check_func) |
2639 | { |
2640 | static_n_iface_check_funcs--; |
2641 | memmove (dest: static_iface_check_funcs + i, |
2642 | src: static_iface_check_funcs + i + 1, |
2643 | n: sizeof (static_iface_check_funcs[0]) * (static_n_iface_check_funcs - i)); |
2644 | static_iface_check_funcs = g_renew (IFaceCheckFunc, static_iface_check_funcs, static_n_iface_check_funcs); |
2645 | found_it = TRUE; |
2646 | break; |
2647 | } |
2648 | G_WRITE_UNLOCK (&type_rw_lock); |
2649 | |
2650 | if (!found_it) |
2651 | g_warning (G_STRLOC ": cannot remove unregistered class check func %p with data %p" , |
2652 | check_func, check_data); |
2653 | } |
2654 | |
2655 | /* --- type registration --- */ |
2656 | /** |
2657 | * g_type_register_fundamental: |
2658 | * @type_id: a predefined type identifier |
2659 | * @type_name: 0-terminated string used as the name of the new type |
2660 | * @info: #GTypeInfo structure for this type |
2661 | * @finfo: #GTypeFundamentalInfo structure for this type |
2662 | * @flags: bitwise combination of #GTypeFlags values |
2663 | * |
2664 | * Registers @type_id as the predefined identifier and @type_name as the |
2665 | * name of a fundamental type. If @type_id is already registered, or a |
2666 | * type named @type_name is already registered, the behaviour is undefined. |
2667 | * The type system uses the information contained in the #GTypeInfo structure |
2668 | * pointed to by @info and the #GTypeFundamentalInfo structure pointed to by |
2669 | * @finfo to manage the type and its instances. The value of @flags determines |
2670 | * additional characteristics of the fundamental type. |
2671 | * |
2672 | * Returns: the predefined type identifier |
2673 | */ |
2674 | GType |
2675 | g_type_register_fundamental (GType type_id, |
2676 | const gchar *type_name, |
2677 | const GTypeInfo *info, |
2678 | const GTypeFundamentalInfo *finfo, |
2679 | GTypeFlags flags) |
2680 | { |
2681 | TypeNode *node; |
2682 | |
2683 | g_assert_type_system_initialized (); |
2684 | g_return_val_if_fail (type_id > 0, 0); |
2685 | g_return_val_if_fail (type_name != NULL, 0); |
2686 | g_return_val_if_fail (info != NULL, 0); |
2687 | g_return_val_if_fail (finfo != NULL, 0); |
2688 | |
2689 | if (!check_type_name_I (type_name)) |
2690 | return 0; |
2691 | if ((type_id & TYPE_ID_MASK) || |
2692 | type_id > G_TYPE_FUNDAMENTAL_MAX) |
2693 | { |
2694 | g_warning ("attempt to register fundamental type '%s' with invalid type id (%" G_GSIZE_FORMAT ")" , |
2695 | type_name, |
2696 | type_id); |
2697 | return 0; |
2698 | } |
2699 | if ((finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) && |
2700 | !(finfo->type_flags & G_TYPE_FLAG_CLASSED)) |
2701 | { |
2702 | g_warning ("cannot register instantiatable fundamental type '%s' as non-classed" , |
2703 | type_name); |
2704 | return 0; |
2705 | } |
2706 | if (lookup_type_node_I (utype: type_id)) |
2707 | { |
2708 | g_warning ("cannot register existing fundamental type '%s' (as '%s')" , |
2709 | type_descriptive_name_I (type_id), |
2710 | type_name); |
2711 | return 0; |
2712 | } |
2713 | |
2714 | G_WRITE_LOCK (&type_rw_lock); |
2715 | node = type_node_fundamental_new_W (ftype: type_id, name: type_name, type_flags: finfo->type_flags); |
2716 | type_add_flags_W (node, flags); |
2717 | |
2718 | if (check_type_info_I (NULL, NODE_FUNDAMENTAL_TYPE (node), type_name, info)) |
2719 | type_data_make_W (node, info, |
2720 | value_table: check_value_table_I (type_name, value_table: info->value_table) ? info->value_table : NULL); |
2721 | G_WRITE_UNLOCK (&type_rw_lock); |
2722 | |
2723 | return NODE_TYPE (node); |
2724 | } |
2725 | |
2726 | /** |
2727 | * g_type_register_static_simple: (skip) |
2728 | * @parent_type: type from which this type will be derived |
2729 | * @type_name: 0-terminated string used as the name of the new type |
2730 | * @class_size: size of the class structure (see #GTypeInfo) |
2731 | * @class_init: location of the class initialization function (see #GTypeInfo) |
2732 | * @instance_size: size of the instance structure (see #GTypeInfo) |
2733 | * @instance_init: location of the instance initialization function (see #GTypeInfo) |
2734 | * @flags: bitwise combination of #GTypeFlags values |
2735 | * |
2736 | * Registers @type_name as the name of a new static type derived from |
2737 | * @parent_type. The value of @flags determines the nature (e.g. |
2738 | * abstract or not) of the type. It works by filling a #GTypeInfo |
2739 | * struct and calling g_type_register_static(). |
2740 | * |
2741 | * Since: 2.12 |
2742 | * |
2743 | * Returns: the new type identifier |
2744 | */ |
2745 | GType |
2746 | g_type_register_static_simple (GType parent_type, |
2747 | const gchar *type_name, |
2748 | guint class_size, |
2749 | GClassInitFunc class_init, |
2750 | guint instance_size, |
2751 | GInstanceInitFunc instance_init, |
2752 | GTypeFlags flags) |
2753 | { |
2754 | GTypeInfo info; |
2755 | |
2756 | /* Instances are not allowed to be larger than this. If you have a big |
2757 | * fixed-length array or something, point to it instead. |
2758 | */ |
2759 | g_return_val_if_fail (class_size <= G_MAXUINT16, G_TYPE_INVALID); |
2760 | g_return_val_if_fail (instance_size <= G_MAXUINT16, G_TYPE_INVALID); |
2761 | |
2762 | info.class_size = class_size; |
2763 | info.base_init = NULL; |
2764 | info.base_finalize = NULL; |
2765 | info.class_init = class_init; |
2766 | info.class_finalize = NULL; |
2767 | info.class_data = NULL; |
2768 | info.instance_size = instance_size; |
2769 | info.n_preallocs = 0; |
2770 | info.instance_init = instance_init; |
2771 | info.value_table = NULL; |
2772 | |
2773 | return g_type_register_static (parent_type, type_name, info: &info, flags); |
2774 | } |
2775 | |
2776 | /** |
2777 | * g_type_register_static: |
2778 | * @parent_type: type from which this type will be derived |
2779 | * @type_name: 0-terminated string used as the name of the new type |
2780 | * @info: #GTypeInfo structure for this type |
2781 | * @flags: bitwise combination of #GTypeFlags values |
2782 | * |
2783 | * Registers @type_name as the name of a new static type derived from |
2784 | * @parent_type. The type system uses the information contained in the |
2785 | * #GTypeInfo structure pointed to by @info to manage the type and its |
2786 | * instances (if not abstract). The value of @flags determines the nature |
2787 | * (e.g. abstract or not) of the type. |
2788 | * |
2789 | * Returns: the new type identifier |
2790 | */ |
2791 | GType |
2792 | g_type_register_static (GType parent_type, |
2793 | const gchar *type_name, |
2794 | const GTypeInfo *info, |
2795 | GTypeFlags flags) |
2796 | { |
2797 | TypeNode *pnode, *node; |
2798 | GType type = 0; |
2799 | |
2800 | g_assert_type_system_initialized (); |
2801 | g_return_val_if_fail (parent_type > 0, 0); |
2802 | g_return_val_if_fail (type_name != NULL, 0); |
2803 | g_return_val_if_fail (info != NULL, 0); |
2804 | |
2805 | if (!check_type_name_I (type_name) || |
2806 | !check_derivation_I (parent_type, type_name)) |
2807 | return 0; |
2808 | if (info->class_finalize) |
2809 | { |
2810 | g_warning ("class finalizer specified for static type '%s'" , |
2811 | type_name); |
2812 | return 0; |
2813 | } |
2814 | |
2815 | pnode = lookup_type_node_I (utype: parent_type); |
2816 | G_WRITE_LOCK (&type_rw_lock); |
2817 | type_data_ref_Wm (node: pnode); |
2818 | if (check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (pnode), type_name, info)) |
2819 | { |
2820 | node = type_node_new_W (pnode, name: type_name, NULL); |
2821 | type_add_flags_W (node, flags); |
2822 | type = NODE_TYPE (node); |
2823 | type_data_make_W (node, info, |
2824 | value_table: check_value_table_I (type_name, value_table: info->value_table) ? info->value_table : NULL); |
2825 | } |
2826 | G_WRITE_UNLOCK (&type_rw_lock); |
2827 | |
2828 | return type; |
2829 | } |
2830 | |
2831 | /** |
2832 | * g_type_register_dynamic: |
2833 | * @parent_type: type from which this type will be derived |
2834 | * @type_name: 0-terminated string used as the name of the new type |
2835 | * @plugin: #GTypePlugin structure to retrieve the #GTypeInfo from |
2836 | * @flags: bitwise combination of #GTypeFlags values |
2837 | * |
2838 | * Registers @type_name as the name of a new dynamic type derived from |
2839 | * @parent_type. The type system uses the information contained in the |
2840 | * #GTypePlugin structure pointed to by @plugin to manage the type and its |
2841 | * instances (if not abstract). The value of @flags determines the nature |
2842 | * (e.g. abstract or not) of the type. |
2843 | * |
2844 | * Returns: the new type identifier or #G_TYPE_INVALID if registration failed |
2845 | */ |
2846 | GType |
2847 | g_type_register_dynamic (GType parent_type, |
2848 | const gchar *type_name, |
2849 | GTypePlugin *plugin, |
2850 | GTypeFlags flags) |
2851 | { |
2852 | TypeNode *pnode, *node; |
2853 | GType type; |
2854 | |
2855 | g_assert_type_system_initialized (); |
2856 | g_return_val_if_fail (parent_type > 0, 0); |
2857 | g_return_val_if_fail (type_name != NULL, 0); |
2858 | g_return_val_if_fail (plugin != NULL, 0); |
2859 | |
2860 | if (!check_type_name_I (type_name) || |
2861 | !check_derivation_I (parent_type, type_name) || |
2862 | !check_plugin_U (plugin, TRUE, FALSE, type_name)) |
2863 | return 0; |
2864 | |
2865 | G_WRITE_LOCK (&type_rw_lock); |
2866 | pnode = lookup_type_node_I (utype: parent_type); |
2867 | node = type_node_new_W (pnode, name: type_name, plugin); |
2868 | type_add_flags_W (node, flags); |
2869 | type = NODE_TYPE (node); |
2870 | G_WRITE_UNLOCK (&type_rw_lock); |
2871 | |
2872 | return type; |
2873 | } |
2874 | |
2875 | /** |
2876 | * g_type_add_interface_static: |
2877 | * @instance_type: #GType value of an instantiatable type |
2878 | * @interface_type: #GType value of an interface type |
2879 | * @info: #GInterfaceInfo structure for this |
2880 | * (@instance_type, @interface_type) combination |
2881 | * |
2882 | * Adds @interface_type to the static @instance_type. |
2883 | * The information contained in the #GInterfaceInfo structure |
2884 | * pointed to by @info is used to manage the relationship. |
2885 | */ |
2886 | void |
2887 | g_type_add_interface_static (GType instance_type, |
2888 | GType interface_type, |
2889 | const GInterfaceInfo *info) |
2890 | { |
2891 | /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */ |
2892 | g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type)); |
2893 | g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE); |
2894 | |
2895 | /* we only need to lock class_init_rec_mutex if instance_type already has its |
2896 | * class initialized, however this function is rarely enough called to take |
2897 | * the simple route and always acquire class_init_rec_mutex. |
2898 | */ |
2899 | g_rec_mutex_lock (rec_mutex: &class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */ |
2900 | G_WRITE_LOCK (&type_rw_lock); |
2901 | if (check_add_interface_L (instance_type, iface_type: interface_type)) |
2902 | { |
2903 | TypeNode *node = lookup_type_node_I (utype: instance_type); |
2904 | TypeNode *iface = lookup_type_node_I (utype: interface_type); |
2905 | if (check_interface_info_I (iface, NODE_TYPE (node), info)) |
2906 | type_add_interface_Wm (node, iface, info, NULL); |
2907 | } |
2908 | G_WRITE_UNLOCK (&type_rw_lock); |
2909 | g_rec_mutex_unlock (rec_mutex: &class_init_rec_mutex); |
2910 | } |
2911 | |
2912 | /** |
2913 | * g_type_add_interface_dynamic: |
2914 | * @instance_type: #GType value of an instantiatable type |
2915 | * @interface_type: #GType value of an interface type |
2916 | * @plugin: #GTypePlugin structure to retrieve the #GInterfaceInfo from |
2917 | * |
2918 | * Adds @interface_type to the dynamic @instance_type. The information |
2919 | * contained in the #GTypePlugin structure pointed to by @plugin |
2920 | * is used to manage the relationship. |
2921 | */ |
2922 | void |
2923 | g_type_add_interface_dynamic (GType instance_type, |
2924 | GType interface_type, |
2925 | GTypePlugin *plugin) |
2926 | { |
2927 | TypeNode *node; |
2928 | /* G_TYPE_IS_INSTANTIATABLE() is an external call: _U */ |
2929 | g_return_if_fail (G_TYPE_IS_INSTANTIATABLE (instance_type)); |
2930 | g_return_if_fail (g_type_parent (interface_type) == G_TYPE_INTERFACE); |
2931 | |
2932 | node = lookup_type_node_I (utype: instance_type); |
2933 | if (!check_plugin_U (plugin, FALSE, TRUE, NODE_NAME (node))) |
2934 | return; |
2935 | |
2936 | /* see comment in g_type_add_interface_static() about class_init_rec_mutex */ |
2937 | g_rec_mutex_lock (rec_mutex: &class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */ |
2938 | G_WRITE_LOCK (&type_rw_lock); |
2939 | if (check_add_interface_L (instance_type, iface_type: interface_type)) |
2940 | { |
2941 | TypeNode *iface = lookup_type_node_I (utype: interface_type); |
2942 | type_add_interface_Wm (node, iface, NULL, plugin); |
2943 | } |
2944 | G_WRITE_UNLOCK (&type_rw_lock); |
2945 | g_rec_mutex_unlock (rec_mutex: &class_init_rec_mutex); |
2946 | } |
2947 | |
2948 | |
2949 | /* --- public API functions --- */ |
2950 | /** |
2951 | * g_type_class_ref: |
2952 | * @type: type ID of a classed type |
2953 | * |
2954 | * Increments the reference count of the class structure belonging to |
2955 | * @type. This function will demand-create the class if it doesn't |
2956 | * exist already. |
2957 | * |
2958 | * Returns: (type GObject.TypeClass) (transfer none): the #GTypeClass |
2959 | * structure for the given type ID |
2960 | */ |
2961 | gpointer |
2962 | g_type_class_ref (GType type) |
2963 | { |
2964 | TypeNode *node; |
2965 | GType ptype; |
2966 | gboolean holds_ref; |
2967 | GTypeClass *pclass; |
2968 | |
2969 | /* optimize for common code path */ |
2970 | node = lookup_type_node_I (utype: type); |
2971 | if (!node || !node->is_classed) |
2972 | { |
2973 | g_warning ("cannot retrieve class for invalid (unclassed) type '%s'" , |
2974 | type_descriptive_name_I (type)); |
2975 | return NULL; |
2976 | } |
2977 | |
2978 | if (G_LIKELY (type_data_ref_U (node))) |
2979 | { |
2980 | if (G_LIKELY (g_atomic_int_get (&node->data->class.init_state) == INITIALIZED)) |
2981 | return node->data->class.class; |
2982 | holds_ref = TRUE; |
2983 | } |
2984 | else |
2985 | holds_ref = FALSE; |
2986 | |
2987 | /* here, we either have node->data->class.class == NULL, or a recursive |
2988 | * call to g_type_class_ref() with a partly initialized class, or |
2989 | * node->data->class.init_state == INITIALIZED, because any |
2990 | * concurrently running initialization was guarded by class_init_rec_mutex. |
2991 | */ |
2992 | g_rec_mutex_lock (rec_mutex: &class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */ |
2993 | |
2994 | /* we need an initialized parent class for initializing derived classes */ |
2995 | ptype = NODE_PARENT_TYPE (node); |
2996 | pclass = ptype ? g_type_class_ref (type: ptype) : NULL; |
2997 | |
2998 | G_WRITE_LOCK (&type_rw_lock); |
2999 | |
3000 | if (!holds_ref) |
3001 | type_data_ref_Wm (node); |
3002 | |
3003 | if (!node->data->class.class) /* class uninitialized */ |
3004 | type_class_init_Wm (node, pclass); |
3005 | |
3006 | G_WRITE_UNLOCK (&type_rw_lock); |
3007 | |
3008 | if (pclass) |
3009 | g_type_class_unref (g_class: pclass); |
3010 | |
3011 | g_rec_mutex_unlock (rec_mutex: &class_init_rec_mutex); |
3012 | |
3013 | return node->data->class.class; |
3014 | } |
3015 | |
3016 | /** |
3017 | * g_type_class_unref: |
3018 | * @g_class: (type GObject.TypeClass): a #GTypeClass structure to unref |
3019 | * |
3020 | * Decrements the reference count of the class structure being passed in. |
3021 | * Once the last reference count of a class has been released, classes |
3022 | * may be finalized by the type system, so further dereferencing of a |
3023 | * class pointer after g_type_class_unref() are invalid. |
3024 | */ |
3025 | void |
3026 | g_type_class_unref (gpointer g_class) |
3027 | { |
3028 | TypeNode *node; |
3029 | GTypeClass *class = g_class; |
3030 | |
3031 | g_return_if_fail (g_class != NULL); |
3032 | |
3033 | node = lookup_type_node_I (utype: class->g_type); |
3034 | if (node && node->is_classed && NODE_REFCOUNT (node)) |
3035 | type_data_unref_U (node, FALSE); |
3036 | else |
3037 | g_warning ("cannot unreference class of invalid (unclassed) type '%s'" , |
3038 | type_descriptive_name_I (class->g_type)); |
3039 | } |
3040 | |
3041 | /** |
3042 | * g_type_class_unref_uncached: (skip) |
3043 | * @g_class: (type GObject.TypeClass): a #GTypeClass structure to unref |
3044 | * |
3045 | * A variant of g_type_class_unref() for use in #GTypeClassCacheFunc |
3046 | * implementations. It unreferences a class without consulting the chain |
3047 | * of #GTypeClassCacheFuncs, avoiding the recursion which would occur |
3048 | * otherwise. |
3049 | */ |
3050 | void |
3051 | g_type_class_unref_uncached (gpointer g_class) |
3052 | { |
3053 | TypeNode *node; |
3054 | GTypeClass *class = g_class; |
3055 | |
3056 | g_return_if_fail (g_class != NULL); |
3057 | |
3058 | node = lookup_type_node_I (utype: class->g_type); |
3059 | if (node && node->is_classed && NODE_REFCOUNT (node)) |
3060 | type_data_unref_U (node, TRUE); |
3061 | else |
3062 | g_warning ("cannot unreference class of invalid (unclassed) type '%s'" , |
3063 | type_descriptive_name_I (class->g_type)); |
3064 | } |
3065 | |
3066 | /** |
3067 | * g_type_class_peek: |
3068 | * @type: type ID of a classed type |
3069 | * |
3070 | * This function is essentially the same as g_type_class_ref(), |
3071 | * except that the classes reference count isn't incremented. |
3072 | * As a consequence, this function may return %NULL if the class |
3073 | * of the type passed in does not currently exist (hasn't been |
3074 | * referenced before). |
3075 | * |
3076 | * Returns: (type GObject.TypeClass) (transfer none): the #GTypeClass |
3077 | * structure for the given type ID or %NULL if the class does not |
3078 | * currently exist |
3079 | */ |
3080 | gpointer |
3081 | g_type_class_peek (GType type) |
3082 | { |
3083 | TypeNode *node; |
3084 | gpointer class; |
3085 | |
3086 | node = lookup_type_node_I (utype: type); |
3087 | if (node && node->is_classed && NODE_REFCOUNT (node) && |
3088 | g_atomic_int_get (&node->data->class.init_state) == INITIALIZED) |
3089 | /* ref_count _may_ be 0 */ |
3090 | class = node->data->class.class; |
3091 | else |
3092 | class = NULL; |
3093 | |
3094 | return class; |
3095 | } |
3096 | |
3097 | /** |
3098 | * g_type_class_peek_static: |
3099 | * @type: type ID of a classed type |
3100 | * |
3101 | * A more efficient version of g_type_class_peek() which works only for |
3102 | * static types. |
3103 | * |
3104 | * Returns: (type GObject.TypeClass) (transfer none): the #GTypeClass |
3105 | * structure for the given type ID or %NULL if the class does not |
3106 | * currently exist or is dynamically loaded |
3107 | * |
3108 | * Since: 2.4 |
3109 | */ |
3110 | gpointer |
3111 | g_type_class_peek_static (GType type) |
3112 | { |
3113 | TypeNode *node; |
3114 | gpointer class; |
3115 | |
3116 | node = lookup_type_node_I (utype: type); |
3117 | if (node && node->is_classed && NODE_REFCOUNT (node) && |
3118 | /* peek only static types: */ node->plugin == NULL && |
3119 | g_atomic_int_get (&node->data->class.init_state) == INITIALIZED) |
3120 | /* ref_count _may_ be 0 */ |
3121 | class = node->data->class.class; |
3122 | else |
3123 | class = NULL; |
3124 | |
3125 | return class; |
3126 | } |
3127 | |
3128 | /** |
3129 | * g_type_class_peek_parent: |
3130 | * @g_class: (type GObject.TypeClass): the #GTypeClass structure to |
3131 | * retrieve the parent class for |
3132 | * |
3133 | * This is a convenience function often needed in class initializers. |
3134 | * It returns the class structure of the immediate parent type of the |
3135 | * class passed in. Since derived classes hold a reference count on |
3136 | * their parent classes as long as they are instantiated, the returned |
3137 | * class will always exist. |
3138 | * |
3139 | * This function is essentially equivalent to: |
3140 | * g_type_class_peek (g_type_parent (G_TYPE_FROM_CLASS (g_class))) |
3141 | * |
3142 | * Returns: (type GObject.TypeClass) (transfer none): the parent class |
3143 | * of @g_class |
3144 | */ |
3145 | gpointer |
3146 | g_type_class_peek_parent (gpointer g_class) |
3147 | { |
3148 | TypeNode *node; |
3149 | gpointer class = NULL; |
3150 | |
3151 | g_return_val_if_fail (g_class != NULL, NULL); |
3152 | |
3153 | node = lookup_type_node_I (G_TYPE_FROM_CLASS (g_class)); |
3154 | /* We used to acquire a read lock here. That is not necessary, since |
3155 | * parent->data->class.class is constant as long as the derived class |
3156 | * exists. |
3157 | */ |
3158 | if (node && node->is_classed && node->data && NODE_PARENT_TYPE (node)) |
3159 | { |
3160 | node = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
3161 | class = node->data->class.class; |
3162 | } |
3163 | else if (NODE_PARENT_TYPE (node)) |
3164 | g_warning (G_STRLOC ": invalid class pointer '%p'" , g_class); |
3165 | |
3166 | return class; |
3167 | } |
3168 | |
3169 | /** |
3170 | * g_type_interface_peek: |
3171 | * @instance_class: (type GObject.TypeClass): a #GTypeClass structure |
3172 | * @iface_type: an interface ID which this class conforms to |
3173 | * |
3174 | * Returns the #GTypeInterface structure of an interface to which the |
3175 | * passed in class conforms. |
3176 | * |
3177 | * Returns: (type GObject.TypeInterface) (transfer none): the #GTypeInterface |
3178 | * structure of @iface_type if implemented by @instance_class, %NULL |
3179 | * otherwise |
3180 | */ |
3181 | gpointer |
3182 | g_type_interface_peek (gpointer instance_class, |
3183 | GType iface_type) |
3184 | { |
3185 | TypeNode *node; |
3186 | TypeNode *iface; |
3187 | gpointer vtable = NULL; |
3188 | GTypeClass *class = instance_class; |
3189 | |
3190 | g_return_val_if_fail (instance_class != NULL, NULL); |
3191 | |
3192 | node = lookup_type_node_I (utype: class->g_type); |
3193 | iface = lookup_type_node_I (utype: iface_type); |
3194 | if (node && node->is_instantiatable && iface) |
3195 | type_lookup_iface_vtable_I (node, iface_node: iface, vtable_ptr: &vtable); |
3196 | else |
3197 | g_warning (G_STRLOC ": invalid class pointer '%p'" , class); |
3198 | |
3199 | return vtable; |
3200 | } |
3201 | |
3202 | /** |
3203 | * g_type_interface_peek_parent: |
3204 | * @g_iface: (type GObject.TypeInterface): a #GTypeInterface structure |
3205 | * |
3206 | * Returns the corresponding #GTypeInterface structure of the parent type |
3207 | * of the instance type to which @g_iface belongs. This is useful when |
3208 | * deriving the implementation of an interface from the parent type and |
3209 | * then possibly overriding some methods. |
3210 | * |
3211 | * Returns: (transfer none) (type GObject.TypeInterface): the |
3212 | * corresponding #GTypeInterface structure of the parent type of the |
3213 | * instance type to which @g_iface belongs, or %NULL if the parent |
3214 | * type doesn't conform to the interface |
3215 | */ |
3216 | gpointer |
3217 | g_type_interface_peek_parent (gpointer g_iface) |
3218 | { |
3219 | TypeNode *node; |
3220 | TypeNode *iface; |
3221 | gpointer vtable = NULL; |
3222 | GTypeInterface *iface_class = g_iface; |
3223 | |
3224 | g_return_val_if_fail (g_iface != NULL, NULL); |
3225 | |
3226 | iface = lookup_type_node_I (utype: iface_class->g_type); |
3227 | node = lookup_type_node_I (utype: iface_class->g_instance_type); |
3228 | if (node) |
3229 | node = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
3230 | if (node && node->is_instantiatable && iface) |
3231 | type_lookup_iface_vtable_I (node, iface_node: iface, vtable_ptr: &vtable); |
3232 | else if (node) |
3233 | g_warning (G_STRLOC ": invalid interface pointer '%p'" , g_iface); |
3234 | |
3235 | return vtable; |
3236 | } |
3237 | |
3238 | /** |
3239 | * g_type_default_interface_ref: |
3240 | * @g_type: an interface type |
3241 | * |
3242 | * Increments the reference count for the interface type @g_type, |
3243 | * and returns the default interface vtable for the type. |
3244 | * |
3245 | * If the type is not currently in use, then the default vtable |
3246 | * for the type will be created and initialized by calling |
3247 | * the base interface init and default vtable init functions for |
3248 | * the type (the @base_init and @class_init members of #GTypeInfo). |
3249 | * Calling g_type_default_interface_ref() is useful when you |
3250 | * want to make sure that signals and properties for an interface |
3251 | * have been installed. |
3252 | * |
3253 | * Since: 2.4 |
3254 | * |
3255 | * Returns: (type GObject.TypeInterface) (transfer none): the default |
3256 | * vtable for the interface; call g_type_default_interface_unref() |
3257 | * when you are done using the interface. |
3258 | */ |
3259 | gpointer |
3260 | g_type_default_interface_ref (GType g_type) |
3261 | { |
3262 | TypeNode *node; |
3263 | gpointer dflt_vtable; |
3264 | |
3265 | G_WRITE_LOCK (&type_rw_lock); |
3266 | |
3267 | node = lookup_type_node_I (utype: g_type); |
3268 | if (!node || !NODE_IS_IFACE (node) || |
3269 | (node->data && NODE_REFCOUNT (node) == 0)) |
3270 | { |
3271 | G_WRITE_UNLOCK (&type_rw_lock); |
3272 | g_warning ("cannot retrieve default vtable for invalid or non-interface type '%s'" , |
3273 | type_descriptive_name_I (g_type)); |
3274 | return NULL; |
3275 | } |
3276 | |
3277 | if (!node->data || !node->data->iface.dflt_vtable) |
3278 | { |
3279 | G_WRITE_UNLOCK (&type_rw_lock); |
3280 | g_rec_mutex_lock (rec_mutex: &class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */ |
3281 | G_WRITE_LOCK (&type_rw_lock); |
3282 | node = lookup_type_node_I (utype: g_type); |
3283 | type_data_ref_Wm (node); |
3284 | type_iface_ensure_dflt_vtable_Wm (iface: node); |
3285 | g_rec_mutex_unlock (rec_mutex: &class_init_rec_mutex); |
3286 | } |
3287 | else |
3288 | type_data_ref_Wm (node); /* ref_count >= 1 already */ |
3289 | |
3290 | dflt_vtable = node->data->iface.dflt_vtable; |
3291 | G_WRITE_UNLOCK (&type_rw_lock); |
3292 | |
3293 | return dflt_vtable; |
3294 | } |
3295 | |
3296 | /** |
3297 | * g_type_default_interface_peek: |
3298 | * @g_type: an interface type |
3299 | * |
3300 | * If the interface type @g_type is currently in use, returns its |
3301 | * default interface vtable. |
3302 | * |
3303 | * Since: 2.4 |
3304 | * |
3305 | * Returns: (type GObject.TypeInterface) (transfer none): the default |
3306 | * vtable for the interface, or %NULL if the type is not currently |
3307 | * in use |
3308 | */ |
3309 | gpointer |
3310 | g_type_default_interface_peek (GType g_type) |
3311 | { |
3312 | TypeNode *node; |
3313 | gpointer vtable; |
3314 | |
3315 | node = lookup_type_node_I (utype: g_type); |
3316 | if (node && NODE_IS_IFACE (node) && NODE_REFCOUNT (node)) |
3317 | vtable = node->data->iface.dflt_vtable; |
3318 | else |
3319 | vtable = NULL; |
3320 | |
3321 | return vtable; |
3322 | } |
3323 | |
3324 | /** |
3325 | * g_type_default_interface_unref: |
3326 | * @g_iface: (type GObject.TypeInterface): the default vtable |
3327 | * structure for an interface, as returned by g_type_default_interface_ref() |
3328 | * |
3329 | * Decrements the reference count for the type corresponding to the |
3330 | * interface default vtable @g_iface. If the type is dynamic, then |
3331 | * when no one is using the interface and all references have |
3332 | * been released, the finalize function for the interface's default |
3333 | * vtable (the @class_finalize member of #GTypeInfo) will be called. |
3334 | * |
3335 | * Since: 2.4 |
3336 | */ |
3337 | void |
3338 | g_type_default_interface_unref (gpointer g_iface) |
3339 | { |
3340 | TypeNode *node; |
3341 | GTypeInterface *vtable = g_iface; |
3342 | |
3343 | g_return_if_fail (g_iface != NULL); |
3344 | |
3345 | node = lookup_type_node_I (utype: vtable->g_type); |
3346 | if (node && NODE_IS_IFACE (node)) |
3347 | type_data_unref_U (node, FALSE); |
3348 | else |
3349 | g_warning ("cannot unreference invalid interface default vtable for '%s'" , |
3350 | type_descriptive_name_I (vtable->g_type)); |
3351 | } |
3352 | |
3353 | /** |
3354 | * g_type_name: |
3355 | * @type: type to return name for |
3356 | * |
3357 | * Get the unique name that is assigned to a type ID. Note that this |
3358 | * function (like all other GType API) cannot cope with invalid type |
3359 | * IDs. %G_TYPE_INVALID may be passed to this function, as may be any |
3360 | * other validly registered type ID, but randomized type IDs should |
3361 | * not be passed in and will most likely lead to a crash. |
3362 | * |
3363 | * Returns: static type name or %NULL |
3364 | */ |
3365 | const gchar * |
3366 | g_type_name (GType type) |
3367 | { |
3368 | TypeNode *node; |
3369 | |
3370 | g_assert_type_system_initialized (); |
3371 | |
3372 | node = lookup_type_node_I (utype: type); |
3373 | |
3374 | return node ? NODE_NAME (node) : NULL; |
3375 | } |
3376 | |
3377 | /** |
3378 | * g_type_qname: |
3379 | * @type: type to return quark of type name for |
3380 | * |
3381 | * Get the corresponding quark of the type IDs name. |
3382 | * |
3383 | * Returns: the type names quark or 0 |
3384 | */ |
3385 | GQuark |
3386 | g_type_qname (GType type) |
3387 | { |
3388 | TypeNode *node; |
3389 | |
3390 | node = lookup_type_node_I (utype: type); |
3391 | |
3392 | return node ? node->qname : 0; |
3393 | } |
3394 | |
3395 | /** |
3396 | * g_type_from_name: |
3397 | * @name: type name to look up |
3398 | * |
3399 | * Look up the type ID from a given type name, returning 0 if no type |
3400 | * has been registered under this name (this is the preferred method |
3401 | * to find out by name whether a specific type has been registered |
3402 | * yet). |
3403 | * |
3404 | * Returns: corresponding type ID or 0 |
3405 | */ |
3406 | GType |
3407 | g_type_from_name (const gchar *name) |
3408 | { |
3409 | GType type = 0; |
3410 | |
3411 | g_return_val_if_fail (name != NULL, 0); |
3412 | |
3413 | G_READ_LOCK (&type_rw_lock); |
3414 | type = (GType) g_hash_table_lookup (hash_table: static_type_nodes_ht, key: name); |
3415 | G_READ_UNLOCK (&type_rw_lock); |
3416 | |
3417 | return type; |
3418 | } |
3419 | |
3420 | /** |
3421 | * g_type_parent: |
3422 | * @type: the derived type |
3423 | * |
3424 | * Return the direct parent type of the passed in type. If the passed |
3425 | * in type has no parent, i.e. is a fundamental type, 0 is returned. |
3426 | * |
3427 | * Returns: the parent type |
3428 | */ |
3429 | GType |
3430 | g_type_parent (GType type) |
3431 | { |
3432 | TypeNode *node; |
3433 | |
3434 | node = lookup_type_node_I (utype: type); |
3435 | |
3436 | return node ? NODE_PARENT_TYPE (node) : 0; |
3437 | } |
3438 | |
3439 | /** |
3440 | * g_type_depth: |
3441 | * @type: a #GType |
3442 | * |
3443 | * Returns the length of the ancestry of the passed in type. This |
3444 | * includes the type itself, so that e.g. a fundamental type has depth 1. |
3445 | * |
3446 | * Returns: the depth of @type |
3447 | */ |
3448 | guint |
3449 | g_type_depth (GType type) |
3450 | { |
3451 | TypeNode *node; |
3452 | |
3453 | node = lookup_type_node_I (utype: type); |
3454 | |
3455 | return node ? node->n_supers + 1 : 0; |
3456 | } |
3457 | |
3458 | /** |
3459 | * g_type_next_base: |
3460 | * @leaf_type: descendant of @root_type and the type to be returned |
3461 | * @root_type: immediate parent of the returned type |
3462 | * |
3463 | * Given a @leaf_type and a @root_type which is contained in its |
3464 | * ancestry, return the type that @root_type is the immediate parent |
3465 | * of. In other words, this function determines the type that is |
3466 | * derived directly from @root_type which is also a base class of |
3467 | * @leaf_type. Given a root type and a leaf type, this function can |
3468 | * be used to determine the types and order in which the leaf type is |
3469 | * descended from the root type. |
3470 | * |
3471 | * Returns: immediate child of @root_type and ancestor of @leaf_type |
3472 | */ |
3473 | GType |
3474 | g_type_next_base (GType type, |
3475 | GType base_type) |
3476 | { |
3477 | GType atype = 0; |
3478 | TypeNode *node; |
3479 | |
3480 | node = lookup_type_node_I (utype: type); |
3481 | if (node) |
3482 | { |
3483 | TypeNode *base_node = lookup_type_node_I (utype: base_type); |
3484 | |
3485 | if (base_node && base_node->n_supers < node->n_supers) |
3486 | { |
3487 | guint n = node->n_supers - base_node->n_supers; |
3488 | |
3489 | if (node->supers[n] == base_type) |
3490 | atype = node->supers[n - 1]; |
3491 | } |
3492 | } |
3493 | |
3494 | return atype; |
3495 | } |
3496 | |
3497 | static inline gboolean |
3498 | type_node_check_conformities_UorL (TypeNode *node, |
3499 | TypeNode *iface_node, |
3500 | /* support_inheritance */ |
3501 | gboolean support_interfaces, |
3502 | gboolean support_prerequisites, |
3503 | gboolean have_lock) |
3504 | { |
3505 | gboolean match; |
3506 | |
3507 | if (/* support_inheritance && */ |
3508 | NODE_IS_ANCESTOR (iface_node, node)) |
3509 | return TRUE; |
3510 | |
3511 | support_interfaces = support_interfaces && node->is_instantiatable && NODE_IS_IFACE (iface_node); |
3512 | support_prerequisites = support_prerequisites && NODE_IS_IFACE (node); |
3513 | match = FALSE; |
3514 | if (support_interfaces) |
3515 | { |
3516 | if (have_lock) |
3517 | { |
3518 | if (type_lookup_iface_entry_L (node, iface_node)) |
3519 | match = TRUE; |
3520 | } |
3521 | else |
3522 | { |
3523 | if (type_lookup_iface_vtable_I (node, iface_node, NULL)) |
3524 | match = TRUE; |
3525 | } |
3526 | } |
3527 | if (!match && |
3528 | support_prerequisites) |
3529 | { |
3530 | if (!have_lock) |
3531 | G_READ_LOCK (&type_rw_lock); |
3532 | if (support_prerequisites && type_lookup_prerequisite_L (iface: node, NODE_TYPE (iface_node))) |
3533 | match = TRUE; |
3534 | if (!have_lock) |
3535 | G_READ_UNLOCK (&type_rw_lock); |
3536 | } |
3537 | return match; |
3538 | } |
3539 | |
3540 | static gboolean |
3541 | type_node_is_a_L (TypeNode *node, |
3542 | TypeNode *iface_node) |
3543 | { |
3544 | return type_node_check_conformities_UorL (node, iface_node, TRUE, TRUE, TRUE); |
3545 | } |
3546 | |
3547 | static inline gboolean |
3548 | type_node_conforms_to_U (TypeNode *node, |
3549 | TypeNode *iface_node, |
3550 | gboolean support_interfaces, |
3551 | gboolean support_prerequisites) |
3552 | { |
3553 | return type_node_check_conformities_UorL (node, iface_node, support_interfaces, support_prerequisites, FALSE); |
3554 | } |
3555 | |
3556 | /** |
3557 | * g_type_is_a: |
3558 | * @type: type to check ancestry for |
3559 | * @is_a_type: possible ancestor of @type or interface that @type |
3560 | * could conform to |
3561 | * |
3562 | * If @is_a_type is a derivable type, check whether @type is a |
3563 | * descendant of @is_a_type. If @is_a_type is an interface, check |
3564 | * whether @type conforms to it. |
3565 | * |
3566 | * Returns: %TRUE if @type is a @is_a_type |
3567 | */ |
3568 | gboolean |
3569 | g_type_is_a (GType type, |
3570 | GType iface_type) |
3571 | { |
3572 | TypeNode *node, *iface_node; |
3573 | gboolean is_a; |
3574 | |
3575 | if (type == iface_type) |
3576 | return TRUE; |
3577 | |
3578 | node = lookup_type_node_I (utype: type); |
3579 | iface_node = lookup_type_node_I (utype: iface_type); |
3580 | is_a = node && iface_node && type_node_conforms_to_U (node, iface_node, TRUE, TRUE); |
3581 | |
3582 | return is_a; |
3583 | } |
3584 | |
3585 | /** |
3586 | * g_type_children: |
3587 | * @type: the parent type |
3588 | * @n_children: (out) (optional): location to store the length of |
3589 | * the returned array, or %NULL |
3590 | * |
3591 | * Return a newly allocated and 0-terminated array of type IDs, listing |
3592 | * the child types of @type. |
3593 | * |
3594 | * Returns: (array length=n_children) (transfer full): Newly allocated |
3595 | * and 0-terminated array of child types, free with g_free() |
3596 | */ |
3597 | GType* |
3598 | g_type_children (GType type, |
3599 | guint *n_children) |
3600 | { |
3601 | TypeNode *node; |
3602 | |
3603 | node = lookup_type_node_I (utype: type); |
3604 | if (node) |
3605 | { |
3606 | GType *children; |
3607 | |
3608 | G_READ_LOCK (&type_rw_lock); /* ->children is relocatable */ |
3609 | children = g_new (GType, node->n_children + 1); |
3610 | if (node->n_children != 0) |
3611 | memcpy (dest: children, src: node->children, n: sizeof (GType) * node->n_children); |
3612 | children[node->n_children] = 0; |
3613 | |
3614 | if (n_children) |
3615 | *n_children = node->n_children; |
3616 | G_READ_UNLOCK (&type_rw_lock); |
3617 | |
3618 | return children; |
3619 | } |
3620 | else |
3621 | { |
3622 | if (n_children) |
3623 | *n_children = 0; |
3624 | |
3625 | return NULL; |
3626 | } |
3627 | } |
3628 | |
3629 | /** |
3630 | * g_type_interfaces: |
3631 | * @type: the type to list interface types for |
3632 | * @n_interfaces: (out) (optional): location to store the length of |
3633 | * the returned array, or %NULL |
3634 | * |
3635 | * Return a newly allocated and 0-terminated array of type IDs, listing |
3636 | * the interface types that @type conforms to. |
3637 | * |
3638 | * Returns: (array length=n_interfaces) (transfer full): Newly allocated |
3639 | * and 0-terminated array of interface types, free with g_free() |
3640 | */ |
3641 | GType* |
3642 | g_type_interfaces (GType type, |
3643 | guint *n_interfaces) |
3644 | { |
3645 | TypeNode *node; |
3646 | |
3647 | node = lookup_type_node_I (utype: type); |
3648 | if (node && node->is_instantiatable) |
3649 | { |
3650 | IFaceEntries *entries; |
3651 | GType *ifaces; |
3652 | guint i; |
3653 | |
3654 | G_READ_LOCK (&type_rw_lock); |
3655 | entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node); |
3656 | if (entries) |
3657 | { |
3658 | ifaces = g_new (GType, IFACE_ENTRIES_N_ENTRIES (entries) + 1); |
3659 | for (i = 0; i < IFACE_ENTRIES_N_ENTRIES (entries); i++) |
3660 | ifaces[i] = entries->entry[i].iface_type; |
3661 | } |
3662 | else |
3663 | { |
3664 | ifaces = g_new (GType, 1); |
3665 | i = 0; |
3666 | } |
3667 | ifaces[i] = 0; |
3668 | |
3669 | if (n_interfaces) |
3670 | *n_interfaces = i; |
3671 | G_READ_UNLOCK (&type_rw_lock); |
3672 | |
3673 | return ifaces; |
3674 | } |
3675 | else |
3676 | { |
3677 | if (n_interfaces) |
3678 | *n_interfaces = 0; |
3679 | |
3680 | return NULL; |
3681 | } |
3682 | } |
3683 | |
3684 | typedef struct _QData QData; |
3685 | struct _GData |
3686 | { |
3687 | guint n_qdatas; |
3688 | QData *qdatas; |
3689 | }; |
3690 | struct _QData |
3691 | { |
3692 | GQuark quark; |
3693 | gpointer data; |
3694 | }; |
3695 | |
3696 | static inline gpointer |
3697 | type_get_qdata_L (TypeNode *node, |
3698 | GQuark quark) |
3699 | { |
3700 | GData *gdata = node->global_gdata; |
3701 | |
3702 | if (quark && gdata && gdata->n_qdatas) |
3703 | { |
3704 | QData *qdatas = gdata->qdatas - 1; |
3705 | guint n_qdatas = gdata->n_qdatas; |
3706 | |
3707 | do |
3708 | { |
3709 | guint i; |
3710 | QData *check; |
3711 | |
3712 | i = (n_qdatas + 1) / 2; |
3713 | check = qdatas + i; |
3714 | if (quark == check->quark) |
3715 | return check->data; |
3716 | else if (quark > check->quark) |
3717 | { |
3718 | n_qdatas -= i; |
3719 | qdatas = check; |
3720 | } |
3721 | else /* if (quark < check->quark) */ |
3722 | n_qdatas = i - 1; |
3723 | } |
3724 | while (n_qdatas); |
3725 | } |
3726 | return NULL; |
3727 | } |
3728 | |
3729 | /** |
3730 | * g_type_get_qdata: |
3731 | * @type: a #GType |
3732 | * @quark: a #GQuark id to identify the data |
3733 | * |
3734 | * Obtains data which has previously been attached to @type |
3735 | * with g_type_set_qdata(). |
3736 | * |
3737 | * Note that this does not take subtyping into account; data |
3738 | * attached to one type with g_type_set_qdata() cannot |
3739 | * be retrieved from a subtype using g_type_get_qdata(). |
3740 | * |
3741 | * Returns: (transfer none): the data, or %NULL if no data was found |
3742 | */ |
3743 | gpointer |
3744 | g_type_get_qdata (GType type, |
3745 | GQuark quark) |
3746 | { |
3747 | TypeNode *node; |
3748 | gpointer data; |
3749 | |
3750 | node = lookup_type_node_I (utype: type); |
3751 | if (node) |
3752 | { |
3753 | G_READ_LOCK (&type_rw_lock); |
3754 | data = type_get_qdata_L (node, quark); |
3755 | G_READ_UNLOCK (&type_rw_lock); |
3756 | } |
3757 | else |
3758 | { |
3759 | g_return_val_if_fail (node != NULL, NULL); |
3760 | data = NULL; |
3761 | } |
3762 | return data; |
3763 | } |
3764 | |
3765 | static inline void |
3766 | type_set_qdata_W (TypeNode *node, |
3767 | GQuark quark, |
3768 | gpointer data) |
3769 | { |
3770 | GData *gdata; |
3771 | QData *qdata; |
3772 | guint i; |
3773 | |
3774 | /* setup qdata list if necessary */ |
3775 | if (!node->global_gdata) |
3776 | node->global_gdata = g_new0 (GData, 1); |
3777 | gdata = node->global_gdata; |
3778 | |
3779 | /* try resetting old data */ |
3780 | qdata = gdata->qdatas; |
3781 | for (i = 0; i < gdata->n_qdatas; i++) |
3782 | if (qdata[i].quark == quark) |
3783 | { |
3784 | qdata[i].data = data; |
3785 | return; |
3786 | } |
3787 | |
3788 | /* add new entry */ |
3789 | gdata->n_qdatas++; |
3790 | gdata->qdatas = g_renew (QData, gdata->qdatas, gdata->n_qdatas); |
3791 | qdata = gdata->qdatas; |
3792 | for (i = 0; i < gdata->n_qdatas - 1; i++) |
3793 | if (qdata[i].quark > quark) |
3794 | break; |
3795 | memmove (dest: qdata + i + 1, src: qdata + i, n: sizeof (qdata[0]) * (gdata->n_qdatas - i - 1)); |
3796 | qdata[i].quark = quark; |
3797 | qdata[i].data = data; |
3798 | } |
3799 | |
3800 | /** |
3801 | * g_type_set_qdata: |
3802 | * @type: a #GType |
3803 | * @quark: a #GQuark id to identify the data |
3804 | * @data: the data |
3805 | * |
3806 | * Attaches arbitrary data to a type. |
3807 | */ |
3808 | void |
3809 | g_type_set_qdata (GType type, |
3810 | GQuark quark, |
3811 | gpointer data) |
3812 | { |
3813 | TypeNode *node; |
3814 | |
3815 | g_return_if_fail (quark != 0); |
3816 | |
3817 | node = lookup_type_node_I (utype: type); |
3818 | if (node) |
3819 | { |
3820 | G_WRITE_LOCK (&type_rw_lock); |
3821 | type_set_qdata_W (node, quark, data); |
3822 | G_WRITE_UNLOCK (&type_rw_lock); |
3823 | } |
3824 | else |
3825 | g_return_if_fail (node != NULL); |
3826 | } |
3827 | |
3828 | static void |
3829 | type_add_flags_W (TypeNode *node, |
3830 | GTypeFlags flags) |
3831 | { |
3832 | guint dflags; |
3833 | |
3834 | g_return_if_fail ((flags & ~TYPE_FLAG_MASK) == 0); |
3835 | g_return_if_fail (node != NULL); |
3836 | |
3837 | if ((flags & TYPE_FLAG_MASK) && node->is_classed && node->data && node->data->class.class) |
3838 | g_warning ("tagging type '%s' as abstract after class initialization" , NODE_NAME (node)); |
3839 | dflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags)); |
3840 | dflags |= flags; |
3841 | type_set_qdata_W (node, quark: static_quark_type_flags, GUINT_TO_POINTER (dflags)); |
3842 | } |
3843 | |
3844 | /** |
3845 | * g_type_query: |
3846 | * @type: #GType of a static, classed type |
3847 | * @query: (out caller-allocates): a user provided structure that is |
3848 | * filled in with constant values upon success |
3849 | * |
3850 | * Queries the type system for information about a specific type. |
3851 | * This function will fill in a user-provided structure to hold |
3852 | * type-specific information. If an invalid #GType is passed in, the |
3853 | * @type member of the #GTypeQuery is 0. All members filled into the |
3854 | * #GTypeQuery structure should be considered constant and have to be |
3855 | * left untouched. |
3856 | */ |
3857 | void |
3858 | g_type_query (GType type, |
3859 | GTypeQuery *query) |
3860 | { |
3861 | TypeNode *node; |
3862 | |
3863 | g_return_if_fail (query != NULL); |
3864 | |
3865 | /* if node is not static and classed, we won't allow query */ |
3866 | query->type = 0; |
3867 | node = lookup_type_node_I (utype: type); |
3868 | if (node && node->is_classed && !node->plugin) |
3869 | { |
3870 | /* type is classed and probably even instantiatable */ |
3871 | G_READ_LOCK (&type_rw_lock); |
3872 | if (node->data) /* type is static or referenced */ |
3873 | { |
3874 | query->type = NODE_TYPE (node); |
3875 | query->type_name = NODE_NAME (node); |
3876 | query->class_size = node->data->class.class_size; |
3877 | query->instance_size = node->is_instantiatable ? node->data->instance.instance_size : 0; |
3878 | } |
3879 | G_READ_UNLOCK (&type_rw_lock); |
3880 | } |
3881 | } |
3882 | |
3883 | /** |
3884 | * g_type_get_instance_count: |
3885 | * @type: a #GType |
3886 | * |
3887 | * Returns the number of instances allocated of the particular type; |
3888 | * this is only available if GLib is built with debugging support and |
3889 | * the instance_count debug flag is set (by setting the GOBJECT_DEBUG |
3890 | * variable to include instance-count). |
3891 | * |
3892 | * Returns: the number of instances allocated of the given type; |
3893 | * if instance counts are not available, returns 0. |
3894 | * |
3895 | * Since: 2.44 |
3896 | */ |
3897 | int |
3898 | g_type_get_instance_count (GType type) |
3899 | { |
3900 | #ifdef G_ENABLE_DEBUG |
3901 | TypeNode *node; |
3902 | |
3903 | node = lookup_type_node_I (utype: type); |
3904 | g_return_val_if_fail (node != NULL, 0); |
3905 | |
3906 | return g_atomic_int_get (&node->instance_count); |
3907 | #else |
3908 | return 0; |
3909 | #endif |
3910 | } |
3911 | |
3912 | /* --- implementation details --- */ |
3913 | gboolean |
3914 | g_type_test_flags (GType type, |
3915 | guint flags) |
3916 | { |
3917 | TypeNode *node; |
3918 | gboolean result = FALSE; |
3919 | |
3920 | node = lookup_type_node_I (utype: type); |
3921 | if (node) |
3922 | { |
3923 | guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK; |
3924 | guint tflags = flags & TYPE_FLAG_MASK; |
3925 | |
3926 | if (fflags) |
3927 | { |
3928 | GTypeFundamentalInfo *finfo = type_node_fundamental_info_I (node); |
3929 | |
3930 | fflags = (finfo->type_flags & fflags) == fflags; |
3931 | } |
3932 | else |
3933 | fflags = TRUE; |
3934 | |
3935 | if (tflags) |
3936 | { |
3937 | G_READ_LOCK (&type_rw_lock); |
3938 | tflags = (tflags & GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags))) == tflags; |
3939 | G_READ_UNLOCK (&type_rw_lock); |
3940 | } |
3941 | else |
3942 | tflags = TRUE; |
3943 | |
3944 | result = tflags && fflags; |
3945 | } |
3946 | |
3947 | return result; |
3948 | } |
3949 | |
3950 | /** |
3951 | * g_type_get_plugin: |
3952 | * @type: #GType to retrieve the plugin for |
3953 | * |
3954 | * Returns the #GTypePlugin structure for @type. |
3955 | * |
3956 | * Returns: (transfer none): the corresponding plugin |
3957 | * if @type is a dynamic type, %NULL otherwise |
3958 | */ |
3959 | GTypePlugin* |
3960 | g_type_get_plugin (GType type) |
3961 | { |
3962 | TypeNode *node; |
3963 | |
3964 | node = lookup_type_node_I (utype: type); |
3965 | |
3966 | return node ? node->plugin : NULL; |
3967 | } |
3968 | |
3969 | /** |
3970 | * g_type_interface_get_plugin: |
3971 | * @instance_type: #GType of an instantiatable type |
3972 | * @interface_type: #GType of an interface type |
3973 | * |
3974 | * Returns the #GTypePlugin structure for the dynamic interface |
3975 | * @interface_type which has been added to @instance_type, or %NULL |
3976 | * if @interface_type has not been added to @instance_type or does |
3977 | * not have a #GTypePlugin structure. See g_type_add_interface_dynamic(). |
3978 | * |
3979 | * Returns: (transfer none): the #GTypePlugin for the dynamic |
3980 | * interface @interface_type of @instance_type |
3981 | */ |
3982 | GTypePlugin* |
3983 | g_type_interface_get_plugin (GType instance_type, |
3984 | GType interface_type) |
3985 | { |
3986 | TypeNode *node; |
3987 | TypeNode *iface; |
3988 | |
3989 | g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL); /* G_TYPE_IS_INTERFACE() is an external call: _U */ |
3990 | |
3991 | node = lookup_type_node_I (utype: instance_type); |
3992 | iface = lookup_type_node_I (utype: interface_type); |
3993 | if (node && iface) |
3994 | { |
3995 | IFaceHolder *iholder; |
3996 | GTypePlugin *plugin; |
3997 | |
3998 | G_READ_LOCK (&type_rw_lock); |
3999 | |
4000 | iholder = iface_node_get_holders_L (iface); |
4001 | while (iholder && iholder->instance_type != instance_type) |
4002 | iholder = iholder->next; |
4003 | plugin = iholder ? iholder->plugin : NULL; |
4004 | |
4005 | G_READ_UNLOCK (&type_rw_lock); |
4006 | |
4007 | return plugin; |
4008 | } |
4009 | |
4010 | g_return_val_if_fail (node == NULL, NULL); |
4011 | g_return_val_if_fail (iface == NULL, NULL); |
4012 | |
4013 | g_warning (G_STRLOC ": attempt to look up plugin for invalid instance/interface type pair." ); |
4014 | |
4015 | return NULL; |
4016 | } |
4017 | |
4018 | /** |
4019 | * g_type_fundamental_next: |
4020 | * |
4021 | * Returns the next free fundamental type id which can be used to |
4022 | * register a new fundamental type with g_type_register_fundamental(). |
4023 | * The returned type ID represents the highest currently registered |
4024 | * fundamental type identifier. |
4025 | * |
4026 | * Returns: the next available fundamental type ID to be registered, |
4027 | * or 0 if the type system ran out of fundamental type IDs |
4028 | */ |
4029 | GType |
4030 | g_type_fundamental_next (void) |
4031 | { |
4032 | GType type; |
4033 | |
4034 | G_READ_LOCK (&type_rw_lock); |
4035 | type = static_fundamental_next; |
4036 | G_READ_UNLOCK (&type_rw_lock); |
4037 | type = G_TYPE_MAKE_FUNDAMENTAL (type); |
4038 | return type <= G_TYPE_FUNDAMENTAL_MAX ? type : 0; |
4039 | } |
4040 | |
4041 | /** |
4042 | * g_type_fundamental: |
4043 | * @type_id: valid type ID |
4044 | * |
4045 | * Internal function, used to extract the fundamental type ID portion. |
4046 | * Use G_TYPE_FUNDAMENTAL() instead. |
4047 | * |
4048 | * Returns: fundamental type ID |
4049 | */ |
4050 | GType |
4051 | g_type_fundamental (GType type_id) |
4052 | { |
4053 | TypeNode *node = lookup_type_node_I (utype: type_id); |
4054 | |
4055 | return node ? NODE_FUNDAMENTAL_TYPE (node) : 0; |
4056 | } |
4057 | |
4058 | gboolean |
4059 | g_type_check_instance_is_a (GTypeInstance *type_instance, |
4060 | GType iface_type) |
4061 | { |
4062 | TypeNode *node, *iface; |
4063 | gboolean check; |
4064 | |
4065 | if (!type_instance || !type_instance->g_class) |
4066 | return FALSE; |
4067 | |
4068 | node = lookup_type_node_I (utype: type_instance->g_class->g_type); |
4069 | iface = lookup_type_node_I (utype: iface_type); |
4070 | check = node && node->is_instantiatable && iface && type_node_conforms_to_U (node, iface_node: iface, TRUE, FALSE); |
4071 | |
4072 | return check; |
4073 | } |
4074 | |
4075 | gboolean |
4076 | g_type_check_instance_is_fundamentally_a (GTypeInstance *type_instance, |
4077 | GType fundamental_type) |
4078 | { |
4079 | TypeNode *node; |
4080 | if (!type_instance || !type_instance->g_class) |
4081 | return FALSE; |
4082 | node = lookup_type_node_I (utype: type_instance->g_class->g_type); |
4083 | return node && (NODE_FUNDAMENTAL_TYPE(node) == fundamental_type); |
4084 | } |
4085 | |
4086 | gboolean |
4087 | g_type_check_class_is_a (GTypeClass *type_class, |
4088 | GType is_a_type) |
4089 | { |
4090 | TypeNode *node, *iface; |
4091 | gboolean check; |
4092 | |
4093 | if (!type_class) |
4094 | return FALSE; |
4095 | |
4096 | node = lookup_type_node_I (utype: type_class->g_type); |
4097 | iface = lookup_type_node_I (utype: is_a_type); |
4098 | check = node && node->is_classed && iface && type_node_conforms_to_U (node, iface_node: iface, FALSE, FALSE); |
4099 | |
4100 | return check; |
4101 | } |
4102 | |
4103 | GTypeInstance* |
4104 | g_type_check_instance_cast (GTypeInstance *type_instance, |
4105 | GType iface_type) |
4106 | { |
4107 | if (type_instance) |
4108 | { |
4109 | if (type_instance->g_class) |
4110 | { |
4111 | TypeNode *node, *iface; |
4112 | gboolean is_instantiatable, check; |
4113 | |
4114 | node = lookup_type_node_I (utype: type_instance->g_class->g_type); |
4115 | is_instantiatable = node && node->is_instantiatable; |
4116 | iface = lookup_type_node_I (utype: iface_type); |
4117 | check = is_instantiatable && iface && type_node_conforms_to_U (node, iface_node: iface, TRUE, FALSE); |
4118 | if (check) |
4119 | return type_instance; |
4120 | |
4121 | if (is_instantiatable) |
4122 | g_warning ("invalid cast from '%s' to '%s'" , |
4123 | type_descriptive_name_I (type_instance->g_class->g_type), |
4124 | type_descriptive_name_I (iface_type)); |
4125 | else |
4126 | g_warning ("invalid uninstantiatable type '%s' in cast to '%s'" , |
4127 | type_descriptive_name_I (type_instance->g_class->g_type), |
4128 | type_descriptive_name_I (iface_type)); |
4129 | } |
4130 | else |
4131 | g_warning ("invalid unclassed pointer in cast to '%s'" , |
4132 | type_descriptive_name_I (iface_type)); |
4133 | } |
4134 | |
4135 | return type_instance; |
4136 | } |
4137 | |
4138 | GTypeClass* |
4139 | g_type_check_class_cast (GTypeClass *type_class, |
4140 | GType is_a_type) |
4141 | { |
4142 | if (type_class) |
4143 | { |
4144 | TypeNode *node, *iface; |
4145 | gboolean is_classed, check; |
4146 | |
4147 | node = lookup_type_node_I (utype: type_class->g_type); |
4148 | is_classed = node && node->is_classed; |
4149 | iface = lookup_type_node_I (utype: is_a_type); |
4150 | check = is_classed && iface && type_node_conforms_to_U (node, iface_node: iface, FALSE, FALSE); |
4151 | if (check) |
4152 | return type_class; |
4153 | |
4154 | if (is_classed) |
4155 | g_warning ("invalid class cast from '%s' to '%s'" , |
4156 | type_descriptive_name_I (type_class->g_type), |
4157 | type_descriptive_name_I (is_a_type)); |
4158 | else |
4159 | g_warning ("invalid unclassed type '%s' in class cast to '%s'" , |
4160 | type_descriptive_name_I (type_class->g_type), |
4161 | type_descriptive_name_I (is_a_type)); |
4162 | } |
4163 | else |
4164 | g_warning ("invalid class cast from (NULL) pointer to '%s'" , |
4165 | type_descriptive_name_I (is_a_type)); |
4166 | return type_class; |
4167 | } |
4168 | |
4169 | /** |
4170 | * g_type_check_instance: |
4171 | * @instance: a valid #GTypeInstance structure |
4172 | * |
4173 | * Private helper function to aid implementation of the |
4174 | * G_TYPE_CHECK_INSTANCE() macro. |
4175 | * |
4176 | * Returns: %TRUE if @instance is valid, %FALSE otherwise |
4177 | */ |
4178 | gboolean |
4179 | g_type_check_instance (GTypeInstance *type_instance) |
4180 | { |
4181 | /* this function is just here to make the signal system |
4182 | * conveniently elaborated on instance checks |
4183 | */ |
4184 | if (type_instance) |
4185 | { |
4186 | if (type_instance->g_class) |
4187 | { |
4188 | TypeNode *node = lookup_type_node_I (utype: type_instance->g_class->g_type); |
4189 | |
4190 | if (node && node->is_instantiatable) |
4191 | return TRUE; |
4192 | |
4193 | g_warning ("instance of invalid non-instantiatable type '%s'" , |
4194 | type_descriptive_name_I (type_instance->g_class->g_type)); |
4195 | } |
4196 | else |
4197 | g_warning ("instance with invalid (NULL) class pointer" ); |
4198 | } |
4199 | else |
4200 | g_warning ("invalid (NULL) pointer instance" ); |
4201 | |
4202 | return FALSE; |
4203 | } |
4204 | |
4205 | static inline gboolean |
4206 | type_check_is_value_type_U (GType type) |
4207 | { |
4208 | GTypeFlags tflags = G_TYPE_FLAG_VALUE_ABSTRACT; |
4209 | TypeNode *node; |
4210 | |
4211 | /* common path speed up */ |
4212 | node = lookup_type_node_I (utype: type); |
4213 | if (node && node->mutatable_check_cache) |
4214 | return TRUE; |
4215 | |
4216 | G_READ_LOCK (&type_rw_lock); |
4217 | restart_check: |
4218 | if (node) |
4219 | { |
4220 | if (node->data && NODE_REFCOUNT (node) > 0 && |
4221 | node->data->common.value_table->value_init) |
4222 | tflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags)); |
4223 | else if (NODE_IS_IFACE (node)) |
4224 | { |
4225 | guint i; |
4226 | |
4227 | for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++) |
4228 | { |
4229 | GType prtype = IFACE_NODE_PREREQUISITES (node)[i]; |
4230 | TypeNode *prnode = lookup_type_node_I (utype: prtype); |
4231 | |
4232 | if (prnode->is_instantiatable) |
4233 | { |
4234 | type = prtype; |
4235 | node = lookup_type_node_I (utype: type); |
4236 | goto restart_check; |
4237 | } |
4238 | } |
4239 | } |
4240 | } |
4241 | G_READ_UNLOCK (&type_rw_lock); |
4242 | |
4243 | return !(tflags & G_TYPE_FLAG_VALUE_ABSTRACT); |
4244 | } |
4245 | |
4246 | gboolean |
4247 | g_type_check_is_value_type (GType type) |
4248 | { |
4249 | return type_check_is_value_type_U (type); |
4250 | } |
4251 | |
4252 | gboolean |
4253 | g_type_check_value (const GValue *value) |
4254 | { |
4255 | return value && type_check_is_value_type_U (type: value->g_type); |
4256 | } |
4257 | |
4258 | gboolean |
4259 | g_type_check_value_holds (const GValue *value, |
4260 | GType type) |
4261 | { |
4262 | return value && type_check_is_value_type_U (type: value->g_type) && g_type_is_a (type: value->g_type, iface_type: type); |
4263 | } |
4264 | |
4265 | /** |
4266 | * g_type_value_table_peek: (skip) |
4267 | * @type: a #GType |
4268 | * |
4269 | * Returns the location of the #GTypeValueTable associated with @type. |
4270 | * |
4271 | * Note that this function should only be used from source code |
4272 | * that implements or has internal knowledge of the implementation of |
4273 | * @type. |
4274 | * |
4275 | * Returns: location of the #GTypeValueTable associated with @type or |
4276 | * %NULL if there is no #GTypeValueTable associated with @type |
4277 | */ |
4278 | GTypeValueTable* |
4279 | g_type_value_table_peek (GType type) |
4280 | { |
4281 | GTypeValueTable *vtable = NULL; |
4282 | TypeNode *node = lookup_type_node_I (utype: type); |
4283 | gboolean has_refed_data, has_table; |
4284 | |
4285 | if (node && NODE_REFCOUNT (node) && node->mutatable_check_cache) |
4286 | return node->data->common.value_table; |
4287 | |
4288 | G_READ_LOCK (&type_rw_lock); |
4289 | |
4290 | restart_table_peek: |
4291 | has_refed_data = node && node->data && NODE_REFCOUNT (node) > 0; |
4292 | has_table = has_refed_data && node->data->common.value_table->value_init; |
4293 | if (has_refed_data) |
4294 | { |
4295 | if (has_table) |
4296 | vtable = node->data->common.value_table; |
4297 | else if (NODE_IS_IFACE (node)) |
4298 | { |
4299 | guint i; |
4300 | |
4301 | for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++) |
4302 | { |
4303 | GType prtype = IFACE_NODE_PREREQUISITES (node)[i]; |
4304 | TypeNode *prnode = lookup_type_node_I (utype: prtype); |
4305 | |
4306 | if (prnode->is_instantiatable) |
4307 | { |
4308 | type = prtype; |
4309 | node = lookup_type_node_I (utype: type); |
4310 | goto restart_table_peek; |
4311 | } |
4312 | } |
4313 | } |
4314 | } |
4315 | |
4316 | G_READ_UNLOCK (&type_rw_lock); |
4317 | |
4318 | if (vtable) |
4319 | return vtable; |
4320 | |
4321 | if (!node) |
4322 | g_warning (G_STRLOC ": type id '%" G_GSIZE_FORMAT "' is invalid" , type); |
4323 | if (!has_refed_data) |
4324 | g_warning ("can't peek value table for type '%s' which is not currently referenced" , |
4325 | type_descriptive_name_I (type)); |
4326 | |
4327 | return NULL; |
4328 | } |
4329 | |
4330 | const gchar * |
4331 | g_type_name_from_instance (GTypeInstance *instance) |
4332 | { |
4333 | if (!instance) |
4334 | return "<NULL-instance>" ; |
4335 | else |
4336 | return g_type_name_from_class (g_class: instance->g_class); |
4337 | } |
4338 | |
4339 | const gchar * |
4340 | g_type_name_from_class (GTypeClass *g_class) |
4341 | { |
4342 | if (!g_class) |
4343 | return "<NULL-class>" ; |
4344 | else |
4345 | return g_type_name (type: g_class->g_type); |
4346 | } |
4347 | |
4348 | |
4349 | /* --- private api for gboxed.c --- */ |
4350 | gpointer |
4351 | _g_type_boxed_copy (GType type, gpointer value) |
4352 | { |
4353 | TypeNode *node = lookup_type_node_I (utype: type); |
4354 | |
4355 | return node->data->boxed.copy_func (value); |
4356 | } |
4357 | |
4358 | void |
4359 | _g_type_boxed_free (GType type, gpointer value) |
4360 | { |
4361 | TypeNode *node = lookup_type_node_I (utype: type); |
4362 | |
4363 | node->data->boxed.free_func (value); |
4364 | } |
4365 | |
4366 | void |
4367 | _g_type_boxed_init (GType type, |
4368 | GBoxedCopyFunc copy_func, |
4369 | GBoxedFreeFunc free_func) |
4370 | { |
4371 | TypeNode *node = lookup_type_node_I (utype: type); |
4372 | |
4373 | node->data->boxed.copy_func = copy_func; |
4374 | node->data->boxed.free_func = free_func; |
4375 | } |
4376 | |
4377 | /* --- initialization --- */ |
4378 | /** |
4379 | * g_type_init_with_debug_flags: |
4380 | * @debug_flags: bitwise combination of #GTypeDebugFlags values for |
4381 | * debugging purposes |
4382 | * |
4383 | * This function used to initialise the type system with debugging |
4384 | * flags. Since GLib 2.36, the type system is initialised automatically |
4385 | * and this function does nothing. |
4386 | * |
4387 | * If you need to enable debugging features, use the GOBJECT_DEBUG |
4388 | * environment variable. |
4389 | * |
4390 | * Deprecated: 2.36: the type system is now initialised automatically |
4391 | */ |
4392 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
4393 | void |
4394 | g_type_init_with_debug_flags (GTypeDebugFlags debug_flags) |
4395 | { |
4396 | g_assert_type_system_initialized (); |
4397 | |
4398 | if (debug_flags) |
4399 | g_message ("g_type_init_with_debug_flags() is no longer supported. Use the GOBJECT_DEBUG environment variable." ); |
4400 | } |
4401 | G_GNUC_END_IGNORE_DEPRECATIONS |
4402 | |
4403 | /** |
4404 | * g_type_init: |
4405 | * |
4406 | * This function used to initialise the type system. Since GLib 2.36, |
4407 | * the type system is initialised automatically and this function does |
4408 | * nothing. |
4409 | * |
4410 | * Deprecated: 2.36: the type system is now initialised automatically |
4411 | */ |
4412 | void |
4413 | g_type_init (void) |
4414 | { |
4415 | g_assert_type_system_initialized (); |
4416 | } |
4417 | |
4418 | static void |
4419 | gobject_init (void) |
4420 | { |
4421 | const gchar *env_string; |
4422 | GTypeInfo info; |
4423 | TypeNode *node; |
4424 | GType type G_GNUC_UNUSED /* when compiling with G_DISABLE_ASSERT */; |
4425 | |
4426 | /* Ensure GLib is initialized first, see |
4427 | * https://bugzilla.gnome.org/show_bug.cgi?id=756139 |
4428 | */ |
4429 | GLIB_PRIVATE_CALL (glib_init) (); |
4430 | |
4431 | G_WRITE_LOCK (&type_rw_lock); |
4432 | |
4433 | /* setup GObject library wide debugging flags */ |
4434 | env_string = g_getenv (variable: "GOBJECT_DEBUG" ); |
4435 | if (env_string != NULL) |
4436 | { |
4437 | GDebugKey debug_keys[] = { |
4438 | { "objects" , G_TYPE_DEBUG_OBJECTS }, |
4439 | { "instance-count" , G_TYPE_DEBUG_INSTANCE_COUNT }, |
4440 | { "signals" , G_TYPE_DEBUG_SIGNALS }, |
4441 | }; |
4442 | |
4443 | _g_type_debug_flags = g_parse_debug_string (string: env_string, keys: debug_keys, G_N_ELEMENTS (debug_keys)); |
4444 | } |
4445 | |
4446 | /* quarks */ |
4447 | static_quark_type_flags = g_quark_from_static_string (string: "-g-type-private--GTypeFlags" ); |
4448 | static_quark_iface_holder = g_quark_from_static_string (string: "-g-type-private--IFaceHolder" ); |
4449 | static_quark_dependants_array = g_quark_from_static_string (string: "-g-type-private--dependants-array" ); |
4450 | |
4451 | /* type qname hash table */ |
4452 | static_type_nodes_ht = g_hash_table_new (hash_func: g_str_hash, key_equal_func: g_str_equal); |
4453 | |
4454 | /* invalid type G_TYPE_INVALID (0) |
4455 | */ |
4456 | static_fundamental_type_nodes[0] = NULL; |
4457 | |
4458 | /* void type G_TYPE_NONE |
4459 | */ |
4460 | node = type_node_fundamental_new_W (G_TYPE_NONE, name: g_intern_static_string (string: "void" ), type_flags: 0); |
4461 | type = NODE_TYPE (node); |
4462 | g_assert (type == G_TYPE_NONE); |
4463 | |
4464 | /* interface fundamental type G_TYPE_INTERFACE (!classed) |
4465 | */ |
4466 | memset (s: &info, c: 0, n: sizeof (info)); |
4467 | node = type_node_fundamental_new_W (G_TYPE_INTERFACE, name: g_intern_static_string (string: "GInterface" ), type_flags: G_TYPE_FLAG_DERIVABLE); |
4468 | type = NODE_TYPE (node); |
4469 | type_data_make_W (node, info: &info, NULL); |
4470 | g_assert (type == G_TYPE_INTERFACE); |
4471 | |
4472 | G_WRITE_UNLOCK (&type_rw_lock); |
4473 | |
4474 | _g_value_c_init (); |
4475 | |
4476 | /* G_TYPE_TYPE_PLUGIN |
4477 | */ |
4478 | g_type_ensure (type: g_type_plugin_get_type ()); |
4479 | |
4480 | /* G_TYPE_* value types |
4481 | */ |
4482 | _g_value_types_init (); |
4483 | |
4484 | /* G_TYPE_ENUM & G_TYPE_FLAGS |
4485 | */ |
4486 | _g_enum_types_init (); |
4487 | |
4488 | /* G_TYPE_BOXED |
4489 | */ |
4490 | _g_boxed_type_init (); |
4491 | |
4492 | /* G_TYPE_PARAM |
4493 | */ |
4494 | _g_param_type_init (); |
4495 | |
4496 | /* G_TYPE_OBJECT |
4497 | */ |
4498 | _g_object_type_init (); |
4499 | |
4500 | /* G_TYPE_PARAM_* pspec types |
4501 | */ |
4502 | _g_param_spec_types_init (); |
4503 | |
4504 | /* Value Transformations |
4505 | */ |
4506 | _g_value_transforms_init (); |
4507 | |
4508 | /* Signal system |
4509 | */ |
4510 | _g_signal_init (); |
4511 | } |
4512 | |
4513 | #if defined (G_OS_WIN32) |
4514 | |
4515 | BOOL WINAPI DllMain (HINSTANCE hinstDLL, |
4516 | DWORD fdwReason, |
4517 | LPVOID lpvReserved); |
4518 | |
4519 | BOOL WINAPI |
4520 | DllMain (HINSTANCE hinstDLL, |
4521 | DWORD fdwReason, |
4522 | LPVOID lpvReserved) |
4523 | { |
4524 | switch (fdwReason) |
4525 | { |
4526 | case DLL_PROCESS_ATTACH: |
4527 | gobject_init (); |
4528 | break; |
4529 | |
4530 | default: |
4531 | /* do nothing */ |
4532 | ; |
4533 | } |
4534 | |
4535 | return TRUE; |
4536 | } |
4537 | |
4538 | #elif defined (G_HAS_CONSTRUCTORS) |
4539 | #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA |
4540 | #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(gobject_init_ctor) |
4541 | #endif |
4542 | G_DEFINE_CONSTRUCTOR(gobject_init_ctor) |
4543 | |
4544 | static void |
4545 | gobject_init_ctor (void) |
4546 | { |
4547 | gobject_init (); |
4548 | } |
4549 | |
4550 | #else |
4551 | # error Your platform/compiler is missing constructor support |
4552 | #endif |
4553 | |
4554 | /** |
4555 | * g_type_class_add_private: |
4556 | * @g_class: (type GObject.TypeClass): class structure for an instantiatable |
4557 | * type |
4558 | * @private_size: size of private structure |
4559 | * |
4560 | * Registers a private structure for an instantiatable type. |
4561 | * |
4562 | * When an object is allocated, the private structures for |
4563 | * the type and all of its parent types are allocated |
4564 | * sequentially in the same memory block as the public |
4565 | * structures, and are zero-filled. |
4566 | * |
4567 | * Note that the accumulated size of the private structures of |
4568 | * a type and all its parent types cannot exceed 64 KiB. |
4569 | * |
4570 | * This function should be called in the type's class_init() function. |
4571 | * The private structure can be retrieved using the |
4572 | * G_TYPE_INSTANCE_GET_PRIVATE() macro. |
4573 | * |
4574 | * The following example shows attaching a private structure |
4575 | * MyObjectPrivate to an object MyObject defined in the standard |
4576 | * GObject fashion in the type's class_init() function. |
4577 | * |
4578 | * Note the use of a structure member "priv" to avoid the overhead |
4579 | * of repeatedly calling MY_OBJECT_GET_PRIVATE(). |
4580 | * |
4581 | * |[<!-- language="C" --> |
4582 | * typedef struct _MyObject MyObject; |
4583 | * typedef struct _MyObjectPrivate MyObjectPrivate; |
4584 | * |
4585 | * struct _MyObject { |
4586 | * GObject parent; |
4587 | * |
4588 | * MyObjectPrivate *priv; |
4589 | * }; |
4590 | * |
4591 | * struct _MyObjectPrivate { |
4592 | * int some_field; |
4593 | * }; |
4594 | * |
4595 | * static void |
4596 | * my_object_class_init (MyObjectClass *klass) |
4597 | * { |
4598 | * g_type_class_add_private (klass, sizeof (MyObjectPrivate)); |
4599 | * } |
4600 | * |
4601 | * static void |
4602 | * my_object_init (MyObject *my_object) |
4603 | * { |
4604 | * my_object->priv = G_TYPE_INSTANCE_GET_PRIVATE (my_object, |
4605 | * MY_TYPE_OBJECT, |
4606 | * MyObjectPrivate); |
4607 | * // my_object->priv->some_field will be automatically initialised to 0 |
4608 | * } |
4609 | * |
4610 | * static int |
4611 | * my_object_get_some_field (MyObject *my_object) |
4612 | * { |
4613 | * MyObjectPrivate *priv; |
4614 | * |
4615 | * g_return_val_if_fail (MY_IS_OBJECT (my_object), 0); |
4616 | * |
4617 | * priv = my_object->priv; |
4618 | * |
4619 | * return priv->some_field; |
4620 | * } |
4621 | * ]| |
4622 | * |
4623 | * Since: 2.4 |
4624 | * Deprecated: 2.58: Use the G_ADD_PRIVATE() macro with the `G_DEFINE_*` |
4625 | * family of macros to add instance private data to a type |
4626 | */ |
4627 | void |
4628 | g_type_class_add_private (gpointer g_class, |
4629 | gsize private_size) |
4630 | { |
4631 | GType instance_type = ((GTypeClass *)g_class)->g_type; |
4632 | TypeNode *node = lookup_type_node_I (utype: instance_type); |
4633 | |
4634 | g_return_if_fail (private_size > 0); |
4635 | g_return_if_fail (private_size <= 0xffff); |
4636 | |
4637 | if (!node || !node->is_instantiatable || !node->data || node->data->class.class != g_class) |
4638 | { |
4639 | g_warning ("cannot add private field to invalid (non-instantiatable) type '%s'" , |
4640 | type_descriptive_name_I (instance_type)); |
4641 | return; |
4642 | } |
4643 | |
4644 | if (NODE_PARENT_TYPE (node)) |
4645 | { |
4646 | TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
4647 | if (node->data->instance.private_size != pnode->data->instance.private_size) |
4648 | { |
4649 | g_warning ("g_type_class_add_private() called multiple times for the same type" ); |
4650 | return; |
4651 | } |
4652 | } |
4653 | |
4654 | G_WRITE_LOCK (&type_rw_lock); |
4655 | |
4656 | private_size = ALIGN_STRUCT (node->data->instance.private_size + private_size); |
4657 | g_assert (private_size <= 0xffff); |
4658 | node->data->instance.private_size = private_size; |
4659 | |
4660 | G_WRITE_UNLOCK (&type_rw_lock); |
4661 | } |
4662 | |
4663 | /* semi-private, called only by the G_ADD_PRIVATE macro */ |
4664 | gint |
4665 | g_type_add_instance_private (GType class_gtype, |
4666 | gsize private_size) |
4667 | { |
4668 | TypeNode *node = lookup_type_node_I (utype: class_gtype); |
4669 | |
4670 | g_return_val_if_fail (private_size > 0, 0); |
4671 | g_return_val_if_fail (private_size <= 0xffff, 0); |
4672 | |
4673 | if (!node || !node->is_classed || !node->is_instantiatable || !node->data) |
4674 | { |
4675 | g_warning ("cannot add private field to invalid (non-instantiatable) type '%s'" , |
4676 | type_descriptive_name_I (class_gtype)); |
4677 | return 0; |
4678 | } |
4679 | |
4680 | if (node->plugin != NULL) |
4681 | { |
4682 | g_warning ("cannot use g_type_add_instance_private() with dynamic type '%s'" , |
4683 | type_descriptive_name_I (class_gtype)); |
4684 | return 0; |
4685 | } |
4686 | |
4687 | /* in the future, we want to register the private data size of a type |
4688 | * directly from the get_type() implementation so that we can take full |
4689 | * advantage of the type definition macros that we already have. |
4690 | * |
4691 | * unfortunately, this does not behave correctly if a class in the middle |
4692 | * of the type hierarchy uses the "old style" of private data registration |
4693 | * from the class_init() implementation, as the private data offset is not |
4694 | * going to be known until the full class hierarchy is initialized. |
4695 | * |
4696 | * in order to transition our code to the Glorious New Future™, we proceed |
4697 | * with a two-step implementation: first, we provide this new function to |
4698 | * register the private data size in the get_type() implementation and we |
4699 | * hide it behind a macro. the function will return the private size, instead |
4700 | * of the offset, which will be stored inside a static variable defined by |
4701 | * the G_DEFINE_TYPE_EXTENDED macro. the G_DEFINE_TYPE_EXTENDED macro will |
4702 | * check the variable and call g_type_class_add_instance_private(), which |
4703 | * will use the data size and actually register the private data, then |
4704 | * return the computed offset of the private data, which will be stored |
4705 | * inside the static variable, so we can use it to retrieve the pointer |
4706 | * to the private data structure. |
4707 | * |
4708 | * once all our code has been migrated to the new idiomatic form of private |
4709 | * data registration, we will change the g_type_add_instance_private() |
4710 | * function to actually perform the registration and return the offset |
4711 | * of the private data; g_type_class_add_instance_private() already checks |
4712 | * if the passed argument is negative (meaning that it's an offset in the |
4713 | * GTypeInstance allocation) and becomes a no-op if that's the case. this |
4714 | * should make the migration fully transparent even if we're effectively |
4715 | * copying this macro into everybody's code. |
4716 | */ |
4717 | return private_size; |
4718 | } |
4719 | |
4720 | /* semi-private function, should only be used by G_DEFINE_TYPE_EXTENDED */ |
4721 | void |
4722 | g_type_class_adjust_private_offset (gpointer g_class, |
4723 | gint *private_size_or_offset) |
4724 | { |
4725 | GType class_gtype = ((GTypeClass *) g_class)->g_type; |
4726 | TypeNode *node = lookup_type_node_I (utype: class_gtype); |
4727 | gssize private_size; |
4728 | |
4729 | g_return_if_fail (private_size_or_offset != NULL); |
4730 | |
4731 | /* if we have been passed the offset instead of the private data size, |
4732 | * then we consider this as a no-op, and just return the value. see the |
4733 | * comment in g_type_add_instance_private() for the full explanation. |
4734 | */ |
4735 | if (*private_size_or_offset > 0) |
4736 | g_return_if_fail (*private_size_or_offset <= 0xffff); |
4737 | else |
4738 | return; |
4739 | |
4740 | if (!node || !node->is_classed || !node->is_instantiatable || !node->data) |
4741 | { |
4742 | g_warning ("cannot add private field to invalid (non-instantiatable) type '%s'" , |
4743 | type_descriptive_name_I (class_gtype)); |
4744 | *private_size_or_offset = 0; |
4745 | return; |
4746 | } |
4747 | |
4748 | if (NODE_PARENT_TYPE (node)) |
4749 | { |
4750 | TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
4751 | if (node->data->instance.private_size != pnode->data->instance.private_size) |
4752 | { |
4753 | g_warning ("g_type_add_instance_private() called multiple times for the same type" ); |
4754 | *private_size_or_offset = 0; |
4755 | return; |
4756 | } |
4757 | } |
4758 | |
4759 | G_WRITE_LOCK (&type_rw_lock); |
4760 | |
4761 | private_size = ALIGN_STRUCT (node->data->instance.private_size + *private_size_or_offset); |
4762 | g_assert (private_size <= 0xffff); |
4763 | node->data->instance.private_size = private_size; |
4764 | |
4765 | *private_size_or_offset = -(gint) node->data->instance.private_size; |
4766 | |
4767 | G_WRITE_UNLOCK (&type_rw_lock); |
4768 | } |
4769 | |
4770 | gpointer |
4771 | g_type_instance_get_private (GTypeInstance *instance, |
4772 | GType private_type) |
4773 | { |
4774 | TypeNode *node; |
4775 | |
4776 | g_return_val_if_fail (instance != NULL && instance->g_class != NULL, NULL); |
4777 | |
4778 | node = lookup_type_node_I (utype: private_type); |
4779 | if (G_UNLIKELY (!node || !node->is_instantiatable)) |
4780 | { |
4781 | g_warning ("instance of invalid non-instantiatable type '%s'" , |
4782 | type_descriptive_name_I (instance->g_class->g_type)); |
4783 | return NULL; |
4784 | } |
4785 | |
4786 | return ((gchar *) instance) - node->data->instance.private_size; |
4787 | } |
4788 | |
4789 | /** |
4790 | * g_type_class_get_instance_private_offset: (skip) |
4791 | * @g_class: (type GObject.TypeClass): a #GTypeClass |
4792 | * |
4793 | * Gets the offset of the private data for instances of @g_class. |
4794 | * |
4795 | * This is how many bytes you should add to the instance pointer of a |
4796 | * class in order to get the private data for the type represented by |
4797 | * @g_class. |
4798 | * |
4799 | * You can only call this function after you have registered a private |
4800 | * data area for @g_class using g_type_class_add_private(). |
4801 | * |
4802 | * Returns: the offset, in bytes |
4803 | * |
4804 | * Since: 2.38 |
4805 | **/ |
4806 | gint |
4807 | g_type_class_get_instance_private_offset (gpointer g_class) |
4808 | { |
4809 | GType instance_type; |
4810 | guint16 parent_size; |
4811 | TypeNode *node; |
4812 | |
4813 | g_assert (g_class != NULL); |
4814 | |
4815 | instance_type = ((GTypeClass *) g_class)->g_type; |
4816 | node = lookup_type_node_I (utype: instance_type); |
4817 | |
4818 | g_assert (node != NULL); |
4819 | g_assert (node->is_instantiatable); |
4820 | |
4821 | if (NODE_PARENT_TYPE (node)) |
4822 | { |
4823 | TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
4824 | |
4825 | parent_size = pnode->data->instance.private_size; |
4826 | } |
4827 | else |
4828 | parent_size = 0; |
4829 | |
4830 | if (node->data->instance.private_size == parent_size) |
4831 | g_error ("g_type_class_get_instance_private_offset() called on class %s but it has no private data" , |
4832 | g_type_name (instance_type)); |
4833 | |
4834 | return -(gint) node->data->instance.private_size; |
4835 | } |
4836 | |
4837 | /** |
4838 | * g_type_add_class_private: |
4839 | * @class_type: GType of a classed type |
4840 | * @private_size: size of private structure |
4841 | * |
4842 | * Registers a private class structure for a classed type; |
4843 | * when the class is allocated, the private structures for |
4844 | * the class and all of its parent types are allocated |
4845 | * sequentially in the same memory block as the public |
4846 | * structures, and are zero-filled. |
4847 | * |
4848 | * This function should be called in the |
4849 | * type's get_type() function after the type is registered. |
4850 | * The private structure can be retrieved using the |
4851 | * G_TYPE_CLASS_GET_PRIVATE() macro. |
4852 | * |
4853 | * Since: 2.24 |
4854 | */ |
4855 | void |
4856 | g_type_add_class_private (GType class_type, |
4857 | gsize private_size) |
4858 | { |
4859 | TypeNode *node = lookup_type_node_I (utype: class_type); |
4860 | gsize offset; |
4861 | |
4862 | g_return_if_fail (private_size > 0); |
4863 | |
4864 | if (!node || !node->is_classed || !node->data) |
4865 | { |
4866 | g_warning ("cannot add class private field to invalid type '%s'" , |
4867 | type_descriptive_name_I (class_type)); |
4868 | return; |
4869 | } |
4870 | |
4871 | if (NODE_PARENT_TYPE (node)) |
4872 | { |
4873 | TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); |
4874 | if (node->data->class.class_private_size != pnode->data->class.class_private_size) |
4875 | { |
4876 | g_warning ("g_type_add_class_private() called multiple times for the same type" ); |
4877 | return; |
4878 | } |
4879 | } |
4880 | |
4881 | G_WRITE_LOCK (&type_rw_lock); |
4882 | |
4883 | offset = ALIGN_STRUCT (node->data->class.class_private_size); |
4884 | node->data->class.class_private_size = offset + private_size; |
4885 | |
4886 | G_WRITE_UNLOCK (&type_rw_lock); |
4887 | } |
4888 | |
4889 | gpointer |
4890 | g_type_class_get_private (GTypeClass *klass, |
4891 | GType private_type) |
4892 | { |
4893 | TypeNode *class_node; |
4894 | TypeNode *private_node; |
4895 | TypeNode *parent_node; |
4896 | gsize offset; |
4897 | |
4898 | g_return_val_if_fail (klass != NULL, NULL); |
4899 | |
4900 | class_node = lookup_type_node_I (utype: klass->g_type); |
4901 | if (G_UNLIKELY (!class_node || !class_node->is_classed)) |
4902 | { |
4903 | g_warning ("class of invalid type '%s'" , |
4904 | type_descriptive_name_I (klass->g_type)); |
4905 | return NULL; |
4906 | } |
4907 | |
4908 | private_node = lookup_type_node_I (utype: private_type); |
4909 | if (G_UNLIKELY (!private_node || !NODE_IS_ANCESTOR (private_node, class_node))) |
4910 | { |
4911 | g_warning ("attempt to retrieve private data for invalid type '%s'" , |
4912 | type_descriptive_name_I (private_type)); |
4913 | return NULL; |
4914 | } |
4915 | |
4916 | offset = ALIGN_STRUCT (class_node->data->class.class_size); |
4917 | |
4918 | if (NODE_PARENT_TYPE (private_node)) |
4919 | { |
4920 | parent_node = lookup_type_node_I (NODE_PARENT_TYPE (private_node)); |
4921 | g_assert (parent_node->data && NODE_REFCOUNT (parent_node) > 0); |
4922 | |
4923 | if (G_UNLIKELY (private_node->data->class.class_private_size == parent_node->data->class.class_private_size)) |
4924 | { |
4925 | g_warning ("g_type_instance_get_class_private() requires a prior call to g_type_add_class_private()" ); |
4926 | return NULL; |
4927 | } |
4928 | |
4929 | offset += ALIGN_STRUCT (parent_node->data->class.class_private_size); |
4930 | } |
4931 | |
4932 | return G_STRUCT_MEMBER_P (klass, offset); |
4933 | } |
4934 | |
4935 | /** |
4936 | * g_type_ensure: |
4937 | * @type: a #GType |
4938 | * |
4939 | * Ensures that the indicated @type has been registered with the |
4940 | * type system, and its _class_init() method has been run. |
4941 | * |
4942 | * In theory, simply calling the type's _get_type() method (or using |
4943 | * the corresponding macro) is supposed take care of this. However, |
4944 | * _get_type() methods are often marked %G_GNUC_CONST for performance |
4945 | * reasons, even though this is technically incorrect (since |
4946 | * %G_GNUC_CONST requires that the function not have side effects, |
4947 | * which _get_type() methods do on the first call). As a result, if |
4948 | * you write a bare call to a _get_type() macro, it may get optimized |
4949 | * out by the compiler. Using g_type_ensure() guarantees that the |
4950 | * type's _get_type() method is called. |
4951 | * |
4952 | * Since: 2.34 |
4953 | */ |
4954 | void |
4955 | g_type_ensure (GType type) |
4956 | { |
4957 | /* In theory, @type has already been resolved and so there's nothing |
4958 | * to do here. But this protects us in the case where the function |
4959 | * gets inlined (as it might in gobject_init_ctor() above). |
4960 | */ |
4961 | if (G_UNLIKELY (type == (GType)-1)) |
4962 | g_error ("can't happen" ); |
4963 | } |
4964 | |