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:
parent
ee0174001b
commit
77d9007a88
40
Lua/lbp.c
40
Lua/lbp.c
@ -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
2
bp.c
@ -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);
|
||||
|
6
match.c
6
match.c
@ -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 {
|
||||
|
64
pattern.c
64
pattern.c
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user