]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
Write optimizator for plus operator.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 19 Mar 2015 10:04:56 +0000 (10:04 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 19 Mar 2015 10:04:56 +0000 (10:04 +0000)
src/libutil/expression.c

index e103b5b6025830fa202138ba1544cede11126097..113b87ecad051d3e6e4efee328ea377d80f99f37 100644 (file)
@@ -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;