base: Make the Value stat's functor method accept lambdas.

This class can already accept a proxy variable and a "functor" which is
a pointer to either a function or an instance of a class with the ()
operator overloaded.

This change adds a FunctorProxy partial specialization which accepts
anything that can be used to construct a std::function<Result()>. The
constructor argument is copied and stored in the proxy which makes it
possible to define a lambda inline without having to keep a copy of it
around for the proxy to point to.

Also, the ValueBase stat's functor method now has a second version which
accepts a const reference rather than just a reference to its argument.
We need both because when accepting a reference to a lambda it needs to
be a const reference, but when accepting a pointer to a functor object,
we don't want it to be const because that would force the () operator to
also be const.

Change-Id: Icb1b3682d51b721f6e16614490ed0fe289cee094
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/32901
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
This commit is contained in:
Gabe Black
2020-08-18 20:48:06 -07:00
parent f0e63088ab
commit e020184843
2 changed files with 50 additions and 13 deletions

View File

@@ -791,7 +791,7 @@ class ValueProxy : public ProxyInfo
Result total() const { return *scalar; }
};
template <class T>
template <class T, class Enabled=void>
class FunctorProxy : public ProxyInfo
{
private:
@@ -804,6 +804,27 @@ class FunctorProxy : public ProxyInfo
Result total() const { return (*functor)(); }
};
/**
* Template specialization for type std::function<Result()> which holds a copy
* of its target instead of a pointer to it. This makes it possible to use a
* lambda or other type inline without having to keep track of an instance
* somewhere else.
*/
template <class T>
class FunctorProxy<T,
typename std::enable_if<std::is_constructible<std::function<Result()>,
const T &>::value>::type> : public ProxyInfo
{
private:
std::function<Result()> functor;
public:
FunctorProxy(const T &func) : functor(func) {}
Counter value() const { return functor(); }
Result result() const { return functor(); }
Result total() const { return functor(); }
};
/**
* A proxy similar to the FunctorProxy, but allows calling a method of a bound
* object, instead of a global free-standing function.
@@ -847,6 +868,15 @@ class ValueBase : public DataWrap<Derived, ScalarInfoProxy>
return this->self();
}
template <class T>
Derived &
functor(const T &func)
{
proxy = new FunctorProxy<T>(func);
this->setInit();
return this->self();
}
template <class T>
Derived &
functor(T &func)

View File

@@ -88,6 +88,7 @@ struct StatTest
Vector2d s16;
Value s17;
Value s18;
Value s19;
Histogram h01;
Histogram h02;
Histogram h03;
@@ -102,8 +103,8 @@ struct StatTest
Histogram h12;
SparseHistogram sh1;
Vector s19;
Vector s20;
Vector s21;
Formula f1;
Formula f2;
@@ -254,6 +255,12 @@ StatTest::init()
.desc("this is stat 18")
;
s19
.functor([]() { return 0; })
.name("Stat19")
.desc("this is stat 19")
;
h01
.init(11)
.name("Histogram01")
@@ -361,18 +368,18 @@ StatTest::init()
.desc("this is formula 4")
;
s19
.init(2)
.name("Stat19")
.desc("this is statistic 19 for vector op testing")
.flags(total | nozero | nonan)
;
s20
.init(2)
.name("Stat20")
.desc("this is statistic 20 for vector op testing")
.flags(total | nozero | nonan)
;
s21
.init(2)
.name("Stat21")
.desc("this is statistic 21 for vector op testing")
.flags(total | nozero | nonan)
;
f6
.name("vector_op_test_formula")
@@ -386,7 +393,7 @@ StatTest::init()
f4 += constant(10.0);
f4 += s5[3];
f5 = constant(1);
f6 = s19/s20;
f6 = s20/s21;
}
void
@@ -663,10 +670,10 @@ StatTest::run()
sh1.sample(random() % 10000);
}
s19[0] = 1;
s19[1] = 100000;
s20[0] = 100000;
s20[1] = 1;
s20[0] = 1;
s20[1] = 100000;
s21[0] = 100000;
s21[1] = 1;
}