#define BACK ((SYMBOL)0)
#define ROOT ((STATE) 0)
+extern const guchar lc_map[256];
int
acism_lookup(ac_trie_t const *psp, const char *text, size_t len,
ACISM_ACTION *cb, void *context, int *statep, bool caseless)
{
- ac_trie_t const ps = *psp;
char const *cp = text, *endp = cp + len;
uint8_t s;
STATE state = *statep;
int ret = 0;
while (cp < endp) {
- s = caseless ? g_ascii_tolower (*cp++) : *cp++;
- _SYMBOL sym = ps.symv[s];
+ s = caseless ? lc_map[(guint8)*cp++] : *cp++;
+ _SYMBOL sym = psp->symv[s];
if (!sym) {
// Input byte is not in any pattern string.
state = ROOT;
// following the backref chain.
TRAN next;
- while (!t_valid(&ps, next = p_tran(&ps, state, sym)) && state != ROOT) {
- TRAN back = p_tran(&ps, state, BACK);
- state = t_valid(&ps, back) ? t_next(&ps, back) : ROOT;
+ while (!t_valid(psp, next = p_tran(psp, state, sym)) && state != ROOT) {
+ TRAN back = p_tran(psp, state, BACK);
+ state = t_valid(psp, back) ? t_next(psp, back) : ROOT;
}
- if (!t_valid(&ps, next))
+ if (!t_valid(psp, next))
continue;
if (!(next & (IS_MATCH | IS_SUFFIX))) {
// No complete match yet; keep going.
- state = t_next(&ps, next);
+ state = t_next(psp, next);
continue;
}
// Initially state is ROOT. The chain search saves the
// first state from which the next char has a transition.
- state = t_isleaf(&ps, next) ? 0 : t_next(&ps, next);
+ state = t_isleaf(psp, next) ? 0 : t_next(psp, next);
while (1) {
- if (t_valid(&ps, next)) {
+ if (t_valid(psp, next)) {
if (next & IS_MATCH) {
unsigned strno, ss = s + sym, i;
- if (t_isleaf(&ps, ps.tranv[ss])) {
- strno = t_strno(&ps, ps.tranv[ss]);
+ if (t_isleaf(psp, psp->tranv[ss])) {
+ strno = t_strno(psp, psp->tranv[ss]);
} else {
- for (i = p_hash(&ps, ss); ps.hashv[i].state != ss; ++i);
- strno = ps.hashv[i].strno;
+ for (i = p_hash(psp, ss); psp->hashv[i].state != ss; ++i);
+ strno = psp->hashv[i].strno;
}
if ((ret = cb(strno, cp - text, context)))
goto EXIT;
}
- if (!state && !t_isleaf(&ps, next))
- state = t_next(&ps, next);
+ if (!state && !t_isleaf(psp, next))
+ state = t_next(psp, next);
if ( state && !(next & IS_SUFFIX))
break;
}
if (s == ROOT)
break;
- TRAN b = p_tran(&ps, s, BACK);
- s = t_valid(&ps, b) ? t_next(&ps, b) : ROOT;
- next = p_tran(&ps, s, sym);
+ TRAN b = p_tran(psp, s, BACK);
+ s = t_valid(psp, b) ? t_next(psp, b) : ROOT;
+ next = p_tran(psp, s, sym);
}
}
EXIT:
if (psp->flags & IS_MMAP)
munmap((char*)psp->tranv - sizeof(ac_trie_t),
sizeof(ac_trie_t) + p_size(psp));
- else free(psp->tranv);
- free(psp);
+ else g_free(psp->tranv);
+ g_free(psp);
}
//EOF
static void fill_symv(ac_trie_t*, ac_trie_pat_t const*, int ns);
static int create_tree(TNODE*, SYMBOL const*symv, ac_trie_pat_t const*strv, int nstrs);
static void add_backlinks(TNODE*, TNODE**, TNODE**);
-static void prune_backlinks(TNODE*);
static int interleave(TNODE*, int nnodes, int nsyms, TNODE**, TNODE**);
static void fill_tranv(ac_trie_t*, TNODE const*);
static void fill_hashv(ac_trie_t*, TNODE const*, int nn);
acism_create(ac_trie_pat_t const* strv, int nstrs)
{
TNODE *tp, **v1 = NULL, **v2 = NULL;
- ac_trie_t *psp = calloc(1, sizeof*psp);
+ ac_trie_t *psp = g_malloc0(sizeof(*psp));
fill_symv(psp, strv, nstrs);
- TNODE *troot = calloc(psp->nchars + 1, sizeof*troot);
+ TNODE *troot = g_new0(TNODE, psp->nchars + 1);
int nnodes = create_tree(troot, psp->symv, strv, nstrs);
NOTE(nnodes);
// v1, v2: breadth-first work vectors for add_backlink and interleave.
- int nhash, i = (nstrs + 1) * sizeof*tp;
- add_backlinks(troot, v1 = malloc(i), v2 = malloc(i));
+ int nhash = 0, i = (nstrs + 1) * sizeof*tp;
- for (tp = troot + nnodes, nhash = 0; --tp > troot;) {
- prune_backlinks(tp);
+ for (tp = troot + nnodes; --tp > troot;) {
nhash += tp->match && tp->child;
}
+ v1 = g_malloc(i);
+ v2 = g_malloc(i);
+ add_backlinks(troot, v1, v2);
// Calculate each node's offset in tranv[]:
psp->tran_size = interleave(troot, nnodes, psp->nsyms, v1, v2);
psp->hash_size = psp->hash_mod + nhash;
}
- set_tranv(psp, calloc(p_size(psp), 1));
+ set_tranv(psp, g_malloc0(p_size(psp)));
if (!psp->tranv) goto FAIL;
fill_tranv(psp, troot);
// The root state (0) must not look like a valid backref.
psp->hash_size = psp->hash_mod;
while ( psp->hashv[psp->hash_size].state) ++psp->hash_size;
while (!psp->hashv[psp->hash_size - 1].state) --psp->hash_size;
- set_tranv(psp, realloc(psp->tranv, p_size(psp)));
+ set_tranv(psp, g_realloc(psp->tranv, p_size(psp)));
}
// Diagnostics/statistics only:
goto DONE;
FAIL: acism_destroy(psp), psp = NULL;
-DONE: free(troot), free(v1), free(v2);
+DONE: g_free(troot), g_free(v1), g_free(v2);
return psp;
}
++psp->nsyms;
#if ACISM_SIZE < 8
psp->sym_bits = bitwid(psp->nsyms);
- psp->sym_mask = ~(-1 << psp->sym_bits);
+ psp->sym_mask = ~(((TRAN)-1) << psp->sym_bits);
#endif
}
TNODE *bp = NULL;
*dpp++ = dstp;
for (tp = srcp->back; tp; tp = tp->back)
- if ((bp = find_child(tp, dstp->sym))) break;
+ if ((bp = find_child(tp, dstp->sym)) && bp->child) break;
if (!bp)
bp = troot;
}
}
-static void
-prune_backlinks(TNODE *tp)
-{
- if (tp->x.nrefs || !tp->child)
- return;
-
- TNODE *bp;
- // (bp != bp->back IFF bp != troot)
- while ((bp = tp->back) && !bp->match && bp != bp->back) {
- HIT("backlinks");
- TNODE *cp = tp->child, *pp = bp->child;
-
- // Search for a child of bp that's not a child of tp
- for (; cp && pp && pp->sym >= cp->sym; cp = cp->next) {
- if (pp->sym == cp->sym) {
- if (pp->match && cp->is_suffix) break;
- pp = pp->next;
- }
- }
-
- if (pp) break;
-
- // So, target of back link is not a suffix match
- // of this node, and its children are a subset
- // of this node's children: prune it.
- HIT("pruned");
- if ((tp->back = bp->back)) {
- tp->back->x.nrefs++;
- if (!--bp->x.nrefs)
- prune_backlinks(bp);
- }
- }
-}
-
static int
interleave(TNODE *troot, int nnodes, int nsyms, TNODE **v1, TNODE **v2)
{
unsigned usev_size = nnodes + nsyms;
- char *usev = calloc(usev_size, sizeof*usev);
+ char *usev = g_new0(char, usev_size);
STATE last_trans = 0, startv[nsyms][2];
TNODE *cp, **tmp;
if (last_trans < last) {
last_trans = last;
if (last + nsyms >= usev_size) {
- char *tmp = realloc(usev, usev_size << 1);
+ char *tmp = g_realloc(usev, usev_size << 1);
if (tmp != NULL) {
usev = tmp;
memset(usev + usev_size, 0, usev_size);
usev_size <<= 1;
} else {
- free(usev);
+ g_free(usev);
/* And handle error */
}
}
*dstp = NULL;
}
- free(usev);
+ g_free(usev);
return last_trans + 1;
}
static void
fill_hashv(ac_trie_t *psp, TNODE const treev[], int nnodes)
{
- STRASH *sv = malloc(psp->hash_mod * sizeof*sv), *sp = sv;
+ STRASH *sv = g_malloc(psp->hash_mod * sizeof*sv), *sp = sv;
int i;
// First pass: insert without resolving collisions.
psp->hashv[i] = *sp;
}
- free(sv);
+ g_free(sv);
}
static void