NVMe: Add constructor of MetricStore to support a range

Now the MetricStore can be constructed with iterators of pointer to
Metrics.

This constructor is needed because the Metric collection can be
determined at runtime instead of compile time.

Change-Id: I558d235a8d42ac91386a8a0f1df3ac311aa05c27
Signed-off-by: Hao Jiang <jianghao@google.com>
diff --git a/src/NVMeController.cpp b/src/NVMeController.cpp
index 3befc25..e4a5ab4 100644
--- a/src/NVMeController.cpp
+++ b/src/NVMeController.cpp
@@ -299,11 +299,13 @@
                       std::chrono::seconds(900)))
             : std::shared_ptr<HostTelemetryMetric>();
 
+    std::list<std::shared_ptr<MetricBase<SchedulerClockType>>> metrics{
+        std::move(identify), std::move(errorInfo), std::move(smart),
+        std::move(fwSlot),   std::move(selfTest),  std::move(hostTelemetry)};
+
     this->metricStore.emplace(
         this->NVMeController::io, this->NVMeController::conn,
-        this->NVMeController::path, std::move(identify), std::move(errorInfo),
-        std::move(smart), std::move(fwSlot), std::move(selfTest),
-        std::move(hostTelemetry));
+        this->NVMeController::path, metrics.begin(), metrics.end());
 }
 
 void NVMeControllerEnabled::start(
diff --git a/src/NVMeMetricStore.hpp b/src/NVMeMetricStore.hpp
index 1d22c39..97ddaa8 100644
--- a/src/NVMeMetricStore.hpp
+++ b/src/NVMeMetricStore.hpp
@@ -59,50 +59,44 @@
         validFlag(std::make_shared<bool>())
     {
         metricStore.erase("");
-        auto vuMetrics = getVendorMatrics(path);
-        for (auto& metric : vuMetrics)
-        {
-            if (!metric)
-            {
-                continue;
-            }
-            auto [itr, res] = metricStore.try_emplace(
-                std::string{metric->getIdentifier()}, std::move(metric));
-            if (!res)
-            {
-                lg2::warning("drop a duplicated vendor metic", "PATH", path,
-                             "METRIC", itr->first);
-            }
-        }
+        insertVUMetrics();
+        emit_added();
+    }
 
-        std::vector<std::string> idCollection;
-        decltype(validFlag)::weak_type weakFlag = validFlag;
-        for (auto& [identifier, metric] : metricStore)
-        {
-            idCollection.push_back(identifier);
-            std::weak_ptr<MetricBase<std::chrono::steady_clock>> weakMetric =
-                metric;
-            metric->registerCompleteCB([this, weakFlag, identifier, weakMetric,
-                                        path{objectPath}](std::error_code ec) {
-                // use validFlag to protect this call
-                if (weakFlag.expired())
+    template <class Itr>
+        requires(std::is_base_of_v<
+                    MetricBase<std::chrono::steady_clock>,
+                    typename std::pointer_traits<
+                        typename std::iter_value_t<Itr>>::element_type>)
+    MetricStore(boost::asio::io_context& io,
+                const std::shared_ptr<sdbusplus::asio::connection>& conn,
+                const std::string& objectPath, const Itr& begin,
+                const Itr& end) :
+        sdbusplus::xyz::openbmc_project::NVMe::server::MetricStore(
+            dynamic_cast<sdbusplus::bus_t&>(*conn), objectPath.c_str()),
+        path(objectPath), io(io),
+        metricStore([&objectPath](const Itr& begin, const Itr& end) {
+            std::unordered_map<std::string, std::shared_ptr<MetricBase<>>> temp;
+            for (auto itr = begin; itr != end; ++itr)
+            {
+                auto& metric = *itr;
+                if (!metric || metric->getIdentifier().empty())
                 {
-                    lg2::info("MetricStore interface expired, update signal "
-                              "skipped.",
-                              "PATH", path);
-                    return;
+                    continue;
                 }
-                auto metric = weakMetric.lock();
-                if (ec || !metric)
+                auto [emplaceItr, res] = temp.try_emplace(
+                    std::string{metric->getIdentifier()}, metric);
+                if (!res)
                 {
-                    // broadcast invalid metric signal
-                    this->signalHelper(identifier, {});
+                    lg2::warning("drop a duplicated metric", "PATH", objectPath,
+                                 "METRIC", emplaceItr->first);
                 }
-                this->signalHelper(identifier, metric);
-            });
-            metric->refresh({});
-        }
-        metricCollection(std::move(idCollection), true);
+            }
+            return temp;
+        }(begin, end)),
+        validFlag(std::make_shared<bool>())
+    {
+        insertVUMetrics();
         emit_added();
     }
     ~MetricStore() override
@@ -147,6 +141,54 @@
         const std::shared_ptr<MetricBase<std::chrono::steady_clock>>&
             metric) noexcept;
 
+    inline void insertVUMetrics()
+    {
+        auto vuMetrics = getVendorMatrics(path);
+        for (auto& metric : vuMetrics)
+        {
+            if (!metric)
+            {
+                continue;
+            }
+            auto [itr, res] = metricStore.try_emplace(
+                std::string{metric->getIdentifier()}, std::move(metric));
+            if (!res)
+            {
+                lg2::warning("drop a duplicated vendor metric", "PATH", path,
+                             "METRIC", itr->first);
+            }
+        }
+
+        std::vector<std::string> idCollection;
+        decltype(validFlag)::weak_type weakFlag = validFlag;
+        for (auto& [identifier, metric] : metricStore)
+        {
+            idCollection.push_back(identifier);
+            std::weak_ptr<MetricBase<std::chrono::steady_clock>> weakMetric =
+                metric;
+            metric->registerCompleteCB([this, weakFlag, identifier, weakMetric,
+                                        path{path}](std::error_code ec) {
+                // use validFlag to protect this call
+                if (weakFlag.expired())
+                {
+                    lg2::info("MetricStore interface expired, update signal "
+                              "skipped.",
+                              "PATH", path);
+                    return;
+                }
+                auto metric = weakMetric.lock();
+                if (ec || !metric)
+                {
+                    // broadcast invalid metric signal
+                    this->signalHelper(identifier, {});
+                }
+                this->signalHelper(identifier, metric);
+            });
+            metric->refresh({});
+        }
+        metricCollection(std::move(idCollection), true);
+    }
+
     std::string path;
     boost::asio::io_context& io;
     std::unordered_map<std::string, std::shared_ptr<MetricBase<>>> metricStore;