thresholds: simplify logic and template

Simplify the Threshold template by turning it into a child-class of the
underlying threshold class and reducing corresponding logic / template
boilerplate.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I0333669cf92255f4d365fedcdb23cbeaf52ba696
diff --git a/thresholds.hpp b/thresholds.hpp
index 31c30e8..e53e496 100644
--- a/thresholds.hpp
+++ b/thresholds.hpp
@@ -11,179 +11,125 @@
 template <typename... T>
 using ServerObject = typename sdbusplus::server::object::object<T...>;
 
-using CriticalIface =
-    sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Critical;
-using CriticalObject = ServerObject<CriticalIface>;
-
-using WarningIface =
-    sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::Warning;
-using WarningObject = ServerObject<WarningIface>;
-
-using SoftShutdownIface =
-    sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::SoftShutdown;
-using SoftShutdownObject = ServerObject<SoftShutdownIface>;
-
-using HardShutdownIface =
-    sdbusplus::xyz::openbmc_project::Sensor::Threshold::server::HardShutdown;
-using HardShutdownObject = ServerObject<HardShutdownIface>;
+namespace threshold_ns =
+    sdbusplus::xyz::openbmc_project::Sensor::Threshold::server;
+using CriticalObject = ServerObject<threshold_ns::Critical>;
+using WarningObject = ServerObject<threshold_ns::Warning>;
+using SoftShutdownObject = ServerObject<threshold_ns::SoftShutdown>;
+using HardShutdownObject = ServerObject<threshold_ns::HardShutdown>;
 
 template <typename T>
-struct Threshold
-{};
+struct Threshold;
 
 template <>
-struct Threshold<WarningObject>
+struct Threshold<WarningObject> : public WarningObject
 {
-  public:
-    static double high(WarningObject* iface)
+    static constexpr auto name = "Warning";
+    using WarningObject::WarningObject;
+
+    auto high()
     {
-        return iface->warningHigh();
+        return warningHigh();
     }
-    static double low(WarningObject* iface)
+    auto low()
     {
-        return iface->warningLow();
+        return warningLow();
     }
 
-    static bool alarmHigh(WarningObject* iface)
+    template <typename... Args>
+    auto alarmHigh(Args... args)
     {
-        return iface->warningAlarmHigh();
+        return warningAlarmHigh(std::forward<Args>(args)...);
     }
 
-    static bool alarmLow(WarningObject* iface)
+    template <typename... Args>
+    auto alarmLow(Args... args)
     {
-        return iface->warningAlarmLow();
-    }
-
-    static void alarmHigh(WarningObject* iface, bool value)
-    {
-        iface->warningAlarmHigh(value);
-    }
-
-    static void alarmLow(WarningObject* iface, bool value)
-    {
-        iface->warningAlarmLow(value);
-    }
-
-    static const char* name()
-    {
-        return "Warning";
+        return warningAlarmLow(std::forward<Args>(args)...);
     }
 };
 
 template <>
-struct Threshold<CriticalObject>
+struct Threshold<CriticalObject> : public CriticalObject
 {
-  public:
-    static double high(CriticalObject* iface)
+    static constexpr auto name = "Critical";
+    using CriticalObject::CriticalObject;
+
+    auto high()
     {
-        return iface->criticalHigh();
+        return criticalHigh();
     }
-    static double low(CriticalObject* iface)
+    auto low()
     {
-        return iface->criticalLow();
+        return criticalLow();
     }
 
-    static bool alarmHigh(CriticalObject* iface)
+    template <typename... Args>
+    auto alarmHigh(Args... args)
     {
-        return iface->criticalAlarmHigh();
+        return criticalAlarmHigh(std::forward<Args>(args)...);
     }
 
-    static bool alarmLow(CriticalObject* iface)
+    template <typename... Args>
+    auto alarmLow(Args... args)
     {
-        return iface->criticalAlarmLow();
-    }
-
-    static void alarmHigh(CriticalObject* iface, bool value)
-    {
-        iface->criticalAlarmHigh(value);
-    }
-
-    static void alarmLow(CriticalObject* iface, bool value)
-    {
-        iface->criticalAlarmLow(value);
-    }
-
-    static const char* name()
-    {
-        return "Critical";
+        return criticalAlarmLow(std::forward<Args>(args)...);
     }
 };
 
 template <>
-struct Threshold<SoftShutdownObject>
+struct Threshold<SoftShutdownObject> : public SoftShutdownObject
 {
-  public:
-    static double high(SoftShutdownObject* iface)
+    static constexpr auto name = "SoftShutdown";
+    using SoftShutdownObject::SoftShutdownObject;
+
+    auto high()
     {
-        return iface->softShutdownHigh();
+        return softShutdownHigh();
     }
-    static double low(SoftShutdownObject* iface)
+    auto low()
     {
-        return iface->softShutdownLow();
+        return softShutdownLow();
     }
 
-    static bool alarmHigh(SoftShutdownObject* iface)
+    template <typename... Args>
+    auto alarmHigh(Args... args)
     {
-        return iface->softShutdownAlarmHigh();
+        return softShutdownAlarmHigh(std::forward<Args>(args)...);
     }
 
-    static bool alarmLow(SoftShutdownObject* iface)
+    template <typename... Args>
+    auto alarmLow(Args... args)
     {
-        return iface->softShutdownAlarmLow();
-    }
-
-    static void alarmHigh(SoftShutdownObject* iface, bool value)
-    {
-        iface->softShutdownAlarmHigh(value);
-    }
-
-    static void alarmLow(SoftShutdownObject* iface, bool value)
-    {
-        iface->softShutdownAlarmLow(value);
-    }
-
-    static const char* name()
-    {
-        return "SoftShutdown";
+        return softShutdownAlarmLow(std::forward<Args>(args)...);
     }
 };
 
 template <>
-struct Threshold<HardShutdownObject>
+struct Threshold<HardShutdownObject> : public HardShutdownObject
 {
-  public:
-    static double high(HardShutdownObject* iface)
+    static constexpr auto name = "HardShutdown";
+    using HardShutdownObject::HardShutdownObject;
+
+    auto high()
     {
-        return iface->hardShutdownHigh();
+        return hardShutdownHigh();
     }
-    static double low(HardShutdownObject* iface)
+    auto low()
     {
-        return iface->hardShutdownLow();
+        return hardShutdownLow();
     }
 
-    static bool alarmHigh(HardShutdownObject* iface)
+    template <typename... Args>
+    auto alarmHigh(Args... args)
     {
-        return iface->hardShutdownAlarmHigh();
+        return hardShutdownAlarmHigh(std::forward<Args>(args)...);
     }
 
-    static bool alarmLow(HardShutdownObject* iface)
+    template <typename... Args>
+    auto alarmLow(Args... args)
     {
-        return iface->hardShutdownAlarmLow();
-    }
-
-    static void alarmHigh(HardShutdownObject* iface, bool value)
-    {
-        iface->hardShutdownAlarmHigh(value);
-    }
-
-    static void alarmLow(HardShutdownObject* iface, bool value)
-    {
-        iface->hardShutdownAlarmLow(value);
-    }
-
-    static const char* name()
-    {
-        return "HardShutdown";
+        return hardShutdownAlarmLow(std::forward<Args>(args)...);
     }
 };
 
diff --git a/virtualSensor.cpp b/virtualSensor.cpp
index 74b04f7..a67077b 100644
--- a/virtualSensor.cpp
+++ b/virtualSensor.cpp
@@ -88,8 +88,8 @@
         if (threshold.contains("CriticalHigh") ||
             threshold.contains("CriticalLow"))
         {
-            criticalIface =
-                std::make_unique<CriticalObject>(bus, objPath.c_str());
+            criticalIface = std::make_unique<Threshold<CriticalObject>>(
+                bus, objPath.c_str());
 
             criticalIface->criticalHigh(threshold.value(
                 "CriticalHigh", std::numeric_limits<double>::quiet_NaN()));
@@ -100,8 +100,8 @@
         if (threshold.contains("WarningHigh") ||
             threshold.contains("WarningLow"))
         {
-            warningIface =
-                std::make_unique<WarningObject>(bus, objPath.c_str());
+            warningIface = std::make_unique<Threshold<WarningObject>>(
+                bus, objPath.c_str());
 
             warningIface->warningHigh(threshold.value(
                 "WarningHigh", std::numeric_limits<double>::quiet_NaN()));
@@ -112,8 +112,8 @@
         if (threshold.contains("HardShutdownHigh") ||
             threshold.contains("HardShutdownLow"))
         {
-            hardShutdownIface =
-                std::make_unique<HardShutdownObject>(bus, objPath.c_str());
+            hardShutdownIface = std::make_unique<Threshold<HardShutdownObject>>(
+                bus, objPath.c_str());
 
             hardShutdownIface->hardShutdownHigh(threshold.value(
                 "HardShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
@@ -124,8 +124,8 @@
         if (threshold.contains("SoftShutdownHigh") ||
             threshold.contains("SoftShutdownLow"))
         {
-            softShutdownIface =
-                std::make_unique<SoftShutdownObject>(bus, objPath.c_str());
+            softShutdownIface = std::make_unique<Threshold<SoftShutdownObject>>(
+                bus, objPath.c_str());
 
             softShutdownIface->softShutdownHigh(threshold.value(
                 "SoftShutdownHigh", std::numeric_limits<double>::quiet_NaN()));
@@ -248,10 +248,10 @@
         std::cout << "Sensor value is " << val << "\n";
 
     /* Check sensor thresholds and log required message */
-    checkThresholds(val, warningIface.get());
-    checkThresholds(val, criticalIface.get());
-    checkThresholds(val, softShutdownIface.get());
-    checkThresholds(val, hardShutdownIface.get());
+    checkThresholds(val, warningIface);
+    checkThresholds(val, criticalIface);
+    checkThresholds(val, softShutdownIface);
+    checkThresholds(val, hardShutdownIface);
 }
 
 /** @brief Parsing Virtual Sensor config JSON file  */
diff --git a/virtualSensor.hpp b/virtualSensor.hpp
index 13e342c..62042d8 100644
--- a/virtualSensor.hpp
+++ b/virtualSensor.hpp
@@ -108,13 +108,13 @@
     exprtk::rtl::vecops::package<double> vecopsPackage;
 
     /** @brief The critical threshold interface object */
-    std::unique_ptr<CriticalObject> criticalIface;
+    std::unique_ptr<Threshold<CriticalObject>> criticalIface;
     /** @brief The warning threshold interface object */
-    std::unique_ptr<WarningObject> warningIface;
+    std::unique_ptr<Threshold<WarningObject>> warningIface;
     /** @brief The soft shutdown threshold interface object */
-    std::unique_ptr<SoftShutdownObject> softShutdownIface;
+    std::unique_ptr<Threshold<SoftShutdownObject>> softShutdownIface;
     /** @brief The hard shutdown threshold interface object */
-    std::unique_ptr<HardShutdownObject> hardShutdownIface;
+    std::unique_ptr<Threshold<HardShutdownObject>> hardShutdownIface;
 
     /** @brief Read config from json object and initialize sensor data
      * for each virtual sensor
@@ -123,50 +123,47 @@
                            const std::string& objPath);
 
     /** @brief Check Sensor threshold and update alarm and log */
-    template <typename T>
-    void checkThresholds(double value, T* iface)
+    template <typename V, typename T>
+    void checkThresholds(V value, T& threshold)
     {
-        if (iface)
-        {
-            if (value >= Threshold<T>::high(iface))
-            {
-                if (!Threshold<T>::alarmHigh(iface))
-                {
-                    Threshold<T>::alarmHigh(iface, true);
-                    log<level::ERR>(fmt::format("ASSERT: {} has exceeded the "
-                                                "{} high threshold",
-                                                name, Threshold<T>::name())
-                                        .c_str());
-                }
-            }
-            else if (Threshold<T>::alarmHigh(iface))
-            {
-                Threshold<T>::alarmHigh(iface, false);
-                log<level::INFO>(fmt::format("DEASSERT: {} is under the "
-                                             "{} high threshold",
-                                             name, Threshold<T>::name())
-                                     .c_str());
-            }
+        if (!threshold)
+            return;
 
-            if (value <= Threshold<T>::low(iface))
+        static constexpr auto tname = T::element_type::name;
+
+        auto alarmHigh = threshold->alarmHigh();
+        if ((!alarmHigh && value >= threshold->high()) || alarmHigh)
+        {
+            if (!alarmHigh)
             {
-                if (!Threshold<T>::alarmLow(iface))
-                {
-                    Threshold<T>::alarmLow(iface, true);
-                    log<level::ERR>(fmt::format("ASSERT: {} is under the "
-                                                "{} high threshold",
-                                                name, Threshold<T>::name())
-                                        .c_str());
-                }
+                constexpr auto msg =
+                    "ASSERT: {} has exceeded the {} high threshold";
+                log<level::ERR>(fmt::format(msg, name, tname).c_str());
             }
-            else if (Threshold<T>::alarmLow(iface))
+            else
             {
-                Threshold<T>::alarmLow(iface, false);
-                log<level::INFO>(fmt::format("DEASSERT: {} is above the "
-                                             "{} high threshold",
-                                             name, Threshold<T>::name())
-                                     .c_str());
+                constexpr auto msg =
+                    "DEASSERT: {} is under the {} high threshold";
+                log<level::INFO>(fmt::format(msg, name, tname).c_str());
             }
+            threshold->alarmHigh(!alarmHigh);
+        }
+
+        auto alarmLow = threshold->alarmLow();
+        if ((!alarmLow && value <= threshold->low()) || alarmLow)
+        {
+            if (!alarmLow)
+            {
+                constexpr auto msg = "ASSERT: {} is under the {} low threshold";
+                log<level::ERR>(fmt::format(msg, name, tname).c_str());
+            }
+            else
+            {
+                constexpr auto msg =
+                    "DEASSERT: {} is above the {} low threshold";
+                log<level::INFO>(fmt::format(msg, name, tname).c_str());
+            }
+            threshold->alarmLow(!alarmLow);
         }
     }
 };