summaryrefslogtreecommitdiffstats
path: root/eval
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2017-10-19 13:30:50 +0000
committerHåvard Pettersen <havardpe@oath.com>2017-10-19 13:33:42 +0000
commit4ad63aeca673e665a773cda0c5a61b85940f7d18 (patch)
treed625e0b079113257b2383bb24b86375ad87bf836 /eval
parentb2bca50263aa1a7dbd3c30b932296507bce0db7a (diff)
use raw function pointers for map/join
Diffstat (limited to 'eval')
-rw-r--r--eval/src/vespa/eval/eval/operation.cpp29
-rw-r--r--eval/src/vespa/eval/eval/operation.h36
-rw-r--r--eval/src/vespa/eval/eval/simple_tensor.cpp4
-rw-r--r--eval/src/vespa/eval/eval/simple_tensor.h7
-rw-r--r--eval/src/vespa/eval/eval/simple_tensor_engine.cpp8
-rw-r--r--eval/src/vespa/eval/eval/simple_tensor_engine.h4
-rw-r--r--eval/src/vespa/eval/eval/tensor_engine.h6
-rw-r--r--eval/src/vespa/eval/eval/test/tensor_conformance.cpp16
-rw-r--r--eval/src/vespa/eval/tensor/default_tensor_engine.cpp4
-rw-r--r--eval/src/vespa/eval/tensor/default_tensor_engine.h4
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;