base: Make the Value stat's functor method accept lambdas.
authorGabe Black <gabeblack@google.com>
Wed, 19 Aug 2020 03:48:06 +0000 (20:48 -0700)
committerGabe Black <gabeblack@google.com>
Tue, 1 Sep 2020 21:57:34 +0000 (21:57 +0000)
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>

src/base/statistics.hh
src/unittest/stattest.cc

index 96cd43fec776036bc4cc781ec40717487cf61bf8..c66454053cc6f83197f47430b77552428abb7caf 100644 (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)
index 883185a1ebca5777dfe54f5656eff0fed3ea738d..40307357c520d376975146a98a2f4e304b80cc9c 100644 (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;
 
 }