From fa30b0fb42d2e229de9f760bfa842f25738efc18 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 22 Oct 2016 23:45:55 +0200
Subject: Made all segments share their content to save memory.

---
 ChangeLog                    |   9 +
 src/glibext/gbuffersegment.c | 413 +++++++++++++++++++++++++++++++++++--------
 src/glibext/gbuffersegment.h |  12 ++
 src/gui/core/core.c          |   7 +-
 4 files changed, 365 insertions(+), 76 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 78a5a8a..4be9aa4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,15 @@
 16-10-22  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/glibext/gbuffersegment.c:
+	* src/glibext/gbuffersegment.h:
+	Make all segments share their content to save memory.
+
+	* src/gui/core/core.c:
+	Setup and free the global hash table for segment contents.
+
+16-10-22  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/glibext/gbuffersegment.c:
 	Reduce the memory usage by cutting down the size of GBufferSegment from
 	152 bytes to 64 bytes.
 
diff --git a/src/glibext/gbuffersegment.c b/src/glibext/gbuffersegment.c
index 43c710c..a2947ae 100644
--- a/src/glibext/gbuffersegment.c
+++ b/src/glibext/gbuffersegment.c
@@ -24,6 +24,8 @@
 #include "gbuffersegment.h"
 
 
+#include <assert.h>
+#include <limits.h>
 #include <malloc.h>
 #include <stdbool.h>
 #include <stdlib.h>
@@ -37,7 +39,7 @@
 
 
 
-/* -------------------- NATURE DE BASE POUR UN FRAGMENT DE TEXTE -------------------- */
+/* ----------------------- ISOLATION DE CONTENUS PARTAGEABLES ----------------------- */
 
 
 /* Propriétés de rendu */
@@ -59,6 +61,40 @@ typedef struct _rendering_pattern_t
 
 } rendering_pattern_t;
 
+/* Contenu brut pour segment, potentiellement commun */
+typedef struct _seg_content
+{
+    unsigned int ref_count;                 /* Compteur de références      */
+
+    rendering_pattern_t *pattern;           /* Propriétés du rendu         */
+
+    fnv64_t hash;                           /* Empreinte pour comparaisons */
+    char text[0];                           /* Texte brut conservé         */
+
+} seg_content;
+
+
+/* Conservation de toutes les créations partagées */
+static GHashTable *_segcnt_htable;
+
+
+/* Fournit l'empreinte d'un contenu pour segments. */
+static guint get_seg_content_hash(const seg_content *);
+
+/* Détermine si deux contenus pour segments sont identiques. */
+static bool is_seg_content_equal(const seg_content *, const seg_content *);
+
+/* Détermine si deux contenus pour segments sont identiques. */
+static seg_content *get_shared_content(const seg_content *);
+
+/* Abandonne un contenu pour segments. */
+static void release_shared_content(seg_content *);
+
+
+
+/* -------------------- NATURE DE BASE POUR UN FRAGMENT DE TEXTE -------------------- */
+
+
 /* Nom des éléments CSS */
 
 #define SEGMENT_NAME(s) "segment-" s
@@ -103,14 +139,9 @@ struct _GBufferSegment
 {
     GObject parent;                         /* A laisser en premier        */
 
-    GObject *creator;                       /* Objet à l'origine du segment*/
-
-    char *text;                             /* Texte brut conservé         */
-    fnv64_t hash;                           /* Empreinte pour comparaisons */
-
-    rendering_pattern_t *pattern;           /* Propriétés du rendu         */
+    seg_content *content;                   /* Contenu, partagé ou non     */
 
-    gint x_advance;                         /* Dimensions du texte         */
+    GObject *creator;                       /* Objet à l'origine du segment*/
 
 };
 
@@ -144,9 +175,8 @@ static void g_buffer_segment_dispose(GBufferSegment *);
 /* Procède à la libération totale de la mémoire. */
 static void g_buffer_segment_finalize(GBufferSegment *);
 
-/* Définit les dernières propriétés de rendu restantes. */
-static void g_buffer_segment_prepare(GBufferSegment *, size_t);
-
+/* Met à jour le contenu d'un fragment de texte. */
+void g_buffer_segment_set_text(GBufferSegment *, rendering_pattern_t *, const char *, size_t);
 
 
 
@@ -164,6 +194,201 @@ struct _segcnt_list
 
 
 /* ---------------------------------------------------------------------------------- */
+/*                         ISOLATION DE CONTENUS PARTAGEABLES                         */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Initialise la table mémorisant les contenus pour segments.   *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool init_segment_content_hash_table(void)
+{
+    _segcnt_htable = g_hash_table_new_full((GHashFunc)get_seg_content_hash,
+                                           (GEqualFunc)is_seg_content_equal,
+                                           free, NULL);
+
+    return (_segcnt_htable != NULL);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Organise la sortie de la table des contenus pour segments.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void exit_segment_content_hash_table(void)
+{
+    assert(g_hash_table_size(_segcnt_htable) == 0);
+
+    g_hash_table_unref(_segcnt_htable);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = contenu pour segment à consulter.                  *
+*                                                                             *
+*  Description : Fournit l'empreinte d'un contenu pour segments.              *
+*                                                                             *
+*  Retour      : Empreinte de lu contenu représenté.                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static guint get_seg_content_hash(const seg_content *content)
+{
+    return content->hash;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = premier contenu pour segment à analyser.           *
+*                other   = second contenu pour segment à analyser.            *
+*                                                                             *
+*  Description : Détermine si deux contenus pour segments sont identiques.    *
+*                                                                             *
+*  Retour      : Bilan de la comparaison.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool is_seg_content_equal(const seg_content *content, const seg_content *other)
+{
+    bool result;                            /* Résultat à retourner        */
+
+    result = (content->pattern == other->pattern);
+
+    result &= (cmp_fnv_64a(content->hash, other->hash) == 0);
+
+    result &= (strcmp(content->text, other->text) == 0);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = premier contenu pour segment à analyser.           *
+*                other   = second contenu pour segment à analyser.            *
+*                                                                             *
+*  Description : Détermine si deux contenus pour segments sont identiques.    *
+*                                                                             *
+*  Retour      : Bilan de la comparaison.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static seg_content *get_shared_content(const seg_content *content)
+{
+    seg_content *result;                    /* Contenu partagé à renvoyer  */
+    gboolean found;                         /* Le contenu existe déjà ?    */
+    size_t allocated;                       /* Besoin complet en mémoire   */
+#ifndef NDEBUG
+    gboolean created;                       /* Validation de mise en place */
+#endif
+
+    /**
+     * On considère qu'il n'y a pas besoin de mutex ici, puisque toutes les
+     * opérations se réalisent à priori dans le seul thread principal pour l'affichage.
+     */
+
+    found = g_hash_table_lookup_extended(_segcnt_htable, content, (gpointer *)&result, NULL);
+
+    if (!found)
+    {
+        allocated = sizeof(seg_content) + strlen(content->text) + 1;
+
+        result = (seg_content *)malloc(allocated);
+
+        memcpy(result, content, allocated);
+
+        result->ref_count = 1;
+
+#ifndef NDEBUG
+        created = g_hash_table_insert(_segcnt_htable, result, result);
+        assert(created);
+#else
+        g_hash_table_insert(_segcnt_htable, result, result);
+#endif
+
+    }
+
+    else
+    {
+        assert(result->ref_count < UINT_MAX);
+
+        result->ref_count++;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : content = contenu pour segments à délaisser.                 *
+*                                                                             *
+*  Description : Abandonne un contenu pour segments.                          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void release_shared_content(seg_content *content)
+{
+#ifndef NDEBUG
+    gboolean deleted;                       /* Validation de suppression   */
+#endif
+
+    /**
+     * On considère qu'il n'y a pas besoin de mutex ici, puisque toutes les
+     * opérations se réalisent à priori dans le seul thread principal pour l'affichage.
+     */
+
+    if (--content->ref_count == 0)
+    {
+#ifndef NDEBUG
+        deleted = g_hash_table_remove(_segcnt_htable, content);
+        assert(deleted);
+#else
+        g_hash_table_remove(_segcnt_htable, content);
+#endif
+    }
+
+}
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
 /*                      NATURE DE BASE POUR UN FRAGMENT DE TEXTE                      */
 /* ---------------------------------------------------------------------------------- */
 
@@ -361,6 +586,8 @@ static void g_buffer_segment_init(GBufferSegment *segment)
 
 static void g_buffer_segment_dispose(GBufferSegment *segment)
 {
+    release_shared_content(segment->content);
+
     if (segment->creator != NULL)
         g_object_unref(segment->creator);
 
@@ -409,13 +636,9 @@ GBufferSegment *g_buffer_segment_new(RenderingTagType type, const char *text, si
 
     result = g_object_new(G_TYPE_BUFFER_SEGMENT, NULL);
 
-    result->text = strndup(text, length);
-    result->hash = fnv_64a_hash(result->text);
-
     class = G_BUFFER_SEGMENT_GET_CLASS(result);
-    result->pattern = &class->patterns[type];
 
-    g_buffer_segment_prepare(result, length);
+    g_buffer_segment_set_text(result, &class->patterns[type], text, length);
 
     return result;
 
@@ -424,10 +647,10 @@ GBufferSegment *g_buffer_segment_new(RenderingTagType type, const char *text, si
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : segment = instance de segment à affiner.                     *
-*                text    = chaîne de caractères à traiter.                    *
+*  Paramètres  : segment = instance de segment à compléter.                   *
+*                obj     = instance GLib quelconque à mémoriser.              *
 *                                                                             *
-*  Description : Définit les dernières propriétés de rendu restantes.         *
+*  Description : Associe à un segment un objet GLib identifié comme créateur. *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -435,20 +658,13 @@ GBufferSegment *g_buffer_segment_new(RenderingTagType type, const char *text, si
 *                                                                             *
 ******************************************************************************/
 
-static void g_buffer_segment_prepare(GBufferSegment *segment, size_t length)
+void g_buffer_segment_set_creator(GBufferSegment *segment, GObject *obj)
 {
-    GBufferSegmentClass *class;             /* Classe associée à l'instance*/
-    cairo_font_slant_t slant;               /* Style d'impression          */
-    cairo_font_weight_t weight;             /* Poids de la police          */
-
-    /* Taille */
-
-    class = G_BUFFER_SEGMENT_GET_CLASS(segment);
-
-    slant = segment->pattern->slant;
-    weight = segment->pattern->weight;
+    if (segment->creator != NULL)
+        g_object_unref(segment->creator);
 
-    segment->x_advance = class->x_advances[CAIRO_FONT_INDEX(slant, weight)] * length;
+    segment->creator = obj;
+    g_object_ref(obj);
 
 }
 
@@ -456,45 +672,61 @@ static void g_buffer_segment_prepare(GBufferSegment *segment, size_t length)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : segment = instance de segment à compléter.                   *
-*                obj     = instance GLib quelconque à mémoriser.              *
 *                                                                             *
-*  Description : Associe à un segment un objet GLib identifié comme créateur. *
+*  Description : Renvoie vers un éventuel objet lié en tant que créateur.     *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Instance GLib quelconque ou NULL si aucune référencée.       *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_segment_set_creator(GBufferSegment *segment, GObject *obj)
+GObject *g_buffer_segment_get_creator(const GBufferSegment *segment)
 {
     if (segment->creator != NULL)
-        g_object_unref(segment->creator);
+        g_object_ref(segment->creator);
 
-    segment->creator = obj;
-    g_object_ref(obj);
+    return segment->creator;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : segment = instance de segment à compléter.                   *
+*  Paramètres  : segment = fragment de texte à mettre à jour.                 *
+*                pattern = paramètres d'impression du texte.                  *
+*                text    = chaîne de caractères à traiter.                    *
+*                length  = quantité de ces caractères.                        *
 *                                                                             *
-*  Description : Renvoie vers un éventuel objet lié en tant que créateur.     *
+*  Description : Met à jour le contenu d'un fragment de texte.                *
 *                                                                             *
-*  Retour      : Instance GLib quelconque ou NULL si aucune référencée.       *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GObject *g_buffer_segment_get_creator(const GBufferSegment *segment)
+void g_buffer_segment_set_text(GBufferSegment *segment, rendering_pattern_t *pattern, const char *text, size_t length)
 {
-    if (segment->creator != NULL)
-        g_object_ref(segment->creator);
+    char atmp[sizeof(seg_content) + 128];   /* Allocation static facile    */
+    seg_content *content;                   /* Contenu à mettre en place ? */
 
-    return segment->creator;
+    if (length < (sizeof(atmp) - sizeof(seg_content)))
+        content = (seg_content *)atmp;
+    else
+        content = (seg_content *)malloc(sizeof(seg_content) + length + 1);
+
+    content->pattern = pattern;
+
+    content->hash = fnv_64a_hash(text);
+
+    memcpy(content->text, text, length);
+    content->text[length] = '\0';
+
+    segment->content = get_shared_content(content);
+
+    if (content != (seg_content *)atmp)
+        free(content);
 
 }
 
@@ -515,12 +747,17 @@ GObject *g_buffer_segment_get_creator(const GBufferSegment *segment)
 
 void g_buffer_segment_update_text(GBufferSegment *segment, const char *text, size_t length)
 {
-    free(segment->text);
+    rendering_pattern_t *pattern;           /* Conservation des paramètres */
+
+    /* Destruction */
+
+    pattern = segment->content->pattern;
+
+    release_shared_content(segment->content);
 
-    segment->text = strndup(text, length);
-    segment->hash = fnv_64a_hash(segment->text);
+    /* Création */
 
-    g_buffer_segment_prepare(segment, length);
+    g_buffer_segment_set_text(segment, pattern, text, length);
 
     g_signal_emit_by_name(segment, "content-changed");
 
@@ -544,9 +781,7 @@ bool g_buffer_segment_compare(const GBufferSegment *segment, const GBufferSegmen
 {
     bool result;                            /* Bilan à retourner           */
 
-    result = (cmp_fnv_64a(segment->hash, ref->hash) == 0);
-
-    result &= (strcmp(segment->text, ref->text) == 0);
+    result = is_seg_content_equal(segment->content, ref->content);
 
     return result;
 
@@ -569,12 +804,15 @@ bool g_buffer_segment_compare(const GBufferSegment *segment, const GBufferSegmen
 char *g_buffer_segment_get_text(const GBufferSegment *segment, bool markup)
 {
     char *result;                           /* Description à renvoyer      */
+    const seg_content *content;             /* Accès au contenu            */
     char color[7];                          /* Couleur hexadécimale        */
     char *valid;
 
+    content = segment->content;
+
     /* Résolution du cas simple */
     if (!markup)
-        return strdup(segment->text);
+        return strdup(content->text);
 
     result = strdup("<span ");
 
@@ -583,9 +821,9 @@ char *g_buffer_segment_get_text(const GBufferSegment *segment, bool markup)
     result = stradd(result, "foreground=\"#");
 
     snprintf(color, sizeof(color), "%02hhx%02hhx%02hhx",
-             (unsigned char)(segment->pattern->foreground.color.red * 255),
-             (unsigned char)(segment->pattern->foreground.color.green * 255),
-             (unsigned char)(segment->pattern->foreground.color.blue * 255));
+             (unsigned char)(content->pattern->foreground.color.red * 255),
+             (unsigned char)(content->pattern->foreground.color.green * 255),
+             (unsigned char)(content->pattern->foreground.color.blue * 255));
 
     result = stradd(result, color);
 
@@ -595,7 +833,7 @@ char *g_buffer_segment_get_text(const GBufferSegment *segment, bool markup)
 
     result = stradd(result, "style=\"");
 
-    switch (segment->pattern->slant)
+    switch (content->pattern->slant)
     {
         case CAIRO_FONT_SLANT_NORMAL:
             result = stradd(result, "normal");
@@ -617,7 +855,7 @@ char *g_buffer_segment_get_text(const GBufferSegment *segment, bool markup)
 
     result = stradd(result, "weight=\"");
 
-    switch (segment->pattern->weight)
+    switch (content->pattern->weight)
     {
         case CAIRO_FONT_WEIGHT_NORMAL:
             result = stradd(result, "normal");
@@ -635,7 +873,7 @@ char *g_buffer_segment_get_text(const GBufferSegment *segment, bool markup)
 
     result = stradd(result, ">");
 
-    valid = strdup(segment->text);
+    valid = strdup(content->text);
     valid = strrpl(valid, "<", "&lt;");
     valid = strrpl(valid, "&", "&amp;");
 
@@ -664,7 +902,22 @@ char *g_buffer_segment_get_text(const GBufferSegment *segment, bool markup)
 
 gint g_buffer_segment_get_width(const GBufferSegment *segment)
 {
-    return segment->x_advance;
+    gint result;                            /* Largeur à retourner         */
+    GBufferSegmentClass *class;             /* Classe associée à l'instance*/
+    const seg_content *content;             /* Accès au contenu            */
+    cairo_font_slant_t slant;               /* Style d'impression          */
+    cairo_font_weight_t weight;             /* Poids de la police          */
+
+    class = G_BUFFER_SEGMENT_GET_CLASS(segment);
+
+    content = segment->content;
+
+    slant = content->pattern->slant;
+    weight = content->pattern->weight;
+
+    result = class->x_advances[CAIRO_FONT_INDEX(slant, weight)] * strlen(content->text);
+
+    return result;
 
 }
 
@@ -698,7 +951,7 @@ gint g_buffer_segment_get_caret_position(const GBufferSegment *segment, gint x)
 
     else
     {
-        char_width = width / strlen(segment->text);
+        char_width = width / strlen(segment->content->text);
 
         result = (x / char_width) * char_width;
         if ((x % char_width) > (char_width / 2))
@@ -735,7 +988,7 @@ bool g_buffer_segment_move_caret(const GBufferSegment *segment, gint *x, bool ct
     result = false;
 
     width = g_buffer_segment_get_width(segment);
-    char_width = width / strlen(segment->text);
+    char_width = width / strlen(segment->content->text);
 
     if (dir == GDK_SCROLL_LEFT)
     {
@@ -794,12 +1047,16 @@ bool g_buffer_segment_move_caret(const GBufferSegment *segment, gint *x, bool ct
 void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cr, gint *x, gint y, const segcnt_list *list)
 {
     bool selected;                          /* Marquer une sélection ?     */
+    gint width;                             /* Largeur du segment          */
     GBufferSegmentClass *class;             /* Accès aux infos globales    */
-    const rendering_color_t *used_fg;       /* Couleur d'impression utile  */
     cairo_operator_t old;                   /* Sauvegarde avant changement */
+    const seg_content *content;             /* Accès au contenu            */
+    const rendering_color_t *used_fg;       /* Couleur d'impression utile  */
 
     selected = selection_list_has_segment_content(list, segment);
 
+    width = g_buffer_segment_get_width(segment);
+
     /* Fond du texte */
     if (selected)
     {
@@ -811,7 +1068,7 @@ void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cr, gint *x, gint y
                               class->selection_bg.color.blue,
                               class->selection_bg.color.alpha);
 
-        cairo_rectangle(cr, *x, y, segment->x_advance, 17);
+        cairo_rectangle(cr, *x, y, width, 17);
 
         old = cairo_get_operator(cr);
         cairo_set_operator(cr, CAIRO_OPERATOR_DIFFERENCE);
@@ -822,10 +1079,12 @@ void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cr, gint *x, gint y
 
     /* Couleur d'impression */
 
+    content = segment->content;
+
     if (selected)
-        used_fg = &segment->pattern->inverted;
+        used_fg = &content->pattern->inverted;
     else
-        used_fg = &segment->pattern->foreground;
+        used_fg = &content->pattern->foreground;
 
     if (used_fg->has_color)
         cairo_set_source_rgba(cr,
@@ -838,14 +1097,14 @@ void g_buffer_segment_draw(GBufferSegment *segment, cairo_t *cr, gint *x, gint y
 
     /* Impression du texte */
 
-    cairo_select_font_face(cr, "mono", segment->pattern->slant, segment->pattern->weight);
+    cairo_select_font_face(cr, "mono", content->pattern->slant, content->pattern->weight);
     cairo_set_font_size(cr, 13);
 
     cairo_move_to(cr, *x, y + 17 - 3);  /* 3 = font extents.descent */
 
-    cairo_show_text(cr, segment->text);
+    cairo_show_text(cr, content->text);
 
-    *x += segment->x_advance;
+    *x += width;
 
 }
 
@@ -944,21 +1203,24 @@ void g_buffer_segment_export_style(buffer_export_context *ctx, BufferExportType
 
 void g_buffer_segment_export(const GBufferSegment *segment, buffer_export_context *ctx, BufferExportType type)
 {
+    const seg_content *content;             /* Accès au contenu            */
     GBufferSegmentClass *class;             /* Classe des segments         */
     size_t index;                           /* Indice du modèle de rendu   */
 
+    content = segment->content;
+
     switch (type)
     {
         case BET_HTML:
             class = G_BUFFER_SEGMENT_GET_CLASS(segment);
-            index = (segment->pattern - class->patterns);
+            index = (content->pattern - class->patterns);
             dprintf(ctx->fd, "<SPAN class=\"%s\">", _segment_names[index]);
             break;
         default:
             break;
     }
 
-    dprintf(ctx->fd, "%s", segment->text);
+    dprintf(ctx->fd, "%s", content->text);
 
     switch (type)
     {
@@ -1069,20 +1331,23 @@ bool reset_segment_content_list(segcnt_list *list)
 bool add_segment_content_to_selection_list(segcnt_list *list, const GBufferSegment *segment)
 {
     bool result;                            /* Bilan à retourner           */
+    const seg_content *content;             /* Accès au contenu            */
     size_t i;                               /* Boucle de parcours          */
 
     static const char white_list[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
     result = false;
 
+    content = segment->content;
+
     for (i = 0; i < (sizeof(white_list) - 1) && !result; i++)
-        result = (strchr(segment->text, white_list[i]) != NULL);
+        result = (strchr(content->text, white_list[i]) != NULL);
 
     if (result)
     {
         list->hashes = (fnv64_t *)realloc(list->hashes, ++list->count * sizeof(fnv64_t));
 
-        list->hashes[list->count - 1] = segment->hash;
+        list->hashes[list->count - 1] = content->hash;
 
     }
 
@@ -1112,7 +1377,7 @@ bool selection_list_has_segment_content(const segcnt_list *list, const GBufferSe
     result = false;
 
     for (i = 0; i < list->count && !result; i++)
-        result = (cmp_fnv_64a(list->hashes[i], segment->hash) == 0);
+        result = (cmp_fnv_64a(list->hashes[i], segment->content->hash) == 0);
 
     return result;
 
diff --git a/src/glibext/gbuffersegment.h b/src/glibext/gbuffersegment.h
index 57e3575..911df7b 100644
--- a/src/glibext/gbuffersegment.h
+++ b/src/glibext/gbuffersegment.h
@@ -36,6 +36,18 @@
 typedef struct _segcnt_list segcnt_list;
 
 
+
+/* ----------------------- ISOLATION DE CONTENUS PARTAGEABLES ----------------------- */
+
+
+/* Initialise la table mémorisant les contenus pour segments. */
+bool init_segment_content_hash_table(void);
+
+/* Organise la sortie de la table des contenus pour segments. */
+void exit_segment_content_hash_table(void);
+
+
+
 /* -------------------- NATURE DE BASE POUR UN FRAGMENT DE TEXTE -------------------- */
 
 
diff --git a/src/gui/core/core.c b/src/gui/core/core.c
index 16e5cc8..dbff1b8 100644
--- a/src/gui/core/core.c
+++ b/src/gui/core/core.c
@@ -28,6 +28,7 @@
 
 
 #include "../../core/params.h"
+#include "../../glibext/gbuffersegment.h"
 
 
 
@@ -47,9 +48,10 @@ bool load_all_gui_components(GObject *ref)
 {
     bool result;                            /* Bilan à retourner           */
 
-    result = true;
+    result = init_segment_content_hash_table();
 
-    load_main_panels(ref);
+    if (result)
+        load_main_panels(ref);
 
     return result;
 
@@ -93,5 +95,6 @@ bool complete_loading_of_all_gui_components(GGenConfig *config)
 
 void unload_all_gui_components(void)
 {
+    exit_segment_content_hash_table();
 
 }
-- 
cgit v0.11.2-87-g4458