Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FilterX operator optimization for literals #390

Merged
merged 9 commits into from
Nov 29, 2024
78 changes: 62 additions & 16 deletions lib/filterx/expr-boolalg.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@
*/
#include "filterx/expr-boolalg.h"
#include "filterx/object-primitive.h"
#include "filterx/expr-literal.h"

static inline gboolean
_literal_expr_truthy(FilterXExpr *expr)
{
FilterXObject *result = filterx_expr_eval(expr);
g_assert(result);

gboolean truthy = filterx_object_truthy(result);
filterx_object_unref(result);

return truthy;
}

static FilterXObject *
_eval_not(FilterXExpr *s)
Expand All @@ -44,6 +57,9 @@ _eval_not(FilterXExpr *s)
FilterXExpr *
filterx_unary_not_new(FilterXExpr *operand)
{
if (filterx_expr_is_literal(operand))
return filterx_literal_new(filterx_boolean_new(!_literal_expr_truthy(operand)));

FilterXUnaryOp *self = g_new0(FilterXUnaryOp, 1);

filterx_unary_op_init_instance(self, operand);
Expand All @@ -59,17 +75,20 @@ _eval_and(FilterXExpr *s)
/* we only evaluate our rhs if lhs is true, e.g. we do fast circuit
* evaluation just like most languages */

FilterXObject *result = filterx_expr_eval(self->lhs);
if (!result)
return NULL;
if (self->lhs)
{
FilterXObject *result = filterx_expr_eval(self->lhs);
if (!result)
return NULL;

gboolean lhs_truthy = filterx_object_truthy(result);
filterx_object_unref(result);
gboolean lhs_truthy = filterx_object_truthy(result);
filterx_object_unref(result);

if (!lhs_truthy)
return filterx_boolean_new(FALSE);
if (!lhs_truthy)
return filterx_boolean_new(FALSE);
}

result = filterx_expr_eval(self->rhs);
FilterXObject *result = filterx_expr_eval(self->rhs);
if (!result)
return NULL;

Expand All @@ -85,9 +104,21 @@ _eval_and(FilterXExpr *s)
FilterXExpr *
filterx_binary_and_new(FilterXExpr *lhs, FilterXExpr *rhs)
{
if (filterx_expr_is_literal(lhs))
{
if (!_literal_expr_truthy(lhs))
return filterx_literal_new(filterx_boolean_new(FALSE));

if (filterx_expr_is_literal(rhs))
return filterx_literal_new(filterx_boolean_new(_literal_expr_truthy(rhs)));
}

FilterXBinaryOp *self = g_new0(FilterXBinaryOp, 1);

filterx_binary_op_init_instance(self, lhs, rhs);
if (filterx_expr_is_literal(lhs))
self->lhs = NULL;

self->super.eval = _eval_and;
return &self->super;
}
Expand All @@ -100,17 +131,20 @@ _eval_or(FilterXExpr *s)
/* we only evaluate our rhs if lhs is false, e.g. we do fast circuit
* evaluation just like most languages */

FilterXObject *result = filterx_expr_eval(self->lhs);
if (!result)
return NULL;
if (self->lhs)
{
FilterXObject *result = filterx_expr_eval(self->lhs);
if (!result)
return NULL;

gboolean lhs_truthy = filterx_object_truthy(result);
filterx_object_unref(result);
gboolean lhs_truthy = filterx_object_truthy(result);
filterx_object_unref(result);

if (lhs_truthy)
return filterx_boolean_new(TRUE);
if (lhs_truthy)
return filterx_boolean_new(TRUE);
}

result = filterx_expr_eval(self->rhs);
FilterXObject *result = filterx_expr_eval(self->rhs);
if (!result)
return NULL;

Expand All @@ -126,9 +160,21 @@ _eval_or(FilterXExpr *s)
FilterXExpr *
filterx_binary_or_new(FilterXExpr *lhs, FilterXExpr *rhs)
{
if (filterx_expr_is_literal(lhs))
{
if (_literal_expr_truthy(lhs))
return filterx_literal_new(filterx_boolean_new(TRUE));

if (filterx_expr_is_literal(rhs))
return filterx_literal_new(filterx_boolean_new(_literal_expr_truthy(rhs)));
}

FilterXBinaryOp *self = g_new0(FilterXBinaryOp, 1);

filterx_binary_op_init_instance(self, lhs, rhs);
if (filterx_expr_is_literal(lhs))
self->lhs = NULL;

self->super.eval = _eval_or;
return &self->super;
}
45 changes: 40 additions & 5 deletions lib/filterx/expr-comparison.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "filterx/object-message-value.h"
#include "filterx/filterx-object-istype.h"
#include "filterx/filterx-ref.h"
#include "filterx/expr-literal.h"
#include "object-primitive.h"
#include "generic-number.h"
#include "parse-number.h"
Expand All @@ -42,6 +43,8 @@ typedef struct _FilterXComparison
{
FilterXBinaryOp super;
gint operator;
FilterXObject *literal_lhs;
FilterXObject *literal_rhs;
} FilterXComparison;

static void
Expand Down Expand Up @@ -187,22 +190,28 @@ _evaluate_type_and_value_based(FilterXObject *lhs, FilterXObject *rhs, gint oper
return _evaluate_type_aware(lhs, rhs, operator);
}

static inline FilterXObject *
_eval_based_on_compare_mode(FilterXExpr *expr, gint compare_mode)
{
gboolean typed_eval_needed = compare_mode & FCMPX_TYPE_AWARE || compare_mode & FCMPX_TYPE_AND_VALUE_BASED;
return typed_eval_needed ? filterx_expr_eval_typed(expr) : filterx_expr_eval(expr);
}

static FilterXObject *
_eval(FilterXExpr *s)
{
FilterXComparison *self = (FilterXComparison *) s;

gint compare_mode = self->operator & FCMPX_MODE_MASK;
gint operator = self->operator & FCMPX_OP_MASK;
gboolean typed_eval_needed = compare_mode & FCMPX_TYPE_AWARE || compare_mode & FCMPX_TYPE_AND_VALUE_BASED;

FilterXObject *lhs_object = typed_eval_needed ? filterx_expr_eval_typed(self->super.lhs) : filterx_expr_eval(
self->super.lhs);
FilterXObject *lhs_object = self->literal_lhs ? filterx_object_ref(self->literal_lhs)
: _eval_based_on_compare_mode(self->super.lhs, compare_mode);
if (!lhs_object)
return NULL;

FilterXObject *rhs_object = typed_eval_needed ? filterx_expr_eval_typed(self->super.rhs) : filterx_expr_eval(
self->super.rhs);
FilterXObject *rhs_object = self->literal_rhs ? filterx_object_ref(self->literal_rhs)
: _eval_based_on_compare_mode(self->super.rhs, compare_mode);
if (!rhs_object)
{
filterx_object_unref(lhs_object);
Expand All @@ -228,6 +237,16 @@ _eval(FilterXExpr *s)
return filterx_boolean_new(result);
}

static void
_filterx_comparison_free(FilterXExpr *s)
{
FilterXComparison *self = (FilterXComparison *) s;
filterx_object_unref(self->literal_lhs);
filterx_object_unref(self->literal_rhs);

filterx_binary_op_free_method(s);
}

/* NOTE: takes the object reference */
FilterXExpr *
filterx_comparison_new(FilterXExpr *lhs, FilterXExpr *rhs, gint operator)
Expand All @@ -236,6 +255,22 @@ filterx_comparison_new(FilterXExpr *lhs, FilterXExpr *rhs, gint operator)

filterx_binary_op_init_instance(&self->super, lhs, rhs);
self->super.super.eval = _eval;
self->super.super.free_fn = _filterx_comparison_free;
self->operator = operator;

gint compare_mode = self->operator & FCMPX_MODE_MASK;
if (filterx_expr_is_literal(lhs))
self->literal_lhs = _eval_based_on_compare_mode(lhs, compare_mode);

if (filterx_expr_is_literal(rhs))
self->literal_rhs = _eval_based_on_compare_mode(rhs, compare_mode);

if (filterx_expr_is_literal(lhs) && filterx_expr_is_literal(rhs))
{
FilterXExpr *optimized = filterx_literal_new(_eval(&self->super.super));
filterx_expr_unref(&self->super.super);
return optimized;
}

return &self->super.super;
}
35 changes: 35 additions & 0 deletions lib/filterx/expr-condition.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/

#include "filterx/expr-condition.h"
#include "filterx/expr-literal.h"
#include "filterx/object-primitive.h"
#include "scratch-buffers.h"

Expand Down Expand Up @@ -182,3 +183,37 @@ filterx_conditional_find_tail(FilterXExpr *s)
}
return s;
}

FilterXExpr *
filterx_literal_conditional(FilterXExpr *condition, FilterXExpr *true_branch, FilterXExpr *false_branch)
{
g_assert(filterx_expr_is_literal(condition));

FilterXObject *condition_value = filterx_expr_eval(condition);
g_assert(condition_value);

FilterXExpr *optimized = NULL;

if (filterx_object_truthy(condition_value))
{
if (true_branch)
optimized = true_branch;
else
optimized = filterx_expr_ref(condition);

filterx_expr_unref(false_branch);
}
else
{
if (false_branch)
optimized = false_branch;
else
optimized = filterx_literal_new(filterx_boolean_new(TRUE));

filterx_expr_unref(true_branch);
}

filterx_object_unref(condition_value);
filterx_expr_unref(condition);
return optimized;
}
2 changes: 2 additions & 0 deletions lib/filterx/expr-condition.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ void filterx_conditional_set_false_branch(FilterXExpr *s, FilterXExpr *false_bra
FilterXExpr *filterx_conditional_find_tail(FilterXExpr *s);
FilterXExpr *filterx_conditional_new(FilterXExpr *condition);

FilterXExpr *filterx_literal_conditional(FilterXExpr *condition, FilterXExpr *true_branch, FilterXExpr *false_branch);

#endif
14 changes: 14 additions & 0 deletions lib/filterx/expr-null-coalesce.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

#include "filterx/expr-null-coalesce.h"
#include "filterx/expr-literal.h"
#include "filterx/object-null.h"
#include "filterx/filterx-eval.h"
#include "filterx/object-message-value.h"
Expand Down Expand Up @@ -61,6 +62,19 @@ _eval(FilterXExpr *s)
FilterXExpr *
filterx_null_coalesce_new(FilterXExpr *lhs, FilterXExpr *rhs)
{
if (filterx_expr_is_literal(lhs))
{
FilterXObject *lhs_object = filterx_expr_eval(lhs);
if (!lhs_object || filterx_object_is_type(lhs_object, &FILTERX_TYPE_NAME(null)))
{
filterx_object_unref(lhs_object);
return rhs;
}

filterx_object_unref(lhs_object);
return lhs;
}

FilterXNullCoalesce *self = g_new0(FilterXNullCoalesce, 1);
filterx_binary_op_init_instance(&self->super, lhs, rhs);
self->super.super.eval = _eval;
Expand Down
34 changes: 32 additions & 2 deletions lib/filterx/expr-plus.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,28 @@
#include "expr-plus.h"
#include "object-string.h"
#include "filterx-eval.h"
#include "filterx/expr-literal.h"
#include "scratch-buffers.h"

typedef struct FilterXOperatorPlus
{
FilterXBinaryOp super;
FilterXObject *literal_lhs;
FilterXObject *literal_rhs;
} FilterXOperatorPlus;

static FilterXObject *
_eval(FilterXExpr *s)
{
FilterXOperatorPlus *self = (FilterXOperatorPlus *) s;

FilterXObject *lhs_object = filterx_expr_eval_typed(self->super.lhs);
FilterXObject *lhs_object = self->literal_lhs ? filterx_object_ref(self->literal_lhs)
: filterx_expr_eval_typed(self->super.lhs);
if (!lhs_object)
return NULL;

FilterXObject *rhs_object = filterx_expr_eval(self->super.rhs);
FilterXObject *rhs_object = self->literal_rhs ? filterx_object_ref(self->literal_rhs)
: filterx_expr_eval(self->super.rhs);
if (!rhs_object)
{
filterx_object_unref(lhs_object);
Expand All @@ -52,11 +57,36 @@ _eval(FilterXExpr *s)
return res;
}

static void
_filterx_operator_plus_free(FilterXExpr *s)
{
FilterXOperatorPlus *self = (FilterXOperatorPlus *) s;
filterx_object_unref(self->literal_lhs);
filterx_object_unref(self->literal_rhs);

filterx_binary_op_free_method(s);
}

FilterXExpr *
filterx_operator_plus_new(FilterXExpr *lhs, FilterXExpr *rhs)
{
FilterXOperatorPlus *self = g_new0(FilterXOperatorPlus, 1);
filterx_binary_op_init_instance(&self->super, lhs, rhs);
self->super.super.eval = _eval;
self->super.super.free_fn = _filterx_operator_plus_free;

if (filterx_expr_is_literal(lhs))
self->literal_lhs = filterx_expr_eval_typed(lhs);

if (filterx_expr_is_literal(rhs))
self->literal_rhs = filterx_expr_eval(rhs);

if (filterx_expr_is_literal(lhs) && filterx_expr_is_literal(rhs))
{
FilterXExpr *optimized = filterx_literal_new(_eval(&self->super.super));
filterx_expr_unref(&self->super.super);
return optimized;
}

return &self->super.super;
}
Loading