summaryrefslogtreecommitdiff
path: root/src/glibext
diff options
context:
space:
mode:
Diffstat (limited to 'src/glibext')
-rw-r--r--src/glibext/singleton-int.h21
-rw-r--r--src/glibext/singleton.c352
-rw-r--r--src/glibext/singleton.h23
3 files changed, 362 insertions, 34 deletions
diff --git a/src/glibext/singleton-int.h b/src/glibext/singleton-int.h
index ac31a32..49cfecd 100644
--- a/src/glibext/singleton-int.h
+++ b/src/glibext/singleton-int.h
@@ -29,17 +29,23 @@
+/* Fournit une liste de candidats embarqués par un candidat. */
+typedef GSingletonCandidate ** (* list_inner_instances_fc) (const GSingletonCandidate *, size_t *);
+
+/* Met à jour une liste de candidats embarqués par un candidat. */
+typedef void (* update_inner_instances_fc) (GSingletonCandidate *, GSingletonCandidate **, size_t);
+
/* Fournit l'empreinte d'un candidat à une centralisation. */
typedef guint (* hash_candidate_fc) (const GSingletonCandidate *);
/* Détermine si deux candidats à l'unicité sont identiques. */
typedef gboolean (* is_candidate_equal_fc) (const GSingletonCandidate *, const GSingletonCandidate *);
-/* Marque un candidat comme traité ou en cours de traitement. */
-typedef void (* mark_candidate_as_processed_fc) (GSingletonCandidate *, bool);
+/* Marque un candidat comme figé. */
+typedef void (* set_candidate_ro_fc) (GSingletonCandidate *);
-/* Indique si un objet marqué comme unique. */
-typedef bool (* is_candidate_processed_fc) (const GSingletonCandidate *, bool);
+/* Indique si le candidat est figé. */
+typedef bool (* is_candidate_ro_fc) (GSingletonCandidate *);
/* Instance d'objet visant à être unique (interface) */
@@ -47,11 +53,14 @@ struct _GSingletonCandidateIface
{
GTypeInterface base_iface; /* A laisser en premier */
+ list_inner_instances_fc list_inner; /* Récupération d'internes */
+ update_inner_instances_fc update_inner; /* Mise à jour des éléments */
+
hash_candidate_fc hash; /* Prise d'empreinte */
is_candidate_equal_fc is_equal; /* Comparaison */
- mark_candidate_as_processed_fc mark; /* Définition de l'état */
- is_candidate_processed_fc is_processed; /* Consultation de l'état */
+ set_candidate_ro_fc set_ro; /* Bascule en mode figé */
+ is_candidate_ro_fc is_ro; /* Consultation de l'état */
};
diff --git a/src/glibext/singleton.c b/src/glibext/singleton.c
index f0ce86f..bcd5580 100644
--- a/src/glibext/singleton.c
+++ b/src/glibext/singleton.c
@@ -36,6 +36,18 @@
/* Procède à l'initialisation de l'interface de rassemblement. */
static void g_singleton_candidate_default_init(GSingletonCandidateInterface *);
+/* Met à jour une liste de candidats embarqués par un candidat. */
+static void g_singleton_candidate_update_inner_instances(GSingletonCandidate *, GSingletonCandidate **, size_t);
+
+/* Fournit l'empreinte d'un candidat à une centralisation. */
+static guint _g_singleton_candidate_hash(GSingletonCandidate *, GList **);
+
+/* Détermine si deux candidats à l'unicité sont identiques. */
+static gboolean _g_singleton_candidate_is_equal(GSingletonCandidate *, GSingletonCandidate *, GList **);
+
+/* Marque un candidat comme figé. */
+static void _g_singleton_candidate_set_read_only(GSingletonCandidate *, GList **);
+
/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */
@@ -103,6 +115,73 @@ static void g_singleton_candidate_default_init(GSingletonCandidateInterface *ifa
/******************************************************************************
* *
* Paramètres : candidate = 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 : - *
+* *
+******************************************************************************/
+
+GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingletonCandidate *candidate, size_t *count)
+{
+ GSingletonCandidate **result; /* Instances à retourner */
+ GSingletonCandidateIface *iface; /* Interface utilisée */
+
+ iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
+
+ if (iface->list_inner == NULL)
+ {
+ *count = 0;
+ result = NULL;
+ }
+
+ else
+ result = iface->list_inner(candidate, count);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = 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_singleton_candidate_update_inner_instances(GSingletonCandidate *candidate, GSingletonCandidate **instances, size_t count)
+{
+ GSingletonCandidateIface *iface; /* Interface utilisée */
+
+ iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
+
+ if (iface->update_inner == NULL)
+ assert(iface->list_inner == NULL);
+
+ else
+ {
+ assert(iface->list_inner != NULL);
+ iface->update_inner(candidate, instances, count);
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = objet dont l'instance se veut unique. *
+* processed = liste de candidats déjà traités. *
* *
* Description : Fournit l'empreinte d'un candidat à une centralisation. *
* *
@@ -112,14 +191,70 @@ static void g_singleton_candidate_default_init(GSingletonCandidateInterface *ifa
* *
******************************************************************************/
-guint g_singleton_candidate_hash(const GSingletonCandidate *candidate)
+static guint _g_singleton_candidate_hash(GSingletonCandidate *candidate, GList **processed)
{
guint result; /* Valeur à retourner */
+ GList *skip; /* Détection de boucle */
GSingletonCandidateIface *iface; /* Interface utilisée */
+ GSingletonCandidate **children; /* Instances internes */
+ size_t count; /* Quantité de ces instances */
+ size_t i; /* Boucle de parcours */
- iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
+ skip = g_list_find(*processed, candidate);
+
+ if (skip != NULL)
+ result = 0;
+
+ else
+ {
+ iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
+
+ result = iface->hash(candidate);
+
+ *processed = g_list_append(*processed, candidate);
+
+ children = g_singleton_candidate_list_inner_instances(candidate, &count);
+
+ for (i = 0; i < count; i++)
+ {
+ result ^= _g_singleton_candidate_hash(children[i], processed);
+ g_object_unref(G_OBJECT(children[i]));
+ }
+
+ if (children != NULL)
+ free(children);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = 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 : - *
+* *
+******************************************************************************/
+
+guint g_singleton_candidate_hash(GSingletonCandidate *candidate)
+{
+ guint result; /* Valeur à retourner */
+ GList *processed; /* Suivi des traitements */
+
+ processed = NULL;
+
+ result = _g_singleton_candidate_hash(candidate, &processed);
- result = iface->hash(candidate);
+ assert(processed != NULL);
+
+ g_list_free(processed);
return result;
@@ -130,6 +265,7 @@ guint g_singleton_candidate_hash(const GSingletonCandidate *candidate)
* *
* Paramètres : candidate = objet dont l'instance se veut unique. *
* other = second élément à analyser. *
+* processed = liste de candidats déjà traités. *
* *
* Description : Détermine si deux candidats à l'unicité sont identiques. *
* *
@@ -139,27 +275,117 @@ guint g_singleton_candidate_hash(const GSingletonCandidate *candidate)
* *
******************************************************************************/
-gboolean g_singleton_candidate_is_equal(const GSingletonCandidate *candidate, const GSingletonCandidate *other)
+static gboolean _g_singleton_candidate_is_equal(GSingletonCandidate *candidate, GSingletonCandidate *other, GList **processed)
{
gboolean result; /* Bilan à renvoyer */
+ GList *skip; /* Détection de boucle */
GSingletonCandidateIface *iface; /* Interface utilisée */
+ GSingletonCandidate **children[2]; /* Instances internes */
+ size_t count[2]; /* Quantité de ces instances */
+ size_t i; /* Boucle de parcours */
- iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
+ skip = g_list_find(processed[0], candidate);
+
+ if (skip != NULL)
+ result = (g_list_find(processed[1], other) != NULL);
+
+ else
+ {
+ iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
+
+ result = iface->is_equal(candidate, other);
+
+ processed[0] = g_list_append(processed[0], candidate);
+ processed[1] = g_list_append(processed[1], other);
+
+ if (!result)
+ goto done;
+
+ children[0] = g_singleton_candidate_list_inner_instances(candidate, &count[0]);
+ children[1] = g_singleton_candidate_list_inner_instances(other, &count[1]);
+
+ if (count[0] != count[1])
+ {
+ for (i = 0; i < count[0]; i++)
+ g_object_unref(G_OBJECT(children[0][i]));
- result = iface->is_equal(candidate, other);
+ for (i = 0; i < count[1]; i++)
+ g_object_unref(G_OBJECT(children[1][i]));
+
+ }
+
+ else
+ {
+ for (i = 0; i < count[0] && result; i++)
+ {
+ result = _g_singleton_candidate_is_equal(children[0][i], children[1][i], processed);
+ g_object_unref(G_OBJECT(children[0][i]));
+ g_object_unref(G_OBJECT(children[1][i]));
+ }
+
+ for (; i < count[0]; i++)
+ {
+ g_object_unref(G_OBJECT(children[0][i]));
+ g_object_unref(G_OBJECT(children[1][i]));
+ }
+
+ if (children[0] != NULL)
+ free(children[0]);
+
+ if (children[1] != NULL)
+ free(children[1]);
+
+ }
+
+ }
+
+ done:
return result;
}
+/******************************************************************************
+* *
+* Paramètres : candidate = 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 : - *
+* *
+******************************************************************************/
+
+gboolean g_singleton_candidate_is_equal(GSingletonCandidate *candidate, GSingletonCandidate *other)
+{
+ gboolean result; /* Bilan à renvoyer */
+ GList *processed[2]; /* Suivi des traitements */
+
+ processed[0] = NULL;
+ processed[1] = NULL;
+
+ result = _g_singleton_candidate_is_equal(candidate, other, processed);
+
+ assert(processed[0] != NULL);
+ assert(processed[1] != NULL);
+
+ g_list_free(processed[0]);
+ g_list_free(processed[1]);
+
+ return result;
+
+}
+
/******************************************************************************
* *
* Paramètres : candidate = objet dont l'instance se veut unique. *
-* soon = indique un traitement démarré et en cours. *
+* processed = liste de candidats déjà traités. *
* *
-* Description : Marque un candidat comme traité ou en cours de traitement. *
+* Description : Marque un candidat comme figé. *
* *
* Retour : - *
* *
@@ -167,13 +393,36 @@ gboolean g_singleton_candidate_is_equal(const GSingletonCandidate *candidate, co
* *
******************************************************************************/
-void g_singleton_candidate_mark_as_processed(GSingletonCandidate *candidate, bool soon)
+static void _g_singleton_candidate_set_read_only(GSingletonCandidate *candidate, GList **processed)
{
+ GList *skip; /* Détection de boucle */
GSingletonCandidateIface *iface; /* Interface utilisée */
+ GSingletonCandidate **children; /* Instances internes */
+ size_t count; /* Quantité de ces instances */
+ size_t i; /* Boucle de parcours */
- iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
+ skip = g_list_find(*processed, candidate);
+
+ if (skip == NULL)
+ {
+ iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
+
+ iface->set_ro(candidate);
+
+ *processed = g_list_append(*processed, candidate);
+
+ children = g_singleton_candidate_list_inner_instances(candidate, &count);
- iface->mark(candidate, soon);
+ for (i = 0; i < count; i++)
+ {
+ _g_singleton_candidate_set_read_only(candidate, processed);
+ g_object_unref(G_OBJECT(children[i]));
+ }
+
+ if (children != NULL)
+ free(children);
+
+ }
}
@@ -181,28 +430,53 @@ void g_singleton_candidate_mark_as_processed(GSingletonCandidate *candidate, boo
/******************************************************************************
* *
* Paramètres : candidate = objet dont l'instance se veut unique. *
-* soon = indique un traitement démarré et en cours. *
* *
-* Description : Indique si un objet marqué comme unique. *
+* Description : Marque un candidat comme figé. *
* *
-* Retour : true si l'objet est traité ou en phase de l'être, ou false. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_singleton_candidate_is_processed(const GSingletonCandidate *candidate, bool soon)
+void g_singleton_candidate_set_read_only(GSingletonCandidate *candidate)
{
- bool result; /* Statut à retourner */
+ GList *processed; /* Suivi des traitements */
+
+ processed = NULL;
+
+ _g_singleton_candidate_set_read_only(candidate, &processed);
+
+ assert(processed != NULL);
+
+ g_list_free(processed);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : candidate = 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 : - *
+* *
+******************************************************************************/
+
+bool g_singleton_candidate_is_read_only(GSingletonCandidate *candidate)
+{
+ bool result; /* Etat à retourner */
GSingletonCandidateIface *iface; /* Interface utilisée */
iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate);
- result = iface->is_processed(candidate, soon);
+ result = iface->is_ro(candidate);
return result;
-
}
@@ -348,10 +622,48 @@ GSingletonFactory *g_singleton_factory_new(void)
GSingletonCandidate *g_singleton_factory_get_instance(GSingletonFactory *factory, GSingletonCandidate *candidate)
{
GSingletonCandidate *result; /* Instance unique à retourner */
+ size_t count; /* Quantité d'objets internes */
+ GSingletonCandidate **instances; /* Liste d'instances internes */
+ GSingletonCandidate **updated; /* Nouvelle liste d'instances */
+ bool need_update; /* Mise à jour nécessaire */
+ size_t i; /* Boucle de parcours */
#ifndef NDEBUG
- gboolean status; /* Validation d'une opération */
+ gboolean status; /* Validation d'une opération */
#endif
+ /* Validation des objets internes éventuels */
+
+ instances = g_singleton_candidate_list_inner_instances(candidate, &count);
+
+ if (count > 0)
+ {
+ updated = malloc(count * sizeof(GSingletonCandidate *));
+ need_update = false;
+
+ for (i = 0; i < count; i++)
+ {
+ updated[i] = g_singleton_factory_get_instance(factory, instances[i]);
+ need_update |= (instances[i] != updated[i]);
+ }
+
+ if (need_update)
+ g_singleton_candidate_update_inner_instances(candidate, updated, count);
+
+ for (i = 0; i < count; i++)
+ {
+ g_object_unref(G_OBJECT(updated[i]));
+ g_object_unref(G_OBJECT(instances[i]));
+ }
+
+ free(updated);
+
+ }
+
+ if (instances != NULL)
+ free(instances);
+
+ /* Récupération de l'instance principale */
+
g_mutex_lock(&factory->access);
if (g_hash_table_contains(factory->table, candidate))
@@ -376,6 +688,8 @@ GSingletonCandidate *g_singleton_factory_get_instance(GSingletonFactory *factory
g_hash_table_add(factory->table, candidate);
#endif
+ g_singleton_candidate_set_read_only(candidate);
+
result = candidate;
}
diff --git a/src/glibext/singleton.h b/src/glibext/singleton.h
index 6de9f41..0561f80 100644
--- a/src/glibext/singleton.h
+++ b/src/glibext/singleton.h
@@ -30,6 +30,11 @@
+/* Définition d'un compacteur d'instances de types (instance) */
+typedef struct _GSingletonFactory GSingletonFactory;
+
+
+
/* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */
@@ -51,17 +56,20 @@ typedef struct _GSingletonCandidateIface GSingletonCandidateIface;
/* Détermine le type d'une interface pour la lecture de binaire. */
GType g_singleton_candidate_get_type(void) G_GNUC_CONST;
+/* Fournit une liste de candidats embarqués par un candidat. */
+GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingletonCandidate *, size_t *);
+
/* Fournit l'empreinte d'un candidat à une centralisation. */
-guint g_singleton_candidate_hash(const GSingletonCandidate *);
+guint g_singleton_candidate_hash(GSingletonCandidate *);
/* Détermine si deux candidats à l'unicité sont identiques. */
-gboolean g_singleton_candidate_is_equal(const GSingletonCandidate *, const GSingletonCandidate *);
+gboolean g_singleton_candidate_is_equal(GSingletonCandidate *, GSingletonCandidate *);
-/* Marque un candidat comme traité ou en cours de traitement. */
-void g_singleton_candidate_mark_as_processed(GSingletonCandidate *, bool);
+/* Marque un candidat comme figé. */
+void g_singleton_candidate_set_read_only(GSingletonCandidate *);
-/* Indique si un objet marqué comme unique. */
-bool g_singleton_candidate_is_processed(const GSingletonCandidate *, bool);
+/* Indique si le candidat est figé. */
+bool g_singleton_candidate_is_read_only(GSingletonCandidate *);
@@ -76,9 +84,6 @@ bool g_singleton_candidate_is_processed(const GSingletonCandidate *, bool);
#define G_SINGLETON_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SINGLETON_FACTORY, GSingletonFactoryClass))
-/* Définition d'un compacteur d'instances de types (instance) */
-typedef struct _GSingletonFactory GSingletonFactory;
-
/* Définition d'un compacteur d'instances de types (classe) */
typedef struct _GSingletonFactoryClass GSingletonFactoryClass;