diff options
Diffstat (limited to 'src/glibext/singleton.c')
-rw-r--r-- | src/glibext/singleton.c | 179 |
1 files changed, 92 insertions, 87 deletions
diff --git a/src/glibext/singleton.c b/src/glibext/singleton.c index 65b83e7..4930323 100644 --- a/src/glibext/singleton.c +++ b/src/glibext/singleton.c @@ -26,9 +26,10 @@ #include <assert.h> #include <malloc.h> -#include <stdbool.h> +#include "comparable.h" +#include "hashable.h" #include "singleton-int.h" @@ -39,11 +40,14 @@ /* Procède à l'initialisation de l'interface de rassemblement. */ static void g_singleton_candidate_default_init(GSingletonCandidateInterface *); +/* Fournit une liste de candidats embarqués par un candidat. */ +static GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingletonCandidate *, size_t *); + /* Met à jour une liste de candidats embarqués par un candidat. */ static void g_singleton_candidate_update_inner_instances(GSingletonCandidate *, GSingletonCandidate **, size_t); -/* 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_mark_as_read_only(GSingletonCandidate *); @@ -70,7 +74,9 @@ static void g_singleton_factory_finalize(GSingletonFactory *); /* Détermine le type d'une interface pour la constitution d'objets uniques. */ -G_DEFINE_INTERFACE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT) +G_DEFINE_INTERFACE_WITH_CODE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT, + g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_HASHABLE_OBJECT); + g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_COMPARABLE_OBJECT)) /****************************************************************************** @@ -87,6 +93,13 @@ G_DEFINE_INTERFACE(GSingletonCandidate, g_singleton_candidate, G_TYPE_OBJECT) static void g_singleton_candidate_default_init(GSingletonCandidateInterface *iface) { + iface->list_inner = NULL; + iface->update_inner = NULL; + + iface->mark_as_ro = NULL; + iface->is_ro = NULL; + + iface->dup = NULL; } @@ -113,8 +126,11 @@ GSingletonCandidate **g_singleton_candidate_list_inner_instances(const GSingleto if (iface->list_inner == NULL) { + assert(iface->update_inner == NULL); + *count = 0; result = NULL; + } else @@ -161,17 +177,16 @@ static void g_singleton_candidate_update_inner_instances(GSingletonCandidate *ca * * * Paramètres : candidate = objet dont l'instance se veut unique. * * * -* Description : Fournit l'empreinte d'un candidat à une centralisation. * +* Description : Marque un candidat comme figé. * * * -* Retour : Empreinte de l'élément représenté. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -guint g_singleton_candidate_hash(GSingletonCandidate *candidate) +static void g_singleton_candidate_mark_as_read_only(GSingletonCandidate *candidate) { - guint result; /* Valeur à retourner */ GSingletonCandidateInterface *iface; /* Interface utilisée */ GSingletonCandidate **children; /* Instances internes */ size_t count; /* Quantité de ces instances */ @@ -179,103 +194,62 @@ guint g_singleton_candidate_hash(GSingletonCandidate *candidate) iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); - result = iface->hash(candidate); + iface->mark_as_ro(candidate); children = g_singleton_candidate_list_inner_instances(candidate, &count); for (i = 0; i < count; i++) { - result ^= g_singleton_candidate_hash(children[i]); - unref_object(children[i]); + g_singleton_candidate_mark_as_read_only(children[i]); + unref_object(G_OBJECT(children[i])); } if (children != NULL) free(children); - return result; - } /****************************************************************************** * * * 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. * +* Description : Indique si le candidat est figé. * * * -* Retour : Bilan de la comparaison. * +* Retour : true si le contenu du candidat ne peut plus être modifié. * * * * Remarques : - * * * ******************************************************************************/ -static gboolean _g_singleton_candidate_is_equal(GSingletonCandidate *candidate, GSingletonCandidate *other, GList **processed) +bool g_singleton_candidate_is_read_only(const GSingletonCandidate *candidate) { - gboolean result; /* Bilan à renvoyer */ - GList *skip; /* Détection de boucle */ + bool result; /* Etat à retourner */ GSingletonCandidateInterface *iface; /* Interface utilisée */ - GSingletonCandidate **children[2]; /* Instances internes */ - size_t count[2]; /* Quantité de ces instances */ +#ifndef NDEBUG + GSingletonCandidate **children; /* Instances internes */ + size_t count; /* Quantité de ces instances */ size_t i; /* Boucle de parcours */ +#endif - 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])); - - 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])); - } + iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); - if (children[0] != NULL) - free(children[0]); + result = iface->is_ro(candidate); - if (children[1] != NULL) - free(children[1]); +#ifndef NDEBUG - } + children = g_singleton_candidate_list_inner_instances(candidate, &count); + for (i = 0; i < count; i++) + { + assert(result == g_singleton_candidate_is_read_only(children[i])); + unref_object(G_OBJECT(children[i])); } - done: + if (children != NULL) + free(children); + +#endif return result; @@ -285,31 +259,60 @@ static gboolean _g_singleton_candidate_is_equal(GSingletonCandidate *candidate, /****************************************************************************** * * * 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. * +* Description : Crée une copie modifiable d'un object unique. * * * -* Retour : Bilan de la comparaison. * +* Retour : Nouvelle instance mise en place. * * * * Remarques : - * * * ******************************************************************************/ -gboolean g_singleton_candidate_is_equal(GSingletonCandidate *candidate, GSingletonCandidate *other) +GSingletonCandidate *g_singleton_candidate_dup(const GSingletonCandidate *candidate) { - gboolean result; /* Bilan à renvoyer */ - GList *processed[2]; /* Suivi des traitements */ + GSingletonCandidate *result; /* Instance à retourner */ + GSingletonCandidateInterface *iface; /* Interface utilisée */ + size_t count; /* Quantité d'objets internes */ + GSingletonCandidate **children; /* Liste d'instances internes */ + size_t i; /* Boucle de parcours */ + GSingletonCandidate **new_children; /* Nouvelle liste d'instances */ + + iface = G_SINGLETON_CANDIDATE_GET_IFACE(candidate); + + result = iface->dup(candidate); + + assert(!g_singleton_candidate_is_read_only(result)); + + children = g_singleton_candidate_list_inner_instances(candidate, &count); + + if (count > 0) + { + new_children = malloc(count * sizeof(GSingletonCandidate *)); + + for (i = 0; i < count; i++) + { + new_children[i] = g_singleton_candidate_dup(children[i]); + + assert(!g_singleton_candidate_is_read_only(new_children[i])); + + } + + g_singleton_candidate_update_inner_instances(result, new_children, count); - processed[0] = NULL; - processed[1] = NULL; + for (i = 0; i < count; i++) + { + unref_object(G_OBJECT(new_children[i])); + unref_object(G_OBJECT(children[i])); + } + + free(new_children); - result = _g_singleton_candidate_is_equal(candidate, other, processed); + } - assert(processed[0] != NULL); - assert(processed[1] != NULL); + if (children != NULL) + free(children); - g_list_free(processed[0]); - g_list_free(processed[1]); + assert(G_OBJECT_TYPE(result) == G_OBJECT_TYPE(candidate)); return result; @@ -364,8 +367,8 @@ static void g_singleton_factory_class_init(GSingletonFactoryClass *klass) static void g_singleton_factory_init(GSingletonFactory *factory) { - factory->table = g_hash_table_new_full((GHashFunc)g_singleton_candidate_hash, - (GEqualFunc)g_singleton_candidate_is_equal, + factory->table = g_hash_table_new_full((GHashFunc)g_hashable_object_hash, + (GEqualFunc)g_comparable_object_is_equal, g_object_unref, NULL); g_mutex_init(&factory->access); @@ -524,6 +527,8 @@ GSingletonCandidate *g_singleton_factory_get_instance(GSingletonFactory *factory g_hash_table_add(factory->table, candidate); #endif + g_singleton_candidate_mark_as_read_only(candidate); + result = candidate; } |