*
* KMPS_SOURCE user-defined search input (together with KMPS_GET_CHAR);
* if unset, the one from lib/kmp.h is used
- * KMPS_GET_CHAR(ctx,src,s)
+ * KMPS_GET_CHAR(kmp,src,s)
*
* KMPS_ADD_CONTROLS add control characters at both ends of the input string
* KMPS_MERGE_CONTROLS merge adjacent control characters to a single one
*
* KMPS_EXTRA_ARGS extra arguments to the search routine
* KMPS_EXTRA_VAR extra user-defined structure in search structures
- * KMPS_INIT(ctx,src,s)
- * KMPS_EXIT(ctx,src,s)
- * KMPS_FOUND(ctx,src,s)
- * KMPS_FOUND_CHAIN(ctx,src,s)
- * KMPS_STEP(ctx,src,s)
+ * KMPS_INIT(kmp,src,s)
+ * KMPS_EXIT(kmp,src,s)
+ * KMPS_FOUND(kmp,src,s)
+ * KMPS_FOUND_CHAIN(kmp,src,s)
+ * KMPS_STEP(kmp,src,s)
* KMPS_T
*
* KMPS_WANT_BEST
#endif
#ifndef KMPS_GET_CHAR
-#define KMPS_GET_CHAR(ctx,src,s) ({ KP(get_char)(ctx, &src, &s.c); })
+#define KMPS_GET_CHAR(kmp,src,s) ({ KP(get_char)(kmp, &src, &s.c); })
#endif
struct P(search) {
#else
static void
#endif
-P(search) (struct KP(context) *ctx, P(search_source_t) src
+P(search) (struct KP(struct) *kmp, P(search_source_t) src
# ifdef KMPS_EXTRA_ARGS
, KMPS_EXTRA_ARGS
# endif
)
{
struct P(search) s;
- s.s = &ctx->null;
+ s.s = &kmp->null;
# ifdef KMPS_WANT_BEST
- s.best = &ctx->null;
+ s.best = &kmp->null;
# endif
# ifdef KMPS_ADD_CONTROLS
s.c = KP(control)();
s.c = 0;
# endif
# ifdef KMPS_INIT
- { KMPS_INIT(ctx, src, s); }
+ { KMPS_INIT(kmp, src, s); }
# endif
# ifndef KMPS_ADD_CONTROLS
goto start_read;
#endif
for (;;)
{
- for (struct KP(state) *t = s.s; t && !(s.s = KP(hash_find)(&ctx->hash, t, s.c)); t = t->back);
- s.s = s.s ? : &ctx->null;
+ for (struct KP(state) *t = s.s; t && !(s.s = KP(hash_find)(&kmp->hash, t, s.c)); t = t->back);
+ s.s = s.s ? : &kmp->null;
# ifdef KMPS_STEP
- { KMPS_STEP(ctx, src, s); }
+ { KMPS_STEP(kmp, src, s); }
# endif
# if defined(KMPS_FOUND) || defined(KMPS_FOUND_CHAIN) || defined(KMPS_WANT_BEST)
s.best = s.out;
# endif
#ifdef KMPS_FOUND_CHAIN
- { KMPS_FOUND_CHAIN(ctx, src, s); }
+ { KMPS_FOUND_CHAIN(kmp, src, s); }
# endif
# ifdef KMPS_FOUND
do
- { KMPS_FOUND(ctx, src, s); }
+ { KMPS_FOUND(kmp, src, s); }
while (s.out = s.out->next);
# endif
}
do
{
- if (!KMPS_GET_CHAR(ctx, src, s))
+ if (!KMPS_GET_CHAR(kmp, src, s))
{
# ifdef KMPS_ADD_CONTROLS
- if (!KP(is_control)(ctx, s.c))
+ if (!KP(is_control)(kmp, s.c))
{
s.c = KP(control)();
s.eof = 1;
}
while (0
# ifdef KMPS_MERGE_CONTROLS
- || (KP(is_control)(ctx, last_c) && KP(is_control)(ctx, s.c))
+ || (KP(is_control)(kmp, last_c) && KP(is_control)(kmp, s.c))
# endif
);
}
exit: ;
# ifdef KMPS_EXIT
- { KMPS_EXIT(ctx, src, s); }
+ { KMPS_EXIT(kmp, src, s); }
# endif
}
#define KMPS_KMP_PREFIX(x) GLUE_(kmp1,x)
#define KMPS_WANT_BEST
#define KMPS_T uns
-#define KMPS_EXIT(ctx,src,s) do{ return s.best->len; }while(0)
+#define KMPS_EXIT(kmp,src,s) do{ return s.best->len; }while(0)
#include "lib/kmp-search.h"
#define KMPS_PREFIX(x) GLUE_(kmp1s2,x)
#define KMPS_KMP_PREFIX(x) GLUE_(kmp1,x)
#define KMPS_EXTRA_VAR uns
-#define KMPS_INIT(ctx,src,s) do{ s.v = 0; }while(0)
+#define KMPS_INIT(kmp,src,s) do{ s.v = 0; }while(0)
#define KMPS_T uns
-#define KMPS_FOUND(ctx,src,s) do{ s.v++; }while(0)
-#define KMPS_EXIT(ctx,src,s) do{ return s.v; }while(0)
+#define KMPS_FOUND(kmp,src,s) do{ s.v++; }while(0)
+#define KMPS_EXIT(kmp,src,s) do{ return s.v; }while(0)
#define KMPS_WANT_BEST
#include "lib/kmp-search.h"
test1(void)
{
TRACE("Running test1");
- struct kmp1_context ctx;
- kmp1_init(&ctx);
- kmp1_add(&ctx, "ahoj");
- kmp1_add(&ctx, "hoj");
- kmp1_add(&ctx, "aho");
- kmp1_build(&ctx);
- UNUSED uns best = kmp1s1_search(&ctx, "asjlahslhalahosjkjhojsas");
+ struct kmp1_struct kmp;
+ kmp1_init(&kmp);
+ kmp1_add(&kmp, "ahoj");
+ kmp1_add(&kmp, "hoj");
+ kmp1_add(&kmp, "aho");
+ kmp1_build(&kmp);
+ UNUSED uns best = kmp1s1_search(&kmp, "asjlahslhalahosjkjhojsas");
TRACE("Best match has %d characters", best);
ASSERT(best == 3);
- UNUSED uns count = kmp1s2_search(&ctx, "asjlahslhalahojsjkjhojsas");
+ UNUSED uns count = kmp1s2_search(&kmp, "asjlahslhalahojsjkjhojsas");
ASSERT(count == 4);
- kmp1_cleanup(&ctx);
+ kmp1_cleanup(&kmp);
}
/* TEST2 - various tracing */
#define KMP_USE_UTF8
#define KMP_TOLOWER
#define KMP_ONLYALPHA
-#define KMP_NODE struct { byte *str; uns id; }
+#define KMP_STATE_VARS byte *str; uns id;
#define KMP_ADD_EXTRA_ARGS uns id
#define KMP_ADD_EXTRA_VAR byte *
-#define KMP_ADD_INIT(ctx,src,var) do{ var = src; }while(0)
-#define KMP_ADD_NEW(ctx,src,var,state) do{ TRACE("Inserting string %s with id %d", var, id); \
- state->n.str = var; state->n.id = id; }while(0)
-#define KMP_ADD_DUP(ctx,src,var,state) do{ TRACE("String %s already inserted", var); }while(0)
+#define KMP_ADD_INIT(kmp,src,v) do{ v = src; }while(0)
+#define KMP_ADD_NEW(kmp,src,v,s) do{ TRACE("Inserting string %s with id %d", v, id); \
+ s->u.str = v; s->u.id = id; }while(0)
+#define KMP_ADD_DUP(kmp,src,v,s) do{ TRACE("String %s already inserted", v); }while(0)
#define KMP_WANT_CLEANUP
#define KMP_WANT_SEARCH
#define KMPS_ADD_CONTROLS
#define KMPS_MERGE_CONTROLS
#define KMPS_WANT_BEST
-#define KMPS_FOUND(ctx,src,s) do{ TRACE("String %s with id %d found", s.out->n.str, s.out->n.id); }while(0)
-#define KMPS_STEP(ctx,src,s) do{ TRACE("Got to state %p after reading %d", s.s, s.c); }while(0)
-#define KMPS_EXIT(ctx,src,s) do{ if (s.best->len) TRACE("Best match is %s", s.best->n.str); } while(0)
+#define KMPS_FOUND(kmp,src,s) do{ TRACE("String %s with id %d found", s.out->u.str, s.out->u.id); }while(0)
+#define KMPS_STEP(kmp,src,s) do{ TRACE("Got to state %p after reading %d", s.s, s.c); }while(0)
+#define KMPS_EXIT(kmp,src,s) do{ if (s.best->len) TRACE("Best match is %s", s.best->u.str); } while(0)
#include "lib/kmp.h"
static void
test2(void)
{
TRACE("Running test2");
- struct kmp2_context ctx;
- kmp2_init(&ctx);
- kmp2_add(&ctx, "ahoj", 1);
- kmp2_add(&ctx, "ahoj", 2);
- kmp2_add(&ctx, "hoj", 3);
- kmp2_add(&ctx, "aho", 4);
- kmp2_add(&ctx, "aba", 5);
- kmp2_add(&ctx, "aba", 5);
- kmp2_add(&ctx, "pěl", 5);
- kmp2_build(&ctx);
- kmp2_search(&ctx, "Šíleně žluťoučký kůň úpěl ďábelské ódy labababaks sdahojdhsaladsjhla");
- kmp2_cleanup(&ctx);
+ struct kmp2_struct kmp;
+ kmp2_init(&kmp);
+ kmp2_add(&kmp, "ahoj", 1);
+ kmp2_add(&kmp, "ahoj", 2);
+ kmp2_add(&kmp, "hoj", 3);
+ kmp2_add(&kmp, "aho", 4);
+ kmp2_add(&kmp, "aba", 5);
+ kmp2_add(&kmp, "aba", 5);
+ kmp2_add(&kmp, "pěl", 5);
+ kmp2_build(&kmp);
+ kmp2_search(&kmp, "Šíleně žluťoučký kůň úpěl ďábelské ódy labababaks sdahojdhsaladsjhla");
+ kmp2_cleanup(&kmp);
}
/* TEST3 - random tests */
#define KMP_PREFIX(x) GLUE_(kmp3,x)
-#define KMP_NODE uns
+#define KMP_STATE_VARS uns index;
#define KMP_ADD_EXTRA_ARGS uns index
#define KMP_ADD_EXTRA_VAR byte *
-#define KMP_ADD_INIT(ctx,src,v) do{ v = src; }while(0)
-#define KMP_ADD_NEW(ctx,src,v,s) do{ s->n = index; }while(0)
-#define KMP_ADD_DUP(ctx,src,v,s) do{ *v = 0; }while(0)
+#define KMP_ADD_INIT(kmp,src,v) do{ v = src; }while(0)
+#define KMP_ADD_NEW(kmp,src,v,s) do{ s->u.index = index; }while(0)
+#define KMP_ADD_DUP(kmp,src,v,s) do{ *v = 0; }while(0)
#define KMP_WANT_CLEANUP
#define KMP_WANT_SEARCH
#define KMPS_EXTRA_ARGS uns *cnt, uns *sum
-#define KMPS_FOUND(ctx,src,s) do{ ASSERT(cnt[s.out->n]); cnt[s.out->n]--; sum[0]--; }while(0)
+#define KMPS_FOUND(kmp,src,s) do{ ASSERT(cnt[s.out->u.index]); cnt[s.out->u.index]--; sum[0]--; }while(0)
#include "lib/kmp.h"
static void
mp_flush(pool);
uns n = random_max(100);
byte *s[n];
- struct kmp3_context ctx;
- kmp3_init(&ctx);
+ struct kmp3_struct kmp;
+ kmp3_init(&kmp);
for (uns i = 0; i < n; i++)
{
uns m = random_max(10);
for (uns j = 0; j < m; j++)
s[i][j] = 'a' + random_max(3);
s[i][m] = 0;
- kmp3_add(&ctx, s[i], i);
+ kmp3_add(&kmp, s[i], i);
}
- kmp3_build(&ctx);
+ kmp3_build(&kmp);
for (uns i = 0; i < 10; i++)
{
uns m = random_max(100);
if (!strncmp(b + k, s[j], strlen(s[j])))
cnt[j]++, sum++;
}
- kmp3_search(&ctx, b, cnt, &sum);
+ kmp3_search(&kmp, b, cnt, &sum);
ASSERT(sum == 0);
}
- kmp3_cleanup(&ctx);
+ kmp3_cleanup(&kmp);
}
mp_delete(pool);
}
/* TEST4 - user-defined character type */
-struct kmp4_context;
+struct kmp4_struct;
struct kmp4_state;
static inline int
-kmp4_eq(struct kmp4_context *ctx UNUSED, byte *a, byte *b)
+kmp4_eq(struct kmp4_struct *kmp UNUSED, byte *a, byte *b)
{
return (a == b) || (a && b && *a == *b);
}
static inline uns
-kmp4_hash(struct kmp4_context *ctx UNUSED, struct kmp4_state *s, byte *c)
+kmp4_hash(struct kmp4_struct *kmp UNUSED, struct kmp4_state *s, byte *c)
{
return (c ? (*c << 16) : 0) + (uns)(addr_int_t)s;
}
#define KMP_PREFIX(x) GLUE_(kmp4,x)
#define KMP_CHAR byte *
#define KMP_CONTROL_CHAR NULL
-#define KMP_GET_CHAR(ctx,src,c) ({ c = src++; !!*c; })
+#define KMP_GET_CHAR(kmp,src,c) ({ c = src++; !!*c; })
#define KMP_GIVE_HASHFN
#define KMP_GIVE_EQ
#define KMP_WANT_CLEANUP
#define KMP_WANT_SEARCH
-#define KMPS_FOUND(ctx,src,s) do{ TRACE("found"); }while(0)
+#define KMPS_FOUND(kmp,src,s) do{ TRACE("found"); }while(0)
#define KMPS_ADD_CONTROLS
#define KMPS_MERGE_CONTROLS
#include "lib/kmp.h"
test4(void)
{
TRACE("Running test4");
- struct kmp4_context ctx;
- kmp4_init(&ctx);
- kmp4_add(&ctx, "ahoj");
- kmp4_build(&ctx);
- kmp4_search(&ctx, "djdhaskjdahoahaahojojshdaksjahdahojskj");
- kmp4_cleanup(&ctx);
+ struct kmp4_struct kmp;
+ kmp4_init(&kmp);
+ kmp4_add(&kmp, "ahoj");
+ kmp4_build(&kmp);
+ kmp4_search(&kmp, "djdhaskjdahoahaahojojshdaksjahdahojskj");
+ kmp4_cleanup(&kmp);
}
int
* KMP_CHAR alphabet type, the default is u16
*
* KMP_SOURCE user-defined text source; KMP_GET_CHAR must
- * KMP_GET_CHAR(ctx,src,c) return next character from the input or zero at the end;
+ * KMP_GET_CHAR(kmp,src,c) return next character from the input or zero at the end;
* if not defined, zero-terminated array of bytes is used as the input
*
- * KMP_NODE user-defined data in each state of the automaton
- * KMP_CONTEXT user-defined data in struct context (a structure describing
+ * KMP_VARS user-defined data in main structure (a structure describing
* the whole automaton)
+ * KMP_STATE_VARS user-defined data in each state of the automaton
*
* Parameters which select how the input is interpreted (if KMP_SOURCE is unset):
* KMP_USE_ASCII reads single bytes from the input (default)
* Parameters controlling add():
* KMP_ADD_EXTRA_ARGS extra arguments
* KMP_ADD_EXTRA_VAR structure with extra local variables
- * KMP_ADD_INIT(ctx,src,v)
- * KMP_ADD_NEW(ctx,src,v,s)
- * KMP_ADD_DUP(ctx,src,v,s)
- * KMP_NO_DUPS no support for duplicates
+ * KMP_ADD_INIT(kmp,src,v)
+ * KMP_ADD_NEW(kmp,src,v,s)
+ * KMP_ADD_DUP(kmp,src,v,s)
*
* Parameters to build():
- * KMP_BUILD_STATE(ctx,s) called for all states (including null) in order of non-decreasing tree depth
+ * KMP_BUILD_STATE(kmp,s) called for all states (including null) in order of non-decreasing tree depth
*
* Other parameters:
* KMP_WANT_CLEANUP define cleanup()
typedef struct {} P(node_t);
#endif
-struct P(context);
+struct P(struct);
struct P(state) {
struct P(state) *from; /* state with previous character */
struct P(state) *next; /* largest shorter match */
P(len_t) len; /* largest match, zero otherwise */
P(char_t) c; /* last character */
- P(node_t) n; /* user-defined data */
+ struct {
+# ifdef KMP_STATE_VARS
+ KMP_STATE_VARS
+# endif
+ } u; /* user-defined data*/
};
/* Control char */
static inline P(char_t)
P(control) (void)
{
-#ifdef KMP_CONTROL_CHAR
+# ifdef KMP_CONTROL_CHAR
return KMP_CONTROL_CHAR;
-#else
+# else
return ':';
-#endif
+# endif
}
/* User-defined source */
static inline uns
P(hash_hash) (struct P(hash_table) *t, struct P(state) *f, P(char_t) c)
{
- return P(hash) ((struct P(context) *) t, f, c);
+ return P(hash) ((struct P(struct) *) t, f, c);
}
#else
static inline uns
#ifndef KMP_GIVE_EQ
static inline int
-P(eq) (struct P(context) *ctx UNUSED, P(char_t) c1, P(char_t) c2)
+P(eq) (struct P(struct) *kmp UNUSED, P(char_t) c1, P(char_t) c2)
{
return c1 == c2;
}
#endif
static inline int
-P(is_control) (struct P(context) *ctx, P(char_t) c)
+P(is_control) (struct P(struct) *kmp, P(char_t) c)
{
- return P(eq) (ctx, c, P(control)());
+ return P(eq) (kmp, c, P(control)());
}
#define HASH_GIVE_EQ
static inline int
P(hash_eq) (struct P(hash_table) *t, struct P(state) *f1, P(char_t) c1, struct P(state) *f2, P(char_t) c2)
{
- return f1 == f2 && P(eq)((struct P(context) *) t, c1, c2);
+ return f1 == f2 && P(eq)((struct P(struct) *) t, c1, c2);
}
#ifdef KMP_GIVE_ALLOC
static inline void *
P(hash_alloc) (struct P(hash_table) *t, uns size)
{
- return P(alloc) ((struct P(context) *) t, size);
+ return P(alloc) ((struct P(struct) *) t, size);
}
static inline void
P(hash_free) (struct P(hash_table) *t, void *ptr)
{
- P(free) ((struct P(context) *) t, ptr);
+ P(free) ((struct P(struct) *) t, ptr);
}
#endif
#include "lib/hashtable.h"
#define P(x) KMP_PREFIX(x)
-struct P(context) {
+struct P(struct) {
struct P(hash_table) hash; /* hash table of state transitions */
struct P(state) null; /* null state */
-# ifdef KMP_CONTEXT
- KMP_CONTEXT v; /* user defined data */
-# endif
+ struct {
+# ifdef KMP_VARS
+ KMP_VARS
+# endif
+ } u; /* user-defined data */
};
#ifdef KMP_SOURCE
#ifdef KMP_GET_CHAR
static inline int
-P(get_char) (struct P(context) *ctx UNUSED, P(source_t) *src UNUSED, P(char_t) *c UNUSED)
+P(get_char) (struct P(struct) *kmp UNUSED, P(source_t) *src UNUSED, P(char_t) *c UNUSED)
{
- return KMP_GET_CHAR(ctx, (*src), (*c));
+ return KMP_GET_CHAR(kmp, (*src), (*c));
}
#else
# if defined(KMP_USE_UTF8)
# endif
# endif
static inline int
-P(get_char) (struct P(context) *ctx UNUSED, P(source_t) *src, P(char_t) *c)
+P(get_char) (struct P(struct) *kmp UNUSED, P(source_t) *src, P(char_t) *c)
{
# ifdef KMP_USE_UTF8
uns cc;
#endif
static struct P(state) *
-P(add) (struct P(context) *ctx, P(source_t) src
+P(add) (struct P(struct) *kmp, P(source_t) src
# ifdef KMP_ADD_EXTRA_ARGS
, KMP_ADD_EXTRA_ARGS
# endif
KMP_ADD_EXTRA_VAR v;
# endif
# ifdef KMP_ADD_INIT
- { KMP_ADD_INIT(ctx, src, v); }
+ { KMP_ADD_INIT(kmp, src, v); }
# endif
P(char_t) c;
- if (!P(get_char)(ctx, &src, &c))
+ if (!P(get_char)(kmp, &src, &c))
return NULL;
- struct P(state) *p = &ctx->null, *s;
+ struct P(state) *p = &kmp->null, *s;
uns len = 0;
do
{
- s = P(hash_find)(&ctx->hash, p, c);
+ s = P(hash_find)(&kmp->hash, p, c);
if (!s)
for (;;)
{
- s = P(hash_new)(&ctx->hash, p, c);
+ s = P(hash_new)(&kmp->hash, p, c);
len++;
- if (!(P(get_char)(ctx, &src, &c)))
+ if (!(P(get_char)(kmp, &src, &c)))
goto enter_new;
p = s;
}
p = s;
len++;
}
- while (P(get_char)(ctx, &src, &c));
+ while (P(get_char)(kmp, &src, &c));
# ifdef KMP_NO_DUPS
ASSERT(!s->len);
# else
if (s->len)
{
# ifdef KMP_ADD_DUP
- { KMP_ADD_DUP(ctx, src, v, s); }
+ { KMP_ADD_DUP(kmp, src, v, s); }
# endif
return s;
}
enter_new:
s->len = len;
# ifdef KMP_ADD_NEW
- { KMP_ADD_NEW(ctx, src, v, s); }
+ { KMP_ADD_NEW(kmp, src, v, s); }
# endif
return s;
}
static void
-P(init) (struct P(context) *ctx)
+P(init) (struct P(struct) *kmp)
{
- bzero(&ctx->null, sizeof(struct P(state)));
- P(hash_init)(&ctx->hash);
+ bzero(&kmp->null, sizeof(struct P(state)));
+ P(hash_init)(&kmp->hash);
}
#ifdef KMP_WANT_CLEANUP
static inline void
-P(cleanup) (struct P(context) *ctx)
+P(cleanup) (struct P(struct) *kmp)
{
- P(hash_cleanup)(&ctx->hash);
+ P(hash_cleanup)(&kmp->hash);
}
#endif
static inline int
-P(empty) (struct P(context) *ctx)
+P(empty) (struct P(struct) *kmp)
{
- return !ctx->hash.hash_count;
+ return !kmp->hash.hash_count;
}
static inline struct P(state) *
}
static void
-P(build) (struct P(context) *ctx)
+P(build) (struct P(struct) *kmp)
{
- if (P(empty)(ctx))
+ if (P(empty)(kmp))
return;
uns read = 0, write = 0;
- struct P(state) *fifo[ctx->hash.hash_count], *null = &ctx->null;
+ struct P(state) *fifo[kmp->hash.hash_count], *null = &kmp->null;
for (struct P(state) *s = null->back; s; s = s->next)
fifo[write++] = s;
null->back = NULL;
# ifdef KMP_BUILD_STATE
- { KMP_BUILD_STATE(ctx, null); }
+ { KMP_BUILD_STATE(kmp, null); }
# endif
while (read != write)
{
s->next = NULL;
break;
}
- s->back = P(hash_find)(&ctx->hash, t, s->c);
+ s->back = P(hash_find)(&kmp->hash, t, s->c);
if (s->back)
{
s->next = s->back->len ? s->back : s->back->next;
}
}
# ifdef KMP_BUILD_STATE
- { KMP_BUILD_STATE(ctx, s); }
+ { KMP_BUILD_STATE(kmp, s); }
# endif
}
}
#undef KMP_CHAR
#undef KMP_SOURCE
#undef KMP_GET_CHAR
-#undef KMP_NODE
+#undef KMP_VARS
+#undef KMP_STATE_VARS
#undef KMP_CONTEXT
#undef KMP_USE_ASCII
#undef KMP_USE_UTF8
#undef KMP_ADD_INIT
#undef KMP_ADD_NEW
#undef KMP_ADD_DUP
-#undef KMP_NO_DUPS
#undef KMP_BUILD_STATE
#undef KMP_USE_POOL
#undef KMP_GIVE_ALLOC