From 83dc126565144c26f85de468c57f37a943d4659b Mon Sep 17 00:00:00 2001 From: Garrett Regier Date: Tue, 21 Sep 2021 13:57:08 -0700 Subject: [PATCH] builder: Use a string chunk for precompile Also use an explicit length and avoid g_strndup(). --- gtk/gtkbuilderprecompile.c | 116 +++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 44 deletions(-) diff --git a/gtk/gtkbuilderprecompile.c b/gtk/gtkbuilderprecompile.c index d488094be5..ac00cd19af 100644 --- a/gtk/gtkbuilderprecompile.c +++ b/gtk/gtkbuilderprecompile.c @@ -27,20 +27,21 @@ typedef enum { - RECORD_TYPE_ELEMENT, - RECORD_TYPE_END_ELEMENT, - RECORD_TYPE_TEXT, + RECORD_TYPE_ELEMENT, + RECORD_TYPE_END_ELEMENT, + RECORD_TYPE_TEXT, } RecordTreeType; +/* All strings are owned by the string chunk */ typedef struct { - char *string; + const char *string; + int len; int count; int offset; } RecordDataString; typedef struct RecordDataTree RecordDataTree; -/* All strings are owned by the string table */ struct RecordDataTree { RecordDataTree *parent; RecordTreeType type; @@ -51,6 +52,13 @@ struct RecordDataTree { GList *children; }; +typedef struct { + GHashTable *strings; + GStringChunk *chunks; + RecordDataTree *root; + RecordDataTree *current; +} RecordData; + static RecordDataTree * record_data_tree_new (RecordDataTree *parent, RecordTreeType type, @@ -80,47 +88,74 @@ record_data_tree_free (RecordDataTree *tree) static void record_data_string_free (RecordDataString *s) { - g_free (s->string); g_slice_free (RecordDataString, s); } +static gboolean +record_data_string_equal (gconstpointer _a, + gconstpointer _b) +{ + const RecordDataString *a = _a; + const RecordDataString *b = _b; + + return a->len == b->len && + memcmp (a->string, b->string, a->len) == 0; +} + +/* Copied from g_bytes_hash() */ +static guint +record_data_string_hash (gconstpointer _a) +{ + const RecordDataString *a = _a; + const signed char *p, *e; + guint32 h = 5381; + + for (p = (signed char *)a->string, e = (signed char *)a->string + a->len; p != e; p++) + h = (h << 5) + h + *p; + + return h; +} + +static int +record_data_string_compare (gconstpointer _a, + gconstpointer _b) +{ + const RecordDataString *a = _a; + const RecordDataString *b = _b; + + return b->count - a->count; +} + static RecordDataString * -record_data_string_lookup (GHashTable *strings, +record_data_string_lookup (RecordData *data, const char *str, gssize len) { - char *copy = NULL; - RecordDataString *s; + RecordDataString *s, tmp; - if (len >= 0) - { - /* Ensure str is zero terminated */ - copy = g_strndup (str, len); - str = copy; - } + if (len < 0) + len = strlen (str); - s = g_hash_table_lookup (strings, str); + tmp.string = str; + tmp.len = len; + + s = g_hash_table_lookup (data->strings, &tmp); if (s) { - g_free (copy); s->count++; return s; } s = g_slice_new (RecordDataString); - s->string = copy ? copy : g_strdup (str); + /* The string is zero terminated */ + s->string = g_string_chunk_insert_len (data->chunks, str, len); + s->len = len; s->count = 1; - g_hash_table_insert (strings, s->string, s); + g_hash_table_add (data->strings, s); return s; } -typedef struct { - GHashTable *strings; - RecordDataTree *root; - RecordDataTree *current; -} RecordData; - static void record_start_element (GMarkupParseContext *context, const char *element_name, @@ -135,7 +170,7 @@ record_start_element (GMarkupParseContext *context, int i; child = record_data_tree_new (data->current, RECORD_TYPE_ELEMENT, - record_data_string_lookup (data->strings, element_name, -1)); + record_data_string_lookup (data, element_name, -1)); data->current = child; child->n_attributes = n_attrs; @@ -144,8 +179,8 @@ record_start_element (GMarkupParseContext *context, for (i = 0; i < n_attrs; i++) { - child->attributes[i] = record_data_string_lookup (data->strings, names[i], -1); - child->values[i] = record_data_string_lookup (data->strings, values[i], -1); + child->attributes[i] = record_data_string_lookup (data, names[i], -1); + child->values[i] = record_data_string_lookup (data, values[i], -1); } } @@ -170,7 +205,7 @@ record_text (GMarkupParseContext *context, RecordData *data = user_data; record_data_tree_new (data->current, RECORD_TYPE_TEXT, - record_data_string_lookup (data->strings, text, text_len)); + record_data_string_lookup (data, text, text_len)); } static const GMarkupParser record_parser = @@ -182,16 +217,6 @@ static const GMarkupParser record_parser = NULL, // error, fails immediately }; -static int -compare_string (gconstpointer _a, - gconstpointer _b) -{ - const RecordDataString *a = _a; - const RecordDataString *b = _b; - - return b->count - a->count; -} - static void marshal_uint32 (GString *str, guint32 v) @@ -303,7 +328,9 @@ _gtk_buildable_parser_precompile (const char *text, GString *marshaled; int offset; - data.strings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)record_data_string_free); + data.strings = g_hash_table_new_full (record_data_string_hash, record_data_string_equal, + (GDestroyNotify)record_data_string_free, NULL); + data.chunks = g_string_chunk_new (512); data.root = record_data_tree_new (NULL, RECORD_TYPE_ELEMENT, NULL); data.current = data.root; @@ -313,6 +340,7 @@ _gtk_buildable_parser_precompile (const char *text, !g_markup_parse_context_end_parse (ctx, error)) { record_data_tree_free (data.root); + g_string_chunk_free (data.chunks); g_hash_table_destroy (data.strings); g_markup_parse_context_free (ctx); return NULL; @@ -321,15 +349,14 @@ _gtk_buildable_parser_precompile (const char *text, g_markup_parse_context_free (ctx); string_table = g_hash_table_get_values (data.strings); - - string_table = g_list_sort (string_table, compare_string); + string_table = g_list_sort (string_table, record_data_string_compare); offset = 0; for (l = string_table; l != NULL; l = l->next) { RecordDataString *s = l->data; s->offset = offset; - offset += strlen (s->string) + 1; + offset += s->len + 1; } marshaled = g_string_new (""); @@ -340,7 +367,7 @@ _gtk_buildable_parser_precompile (const char *text, for (l = string_table; l != NULL; l = l->next) { RecordDataString *s = l->data; - g_string_append_len (marshaled, s->string, strlen (s->string) + 1); + g_string_append_len (marshaled, s->string, s->len + 1); } g_list_free (string_table); @@ -348,6 +375,7 @@ _gtk_buildable_parser_precompile (const char *text, marshal_tree (marshaled, data.root); record_data_tree_free (data.root); + g_string_chunk_free (data.chunks); g_hash_table_destroy (data.strings); return g_string_free_to_bytes (marshaled); -- 2.30.2