diff --git a/include/fsm/fsm.h b/include/fsm/fsm.h index 2b4c438f1..a5e6ef388 100644 --- a/include/fsm/fsm.h +++ b/include/fsm/fsm.h @@ -493,5 +493,14 @@ int fsm_fgetc(void *opaque); /* expects opaque to be FILE * */ int fsm_shuffle(struct fsm *fsm, unsigned seed); +/* Attempt to reclaim memory if an FSM has significantly reduced its + * state count. Returns 1 if */ +enum fsm_vacuum_res { + FSM_VACUUM_NO_CHANGE, + FSM_VACUUM_REDUCED_MEMORY, + FSM_VACUUM_ERROC_REALLOC = -1, +} +fsm_vacuum(struct fsm *fsm); + #endif diff --git a/src/libfsm/Makefile b/src/libfsm/Makefile index 005f7d4c6..2b7aba005 100644 --- a/src/libfsm/Makefile +++ b/src/libfsm/Makefile @@ -22,6 +22,7 @@ SRC += src/libfsm/trim.c SRC += src/libfsm/example.c SRC += src/libfsm/getc.c SRC += src/libfsm/shuffle.c +SRC += src/libfsm/vacuum.c SRC += src/libfsm/vm.c # graph things diff --git a/src/libfsm/fsm.c b/src/libfsm/fsm.c index 6a7bb790f..b9f092973 100644 --- a/src/libfsm/fsm.c +++ b/src/libfsm/fsm.c @@ -57,7 +57,7 @@ fsm_new(const struct fsm_options *opt) return NULL; } - new->statealloc = 128; /* guess */ + new->statealloc = FSM_DEFAULT_STATEALLOC; new->statecount = 0; new->endcount = 0; new->capture_info = NULL; diff --git a/src/libfsm/internal.h b/src/libfsm/internal.h index 6e77510a7..024bf99df 100644 --- a/src/libfsm/internal.h +++ b/src/libfsm/internal.h @@ -44,6 +44,9 @@ struct state_array; #define FSM_CAPTURE_MAX INT_MAX +/* guess for default state allocation */ +#define FSM_DEFAULT_STATEALLOC 128 + struct fsm_edge { fsm_state_t state; /* destination */ unsigned char symbol; diff --git a/src/libfsm/libfsm.syms b/src/libfsm/libfsm.syms index f905e1f04..6e1f72dbe 100644 --- a/src/libfsm/libfsm.syms +++ b/src/libfsm/libfsm.syms @@ -68,6 +68,7 @@ fsm_addstate fsm_addstate_bulk fsm_removestate fsm_shuffle +fsm_vacuum fsm_addedge_any fsm_addedge_epsilon diff --git a/src/libfsm/vacuum.c b/src/libfsm/vacuum.c new file mode 100644 index 000000000..2c349c210 --- /dev/null +++ b/src/libfsm/vacuum.c @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Scott Vokes + * + * See LICENCE for the full copyright terms. + */ + +#include +#include +#include + +#include + +#include "internal.h" + +enum fsm_vacuum_res +fsm_vacuum(struct fsm *fsm) +{ + assert(fsm != NULL); + assert(fsm->statecount <= fsm->statealloc); + size_t nceil = fsm->statealloc; + + while ((fsm->statecount < nceil/2) && nceil > 1) { + nceil /= 2; + } + + if (nceil == fsm->statealloc) { + return FSM_VACUUM_NO_CHANGE; + } + + struct fsm_state *nstates = f_realloc(fsm->opt->alloc, + fsm->states, nceil * sizeof(nstates[0])); + if (nstates == NULL) { + return FSM_VACUUM_ERROC_REALLOC; + } + + fsm->states = nstates; + fsm->statealloc = nceil; + + return FSM_VACUUM_REDUCED_MEMORY; +}