stringtable.c (3791B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 #include <glib.h> 21 #include <string.h> 22 23 #include "stringtable.h" 24 #include "utils.h" 25 26 /* alfons - hashed string table (I wasn't content with GStringChunk; 27 * can't recall why :-) */ 28 29 #if 0 30 #define XXX_DEBUG \ 31 debug_print 32 #else 33 #define XXX_DEBUG \ 34 if (0) debug_print 35 #endif 36 37 typedef struct StringEntry_ { 38 gint ref_count; 39 gchar *string; 40 } StringEntry; 41 42 static StringEntry *string_entry_new(const gchar *str) 43 { 44 StringEntry *entry; 45 46 entry = g_new0(StringEntry, 1); 47 entry->ref_count = 1; 48 entry->string = g_strdup(str); 49 return entry; 50 } 51 52 static void string_entry_free(StringEntry *entry) 53 { 54 cm_return_if_fail(entry != NULL); 55 56 g_free(entry->string); 57 g_free(entry); 58 } 59 60 StringTable *string_table_new(void) 61 { 62 StringTable *strtable; 63 64 strtable = g_new0(StringTable, 1); 65 cm_return_val_if_fail(strtable != NULL, NULL); 66 strtable->hash_table = g_hash_table_new(g_str_hash, g_str_equal); 67 if (strtable->hash_table == NULL) { 68 g_free(strtable); 69 return NULL; 70 } 71 return strtable; 72 } 73 74 gchar *string_table_insert_string(StringTable *table, const gchar *str) 75 { 76 StringEntry *entry; 77 78 entry = g_hash_table_lookup(table->hash_table, str); 79 80 if (entry) { 81 entry->ref_count++; 82 XXX_DEBUG ("ref++ for %s (%d)\n", entry->string, 83 entry->ref_count); 84 } else { 85 entry = string_entry_new(str); 86 XXX_DEBUG ("inserting %s\n", str); 87 /* insert entry->string instead of str, since it can be 88 * invalid pointer after this. */ 89 g_hash_table_insert(table->hash_table, entry->string, entry); 90 } 91 92 return entry->string; 93 } 94 95 void string_table_free_string(StringTable *table, const gchar *str) 96 { 97 StringEntry *entry; 98 99 entry = g_hash_table_lookup(table->hash_table, str); 100 101 if (entry) { 102 entry->ref_count--; 103 if (entry->ref_count <= 0) { 104 XXX_DEBUG ("refcount of string %s dropped to zero\n", 105 entry->string); 106 g_hash_table_remove(table->hash_table, str); 107 string_entry_free(entry); 108 } else { 109 XXX_DEBUG ("ref-- for %s (%d)\n", entry->string, 110 entry->ref_count); 111 } 112 } 113 } 114 115 static gboolean string_table_remove_for_each_fn(gchar *key, StringEntry *entry, 116 gpointer user_data) 117 { 118 cm_return_val_if_fail(key != NULL, TRUE); 119 cm_return_val_if_fail(entry != NULL, TRUE); 120 121 string_entry_free(entry); 122 123 return TRUE; 124 } 125 126 void string_table_free(StringTable *table) 127 { 128 cm_return_if_fail(table != NULL); 129 cm_return_if_fail(table->hash_table != NULL); 130 131 g_hash_table_foreach_remove(table->hash_table, 132 (GHRFunc)string_table_remove_for_each_fn, 133 NULL); 134 g_hash_table_destroy(table->hash_table); 135 g_free(table); 136 } 137 138 static void string_table_stats_for_each_fn(gchar *key, StringEntry *entry, 139 guint *totals) 140 { 141 if (entry->ref_count > 1) { 142 *totals += strlen(key) * (entry->ref_count - 1); 143 } 144 } 145 146 void string_table_get_stats(StringTable *table) 147 { 148 guint totals = 0; 149 150 g_hash_table_foreach(table->hash_table, 151 (GHFunc)string_table_stats_for_each_fn, &totals); 152 XXX_DEBUG ("TOTAL UNSPILLED %d (%dK)\n", totals, totals / 1024); 153 }