diff --git a/src/sre_cli.c b/src/sre_cli.c index f53584f..4e0a766 100644 --- a/src/sre_cli.c +++ b/src/sre_cli.c @@ -556,6 +556,8 @@ process_string(sre_char *s, size_t len, sre_program_t *prog, sre_int_t *ovector, printf("splitted pike "); + dd("===== splitted pike ====="); + pctx = sre_vm_pike_create_ctx(pool, prog, ovector, ovecsize); assert(pctx); diff --git a/src/sregex/sre_capture.c b/src/sregex/sre_capture.c index dac5fec..d1c1854 100644 --- a/src/sregex/sre_capture.c +++ b/src/sregex/sre_capture.c @@ -18,25 +18,35 @@ SRE_NOAPI sre_capture_t * -sre_capture_create(sre_pool_t *pool, size_t ovecsize, unsigned clear) +sre_capture_create(sre_pool_t *pool, size_t ovecsize, unsigned clear, + sre_capture_t **freecap) { sre_char *p; sre_capture_t *cap; - p = sre_pnalloc(pool, sizeof(sre_capture_t) + ovecsize); - if (p == NULL) { - return NULL; - } + if (*freecap) { + dd("reusing cap %p", *freecap); + cap = *freecap; + *freecap = cap->next; + cap->next = NULL; + cap->ref = 1; + + } else { + p = sre_pnalloc(pool, sizeof(sre_capture_t) + ovecsize); + if (p == NULL) { + return NULL; + } - cap = (sre_capture_t *) p; + cap = (sre_capture_t *) p; - cap->ovecsize = ovecsize; - cap->ref = 1; - cap->next = NULL; - cap->regex_id = 0; + cap->ovecsize = ovecsize; + cap->ref = 1; + cap->next = NULL; + cap->regex_id = 0; - p += sizeof(sre_capture_t); - cap->vector = (sre_int_t *) p; + p += sizeof(sre_capture_t); + cap->vector = (sre_int_t *) p; + } if (clear) { (void) memset(cap->vector, -1, ovecsize); @@ -55,18 +65,9 @@ sre_capture_update(sre_pool_t *pool, sre_capture_t *cap, sre_uint_t group, dd("update cap %u to %d", group, pos); if (cap->ref > 1) { - if (*freecap) { - dd("reusing cap %p", *freecap); - newcap = *freecap; - *freecap = newcap->next; - newcap->next = NULL; - newcap->ref = 1; - - } else { - newcap = sre_capture_create(pool, cap->ovecsize, 0); - if (newcap == NULL) { - return NULL; - } + newcap = sre_capture_create(pool, cap->ovecsize, 0, freecap); + if (newcap == NULL) { + return NULL; } memcpy(newcap->vector, cap->vector, cap->ovecsize); diff --git a/src/sregex/sre_capture.h b/src/sregex/sre_capture.h index ad6862b..a0bd8df 100644 --- a/src/sregex/sre_capture.h +++ b/src/sregex/sre_capture.h @@ -34,7 +34,7 @@ struct sre_capture_s { SRE_NOAPI sre_capture_t *sre_capture_create(sre_pool_t *pool, size_t ovecsize, - unsigned clear); + unsigned clear, sre_capture_t **freecap); SRE_NOAPI sre_capture_t *sre_capture_update(sre_pool_t *pool, sre_capture_t *cap, sre_uint_t group, sre_int_t pos, diff --git a/src/sregex/sre_core.h b/src/sregex/sre_core.h index 906f8f2..110c616 100644 --- a/src/sregex/sre_core.h +++ b/src/sregex/sre_core.h @@ -11,6 +11,7 @@ #include #include +#include #ifndef SRE_USE_VALGRIND @@ -59,4 +60,9 @@ #endif +#ifndef sre_assert +#define sre_assert assert +#endif + + #endif /* _SRE_CORE_H_INCLUDED_ */ diff --git a/src/sregex/sre_regex_compiler.c b/src/sregex/sre_regex_compiler.c index 26226df..111aafc 100644 --- a/src/sregex/sre_regex_compiler.c +++ b/src/sregex/sre_regex_compiler.c @@ -1,6 +1,6 @@ /* - * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2012-2013 Yichun Zhang (agentzh) * Copyright 2007-2009 Russ Cox. All Rights Reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. @@ -16,6 +16,11 @@ #include +static sre_int_t sre_program_get_leading_bytes(sre_pool_t *pool, + sre_program_t *prog, sre_chain_t **res); +static sre_int_t sre_program_get_leading_bytes_helper(sre_pool_t *pool, + sre_instruction_t *pc, sre_program_t *prog, sre_chain_t **res, + unsigned tag); static sre_uint_t sre_program_len(sre_regex_t *r); static sre_instruction_t *sre_regex_emit_bytecode(sre_pool_t *pool, sre_instruction_t *pc, sre_regex_t *re); @@ -70,6 +75,9 @@ sre_regex_compile(sre_pool_t *pool, sre_regex_t *re) prog->lookahead_asserts = 0; prog->dup_threads = 0; prog->uniq_threads = 0; + prog->nullable = 0; + prog->leading_bytes = NULL; + prog->leading_byte = -1; prog->ovecsize = 0; for (i = 0; i < prog->nregexes; i++) { @@ -77,10 +85,162 @@ sre_regex_compile(sre_pool_t *pool, sre_regex_t *re) } prog->ovecsize *= 2 * sizeof(sre_uint_t); + if (sre_program_get_leading_bytes(pool, prog, &prog->leading_bytes) + == SRE_ERROR) + { + return NULL; + } + + if (prog->leading_bytes && prog->leading_bytes->next == NULL) { + pc = prog->leading_bytes->data; + if (pc->opcode == SRE_OPCODE_CHAR) { + prog->leading_byte = pc->v.ch; + } + } + + dd("nullable: %u", prog->nullable); + +#if (DDEBUG) + { + sre_chain_t *cl; + + for (cl = prog->leading_bytes; cl; cl = cl->next) { + pc = cl->data; + fprintf(stderr, "["); + sre_dump_instruction(stderr, pc, prog->start); + fprintf(stderr, "]"); + } + if (prog->leading_bytes) { + fprintf(stderr, "\n"); + } + } +#endif + return prog; } +static sre_int_t +sre_program_get_leading_bytes(sre_pool_t *pool, sre_program_t *prog, + sre_chain_t **res) +{ + unsigned tag; + sre_int_t rc; + + tag = prog->tag + 1; + + rc = sre_program_get_leading_bytes_helper(pool, prog->start, prog, res, + tag); + prog->tag = tag; + + if (rc == SRE_ERROR) { + return SRE_ERROR; + } + + if (rc == SRE_DECLINED || prog->nullable) { + *res = NULL; + return SRE_DECLINED; + } + + return rc; +} + + +static sre_int_t +sre_program_get_leading_bytes_helper(sre_pool_t *pool, sre_instruction_t *pc, + sre_program_t *prog, sre_chain_t **res, unsigned tag) +{ + sre_int_t rc; + sre_chain_t *cl, *ncl; + sre_instruction_t *bc; + + if (pc->tag == tag) { + return SRE_OK; + } + + if (pc == prog->start + 1) { + /* skip the dot (.) in the initial boilerplate ".*?" */ + return SRE_OK; + } + + pc->tag = tag; + + switch (pc->opcode) { + case SRE_OPCODE_SPLIT: + rc = sre_program_get_leading_bytes_helper(pool, pc->x, prog, res, + tag); + if (rc != SRE_OK) { + return rc; + } + + return sre_program_get_leading_bytes_helper(pool, pc->y, prog, res, + tag); + + case SRE_OPCODE_JMP: + return sre_program_get_leading_bytes_helper(pool, pc->x, prog, res, + tag); + + case SRE_OPCODE_SAVE: + if (++pc == prog->start + prog->len) { + return SRE_OK; + } + + return sre_program_get_leading_bytes_helper(pool, pc, prog, res, + tag); + + case SRE_OPCODE_MATCH: + prog->nullable = 1; + return SRE_DONE; + + case SRE_OPCODE_ASSERT: + if (++pc == prog->start + prog->len) { + return SRE_OK; + } + + return sre_program_get_leading_bytes_helper(pool, pc, prog, res, tag); + + case SRE_OPCODE_ANY: + return SRE_DECLINED; + + default: + /* CHAR, ANY, IN, NOTIN */ + + ncl = sre_palloc(pool, sizeof(sre_chain_t)); + if (ncl == NULL) { + return SRE_ERROR; + } + + ncl->data = pc; + ncl->next = NULL; + + if (*res) { + for (cl = *res; /* void */; cl = cl->next) { + bc = cl->data; + if (bc->opcode == pc->opcode) { + if (bc->opcode == SRE_OPCODE_CHAR) { + if (bc->v.ch == pc->v.ch) { + return SRE_OK; + } + } + } + + if (cl->next == NULL) { + cl->next = ncl; + return SRE_OK; + } + } + + } else { + *res = ncl; + } + + return SRE_OK; + } + + /* impossible to reach here */ +} + + static sre_uint_t sre_program_len(sre_regex_t *r) { diff --git a/src/sregex/sre_vm_bytecode.c b/src/sregex/sre_vm_bytecode.c index 205403e..6ecd852 100644 --- a/src/sregex/sre_vm_bytecode.c +++ b/src/sregex/sre_vm_bytecode.c @@ -14,102 +14,109 @@ SRE_API void sre_program_dump(sre_program_t *prog) { - sre_uint_t i; - sre_vm_range_t *range; sre_instruction_t *pc, *start, *end; start = prog->start; end = prog->start + prog->len; for (pc = start; pc < end; pc++) { + sre_dump_instruction(stdout, pc, start); + printf("\n"); + } +} - switch (pc->opcode) { - case SRE_OPCODE_SPLIT: - printf("%2d. split %d, %d\n", (int) (pc - start), - (int) (pc->x - start), (int) (pc->y - start)); - break; - case SRE_OPCODE_JMP: - printf("%2d. jmp %d\n", (int) (pc - start), (int) (pc->x - start)); - break; +void +sre_dump_instruction(FILE *f, sre_instruction_t *pc, + sre_instruction_t *start) +{ + sre_vm_range_t *range; + sre_uint_t i; - case SRE_OPCODE_CHAR: - printf("%2d. char %d\n", (int) (pc - start), (int) pc->v.ch); - break; + switch (pc->opcode) { + case SRE_OPCODE_SPLIT: + fprintf(f, "%2d. split %d, %d", (int) (pc - start), + (int) (pc->x - start), (int) (pc->y - start)); + break; - case SRE_OPCODE_IN: - printf("%2d. in", (int) (pc - start)); + case SRE_OPCODE_JMP: + fprintf(f, "%2d. jmp %d", (int) (pc - start), (int) (pc->x - start)); + break; - for (i = 0; i < pc->v.ranges->count; i++) { - range = &pc->v.ranges->head[i]; - printf(" %d-%d", range->from, range->to); - } + case SRE_OPCODE_CHAR: + fprintf(f, "%2d. char %d", (int) (pc - start), (int) pc->v.ch); + break; - printf("\n"); - break; + case SRE_OPCODE_IN: + fprintf(f, "%2d. in", (int) (pc - start)); - case SRE_OPCODE_NOTIN: - printf("%2d. notin", (int) (pc - start)); + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + fprintf(f, " %d-%d", range->from, range->to); + } - for (i = 0; i < pc->v.ranges->count; i++) { - range = &pc->v.ranges->head[i]; - printf(" %d-%d", range->from, range->to); - } + break; - printf("\n"); - break; + case SRE_OPCODE_NOTIN: + fprintf(f, "%2d. notin", (int) (pc - start)); - case SRE_OPCODE_ANY: - printf("%2d. any\n", (int) (pc - start)); - break; + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + fprintf(f, " %d-%d", range->from, range->to); + } - case SRE_OPCODE_MATCH: - printf("%2d. match\n", (int) (pc - start)); - break; + break; - case SRE_OPCODE_SAVE: - printf("%2d. save %d\n", (int) (pc - start), (int) pc->v.group); - break; + case SRE_OPCODE_ANY: + fprintf(f, "%2d. any", (int) (pc - start)); + break; - case SRE_OPCODE_ASSERT: - printf("%2d. assert ", (int) (pc - start)); + case SRE_OPCODE_MATCH: + fprintf(f, "%2d. match", (int) (pc - start)); + break; - switch (pc->v.assertion) { - case SRE_REGEX_ASSERT_BIG_A: - printf("\\A"); - break; + case SRE_OPCODE_SAVE: + fprintf(f, "%2d. save %d", (int) (pc - start), + (int) pc->v.group); + break; - case SRE_REGEX_ASSERT_CARET: - printf("^"); - break; + case SRE_OPCODE_ASSERT: + fprintf(f, "%2d. assert ", (int) (pc - start)); - case SRE_REGEX_ASSERT_SMALL_Z: - printf("\\z"); - break; + switch (pc->v.assertion) { + case SRE_REGEX_ASSERT_BIG_A: + fprintf(f, "\\A"); + break; - case SRE_REGEX_ASSERT_BIG_B: - printf("\\B"); - break; + case SRE_REGEX_ASSERT_CARET: + fprintf(f, "^"); + break; - case SRE_REGEX_ASSERT_SMALL_B: - printf("\\b"); - break; + case SRE_REGEX_ASSERT_SMALL_Z: + fprintf(f, "\\z"); + break; - case SRE_REGEX_ASSERT_DOLLAR: - printf("$"); - break; + case SRE_REGEX_ASSERT_BIG_B: + fprintf(f, "\\B"); + break; - default: - printf("?"); - break; - } + case SRE_REGEX_ASSERT_SMALL_B: + fprintf(f, "\\b"); + break; - printf("\n"); + case SRE_REGEX_ASSERT_DOLLAR: + fprintf(f, "$"); break; default: - printf("%2d. unknown\n", (int) (pc - start)); + fprintf(f, "?"); break; } + + break; + + default: + fprintf(f, "%2d. unknown", (int) (pc - start)); + break; } } diff --git a/src/sregex/sre_vm_bytecode.h b/src/sregex/sre_vm_bytecode.h index 53596a3..544f274 100644 --- a/src/sregex/sre_vm_bytecode.h +++ b/src/sregex/sre_vm_bytecode.h @@ -12,6 +12,7 @@ #include +#include typedef enum { @@ -60,6 +61,14 @@ struct sre_instruction_s { }; +typedef struct sre_chain_s sre_chain_t; + +struct sre_chain_s { + void *data; + sre_chain_t *next; +}; + + struct sre_program_s { sre_instruction_t *start; sre_uint_t len; @@ -68,6 +77,9 @@ struct sre_program_s { unsigned uniq_threads; /* unique thread count */ unsigned dup_threads; /* duplicatable thread count */ unsigned lookahead_asserts; + unsigned nullable; + sre_chain_t *leading_bytes; + int leading_byte; sre_uint_t ovecsize; sre_uint_t nregexes; @@ -75,4 +87,8 @@ struct sre_program_s { }; +void sre_dump_instruction(FILE *f, sre_instruction_t *pc, + sre_instruction_t *start); + + #endif /* _SRE_BYTECODE_H_INCLUDED_ */ diff --git a/src/sregex/sre_vm_pike.c b/src/sregex/sre_vm_pike.c index 0d30788..bdb4274 100644 --- a/src/sregex/sre_vm_pike.c +++ b/src/sregex/sre_vm_pike.c @@ -38,6 +38,7 @@ struct sre_vm_pike_thread_s { typedef struct { + sre_uint_t count; sre_vm_pike_thread_t *head; sre_vm_pike_thread_t **next; } sre_vm_pike_thread_list_t; @@ -63,7 +64,11 @@ struct sre_vm_pike_ctx_s { sre_int_t last_matched_pos; /* the pos for the last (partial) match */ + sre_instruction_t **initial_states; + sre_uint_t initial_states_count; + unsigned first_buf:1; + unsigned seen_start_state:1; unsigned eof:1; unsigned empty_capture:1; unsigned seen_newline:1; @@ -80,6 +85,10 @@ static void sre_vm_pike_prepare_temp_captures(sre_program_t *prog, sre_vm_pike_ctx_t *ctx); static sre_int_t sre_vm_pike_prepare_matched_captures(sre_vm_pike_ctx_t *ctx, sre_capture_t *matched, sre_int_t *ovector, sre_int_t complete); +static sre_char *sre_vm_pike_find_first_byte(sre_char *pos, sre_char *last, + int leading_byte, sre_chain_t *leading_bytes); +static void sre_vm_pike_clear_thread_list(sre_vm_pike_ctx_t *ctx, + sre_vm_pike_thread_list_t *list); SRE_API sre_vm_pike_ctx_t * @@ -122,6 +131,10 @@ sre_vm_pike_create_ctx(sre_pool_t *pool, sre_program_t *prog, ctx->ovecsize = ovecsize; ctx->ovector = ovector; + dd("resetting seen start state"); + ctx->seen_start_state = 0; + ctx->initial_states_count = 0; + ctx->initial_states = NULL; ctx->first_buf = 1; ctx->eof = 0; ctx->empty_capture = 0; @@ -182,10 +195,14 @@ sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, sp = input; } + last = input + size; + + dd("processing buffer size %d", (int) size); + if (ctx->first_buf) { ctx->first_buf = 0; - cap = sre_capture_create(pool, prog->ovecsize, 1); + cap = sre_capture_create(pool, prog->ovecsize, 1, &ctx->free_capture); if (cap == NULL) { return SRE_ERROR; } @@ -198,12 +215,23 @@ sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, return SRE_ERROR; } + ctx->initial_states_count = clist->count; + ctx->initial_states = sre_palloc(pool, + sizeof(sre_instruction_t *) + * clist->count); + if (ctx->initial_states == NULL) { + return SRE_ERROR; + } + + /* we skip the last thread because it must always be .*? */ + for (i = 0, t = clist->head; t && t->next; i++, t = t->next) { + ctx->initial_states[i] = t->pc; + } + } else { ctx->tag = prog->tag; } - last = input + size; - for (; sp < last || (eof && sp == last); sp++) { dd("=== pos %d, offset %d (char '%c' (%d)).\n", (int)(sp - input + ctx->processed_bytes), @@ -223,17 +251,79 @@ sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, fprintf(stderr, "\n"); #endif + dd("seen start state: %d", (int) ctx->seen_start_state); + + if (prog->leading_bytes && ctx->seen_start_state) { + dd("resetting seen start state"); + ctx->seen_start_state = 0; + + if (sp == last || clist->count != ctx->initial_states_count) { + dd("skip because sp == last or " + "clist->count != initial states count!"); + goto run_cur_threads; + } + + for (i = 0, t = clist->head; t && t->next; i++, t = t->next) { + if (t->pc != ctx->initial_states[i]) { + dd("skip because pc %d unmatched: %d != %d", (int) i, + (int) (t->pc - prog->start), + (int) (ctx->initial_states[i] - prog->start)); + goto run_cur_threads; + } + } + +#if 1 + dd("XXX found initial state to do first byte search!"); + p = sre_vm_pike_find_first_byte(sp, last, prog->leading_byte, + prog->leading_bytes); + + if (p > sp) { + dd("XXX moved sp by %d bytes", (int) (p - sp)); +#if 0 + fprintf(stderr, "XXX moved sp by %d bytes\n", (int) (p - sp)); +#endif + + sp = p; + + sre_vm_pike_clear_thread_list(ctx, clist); + + cap = sre_capture_create(pool, prog->ovecsize, 1, + &ctx->free_capture); + if (cap == NULL) { + return SRE_ERROR; + } + + ctx->tag++; + rc = sre_vm_pike_add_thread(ctx, clist, prog->start, cap, + (sre_int_t) (sp - input), NULL); + if (rc != SRE_OK) { + prog->tag = ctx->tag; + return SRE_ERROR; + } + + if (sp == last) { + break; + } + } +#endif + } + +run_cur_threads: ctx->tag++; while (clist->head) { t = clist->head; clist->head = t->next; + clist->count--; pc = t->pc; cap = t->capture; - dd("--- #%u: pc %d: opcode %d\n", ctx->tag, (int)(pc - prog->start), - pc->opcode); +#if DDEBUG + fprintf(stderr, "--- #%u", ctx->tag); + sre_dump_instruction(stderr, pc, prog->start); + fprintf(stderr, "\n"); +#endif switch (pc->opcode) { case SRE_OPCODE_IN: @@ -417,6 +507,7 @@ sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, ctx->tag--; list.head = NULL; + list.count = 0; rc = sre_vm_pike_add_thread(ctx, &list, pc + 1, cap, (sre_int_t) (sp - input), NULL); @@ -428,6 +519,7 @@ sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, if (list.head) { *list.next = clist->head; clist->head = list.head; + clist->count += list.count; } ctx->tag++; @@ -456,13 +548,7 @@ sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, sre_vm_pike_free_thread(ctx, t); - while (clist->head) { - t = clist->head; - clist->head = t->next; - - sre_capture_decr_ref(ctx, t->capture); - sre_vm_pike_free_thread(ctx, t); - } + sre_vm_pike_clear_thread_list(ctx, clist); goto step_done; @@ -486,9 +572,7 @@ sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, nlist = tmp; if (nlist->head) { - *nlist->next = ctx->free_threads; - ctx->free_threads = nlist->head; - nlist->head = NULL; + sre_vm_pike_clear_thread_list(ctx, nlist); } if (sp == last) { @@ -533,6 +617,7 @@ sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, *clist->next = ctx->free_threads; ctx->free_threads = clist->head; clist->head = NULL; + clist->count = 0; ctx->eof = 1; } @@ -662,6 +747,7 @@ sre_vm_pike_thread_list_create(sre_pool_t *pool) l->head = NULL; l->next = &l->head; + l->count = 0; return l; } @@ -687,6 +773,11 @@ sre_vm_pike_add_thread(sre_vm_pike_ctx_t *ctx, sre_vm_pike_thread_list_t *l, if (pc->opcode == SRE_OPCODE_SPLIT) { if (pc->y->tag != ctx->tag) { + if (pc == ctx->program->start) { + dd("setting seen start state"); + ctx->seen_start_state = 1; + } + return sre_vm_pike_add_thread(ctx, l, pc->y, capture, pos, pcap); } @@ -705,6 +796,11 @@ sre_vm_pike_add_thread(sre_vm_pike_ctx_t *ctx, sre_vm_pike_thread_list_t *l, return sre_vm_pike_add_thread(ctx, l, pc->x, capture, pos, pcap); case SRE_OPCODE_SPLIT: + if (pc == ctx->program->start) { + dd("setting seen start state"); + ctx->seen_start_state = 1; + } + capture->ref++; rc = sre_vm_pike_add_thread(ctx, l, pc->x, capture, pos, pcap); @@ -740,7 +836,6 @@ sre_vm_pike_add_thread(sre_vm_pike_ctx_t *ctx, sre_vm_pike_thread_list_t *l, return sre_vm_pike_add_thread(ctx, l, pc + 1, cap, pos, pcap); - case SRE_OPCODE_ASSERT: switch (pc->v.assertion) { case SRE_REGEX_ASSERT_BIG_A: @@ -834,6 +929,7 @@ sre_vm_pike_add_thread(sre_vm_pike_ctx_t *ctx, sre_vm_pike_thread_list_t *l, *l->next = t; } + l->count++; l->next = &t->next; dd("added thread: pc %d, bytecode %d", (int) (pc - ctx->program->start), @@ -891,3 +987,94 @@ sre_vm_pike_prepare_matched_captures(sre_vm_pike_ctx_t *ctx, return SRE_OK; } + + +static sre_char * +sre_vm_pike_find_first_byte(sre_char *pos, sre_char *last, + int leading_byte, sre_chain_t *leading_bytes) +{ +#if 1 + int in; + sre_uint_t i; + sre_chain_t *cl; + sre_instruction_t *pc; + sre_vm_range_t *range; + + /* optimize for single CHAR bc */ + if (leading_byte != -1) { + pos = memchr(pos, leading_byte, last - pos); + if (pos == NULL) { + return last; + } + + return pos; + } + + for ( ; pos != last; pos++) { + for (cl = leading_bytes; cl; cl = cl->next) { + pc = cl->data; + switch (pc->opcode) { + case SRE_OPCODE_CHAR: + if (*pos == pc->v.ch) { + return pos; + } + + break; + + case SRE_OPCODE_IN: + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + if (*pos >= range->from && *pos <= range->to) { + return pos; + } + } + + break; + + case SRE_OPCODE_NOTIN: + in = 0; + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + if (*pos >= range->from && *pos <= range->to) { + in = 1; + break; + } + } + + if (in == 0) { + return pos; + } + + break; + + default: + sre_assert(pc->opcode); + break; + } + } + } +#endif + + return pos; +} + + +static void +sre_vm_pike_clear_thread_list(sre_vm_pike_ctx_t *ctx, + sre_vm_pike_thread_list_t *list) +{ + sre_vm_pike_thread_t *t; + + while (list->head) { + t = list->head; + list->head = t->next; + list->count--; + + sre_capture_decr_ref(ctx, t->capture); + sre_vm_pike_free_thread(ctx, t); + } + + sre_assert(list->count == 0); +}