COMPMID-663: Reworked / cleaned up instuments' measurements

Everything used to be stored as double which led to some numbers appearing in scientific notation and some counters values getting corrupted.
Now measurements can be stored as either floating point or integer values.

Added support for raw_data in order to output more detailed information to the JSON files (Will make use of that in the OpenCL timer instrument)

Change-Id: Ie83776b347a764c8bf45b47d7d9d7bec02b04257
Reviewed-on: http://mpd-gerrit.cambridge.arm.com/95035
Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com>
Reviewed-by: Gian Marco Iodice <gianmarco.iodice@arm.com>
Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com>
diff --git a/tests/framework/instruments/Measurement.h b/tests/framework/instruments/Measurement.h
index 324fd51..08624f3 100644
--- a/tests/framework/instruments/Measurement.h
+++ b/tests/framework/instruments/Measurement.h
@@ -25,7 +25,9 @@
 #define ARM_COMPUTE_TEST_MEASUREMENT
 
 #include "../Utils.h"
+#include "arm_compute/core/Error.h"
 
+#include <list>
 #include <ostream>
 #include <string>
 
@@ -35,67 +37,204 @@
 {
 namespace framework
 {
-/** Abstract measurement.
- *
- * Every measurement needs to define it's unit.
- */
-struct IMeasurement
+/** Generic measurement that stores values as either double or long long int. */
+struct Measurement
 {
-    /** Constructor.
-     *
-     * @param[in] unit Unit of the measurement.
-     */
-    explicit IMeasurement(std::string unit)
-        : unit{ std::move(unit) }
+    struct Value
     {
+        /** Constructor
+         *
+         * @param[in] is_floating Will the value stored be floating point ?
+         */
+        Value(bool is_floating)
+            : v{ 0 }, is_floating_point(is_floating)
+        {
+        }
+
+        /** Add the value stored to the stream as a string
+         */
+        friend std::ostream &operator<<(std::ostream &os, const Value &value)
+        {
+            if(value.is_floating_point)
+            {
+                os << arithmetic_to_string(value.v.floating_point);
+            }
+            else
+            {
+                os << arithmetic_to_string(value.v.integer);
+            }
+            return os;
+        }
+        /** Convert the value stored to string
+         */
+        std::string to_string() const
+        {
+            std::stringstream ss;
+            ss << *this;
+            return ss.str();
+        }
+        /** Add with another value and return the sum
+         *
+         * @param[in] b Other value
+         *
+         * @return Sum of the stored value + b
+         */
+        Value operator+(Value b) const
+        {
+            if(is_floating_point)
+            {
+                b.v.floating_point += v.floating_point;
+            }
+            else
+            {
+                b.v.integer += v.integer;
+            }
+            return b;
+        }
+
+        /** Return the stored value divided by an integer.
+         *
+         * @param[in] b Integer to divide the value by.
+         *
+         * @return Stored value / b
+         */
+        Value operator/(int b) const
+        {
+            Value res(is_floating_point);
+            if(is_floating_point)
+            {
+                res.v.floating_point = v.floating_point / b;
+            }
+            else
+            {
+                res.v.integer = v.integer / b;
+            }
+            return res;
+        }
+
+        /** Subtract another value and return the updated stored value.
+         *
+         * @param[in] b Other value
+         *
+         * @return The updated stored value
+         */
+        Value &operator-=(const Value &b)
+        {
+            if(is_floating_point)
+            {
+                v.floating_point -= b.v.floating_point;
+            }
+            else
+            {
+                v.integer -= b.v.integer;
+            }
+            return *this;
+        }
+
+        /** Compare the stored value with another value
+         *
+         * @param[in] b Value to compare against
+         *
+         * @return The result of stored value < b
+         */
+        bool operator<(const Value &b) const
+        {
+            if(is_floating_point)
+            {
+                return v.floating_point < b.v.floating_point;
+            }
+            else
+            {
+                return v.integer < b.v.integer;
+            }
+        }
+
+        /** Stored value */
+        union
+            {
+                double        floating_point;
+                long long int integer;
+            } v;
+        bool is_floating_point; /**< Is the stored value floating point or integer ? */
+    };
+
+    /** Stream output operator to print the measurement.
+     *
+     * Prints value and unit.
+     */
+    friend inline std::ostream &operator<<(std::ostream &os, const Measurement &measurement)
+    {
+        os << measurement._value << " " << measurement._unit;
+        return os;
     }
 
-    std::string unit;
-};
-
-/** Measurement of a specific type. */
-template <typename T>
-struct TypedMeasurement : public IMeasurement
-{
-    /** Constructor.
+    /** Constructor to store a floating point value
      *
-     * @param[in] value Measured value.
-     * @param[in] unit  Unit of the Measurement.
+     * @param[in] v    Value to store
+     * @param[in] unit Unit of @p v
+     * @param[in] raw  (Optional) The raw value(s) @p was generated from.
      */
-    TypedMeasurement(T value, std::string unit)
-        : IMeasurement(std::move(unit)), value{ value }
+    template < typename Floating, typename std::enable_if < !std::is_integral<Floating>::value, int >::type = 0 >
+    Measurement(Floating v, std::string unit, std::list<std::string> raw = {})
+        : _unit(unit), _raw_data(std::move(raw)), _value(true)
     {
+        _value.v.floating_point = static_cast<double>(v);
+        if(_raw_data.empty())
+        {
+            _raw_data = { _value.to_string() };
+        }
     }
 
-    T value;
-};
-
-/** Stream output operator to print the measurement.
- *
- * Prints value and unit.
- */
-template <typename T>
-inline std::ostream &operator<<(std::ostream &os, const TypedMeasurement<T> &measurement)
-{
-    os << measurement.value << measurement.unit;
-    return os;
-}
-
-/** Generic measurement that stores values as double. */
-struct Measurement : public TypedMeasurement<double>
-{
-    using TypedMeasurement::TypedMeasurement;
-
-    /** Conversion constructor.
+    /** Constructor to store an integer value
      *
-     * @param[in] measurement Typed measurement.
+     * @param[in] v    Value to store
+     * @param[in] unit Unit of @p v
+     * @param[in] raw  (Optional) The raw value(s) @p was generated from.
      */
-    template <typename T>
-    Measurement(TypedMeasurement<T> measurement)
-        : Measurement(measurement.value, measurement.unit)
+    template <typename Integer, typename std::enable_if<std::is_integral<Integer>::value, int>::type = 0>
+    Measurement(Integer v, std::string unit, std::list<std::string> raw = {})
+        : _unit(unit), _raw_data(std::move(raw)), _value(false)
     {
+        _value.v.integer = static_cast<long long int>(v);
+        if(_raw_data.empty())
+        {
+            _raw_data = { _value.to_string() };
+        }
     }
+
+    /** Accessor for the unit of the measurement
+     *
+     * @return Unit of the measurement
+     */
+    const std::string &unit() const
+    {
+        return _unit;
+    }
+
+    /** Accessor for the raw data
+     *
+     * @return The raw data
+     */
+    const std::list<std::string> &raw_data() const
+    {
+        return _raw_data;
+    }
+
+    /** Accessor for the stored value
+     *
+     * @return The stored value
+     */
+    const Value &value() const
+    {
+        return _value;
+    }
+
+private:
+    std::string            _unit;
+    std::list<std::string> _raw_data;
+    Value                  _value;
 };
+
 } // namespace framework
 } // namespace test
 } // namespace arm_compute