Refactor of pat_t memory management to use doubly linked lists, and

moving the recursive freeing code from Lua/lbp.c into pattern.c
This commit is contained in:
Bruce Hill 2021-09-26 13:12:02 -07:00
parent ee0174001b
commit 77d9007a88
5 changed files with 57 additions and 62 deletions

View File

@ -112,41 +112,6 @@ static void push_match(lua_State *L, match_t *m, const char *start)
lua_setfield(L, -2, "after");
}
static void recursively_free_pat(pat_t *pat)
{
// Do a depth-first traversal, freeing everyting along the way:
if (!pat) return;
switch (pat->type) {
case BP_DEFINITION:
recursively_free_pat(pat->args.def.def);
recursively_free_pat(pat->args.def.pat);
break;
case BP_REPEAT:
recursively_free_pat(pat->args.repetitions.sep);
recursively_free_pat(pat->args.repetitions.repeat_pat);
break;
case BP_CHAIN: case BP_UPTO: case BP_UPTO_STRICT:
case BP_OTHERWISE: case BP_NOT_MATCH: case BP_MATCH:
recursively_free_pat(pat->args.multiple.first);
recursively_free_pat(pat->args.multiple.second);
break;
case BP_REPLACE:
recursively_free_pat(pat->args.replace.pat);
break;
case BP_CAPTURE:
recursively_free_pat(pat->args.capture.capture_pat);
break;
case BP_NOT: case BP_AFTER: case BP_BEFORE:
recursively_free_pat(pat->args.pat);
break;
case BP_LEFTRECURSION:
recursively_free_pat(pat->args.leftrec.fallback);
break;
default: break;
}
free_pat(pat);
}
static int Lmatch(lua_State *L)
{
if (lua_isstring(L, 1)) {
@ -226,7 +191,7 @@ static int Lreplace(lua_State *L)
lua_pushinteger(L, replacements);
fclose(out);
free_pat(maybe_replacement.value.pat);
delete_pat(&maybe_replacement.value.pat, false);
return 2;
}
@ -281,8 +246,7 @@ static int Lpat_tostring(lua_State *L)
static int Lpat_gc(lua_State *L)
{
pat_t *pat = lua_touserdata(L, 1);
if (pat)
recursively_free_pat(pat);
if (pat) delete_pat(&pat, true);
return 0;
}

2
bp.c
View File

@ -682,7 +682,7 @@ int main(int argc, char *argv[])
// tracking down memory leaks.
free_all_matches();
defs = free_defs(defs, NULL);
free_pat(NULL);
free_all_pats();
while (loaded_files) {
file_t *next = loaded_files->next;
destroy_file(&loaded_files);

View File

@ -531,10 +531,8 @@ static match_t *match(match_ctx_t *ctx, const char *str, pat_t *pat)
ctx2.defs = with_def(ctx->defs, m1->pat->args.capture.namelen, m1->pat->args.capture.name, backref);
++m1->refcount; {
m2 = match(&ctx2, m1->end, pat->args.multiple.second);
if (!m2) { // No need to keep the backref in memory if it didn't match
free_pat(backref);
backref = NULL;
}
if (!m2) // No need to keep the backref in memory if it didn't match
delete_pat(&backref, false);
free_defs(ctx2.defs, ctx->defs);
} --m1->refcount;
} else {

View File

@ -52,6 +52,7 @@ static pat_t *new_pat(enum pattype_e type, const char *start, const char *end, s
static size_t next_pat_id = 1;
pat_t *pat = new(pat_t);
*pat = (pat_t){
.home = &allocated_pats,
.next = allocated_pats,
.type = type,
.start = start,
@ -60,6 +61,7 @@ static pat_t *new_pat(enum pattype_e type, const char *start, const char *end, s
.max_matchlen = maxlen,
.id = next_pat_id++,
};
if (allocated_pats) allocated_pats->home = &pat->next;
allocated_pats = pat;
return pat;
}
@ -635,24 +637,54 @@ maybe_pat_t bp_pattern(const char *str, const char *end)
return (maybe_pat_t){.success = false, .value.error.start = str, .value.error.end = end, .value.error.msg = "Failed to parse this pattern"};
}
void free_pat(pat_t *target)
void free_all_pats(void)
{
if (target) {
for (pat_t **rem = &allocated_pats; *rem; rem = &(*rem)->next) {
if ((*rem) == target) {
pat_t *tmp = *rem;
*rem = (*rem)->next;
delete(&tmp);
break;
}
}
} else {
while (allocated_pats) {
pat_t *tofree = allocated_pats;
allocated_pats = tofree->next;
delete(&tofree);
}
while (allocated_pats) {
pat_t *tofree = allocated_pats;
allocated_pats = tofree->next;
delete(&tofree);
}
}
void delete_pat(pat_t **at_pat, bool recursive)
{
pat_t *pat = *at_pat;
if (!pat) return;
if (recursive) {
switch (pat->type) {
case BP_DEFINITION:
delete_pat(&pat->args.def.def, true);
delete_pat(&pat->args.def.pat, true);
break;
case BP_REPEAT:
delete_pat(&pat->args.repetitions.sep, true);
delete_pat(&pat->args.repetitions.repeat_pat, true);
break;
case BP_CHAIN: case BP_UPTO: case BP_UPTO_STRICT:
case BP_OTHERWISE: case BP_NOT_MATCH: case BP_MATCH:
delete_pat(&pat->args.multiple.first, true);
delete_pat(&pat->args.multiple.second, true);
break;
case BP_REPLACE:
delete_pat(&pat->args.replace.pat, true);
break;
case BP_CAPTURE:
delete_pat(&pat->args.capture.capture_pat, true);
break;
case BP_NOT: case BP_AFTER: case BP_BEFORE:
delete_pat(&pat->args.pat, true);
break;
case BP_LEFTRECURSION:
delete_pat(&pat->args.leftrec.fallback, true);
break;
default: break;
}
}
if (pat->home) *(pat->home) = pat->next;
if (pat->next) pat->next->home = pat->home;
delete(at_pat);
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0

View File

@ -42,7 +42,7 @@ enum pattype_e {
// A struct reperesenting a BP virtual machine operation
//
typedef struct pat_s {
struct pat_s *next;
struct pat_s *next, **home;
enum pattype_e type;
const char *start, *end;
// The bounds of the match length (used for backtracking)
@ -115,8 +115,9 @@ pat_t *chain_together(pat_t *first, pat_t *second);
pat_t *either_pat(pat_t *first, pat_t *second);
__attribute__((nonnull))
maybe_pat_t bp_pattern(const char *str, const char *end);
void free_pat(pat_t *pat);
void free_all_pats(void);
__attribute__((nonnull))
void delete_pat(pat_t **at_pat, bool recursive);
#endif