diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2009-03-19 18:30:51 +0300 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2009-03-19 18:30:51 +0300 |
commit | 4ab332a14d58b2cc9848648e460002f676f0bb56 (patch) | |
tree | 2d8b1f3e0b7edade44694e2bb20dac8fffd3ab2a /src | |
parent | e1250bcf595973ff46cf7766590a1491eddfe60d (diff) | |
download | rspamd-4ab332a14d58b2cc9848648e460002f676f0bb56.tar.gz rspamd-4ab332a14d58b2cc9848648e460002f676f0bb56.zip |
* Add optimization support for regexps
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/regexp.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/src/plugins/regexp.c b/src/plugins/regexp.c index ab9a02220..8c3a9d354 100644 --- a/src/plugins/regexp.c +++ b/src/plugins/regexp.c @@ -264,12 +264,45 @@ process_regexp (struct rspamd_regexp *re, struct worker_task *task) return 0; } +static gboolean +optimize_regexp_expression (struct expression **e, GQueue *stack, gboolean res) +{ + struct expression *it = *e; + gboolean ret = FALSE; + + while (it) { + /* Find first operation for this iterator */ + if (it->type == EXPR_OPERATION) { + /* If this operation is just ! just inverse res and check for further operators */ + if (it->content.operation == '!') { + res = !res; + continue; + } + else if (it->content.operation == '&' && res == FALSE) { + e = ⁢ + ret = TRUE; + } + else if (it->content.operation == '|' && res == TRUE) { + e = ⁢ + ret = TRUE; + } + break; + } + it = it->next; + } + + g_queue_push_head (stack, GSIZE_TO_POINTER (res)); + + return ret; +} + static void process_regexp_item (struct regexp_module_item *item, struct worker_task *task) { GQueue *stack; gsize cur, op1, op2; struct expression *it = item->expr; + gboolean try_optimize = TRUE; stack = g_queue_new (); @@ -278,18 +311,28 @@ process_regexp_item (struct regexp_module_item *item, struct worker_task *task) /* Find corresponding symbol */ cur = process_regexp ((struct rspamd_regexp *)it->content.operand, task); msg_debug ("process_regexp_item: regexp %s found", cur ? "is" : "is not"); - g_queue_push_head (stack, GSIZE_TO_POINTER (cur)); + if (try_optimize) { + try_optimize = optimize_regexp_expression (&it, stack, cur); + } else { + g_queue_push_head (stack, GSIZE_TO_POINTER (cur)); + } + } else if (it->type == EXPR_FUNCTION) { cur = (gsize)call_expression_function ((struct expression_function *)it->content.operand, task); msg_debug ("process_regexp_item: function %s returned %s", ((struct expression_function *)it->content.operand)->name, cur ? "true" : "false"); - g_queue_push_head (stack, GSIZE_TO_POINTER (cur)); + if (try_optimize) { + try_optimize = optimize_regexp_expression (&it, stack, cur); + } else { + g_queue_push_head (stack, GSIZE_TO_POINTER (cur)); + } } else if (it->type == EXPR_OPERATION) { if (g_queue_is_empty (stack)) { /* Queue has no operands for operation, exiting */ g_queue_free (stack); return; } + try_optimize = TRUE; switch (it->content.operation) { case '!': op1 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); |