summaryrefslogtreecommitdiff
path: root/src/glibext/singleton.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glibext/singleton.c')
-rw-r--r--src/glibext/singleton.c352
1 files changed, 333 insertions, 19 deletions
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;
}