builder: Reduce memory usage in precompile

Split the Element and Text nodes into separate structures.
This commit is contained in:
Garrett Regier
2021-09-21 15:13:34 -07:00
committed by Matthias Clasen
parent 1bfd0e5e38
commit 4ce07f41ca

View File

@@ -30,7 +30,7 @@ typedef enum
RECORD_TYPE_ELEMENT, RECORD_TYPE_ELEMENT,
RECORD_TYPE_END_ELEMENT, RECORD_TYPE_END_ELEMENT,
RECORD_TYPE_TEXT, RECORD_TYPE_TEXT,
} RecordTreeType; } RecordDataType;
/* All strings are owned by the string chunk */ /* All strings are owned by the string chunk */
typedef struct { typedef struct {
@@ -42,58 +42,110 @@ typedef struct {
gboolean include_len; gboolean include_len;
} RecordDataString; } RecordDataString;
typedef struct RecordDataTree RecordDataTree; typedef struct {
RecordDataType type;
struct RecordDataTree {
RecordDataTree *parent;
RecordTreeType type;
int n_attributes;
RecordDataString *data;
RecordDataString **attributes;
GList link; GList link;
} RecordDataNode;
typedef struct RecordDataElement RecordDataElement;
struct RecordDataElement {
RecordDataNode base;
RecordDataElement *parent;
int n_attributes;
RecordDataString *name;
RecordDataString **attributes;
GQueue children; GQueue children;
}; };
typedef struct {
RecordDataNode base;
RecordDataString *string;
} RecordDataText;
typedef struct { typedef struct {
GHashTable *strings; GHashTable *strings;
GStringChunk *chunks; GStringChunk *chunks;
RecordDataTree *root; RecordDataElement *root;
RecordDataTree *current; RecordDataElement *current;
} RecordData; } RecordData;
static RecordDataTree * static gpointer
record_data_tree_new (RecordDataTree *parent, record_data_node_new (RecordDataElement *parent,
RecordTreeType type, RecordDataType type,
RecordDataString *data) gsize size)
{ {
RecordDataTree *tree = g_slice_new0 (RecordDataTree); RecordDataNode *node = g_slice_alloc0 (size);
tree->parent = parent; node->type = type;
tree->type = type; node->link.data = node;
tree->data = data;
tree->link.data = tree;
if (parent) if (parent)
g_queue_push_tail_link (&parent->children, &tree->link); g_queue_push_tail_link (&parent->children, &node->link);
return tree; return node;
}
static RecordDataElement *
record_data_element_new (RecordDataElement *parent,
RecordDataString *name)
{
RecordDataElement *element;
element = record_data_node_new (parent,
RECORD_TYPE_ELEMENT,
sizeof (RecordDataElement));
element->parent = parent;
element->name = name;
return element;
} }
static void static void
record_data_tree_free (RecordDataTree *tree) record_data_element_append_text (RecordDataElement *parent,
RecordDataString *string)
{
RecordDataText *text;
text = record_data_node_new (parent,
RECORD_TYPE_TEXT,
sizeof (RecordDataText));
text->string = string;
}
static void
record_data_node_free (RecordDataNode *node)
{ {
GList *l, *next; GList *l, *next;
RecordDataText *text;
RecordDataElement *element;
l = tree->children.head; switch (node->type)
while (l)
{ {
next = l->next; case RECORD_TYPE_ELEMENT:
record_data_tree_free (l->data); element = (RecordDataElement *)node;
l = next;
}
g_free (tree->attributes); l = element->children.head;
g_slice_free (RecordDataTree, tree); while (l)
{
next = l->next;
record_data_node_free (l->data);
l = next;
}
g_free (element->attributes);
g_slice_free (RecordDataElement, element);
break;
case RECORD_TYPE_TEXT:
text = (RecordDataText *)node;
g_slice_free (RecordDataText, text);
break;
case RECORD_TYPE_END_ELEMENT:
default:
g_assert_not_reached ();
}
} }
static void static void
@@ -180,12 +232,12 @@ record_start_element (GMarkupParseContext *context,
{ {
gsize n_attrs = g_strv_length ((char **)names); gsize n_attrs = g_strv_length ((char **)names);
RecordData *data = user_data; RecordData *data = user_data;
RecordDataTree *child; RecordDataElement *child;
RecordDataString **attr_names, **attr_values; RecordDataString *name, **attr_names, **attr_values;
int i; int i;
child = record_data_tree_new (data->current, RECORD_TYPE_ELEMENT, name = record_data_string_lookup (data, element_name, -1);
record_data_string_lookup (data, element_name, -1)); child = record_data_element_new (data->current, name);
data->current = child; data->current = child;
child->n_attributes = n_attrs; child->n_attributes = n_attrs;
@@ -219,9 +271,10 @@ record_text (GMarkupParseContext *context,
GError **error) GError **error)
{ {
RecordData *data = user_data; RecordData *data = user_data;
RecordDataString *string;
record_data_tree_new (data->current, RECORD_TYPE_TEXT, string = record_data_string_lookup (data, text, text_len);
record_data_string_lookup (data, text, text_len)); record_data_element_append_text (data->current, string);
} }
static const GMarkupParser record_parser = static const GMarkupParser record_parser =
@@ -301,42 +354,45 @@ marshal_uint32_len (guint32 v)
static void static void
marshal_tree (GString *marshaled, marshal_tree (GString *marshaled,
RecordDataTree *tree) RecordDataNode *node)
{ {
GList *l; GList *l;
int i; int i;
RecordDataText *text;
RecordDataElement *element;
RecordDataString **attr_names, **attr_values; RecordDataString **attr_names, **attr_values;
/* Special case the root */ switch (node->type)
if (tree->parent == NULL)
{
for (l = tree->children.head; l != NULL; l = l->next)
marshal_tree (marshaled, l->data);
return;
}
switch (tree->type)
{ {
case RECORD_TYPE_ELEMENT: case RECORD_TYPE_ELEMENT:
marshal_uint32 (marshaled, RECORD_TYPE_ELEMENT); element = (RecordDataElement *)node;
marshal_uint32 (marshaled, tree->data->offset);
marshal_uint32 (marshaled, tree->n_attributes);
attr_names = &tree->attributes[0]; /* Special case the root */
attr_values = &tree->attributes[tree->n_attributes]; if (element->parent != NULL)
for (i = 0; i < tree->n_attributes; i++)
{ {
marshal_uint32 (marshaled, attr_names[i]->offset); marshal_uint32 (marshaled, RECORD_TYPE_ELEMENT);
marshal_uint32 (marshaled, attr_values[i]->offset); marshal_uint32 (marshaled, element->name->offset);
marshal_uint32 (marshaled, element->n_attributes);
attr_names = &element->attributes[0];
attr_values = &element->attributes[element->n_attributes];
for (i = 0; i < element->n_attributes; i++)
{
marshal_uint32 (marshaled, attr_names[i]->offset);
marshal_uint32 (marshaled, attr_values[i]->offset);
}
} }
for (l = tree->children.head; l != NULL; l = l->next)
for (l = element->children.head; l != NULL; l = l->next)
marshal_tree (marshaled, l->data); marshal_tree (marshaled, l->data);
marshal_uint32 (marshaled, RECORD_TYPE_END_ELEMENT); if (element->parent != NULL)
marshal_uint32 (marshaled, RECORD_TYPE_END_ELEMENT);
break; break;
case RECORD_TYPE_TEXT: case RECORD_TYPE_TEXT:
text = (RecordDataText *)node;
marshal_uint32 (marshaled, RECORD_TYPE_TEXT); marshal_uint32 (marshaled, RECORD_TYPE_TEXT);
marshal_uint32 (marshaled, tree->data->text_offset); marshal_uint32 (marshaled, text->string->text_offset);
break; break;
case RECORD_TYPE_END_ELEMENT: case RECORD_TYPE_END_ELEMENT:
default: default:
@@ -369,7 +425,7 @@ _gtk_buildable_parser_precompile (const char *text,
data.strings = g_hash_table_new_full (record_data_string_hash, record_data_string_equal, data.strings = g_hash_table_new_full (record_data_string_hash, record_data_string_equal,
(GDestroyNotify)record_data_string_free, NULL); (GDestroyNotify)record_data_string_free, NULL);
data.chunks = g_string_chunk_new (512); data.chunks = g_string_chunk_new (512);
data.root = record_data_tree_new (NULL, RECORD_TYPE_ELEMENT, NULL); data.root = record_data_element_new (NULL, NULL);
data.current = data.root; data.current = data.root;
ctx = g_markup_parse_context_new (&record_parser, G_MARKUP_TREAT_CDATA_AS_TEXT, &data, NULL); ctx = g_markup_parse_context_new (&record_parser, G_MARKUP_TREAT_CDATA_AS_TEXT, &data, NULL);
@@ -377,7 +433,7 @@ _gtk_buildable_parser_precompile (const char *text,
if (!g_markup_parse_context_parse (ctx, text, text_len, error) || if (!g_markup_parse_context_parse (ctx, text, text_len, error) ||
!g_markup_parse_context_end_parse (ctx, error)) !g_markup_parse_context_end_parse (ctx, error))
{ {
record_data_tree_free (data.root); record_data_node_free (&data.root->base);
g_string_chunk_free (data.chunks); g_string_chunk_free (data.chunks);
g_hash_table_destroy (data.strings); g_hash_table_destroy (data.strings);
g_markup_parse_context_free (ctx); g_markup_parse_context_free (ctx);
@@ -421,9 +477,9 @@ _gtk_buildable_parser_precompile (const char *text,
g_list_free (string_table); g_list_free (string_table);
marshal_tree (marshaled, data.root); marshal_tree (marshaled, &data.root->base);
record_data_tree_free (data.root); record_data_node_free (&data.root->base);
g_string_chunk_free (data.chunks); g_string_chunk_free (data.chunks);
g_hash_table_destroy (data.strings); g_hash_table_destroy (data.strings);