/* Chrysalide - Outil d'analyse de fichiers binaires * helpers.h - prototypes pour la simplification des interactions de base avec GLib * * Copyright (C) 2024 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #ifndef _GLIBEXT_HELPERS_H #define _GLIBEXT_HELPERS_H #include #include /** * Les définitions issues de /gobject/gtype.h fournissent des macros * facilitant la déclaration de types pour entêtes. Cependant : * * - G_DECLARE_FINAL_TYPE impose une structure de classe fixe ; * - G_DECLARE_DERIVABLE_TYPE impose une structure d'objet fixe. * * Ces deux macros ne peuvent donc pas être employées en l'état dans Chrysalide. * * Par ailleurs, la fonctionnalité g_autoptr() n'offre pas une séduction totale : * elle conduit à un code inconsistant, avec parfois des libérations explicites, * parfois des libérations invisible gérées par le compilateur. Cet aspect * fonctionnel offert par les macros GLib est donc inutile pour Chrysalide. * * Une nouvelle macro de déclaration est ainsi constituée ici. * * De fait de l'absence d'argument, l'inclusion de la définition suivante n'est * pas possible : * * MOD##_TYPE_##NAME t_n##_get_type() * * La macro traditionnelle doit ainsi être fournie en parallèle à la déclaration * condensée ici. Elle y est d'ailleurs référencée, forçant une déclaration * préalable de manière globale et cohérente dans l'ensemble du code d'emploi. */ #define DECLARE_GTYPE(TN, t_n, MOD, NAME) \ \ GType t_n##_get_type(void) G_GNUC_CONST; \ \ typedef struct _##TN TN; \ typedef struct _##TN##Class TN##Class; \ \ G_GNUC_UNUSED static inline TN *MOD##_##NAME(gconstpointer obj) \ { \ return G_TYPE_CHECK_INSTANCE_CAST(obj, MOD##_TYPE_##NAME, TN); \ } \ \ G_GNUC_UNUSED static inline TN##Class *MOD##_##NAME##_CLASS(gconstpointer klass) \ { \ return G_TYPE_CHECK_CLASS_CAST(klass, MOD##_TYPE_##NAME, TN##Class); \ } \ \ G_GNUC_UNUSED static inline gboolean MOD##_IS_##NAME(gconstpointer obj) \ { \ return G_TYPE_CHECK_INSTANCE_TYPE(obj, MOD##_TYPE_##NAME); \ } \ \ G_GNUC_UNUSED static inline gboolean MOD##_IS_##NAME##_CLASS(gconstpointer klass) \ { \ return G_TYPE_CHECK_CLASS_TYPE(klass, MOD##_TYPE_##NAME); \ } \ \ G_GNUC_UNUSED static inline TN##Class *MOD##_##NAME##_GET_CLASS(gconstpointer obj) \ { \ return G_TYPE_INSTANCE_GET_CLASS(obj, MOD##_TYPE_##NAME, TN##Class); \ } /** * Les principales fonctions incrémentant ou réduisant le nombre de références * attachées à un objet acceptent de simples pointeurs génériques (cf. définitions * du fichier /gobject/gobject.h : * * [...] * void g_object_notify_by_pspec (GObject *object, * GParamSpec *pspec); * void g_object_thaw_notify (GObject *object); * gboolean g_object_is_floating (gpointer object); * gpointer g_object_ref_sink (gpointer object); * gpointer g_object_take_ref (gpointer object); * gpointer g_object_ref (gpointer object); * void g_object_unref (gpointer object); * void g_object_weak_ref (GObject *object, * GWeakNotify notify, * gpointer data); * [...] * * La fonction g_object_unref() débute bien par exemple par une validation * de l'instance, avec un appel à : g_return_if_fail (G_IS_OBJECT (object)). * * Cependant, cette vérification est désactivée en cas de compilation de GLib * avec G_DISABLE_CHECKS. * * Une conversion vers un type donné (par exemple avec G_OBJECT()) est par * ailleurs dépendante d'autres paramètres de compilation, comme le révèle * le fichier /gobject/gtype.h : * * #if defined(G_DISABLE_CAST_CHECKS) || defined(__OPTIMIZE__) * # define _G_TYPE_CIC(ip, gt, ct) ((ct*) (void *) ip) * # define _G_TYPE_CCC(cp, gt, ct) ((ct*) (void *) cp) * #else * # define _G_TYPE_CIC(ip, gt, ct) \ * ((ct*) (void *) g_type_check_instance_cast ((GTypeInstance*) ip, gt)) * # define _G_TYPE_CCC(cp, gt, ct) \ * ((ct*) (void *) g_type_check_class_cast ((GTypeClass*) cp, gt)) * #endif * * Afin d'assurer des conditions de débogage/fuzzing optimales dans tous les * cas de figure, les fonctions de manipulation des références font l'objet * ici d'une couche intermédiaire pour les appels. */ #ifndef NDEBUG # define ref_object(ip) \ do \ { \ GTypeInstance *__inst; \ __inst = g_type_check_instance_cast((GTypeInstance *)ip, G_TYPE_OBJECT); \ assert(__inst != NULL); \ g_object_ref(ip); \ } \ while (0); # define unref_object(ip) \ do \ { \ GTypeInstance *__inst; \ __inst = g_type_check_instance_cast((GTypeInstance *)ip, G_TYPE_OBJECT); \ assert(__inst != NULL); \ g_object_unref(ip); \ } \ while (0); #else # define ref_object(p) g_object_ref(p) # define unref_object(p) g_object_unref(p) #endif #endif /* _GLIBEXT_HELPERS_H */