>From e67eed09457e339e7e2853a770af6ebdd2ebced5 Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy Date: Fri, 2 Oct 2026 21:57:46 +0000 Subject: [PATCH 22/25] regex: optimize tre_set_union set2 is only copied (tags pointer can be shared), set1 may need assertions update or merging tags lists. sets can be shared too so avoid coping set2 if set1 is empty. this reduces code size and memory usage a bit (as there is more sharing instead of copy in some cases) without regressions. the saving can be significant in edge cases e.g. ()|||||... spent >30% time computing num_tags unnecessarily as set1 is empty. --- src/regex/regcomp.c | 39 +++++++-------------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/src/regex/regcomp.c b/src/regex/regcomp.c index bde02ccf..40850456 100644 --- a/src/regex/regcomp.c +++ b/src/regex/regcomp.c @@ -2088,25 +2088,20 @@ tre_set_union(tre_mem_t mem, tre_pos_and_tags_t *set1, tre_pos_and_tags_t *set2, int *new_tags; int num_tags; + if (set1[0].position < 0) + return set2; for (num_tags = 0; tags != NULL && tags[num_tags] >= 0; num_tags++); for (s1 = 0; set1[s1].position >= 0; s1++); for (s2 = 0; set2[s2].position >= 0; s2++); - new_set = tre_mem_calloc(mem, sizeof(*new_set) * (s1 + s2 + 1)); + new_set = tre_mem_alloc(mem, sizeof(*new_set) * (s1 + s2 + 1)); if (!new_set ) return NULL; for (s1 = 0; set1[s1].position >= 0; s1++) { - new_set[s1].position = set1[s1].position; - new_set[s1].code_min = set1[s1].code_min; - new_set[s1].code_max = set1[s1].code_max; - new_set[s1].assertions = set1[s1].assertions | assertions; - new_set[s1].class = set1[s1].class; - new_set[s1].neg_classes = set1[s1].neg_classes; - new_set[s1].backref = set1[s1].backref; - if (set1[s1].tags == NULL && tags == NULL) - new_set[s1].tags = NULL; - else + new_set[s1] = set1[s1]; + new_set[s1].assertions |= assertions; + if (num_tags) { for (i = 0; set1[s1].tags != NULL && set1[s1].tags[i] >= 0; i++); new_tags = tre_mem_alloc(mem, (sizeof(*new_tags) @@ -2121,27 +2116,7 @@ tre_set_union(tre_mem_t mem, tre_pos_and_tags_t *set1, tre_pos_and_tags_t *set2, for (s2 = 0; set2[s2].position >= 0; s2++) { - new_set[s1 + s2].position = set2[s2].position; - new_set[s1 + s2].code_min = set2[s2].code_min; - new_set[s1 + s2].code_max = set2[s2].code_max; - /* XXX - why not | assertions here as well? */ - new_set[s1 + s2].assertions = set2[s2].assertions; - new_set[s1 + s2].class = set2[s2].class; - new_set[s1 + s2].neg_classes = set2[s2].neg_classes; - new_set[s1 + s2].backref = set2[s2].backref; - if (set2[s2].tags == NULL) - new_set[s1 + s2].tags = NULL; - else - { - for (i = 0; set2[s2].tags[i] >= 0; i++); - new_tags = tre_mem_alloc(mem, sizeof(*new_tags) * (i + 1)); - if (new_tags == NULL) - return NULL; - for (j = 0; j < i; j++) - new_tags[j] = set2[s2].tags[j]; - new_tags[j] = -1; - new_set[s1 + s2].tags = new_tags; - } + new_set[s1 + s2] = set2[s2]; } new_set[s1 + s2].position = -1; return new_set; -- 2.52.0