diff options
author | Håvard Pettersen <havardpe@oath.com> | 2017-10-19 13:30:50 +0000 |
---|---|---|
committer | Håvard Pettersen <havardpe@oath.com> | 2017-10-19 13:33:42 +0000 |
commit | 4ad63aeca673e665a773cda0c5a61b85940f7d18 (patch) | |
tree | d625e0b079113257b2383bb24b86375ad87bf836 /eval | |
parent | b2bca50263aa1a7dbd3c30b932296507bce0db7a (diff) |
use raw function pointers for map/join
Diffstat (limited to 'eval')
-rw-r--r-- | eval/src/vespa/eval/eval/operation.cpp | 29 | ||||
-rw-r--r-- | eval/src/vespa/eval/eval/operation.h | 36 | ||||
-rw-r--r-- | eval/src/vespa/eval/eval/simple_tensor.cpp | 4 | ||||
-rw-r--r-- | eval/src/vespa/eval/eval/simple_tensor.h | 7 | ||||
-rw-r--r-- | eval/src/vespa/eval/eval/simple_tensor_engine.cpp | 8 | ||||
-rw-r--r-- | eval/src/vespa/eval/eval/simple_tensor_engine.h | 4 | ||||
-rw-r--r-- | eval/src/vespa/eval/eval/tensor_engine.h | 6 | ||||
-rw-r--r-- | eval/src/vespa/eval/eval/test/tensor_conformance.cpp | 16 | ||||
-rw-r--r-- | eval/src/vespa/eval/tensor/default_tensor_engine.cpp | 4 | ||||
-rw-r--r-- | eval/src/vespa/eval/tensor/default_tensor_engine.h | 4 |
10 files changed, 94 insertions, 24 deletions
diff --git a/eval/src/vespa/eval/eval/operation.cpp b/eval/src/vespa/eval/eval/operation.cpp index f650f6ae194..2fb8d4e1ac8 100644 --- a/eval/src/vespa/eval/eval/operation.cpp +++ b/eval/src/vespa/eval/eval/operation.cpp @@ -4,6 +4,7 @@ #include "value.h" #include "operation_visitor.h" #include <cmath> +#include <assert.h> namespace vespalib { namespace eval { @@ -36,6 +37,34 @@ BinaryOperation::perform(const Value &lhs, const Value &rhs, Stash &stash) const } } +__thread const UnaryOperation *UnaryOperationProxy::_ctx = nullptr; +double UnaryOperationProxy::eval_proxy(double a) { return _ctx->eval(a); } +UnaryOperationProxy::UnaryOperationProxy(const UnaryOperation &op) + : _my_ctx(&op), + _old_ctx(_ctx) +{ + _ctx = _my_ctx; +} +UnaryOperationProxy::~UnaryOperationProxy() +{ + assert(_ctx == _my_ctx); + _ctx = _old_ctx; +} + +__thread const BinaryOperation *BinaryOperationProxy::_ctx = nullptr; +double BinaryOperationProxy::eval_proxy(double a, double b) { return _ctx->eval(a, b); } +BinaryOperationProxy::BinaryOperationProxy(const BinaryOperation &op) + : _my_ctx(&op), + _old_ctx(_ctx) +{ + _ctx = _my_ctx; +} +BinaryOperationProxy::~BinaryOperationProxy() +{ + assert(_ctx == _my_ctx); + _ctx = _old_ctx; +} + template <typename T> void Op1<T>::accept(OperationVisitor &visitor) const { visitor.visit(static_cast<const T&>(*this)); } diff --git a/eval/src/vespa/eval/eval/operation.h b/eval/src/vespa/eval/eval/operation.h index f68998218eb..52ad9047dd6 100644 --- a/eval/src/vespa/eval/eval/operation.h +++ b/eval/src/vespa/eval/eval/operation.h @@ -52,6 +52,42 @@ struct BinaryOperation : Operation { //----------------------------------------------------------------------------- +/** + * Utility class used to adapt stateless function pointers to stateful + * functors by using thread-local bindings. + **/ +class UnaryOperationProxy { +private: + static __thread const UnaryOperation *_ctx; + static double eval_proxy(double a); + const UnaryOperation *_my_ctx; + const UnaryOperation *_old_ctx; +public: + using fun_t = double (*)(double); + UnaryOperationProxy(const UnaryOperation &op); + operator fun_t() const { return eval_proxy; } + ~UnaryOperationProxy(); +}; + +/** + * Utility class used to adapt stateless function pointers to stateful + * functors by using thread-local bindings. + **/ +class BinaryOperationProxy { +private: + static __thread const BinaryOperation *_ctx; + static double eval_proxy(double a, double b); + const BinaryOperation *_my_ctx; + const BinaryOperation *_old_ctx; +public: + using fun_t = double (*)(double, double); + BinaryOperationProxy(const BinaryOperation &op); + operator fun_t() const { return eval_proxy; } + ~BinaryOperationProxy(); +}; + +//----------------------------------------------------------------------------- + template <typename T> struct Op1 : UnaryOperation { virtual void accept(OperationVisitor &visitor) const override; diff --git a/eval/src/vespa/eval/eval/simple_tensor.cpp b/eval/src/vespa/eval/eval/simple_tensor.cpp index 628939550c5..37d2e8747ef 100644 --- a/eval/src/vespa/eval/eval/simple_tensor.cpp +++ b/eval/src/vespa/eval/eval/simple_tensor.cpp @@ -543,7 +543,7 @@ SimpleTensor::SimpleTensor(const ValueType &type_in, Cells cells_in) } std::unique_ptr<SimpleTensor> -SimpleTensor::map(const std::function<double(double)> &function) const +SimpleTensor::map(map_fun_t function) const { Cells cells(_cells); for (auto &cell: cells) { @@ -629,7 +629,7 @@ SimpleTensor::equal(const SimpleTensor &a, const SimpleTensor &b) } std::unique_ptr<SimpleTensor> -SimpleTensor::join(const SimpleTensor &a, const SimpleTensor &b, const std::function<double(double,double)> &function) +SimpleTensor::join(const SimpleTensor &a, const SimpleTensor &b, join_fun_t function) { ValueType result_type = ValueType::join(a.type(), b.type()); if (result_type.is_error()) { diff --git a/eval/src/vespa/eval/eval/simple_tensor.h b/eval/src/vespa/eval/eval/simple_tensor.h index 596d70c331a..3de80483fb3 100644 --- a/eval/src/vespa/eval/eval/simple_tensor.h +++ b/eval/src/vespa/eval/eval/simple_tensor.h @@ -75,17 +75,20 @@ private: Cells _cells; public: + using map_fun_t = double (*)(double); + using join_fun_t = double (*)(double, double); + SimpleTensor(); explicit SimpleTensor(double value); SimpleTensor(const ValueType &type_in, Cells cells_in); const ValueType &type() const { return _type; } const Cells &cells() const { return _cells; } - std::unique_ptr<SimpleTensor> map(const std::function<double(double)> &function) const; + std::unique_ptr<SimpleTensor> map(map_fun_t function) const; std::unique_ptr<SimpleTensor> reduce(Aggregator &aggr, const std::vector<vespalib::string> &dimensions) const; std::unique_ptr<SimpleTensor> rename(const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to) const; static std::unique_ptr<SimpleTensor> create(const TensorSpec &spec); static bool equal(const SimpleTensor &a, const SimpleTensor &b); - static std::unique_ptr<SimpleTensor> join(const SimpleTensor &a, const SimpleTensor &b, const std::function<double(double,double)> &function); + static std::unique_ptr<SimpleTensor> join(const SimpleTensor &a, const SimpleTensor &b, join_fun_t function); static std::unique_ptr<SimpleTensor> concat(const SimpleTensor &a, const SimpleTensor &b, const vespalib::string &dimension); static void encode(const SimpleTensor &tensor, nbostream &output); static std::unique_ptr<SimpleTensor> decode(nbostream &input); diff --git a/eval/src/vespa/eval/eval/simple_tensor_engine.cpp b/eval/src/vespa/eval/eval/simple_tensor_engine.cpp index 898e732b196..18c0f8b471a 100644 --- a/eval/src/vespa/eval/eval/simple_tensor_engine.cpp +++ b/eval/src/vespa/eval/eval/simple_tensor_engine.cpp @@ -127,13 +127,13 @@ SimpleTensorEngine::reduce(const eval::Tensor &tensor, const BinaryOperation &op const Value & SimpleTensorEngine::map(const UnaryOperation &op, const eval::Tensor &a, Stash &stash) const { - return to_value(to_simple(a).map([&op](double x){ return op.eval(x); }), stash); + return to_value(to_simple(a).map(UnaryOperationProxy(op)), stash); } const Value & SimpleTensorEngine::apply(const BinaryOperation &op, const eval::Tensor &a, const eval::Tensor &b, Stash &stash) const { - return to_value(SimpleTensor::join(to_simple(a), to_simple(b), [&op](double x, double y){ return op.eval(x, y); }), stash); + return to_value(SimpleTensor::join(to_simple(a), to_simple(b), BinaryOperationProxy(op)), stash); } //----------------------------------------------------------------------------- @@ -153,13 +153,13 @@ SimpleTensorEngine::decode(nbostream &input, Stash &stash) const //----------------------------------------------------------------------------- const Value & -SimpleTensorEngine::map(const Value &a, const std::function<double(double)> &function, Stash &stash) const +SimpleTensorEngine::map(const Value &a, map_fun_t function, Stash &stash) const { return to_value(to_simple(a, stash).map(function), stash); } const Value & -SimpleTensorEngine::join(const Value &a, const Value &b, const std::function<double(double,double)> &function, Stash &stash) const +SimpleTensorEngine::join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const { return to_value(SimpleTensor::join(to_simple(a, stash), to_simple(b, stash), function), stash); } diff --git a/eval/src/vespa/eval/eval/simple_tensor_engine.h b/eval/src/vespa/eval/eval/simple_tensor_engine.h index 4a4b937d6e0..aebb11036ff 100644 --- a/eval/src/vespa/eval/eval/simple_tensor_engine.h +++ b/eval/src/vespa/eval/eval/simple_tensor_engine.h @@ -31,8 +31,8 @@ public: void encode(const Value &value, nbostream &output, Stash &stash) const override; const Value &decode(nbostream &input, Stash &stash) const override; - const Value &map(const Value &a, const std::function<double(double)> &function, Stash &stash) const override; - const Value &join(const Value &a, const Value &b, const std::function<double(double,double)> &function, Stash &stash) const override; + const Value &map(const Value &a, map_fun_t function, Stash &stash) const override; + const Value &join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const override; const Value &reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const override; const Value &concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const override; const Value &rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const override; diff --git a/eval/src/vespa/eval/eval/tensor_engine.h b/eval/src/vespa/eval/eval/tensor_engine.h index 6c83dd3ec3d..ef269d934d5 100644 --- a/eval/src/vespa/eval/eval/tensor_engine.h +++ b/eval/src/vespa/eval/eval/tensor_engine.h @@ -38,6 +38,8 @@ struct TensorEngine using Tensor = eval::Tensor; using TensorSpec = eval::TensorSpec; using Value = eval::Value; + using map_fun_t = double (*)(double); + using join_fun_t = double (*)(double, double); using BinaryOperation = eval::BinaryOperation; using UnaryOperation = eval::UnaryOperation; using Aggr = eval::Aggr; @@ -57,8 +59,8 @@ struct TensorEngine // havardpe: new API, WIP virtual void encode(const Value &value, nbostream &output, Stash &stash) const = 0; virtual const Value &decode(nbostream &input, Stash &stash) const = 0; - virtual const Value &map(const Value &a, const std::function<double(double)> &function, Stash &stash) const = 0; - virtual const Value &join(const Value &a, const Value &b, const std::function<double(double,double)> &function, Stash &stash) const = 0; + virtual const Value &map(const Value &a, map_fun_t function, Stash &stash) const = 0; + virtual const Value &join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const = 0; virtual const Value &reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const = 0; virtual const Value &concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const = 0; virtual const Value &rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const = 0; diff --git a/eval/src/vespa/eval/eval/test/tensor_conformance.cpp b/eval/src/vespa/eval/eval/test/tensor_conformance.cpp index 8e9c117756b..828c01b47f2 100644 --- a/eval/src/vespa/eval/eval/test/tensor_conformance.cpp +++ b/eval/src/vespa/eval/eval/test/tensor_conformance.cpp @@ -221,8 +221,9 @@ struct ImmediateReduce : Eval { // evaluate tensor map operation using tensor engine immediate api struct ImmediateMap : Eval { - std::function<double(double)> function; - ImmediateMap(const std::function<double(double)> &function_in) : function(function_in) {} + using fun_t = double (*)(double); + fun_t function; + ImmediateMap(fun_t function_in) : function(function_in) {} Result eval(const TensorEngine &engine, const TensorSpec &a) const override { Stash stash; const auto &lhs = make_value(engine, a, stash); @@ -232,8 +233,9 @@ struct ImmediateMap : Eval { // evaluate tensor map operation using tensor engine immediate api struct ImmediateJoin : Eval { - std::function<double(double,double)> function; - ImmediateJoin(const std::function<double(double,double)> &function_in) : function(function_in) {} + using fun_t = double (*)(double, double); + fun_t function; + ImmediateJoin(fun_t function_in) : function(function_in) {} Result eval(const TensorEngine &engine, const TensorSpec &a, const TensorSpec &b) const override { Stash stash; const auto &lhs = make_value(engine, a, stash); @@ -595,9 +597,8 @@ struct TestContext { } void test_map_op(const vespalib::string &expr, const UnaryOperation &op, const Sequence &seq) { - auto function = [&op](double a){ return op.eval(a); }; TEST_DO(test_map_op(ImmediateMapOld(op), op, seq)); - TEST_DO(test_map_op(ImmediateMap(function), op, seq)); + TEST_DO(test_map_op(ImmediateMap(UnaryOperationProxy(op)), op, seq)); TEST_DO(test_map_op(RetainedMap(op), op, seq)); TEST_DO(test_map_op(Expr_T(expr), op, seq)); TEST_DO(test_map_op(Expr_T(make_string("map(x,f(a)(%s))", expr.c_str())), op, seq)); @@ -872,9 +873,8 @@ struct TestContext { } void test_apply_op(const vespalib::string &expr, const BinaryOperation &op, const Sequence &seq) { - auto function = [&op](double a, double b){ return op.eval(a, b); }; TEST_DO(test_apply_op(ImmediateApplyOld(op), op, seq)); - TEST_DO(test_apply_op(ImmediateJoin(function), op, seq)); + TEST_DO(test_apply_op(ImmediateJoin(BinaryOperationProxy(op)), op, seq)); TEST_DO(test_apply_op(RetainedApply(op), op, seq)); TEST_DO(test_apply_op(Expr_TT(expr), op, seq)); TEST_DO(test_apply_op(Expr_TT(make_string("join(x,y,f(a,b)(%s))", expr.c_str())), op, seq)); diff --git a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp index 92a65e96d63..c9ed801dec2 100644 --- a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp +++ b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp @@ -293,13 +293,13 @@ DefaultTensorEngine::decode(nbostream &input, Stash &stash) const //----------------------------------------------------------------------------- const Value & -DefaultTensorEngine::map(const Value &a, const std::function<double(double)> &function, Stash &stash) const +DefaultTensorEngine::map(const Value &a, map_fun_t function, Stash &stash) const { return to_default(simple_engine().map(to_simple(a, stash), function, stash), stash); } const Value & -DefaultTensorEngine::join(const Value &a, const Value &b, const std::function<double(double,double)> &function, Stash &stash) const +DefaultTensorEngine::join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const { return to_default(simple_engine().join(to_simple(a, stash), to_simple(b, stash), function, stash), stash); } diff --git a/eval/src/vespa/eval/tensor/default_tensor_engine.h b/eval/src/vespa/eval/tensor/default_tensor_engine.h index 50ffe709f7c..b4bd717525b 100644 --- a/eval/src/vespa/eval/tensor/default_tensor_engine.h +++ b/eval/src/vespa/eval/tensor/default_tensor_engine.h @@ -33,8 +33,8 @@ public: void encode(const Value &value, nbostream &output, Stash &stash) const override; const Value &decode(nbostream &input, Stash &stash) const override; - const Value &map(const Value &a, const std::function<double(double)> &function, Stash &stash) const override; - const Value &join(const Value &a, const Value &b, const std::function<double(double,double)> &function, Stash &stash) const override; + const Value &map(const Value &a, map_fun_t function, Stash &stash) const override; + const Value &join(const Value &a, const Value &b, join_fun_t function, Stash &stash) const override; const Value &reduce(const Value &a, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) const override; const Value &concat(const Value &a, const Value &b, const vespalib::string &dimension, Stash &stash) const override; const Value &rename(const Value &a, const std::vector<vespalib::string> &from, const std::vector<vespalib::string> &to, Stash &stash) const override; |