aboutsummaryrefslogtreecommitdiffstats
path: root/src/libutil/expression.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2015-03-19 10:04:56 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2015-03-19 10:04:56 +0000
commitfea72a49aa4cfdf749d8293a031761896f2e4c8f (patch)
treebe2777fb79ff71a68c3b109bb9b5671e942104dd /src/libutil/expression.c
parentc6f68e6c198e2c4fcb8453a5ea43730d476e3673 (diff)
downloadrspamd-fea72a49aa4cfdf749d8293a031761896f2e4c8f.tar.gz
rspamd-fea72a49aa4cfdf749d8293a031761896f2e4c8f.zip
Write optimizator for plus operator.
Diffstat (limited to 'src/libutil/expression.c')
-rw-r--r--src/libutil/expression.c152
1 files 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;