diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2021-05-17 23:12:59 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2021-05-17 23:12:59 (GMT) |
commit | 73a09734a145722a3bd6199750fad62b46dd9339 (patch) | |
tree | 9e7e6d7a78d27cb5d6d6048ab02cddf4983f6f45 /src | |
parent | a20cf5f374e64c6db50bf33545dc67804e90eabc (diff) |
Dead with singleton instances containing singleton instances.
Diffstat (limited to 'src')
-rw-r--r-- | src/glibext/singleton-int.h | 21 | ||||
-rw-r--r-- | src/glibext/singleton.c | 352 | ||||
-rw-r--r-- | src/glibext/singleton.h | 23 |
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; |