From ad7ad063caee99a800b54ca16ee34dd32147df66 Mon Sep 17 00:00:00 2001 From: ailin-nemui Date: Tue, 13 Aug 2019 15:29:55 +0200 Subject: [PATCH] implement reference counted strings - on glib >=2.58, use the implementation provided by glib - otherwise, a hash table will contain the strings --- src/core/Makefile.am | 2 + src/core/core.c | 3 + src/core/meson.build | 2 + src/core/refstrings.c | 94 +++++++++++++++++++++++++++++++ src/core/refstrings.h | 24 ++++++++ src/fe-text/textbuffer-commands.c | 8 +++ 6 files changed, 133 insertions(+) create mode 100644 src/core/refstrings.c create mode 100644 src/core/refstrings.h diff --git a/src/core/Makefile.am b/src/core/Makefile.am index c01b8f10..7cf172ef 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -41,6 +41,7 @@ libcore_a_SOURCES = \ queries.c \ rawlog.c \ recode.c \ + refstrings.c \ servers.c \ servers-reconnect.c \ servers-setup.c \ @@ -102,6 +103,7 @@ pkginc_core_HEADERS = \ queries.h \ rawlog.h \ recode.h \ + refstrings.h \ servers.h \ servers-reconnect.h \ servers-setup.h \ diff --git a/src/core/core.c b/src/core/core.c index 8562836a..878d9eb6 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -261,6 +262,7 @@ void core_init(void) nicklist_init(); chat_commands_init(); + i_refstr_init(); wcwidth_wrapper_init(); settings_add_str("misc", "ignore_signals", ""); @@ -286,6 +288,7 @@ void core_deinit(void) signal_remove("irssi init finished", (SIGNAL_FUNC) sig_irssi_init_finished); wcwidth_wrapper_deinit(); + i_refstr_deinit(); chat_commands_deinit(); nicklist_deinit(); diff --git a/src/core/meson.build b/src/core/meson.build index dd5a4d49..b22a16de 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -43,6 +43,7 @@ libcore_a = static_library('core', 'queries.c', 'rawlog.c', 'recode.c', + 'refstrings.c', 'servers-reconnect.c', 'servers-setup.c', 'servers.c', @@ -114,6 +115,7 @@ install_headers( 'queries.h', 'rawlog.h', 'recode.h', + 'refstrings.h', 'servers-reconnect.h', 'servers-setup.h', 'servers.h', diff --git a/src/core/refstrings.c b/src/core/refstrings.c new file mode 100644 index 00000000..4b675fa5 --- /dev/null +++ b/src/core/refstrings.c @@ -0,0 +1,94 @@ +#include + +#include + +#if GLIB_CHECK_VERSION(2, 58, 0) +/* nothing */ +#else + +GHashTable *i_refstr_table; + +void i_refstr_init(void) +{ + i_refstr_table = g_hash_table_new(g_str_hash, g_str_equal); +} + +char *i_refstr_intern(const char *str) +{ + char *ret; + gpointer rc_p, ret_p; + size_t rc; + + if (str == NULL) + return NULL; + + if (g_hash_table_lookup_extended(i_refstr_table, str, &ret_p, &rc_p)) { + rc = GPOINTER_TO_SIZE(rc_p); + ret = ret_p; + } else { + rc = 0; + ret = g_strdup(str); + } + + if (rc + 1 <= G_MAXSIZE) { + g_hash_table_insert(i_refstr_table, ret, GSIZE_TO_POINTER(rc + 1)); + return ret; + } else { + return g_strdup(str); + } +} + +void i_refstr_release(char *str) +{ + char *ret; + gpointer rc_p, ret_p; + size_t rc; + + if (str == NULL) + return; + + if (g_hash_table_lookup_extended(i_refstr_table, str, &ret_p, &rc_p)) { + rc = GPOINTER_TO_SIZE(rc_p); + ret = ret_p; + } else { + rc = 0; + ret = NULL; + } + + if (ret == str) { + if (rc > 1) { + g_hash_table_insert(i_refstr_table, ret, GSIZE_TO_POINTER(rc - 1)); + } else { + g_hash_table_remove(i_refstr_table, ret); + g_free(ret); + } + } else { + g_free(str); + } +} + +void i_refstr_deinit(void) +{ + g_hash_table_foreach(i_refstr_table, (GHFunc) g_free, NULL); + g_hash_table_destroy(i_refstr_table); +} + +char *i_refstr_table_size_info(void) +{ + GHashTableIter iter; + void *k_p, *v_p; + size_t count, mem; + count = 0; + mem = 0; + g_hash_table_iter_init(&iter, i_refstr_table); + while (g_hash_table_iter_next(&iter, &k_p, &v_p)) { + char *key = k_p; + count++; + mem += sizeof(char) * (strlen(key) + 1) + 2 * sizeof(void *); + } + + return g_strdup_printf("Shared strings: %ld, %dkB of data", count, + (int) (mem / 1024)); +} + +#endif diff --git a/src/core/refstrings.h b/src/core/refstrings.h new file mode 100644 index 00000000..79036a20 --- /dev/null +++ b/src/core/refstrings.h @@ -0,0 +1,24 @@ +#ifndef IRSSI_CORE_REFSTRINGS_H +#define IRSSI_CORE_REFSTRINGS_H + +#include + +#if GLIB_CHECK_VERSION(2, 58, 0) + +#define i_refstr_init() /* nothing */ +#define i_refstr_release(str) ((str) == NULL ? NULL : g_ref_string_release(str)) +#define i_refstr_intern(str) ((str) == NULL ? NULL : g_ref_string_new_intern(str)) +#define i_refstr_deinit() /* nothing */ +#define i_refstr_table_size_info() NULL + +#else + +void i_refstr_init(void); +char *i_refstr_intern(const char *str); +void i_refstr_release(char *str); +void i_refstr_deinit(void); +char *i_refstr_table_size_info(void); + +#endif + +#endif diff --git a/src/fe-text/textbuffer-commands.c b/src/fe-text/textbuffer-commands.c index 318ee077..11c0f123 100644 --- a/src/fe-text/textbuffer-commands.c +++ b/src/fe-text/textbuffer-commands.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -358,6 +359,13 @@ static void cmd_scrollback_status(void) printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "Total: %d lines, %dkB of data", total_lines, (int)(total_mem / 1024)); + { + char *tmp = i_refstr_table_size_info(); + if (tmp != NULL) + printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, + "%s", tmp); + g_free(tmp); + } } static void sig_away_changed(SERVER_REC *server)