From c0cc928bfab0af2cdbf16e9a04d41983f4732b93 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 8 Aug 2021 20:24:21 +0200
Subject: Introduce singletons for operands.

---
 plugins/pychrysalide/arch/operand.c      |   4 +
 plugins/pychrysalide/glibext/singleton.c |   4 +-
 src/arch/operand-int.h                   |  15 ++
 src/arch/operand.c                       | 227 ++++++++++++++++++++++++++++++-
 src/arch/operands/immediate.c            |  29 ++++
 src/glibext/singleton-int.h              |   2 +-
 src/glibext/singleton.c                  |   2 +-
 src/glibext/singleton.h                  |   2 +-
 8 files changed, 276 insertions(+), 9 deletions(-)

diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c
index 7fa5118..f3eaa27 100644
--- a/plugins/pychrysalide/arch/operand.c
+++ b/plugins/pychrysalide/arch/operand.c
@@ -35,6 +35,7 @@
 
 #include "../access.h"
 #include "../helpers.h"
+#include "../glibext/singleton.h"
 
 
 
@@ -768,6 +769,9 @@ bool ensure_python_arch_operand_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
+        if (!ensure_python_singleton_candidate_is_registered())
+            return false;
+
         if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type, &PyGObject_Type))
             return false;
 
diff --git a/plugins/pychrysalide/glibext/singleton.c b/plugins/pychrysalide/glibext/singleton.c
index c4592ac..d00648c 100644
--- a/plugins/pychrysalide/glibext/singleton.c
+++ b/plugins/pychrysalide/glibext/singleton.c
@@ -60,7 +60,7 @@ static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *
 static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *);
 
 /* Indique si le candidat est figé. */
-static bool py_singleton_candidate_is_ro_wrapper(GSingletonCandidate *);
+static bool py_singleton_candidate_is_ro_wrapper(const GSingletonCandidate *);
 
 /* Fournit l'empreinte d'un candidat à une centralisation. */
 static PyObject *py_singleton_candidate_hash(PyObject *, PyObject *);
@@ -499,7 +499,7 @@ static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *candidate
 *                                                                             *
 ******************************************************************************/
 
-static bool py_singleton_candidate_is_ro_wrapper(GSingletonCandidate *candidate)
+static bool py_singleton_candidate_is_ro_wrapper(const GSingletonCandidate *candidate)
 {
     bool result;                            /* Etat à retourner            */
     PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
diff --git a/src/arch/operand-int.h b/src/arch/operand-int.h
index a50ec73..ca5204c 100644
--- a/src/arch/operand-int.h
+++ b/src/arch/operand-int.h
@@ -44,6 +44,15 @@ typedef void (* operand_print_fc) (const GArchOperand *, GBufferLine *);
 /* Construit un petit résumé concis de l'opérande. */
 typedef char * (* operand_build_tooltip_fc) (const GArchOperand *, const GLoadedBinary *);
 
+/* Fournit une liste de candidats embarqués par un candidat. */
+typedef GArchOperand ** (* operand_list_inners_fc) (const GArchOperand *, size_t *);
+
+/* Met à jour une liste de candidats embarqués par un candidat. */
+typedef void (* operand_update_inners_fc) (GArchOperand *, GArchOperand **, size_t);
+
+/* Fournit l'empreinte d'un candidat à une centralisation. */
+typedef guint (* operand_hash_fc) (const GArchOperand *);
+
 /* Charge un opérande depuis une mémoire tampon. */
 typedef bool (* unserialize_operand_fc) (GArchOperand *, GAsmStorage *, GBinFormat *, packed_buffer_t *);
 
@@ -56,6 +65,8 @@ struct _GArchOperand
 {
     GObject parent;                         /* A laisser en premier        */
 
+    bool read_only;                         /* Verrouillage du contenu     */
+
 };
 
 
@@ -71,6 +82,10 @@ struct _GArchOperandClass
     operand_print_fc print;                 /* Texte humain équivalent     */
     operand_build_tooltip_fc build_tooltip; /* Construction de description */
 
+    operand_list_inners_fc list_inner;      /* Récupération d'internes     */
+    operand_update_inners_fc update_inner;  /* Mise à jour des éléments    */
+    operand_hash_fc hash;                   /* Prise d'empreinte           */
+
     unserialize_operand_fc unserialize;     /* Chargement depuis un tampon */
     serialize_operand_fc serialize;         /* Conservation dans un tampon */
 
diff --git a/src/arch/operand.c b/src/arch/operand.c
index 3758d7f..66af6d2 100644
--- a/src/arch/operand.c
+++ b/src/arch/operand.c
@@ -33,12 +33,11 @@
 #include "storage.h"
 #include "../common/sort.h"
 #include "../core/logs.h"
+#include "../glibext/singleton-int.h"
 
 
 
-/* ---------------------------------------------------------------------------------- */
-/*                          DEFINITION D'OPERANDE QUELCONQUE                          */
-/* ---------------------------------------------------------------------------------- */
+/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */
 
 
 /* Initialise la classe générique des opérandes. */
@@ -47,6 +46,9 @@ static void g_arch_operand_class_init(GArchOperandClass *);
 /* Initialise une instance d'opérande d'architecture. */
 static void g_arch_operand_init(GArchOperand *);
 
+/* Procède à l'initialisation de l'interface de singleton. */
+static void g_arch_operand_singleton_interface_init(GSingletonCandidateInterface *);
+
 /* Supprime toutes les références externes. */
 static void g_arch_operand_dispose(GArchOperand *);
 
@@ -55,6 +57,29 @@ static void g_arch_operand_finalize(GArchOperand *);
 
 
 
+/* ------------------------ CONTROLE DU VOLUME DES INSTANCES ------------------------ */
+
+
+/* Fournit une liste de candidats embarqués par un candidat. */
+static GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *, size_t *);
+
+/* Met à jour une liste de candidats embarqués par un candidat. */
+static void g_arch_operand_update_inner_instances(GArchOperand *, GArchOperand **, size_t);
+
+/* Fournit l'empreinte d'un candidat à une centralisation. */
+static guint g_arch_operand_hash(const GArchOperand *);
+
+/* Détermine si deux candidats à l'unicité sont identiques. */
+static gboolean g_arch_operand_is_equal(const GArchOperand *, const GArchOperand *);
+
+/* Marque un candidat comme figé. */
+static void g_arch_operand_set_read_only(GArchOperand *);
+
+/* Indique si le candidat est figé. */
+static bool g_arch_operand_is_read_only(GArchOperand *);
+
+
+
 /* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */
 
 
@@ -67,7 +92,8 @@ static bool g_arch_operand_serialize(const GArchOperand *, GAsmStorage *, packed
 
 
 /* Indique le type défini pour un opérande d'architecture. */
-G_DEFINE_TYPE(GArchOperand, g_arch_operand, G_TYPE_OBJECT);
+G_DEFINE_TYPE_WITH_CODE(GArchOperand, g_arch_operand, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE(G_TYPE_SINGLETON_CANDIDATE, g_arch_operand_singleton_interface_init));
 
 
 
@@ -121,6 +147,32 @@ static void g_arch_operand_init(GArchOperand *operand)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : iface = interface GLib à initialiser.                        *
+*                                                                             *
+*  Description : Procède à l'initialisation de l'interface de singleton.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_arch_operand_singleton_interface_init(GSingletonCandidateInterface *iface)
+{
+    iface->list_inner = (list_inner_instances_fc)g_arch_operand_list_inner_instances;
+    iface->update_inner = (update_inner_instances_fc)g_arch_operand_update_inner_instances;
+
+    iface->hash = (hash_candidate_fc)g_arch_operand_hash;
+    iface->is_equal = (is_candidate_equal_fc)g_arch_operand_is_equal;
+
+    iface->set_ro = (set_candidate_ro_fc)g_arch_operand_set_read_only;
+    iface->is_ro = (is_candidate_ro_fc)g_arch_operand_is_read_only;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : operand = instance d'objet GLib à traiter.                   *
 *                                                                             *
 *  Description : Supprime toutes les références externes.                     *
@@ -305,6 +357,173 @@ char *g_arch_operand_build_tooltip(const GArchOperand *operand, const GLoadedBin
 
 
 /* ---------------------------------------------------------------------------------- */
+/*                          CONTROLE DU VOLUME DES INSTANCES                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = objet dont l'instance se veut unique.              *
+*                count   = quantité d'instances à l'unicité internes.         *
+*                                                                             *
+*  Description : Fournit une liste de candidats embarqués par un candidat.    *
+*                                                                             *
+*  Retour      : Liste de candidats internes ou NULL si aucun.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GArchOperand **g_arch_operand_list_inner_instances(const GArchOperand *operand, size_t *count)
+{
+    GArchOperand **result;                  /* Instances à retourner       */
+    GArchOperandClass *class;               /* Classe associée à l'objet   */
+
+    class = G_ARCH_OPERAND_GET_CLASS(operand);
+
+    if (class->list_inner == NULL)
+    {
+        *count = 0;
+        result = NULL;
+    }
+
+    else
+        result = class->list_inner(operand, count);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand   = objet dont l'instance se veut unique.            *
+*                instances = liste de candidats internes devenus singletons.  *
+*                count     = quantité d'instances à l'unicité internes.       *
+*                                                                             *
+*  Description : Met à jour une liste de candidats embarqués par un candidat. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_arch_operand_update_inner_instances(GArchOperand *operand, GArchOperand **instances, size_t count)
+{
+    GArchOperandClass *class;               /* Classe associée à l'objet   */
+
+    class = G_ARCH_OPERAND_GET_CLASS(operand);
+
+    if (class->update_inner == NULL)
+        assert(class->list_inner == NULL);
+
+    else
+    {
+        assert(class->list_inner != NULL);
+        class->update_inner(operand, instances, count);
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = objet dont l'instance se veut unique.              *
+*                                                                             *
+*  Description : Fournit l'empreinte d'un candidat à une centralisation.      *
+*                                                                             *
+*  Retour      : Empreinte de l'élément représenté.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static guint g_arch_operand_hash(const GArchOperand *operand)
+{
+    guint result;                           /* Valeur à retourner          */
+    GArchOperandClass *class;               /* Classe associée à l'objet   */
+
+    class = G_ARCH_OPERAND_GET_CLASS(operand);
+
+    result = class->hash(operand);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = objet dont l'instance se veut unique.              *
+*                other   = second élément à analyser.                         *
+*                                                                             *
+*  Description : Détermine si deux candidats à l'unicité sont identiques.     *
+*                                                                             *
+*  Retour      : Bilan de la comparaison.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static gboolean g_arch_operand_is_equal(const GArchOperand *operand, const GArchOperand *other)
+{
+    gboolean result;                        /* Bilan à renvoyer            */
+    int ret;                                /* Bilan d'une comparaison     */
+
+    ret = g_arch_operand_compare(operand, other);
+
+    result = (ret == 0);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = objet dont l'instance se veut unique.              *
+*                                                                             *
+*  Description : Marque un candidat comme figé.                               *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_arch_operand_set_read_only(GArchOperand *operand)
+{
+    operand->read_only = true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = objet dont l'instance se veut unique.              *
+*                                                                             *
+*  Description : Indique si le candidat est figé.                             *
+*                                                                             *
+*  Retour      : true si le contenu du candidat ne peut plus être modifié.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_arch_operand_is_read_only(GArchOperand *operand)
+{
+    bool result;                            /* Etat à retourner            */
+
+    result = operand->read_only;
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
 /*                       TRANSPOSITIONS VIA CACHE DES OPERANDES                       */
 /* ---------------------------------------------------------------------------------- */
 
diff --git a/src/arch/operands/immediate.c b/src/arch/operands/immediate.c
index cb39fce..6e6925c 100644
--- a/src/arch/operands/immediate.c
+++ b/src/arch/operands/immediate.c
@@ -155,6 +155,9 @@ static void g_imm_operand_print(const GImmOperand *, GBufferLine *);
 /* Construit un petit résumé concis de l'opérande. */
 static char *g_imm_operand_build_tooltip(const GImmOperand *, const GLoadedBinary *);
 
+/* Fournit l'empreinte d'un candidat à une centralisation. */
+static guint g_arch_operand_hash(const GImmOperand *);
+
 /* Charge un opérande depuis une mémoire tampon. */
 static bool g_imm_operand_unserialize(GImmOperand *, GAsmStorage *, GBinFormat *, packed_buffer_t *);
 
@@ -259,6 +262,8 @@ static void g_imm_operand_class_init(GImmOperandClass *klass)
     operand->print = (operand_print_fc)g_imm_operand_print;
     operand->build_tooltip = (operand_build_tooltip_fc)g_imm_operand_build_tooltip;
 
+    operand->hash = (operand_hash_fc)g_arch_operand_hash;
+
     operand->unserialize = (unserialize_operand_fc)g_imm_operand_unserialize;
     operand->serialize = (serialize_operand_fc)g_imm_operand_serialize;
 
@@ -1573,6 +1578,30 @@ void g_imm_operand_as_uleb128(const GImmOperand *operand, uleb128_t *val)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : operand = objet dont l'instance se veut unique.              *
+*                                                                             *
+*  Description : Fournit l'empreinte d'un candidat à une centralisation.      *
+*                                                                             *
+*  Retour      : Empreinte de l'élément représenté.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static guint g_arch_operand_hash(const GImmOperand *operand)
+{
+    guint result;                           /* Valeur à retourner          */
+
+    result = (operand->raw & 0xffffffff);
+    result ^= (operand->raw >> 32);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : operand = opérande d'assemblage à constituer.                *
 *                storage = mécanisme de sauvegarde à manipuler.               *
 *                format  = format binaire chargé associé à l'architecture.    *
diff --git a/src/glibext/singleton-int.h b/src/glibext/singleton-int.h
index 49cfecd..3db17f9 100644
--- a/src/glibext/singleton-int.h
+++ b/src/glibext/singleton-int.h
@@ -45,7 +45,7 @@ typedef gboolean (* is_candidate_equal_fc) (const GSingletonCandidate *, const G
 typedef void (* set_candidate_ro_fc) (GSingletonCandidate *);
 
 /* Indique si le candidat est figé. */
-typedef bool (* is_candidate_ro_fc) (GSingletonCandidate *);
+typedef bool (* is_candidate_ro_fc) (const GSingletonCandidate *);
 
 
 /* Instance d'objet visant à être unique (interface) */
diff --git a/src/glibext/singleton.c b/src/glibext/singleton.c
index bcd5580..78a3ad4 100644
--- a/src/glibext/singleton.c
+++ b/src/glibext/singleton.c
@@ -466,7 +466,7 @@ void g_singleton_candidate_set_read_only(GSingletonCandidate *candidate)
 *                                                                             *
 ******************************************************************************/
 
-bool g_singleton_candidate_is_read_only(GSingletonCandidate *candidate)
+bool g_singleton_candidate_is_read_only(const GSingletonCandidate *candidate)
 {
     bool result;                            /* Etat à retourner            */
     GSingletonCandidateIface *iface;        /* Interface utilisée          */
diff --git a/src/glibext/singleton.h b/src/glibext/singleton.h
index 0561f80..629687a 100644
--- a/src/glibext/singleton.h
+++ b/src/glibext/singleton.h
@@ -69,7 +69,7 @@ gboolean g_singleton_candidate_is_equal(GSingletonCandidate *, GSingletonCandida
 void g_singleton_candidate_set_read_only(GSingletonCandidate *);
 
 /* Indique si le candidat est figé. */
-bool g_singleton_candidate_is_read_only(GSingletonCandidate *);
+bool g_singleton_candidate_is_read_only(const GSingletonCandidate *);
 
 
 
-- 
cgit v0.11.2-87-g4458