From fea72a49aa4cfdf749d8293a031761896f2e4c8f Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Thu, 19 Mar 2015 10:04:56 +0000 Subject: [PATCH] Write optimizator for plus operator. --- src/libutil/expression.c | 152 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 2 deletions(-) diff --git a/src/libutil/expression.c b/src/libutil/expression.c index e103b5b60..113b87eca 100644 --- a/src/libutil/expression.c +++ b/src/libutil/expression.c @@ -549,8 +549,11 @@ err: gint rspamd_process_expression (struct rspamd_expression *expr, gpointer data) { - struct rspamd_expression_elt *elt, *st_elt[2], *ev; - guint i; + struct rspamd_expression_elt *elt, *st_elt[2], *ev, *lim = NULL, + *cmp_op = NULL, *check; + guint i, j, cmp_pos = 0; + gint cur_value = 0; + gboolean done = FALSE; g_assert (expr != NULL); /* Ensure that stack is empty at this point */ @@ -563,6 +566,10 @@ rspamd_process_expression (struct rspamd_expression *expr, gpointer data) if (elt->type == ELT_ATOM || elt->type == ELT_LIMIT) { /* Push this value to the stack without processing */ rspamd_expr_stack_push (expr, elt); + if (elt->type == ELT_LIMIT) { + /* Save for optimizator */ + lim = elt; + } } else { /* @@ -621,6 +628,147 @@ rspamd_process_expression (struct rspamd_expression *expr, gpointer data) rspamd_expr_stack_push (expr, ev); } break; + case OP_PLUS: { + /* First we search for a comparision operator */ + if (lim == NULL || cmp_op == NULL) { + for (j = i + 1; j < expr->expressions->len; j ++) { + check = &g_array_index (expr->expressions, + struct rspamd_expression_elt, j); + if (check->type == ELT_LIMIT && lim == NULL) { + lim = check; + } + else if (check->type == ELT_OP && check->p.op >= OP_LT && + cmp_op == NULL) { + cmp_op = check; + cmp_pos = j; + } + + if (cmp_op && lim) { + break; + } + } + } + g_assert (cmp_op != NULL && lim != NULL); + + g_assert (expr->expression_stack->len > 1); + st_elt[0] = rspamd_expr_stack_pop (expr); + st_elt[1] = rspamd_expr_stack_pop (expr); + ev = CHOSE_OPERAND (st_elt[0], st_elt[1]); + PROCESS_ELT (expr, ev); + cur_value = ev->value; + ev = CHOOSE_REMAIN (st_elt[0], st_elt[1], ev); + PROCESS_ELT (expr, ev); + cur_value += ev->value; + ev->value = cur_value; + /* Now we can check the value against limit */ + switch (cmp_op->p.op) { + case OP_LT: + if (cur_value >= lim->p.lim.val) { + ev->value = 0; + rspamd_expr_stack_push (expr, ev); + done = TRUE; + } + break; + case OP_LE: + if (cur_value > lim->p.lim.val) { + ev->value = 0; + rspamd_expr_stack_push (expr, ev); + done = TRUE; + } + break; + case OP_GT: + if (cur_value > lim->p.lim.val) { + ev->value = 1; + rspamd_expr_stack_push (expr, ev); + done = TRUE; + } + break; + case OP_GE: + if (cur_value >= lim->p.lim.val) { + ev->value = 1; + rspamd_expr_stack_push (expr, ev); + done = TRUE; + } + break; + default: + rspamd_expr_stack_push (expr, ev); + break; + } + /* If we done, then we go forward and skip remaining items */ + if (done) { + i = cmp_pos + 1; + done = FALSE; + lim = NULL; + cur_value = 0; + cmp_op = NULL; + } + break; + } + case OP_LT: + case OP_LE: + case OP_GT: + case OP_GE: { + g_assert (expr->expression_stack->len > 1); + st_elt[0] = rspamd_expr_stack_pop (expr); + st_elt[1] = rspamd_expr_stack_pop (expr); + + if (st_elt[0]->type == ELT_LIMIT) { + lim = st_elt[0]; + ev = st_elt[1]; + } + else { + lim = st_elt[1]; + ev = st_elt[0]; + } + + g_assert (lim->type == ELT_LIMIT && ev->type == ELT_ATOM); + cur_value = ev->value; + + switch (elt->p.op) { + case OP_LT: + if (cur_value >= lim->p.lim.val) { + ev->value = 0; + } + else { + ev->value = 1; + } + break; + case OP_LE: + if (cur_value > lim->p.lim.val) { + ev->value = 0; + } + else { + ev->value = 1; + } + break; + case OP_GT: + if (cur_value > lim->p.lim.val) { + ev->value = 1; + } + else { + ev->value = 0; + } + break; + case OP_GE: + if (cur_value >= lim->p.lim.val) { + ev->value = 1; + } + else { + ev->value = 0; + } + break; + default: + g_assert (0); + break; + } + + done = FALSE; + lim = NULL; + cur_value = 0; + cmp_op = NULL; + rspamd_expr_stack_push (expr, ev); + break; + } default: g_assert (0); break; -- 2.39.5